montana/Formal-Docs/02-Spec/SSOT-Rust.md
2026-05-26 21:14:51 +03:00

73 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SSOT — Rust как единственный источник истины криптографии и протокола
Статус: **обязательный архитектурный инвариант** Montana. Применяется ко всему коду, выпускаемому под именем Montana. Нарушение блокирует релиз.
## Правило
Любая криптографическая, ключевая или протокольная операция — **мнемоника → master_seed**, **derive_account_id**, **derive_node_id**, **ML-DSA-65 / ML-KEM-768 keygen / sign / verify / encap / decap**, **Transaction encoding и подпись**, **state-root computation**, **проверка балансов и переводов** — определена **ровно в одном месте**: Rust-крейтах `Montana/Montana-Protocol/Code/crates/`.
Канонические крейты:
- [`mt-mnemonic`](../../Montana-Protocol/Code/crates/mt-mnemonic/) — 24 слова → master_seed (PBKDF2-HMAC-SHA-256, 2²⁰ итераций, salt `"mt-seed"`); HKDF-Expand для ролей.
- [`mt-crypto`](../../Montana-Protocol/Code/crates/mt-crypto/) — ML-DSA-65 (FIPS 204), ML-KEM-768 (FIPS 203), детерминированные keypair/sign/verify через OpenSSL FIPS provider (через `mt-crypto-native`).
- [`mt-codec`](../../Montana-Protocol/Code/crates/mt-codec/) — domain separators (`b"mt-seed"`, `b"mt-account-key"`, `b"mt-node-key"`, …), canonical byte encoding.
- [`mt-state`](../../Montana-Protocol/Code/crates/mt-state/) — `derive_account_id(suite_id, pubkey) = SHA-256("mt-account" || suite_id_LE || pubkey)`; AccountTable, NodeTable.
- [`mt-account`](../../Montana-Protocol/Code/crates/mt-account/) — Transaction (Transfer / ChangeKey / Anchor / TransferActivation), правила signed_scope, settlement.
Все эти крейты экспортируются через единственный фасад: [`crates/mt-bindings`](../../Montana-Protocol/Code/crates/mt-bindings/) — стабильный C ABI (для iOS/macOS staticlib и Android cdylib) + WASM-binding (для веба).
## Запреты
Нативный клиент Montana (iOS Swift, Android Kotlin/Java, веб JS/TS, macOS Swift, любой будущий) **не имеет права**:
1. Реализовывать **PBKDF2 / HMAC / HKDF / SHA-256** на месте — должен вызывать через FFI.
2. Реализовывать **ML-DSA-65 / ML-KEM-768 / Ed25519-substitute** для генерации ключей или подписи Montana-операций.
3. Иметь свою формулу **address derivation** — только `mt_derive_account_id`.
4. Кодировать `Transaction` своим способом — только через `mt-account` или его экспорт.
5. Хранить дублирующие константы (`PUBKEY_SIZE`, `KDF_ITER`, salts, suite_id) — все берутся из `mt_bindings.h` / Kotlin `MtBindings.*` / WASM exports.
## Эталонный KAT-вектор
`crates/mt-bindings/tests/kat_cross_client.rs` фиксирует:
```
entropy = 32 × 0x00
mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon
abandon abandon abandon abandon abandon abandon abandon abandon
abandon abandon abandon abandon abandon abandon abandon art"
master[..8] = 38a1421ac3ce191f
acc_seed = 08ce5c19768c679fda24c0d3360e57ce03d00c94c175e59f50e9c77894c20818
pubkey[..16] = c1b89f8277a6cec0818419e69add3892
account_id = 9f199584ed120b987b617ba5bff829e176f23e5465dd70cfac5c141dfb131a21
```
Каждый клиент (Swift через `MontanaBindings`, Kotlin через `libmontana.so`, JS через `mt_bindings.wasm`) обязан содержать конформанс-тест, который:
1. Принимает мнемонику-эталон.
2. Вызывает свой биндинг.
3. Сравнивает байт-в-байт с `account_id = 9f199584ed120b987b617ba5bff829e176f23e5465dd70cfac5c141dfb131a21`.
Расхождение хоть в одном бите = клиент сломан, релиз блокируется.
## Сборка артефактов
| Цель | Команда | Артефакт |
|---|---|---|
| macOS arm64 (host) | `cargo build -p mt-bindings --release` | `target/release/libmt_bindings.{a,dylib}` |
| iOS sim arm64 | `cargo build -p mt-bindings --release --target aarch64-apple-ios-sim` | `target/aarch64-apple-ios-sim/release/libmt_bindings.a` |
| iOS device arm64 | `cargo build -p mt-bindings --release --target aarch64-apple-ios` | (требует iOS-OpenSSL cross — отдельная задача) |
| Android arm64 | `cargo ndk -t arm64-v8a build -p mt-bindings --release` | `libmt_bindings.so` |
| Android x86_64 | `cargo ndk -t x86_64 build -p mt-bindings --release` | `libmt_bindings.so` |
| Web | `wasm-pack build crates/mt-bindings --target web --features wasm` | `pkg/mt_bindings.js` + `.wasm` |
C-заголовок: [`crates/mt-bindings/include/mt_bindings.h`](../../Montana-Protocol/Code/crates/mt-bindings/include/mt_bindings.h).
## Жизненный цикл изменений
1. Меняется крипто-параметр (например, KDF_ITER или новый suite_id) → меняется **Rust** + обновляется KAT-вектор.
2. После изменения Rust — пересобирается `mt-bindings`, переразлитваются артефакты для iOS/Android/Web.
3. CI прогоняет KAT во всех клиентах. Любое расхождение = abort.
4. ABI breaking changes — bump `MT_ABI_VERSION` в `lib.rs`; клиенты должны проверить `mt_abi_version()` до использования.
## История
- **2026-05-24** — введение инварианта. До этого: iOS, Android, веб реализовывали PBKDF2 / address / signing самостоятельно с расходящимися параметрами (600k итераций vs 2²⁰, "mt+SHA256(pk)[:20]" vs canonical SHA256-with-domain, Ed25519 vs ML-DSA). Это блокировало байт-точные переводы между клиентами. Mt-bindings и эта спека закрывают расхождение.