73 lines
6.3 KiB
Markdown
73 lines
6.3 KiB
Markdown
# 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 и эта спека закрывают расхождение.
|