# Приложение А. Тест-векторы BIP39 + Montana derivation ## Эталонные BIP39 тест-векторы (из BIP39 spec) ### Vector 1 — 256-bit zero entropy | Поле | Значение | |------|----------| | Entropy (hex) | `0000000000000000000000000000000000000000000000000000000000000000` | | Mnemonic (24 words) | `abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art` | | Seed (PBKDF2-HMAC-SHA512, salt="mnemonic", iter=2048, 64B) | `bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8` | ### Vector 2 — 256-bit max entropy | Поле | Значение | |------|----------| | Entropy (hex) | `ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff` | | Mnemonic (24 words) | `zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote` | ### Vector 3 — стандартный non-trivial | Поле | Значение | |------|----------| | Entropy (hex) | `2041546864449caff939d32d574753fe684d3c947c3346713dd8423e74abcf8c` | | Mnemonic | `cake apple borrow silk endorse fitness top denial coil riot stay wolf luggage oxygen faint major edit measure invite love trap field dilemma oblige` | --- ## Montana-специфичные тест-векторы (mnemonic → address) **Algorithm:** ``` seed = PBKDF2-HMAC-SHA512(NFKD(mnemonic), salt="mnemonic", iter=2048, 64B) preimage = ASCII("montana-v1:") || seed [11 + 64 = 75 bytes] hash = SHA-256(preimage) [32 bytes] address = hash[0..20] → 40 hex characters ``` ### Vector M-1 — zero entropy | Поле | Значение | |------|----------| | Mnemonic | `abandon abandon ... abandon art` (Vector 1 выше) | | Seed (hex) | `bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8` | | Preimage | `6d6f6e74616e612d76313a` (`"montana-v1:"`) `|| seed` | | Montana address | **`0a4aeced1262c63ab0ca57dea1d2e1c893fa4b70`** | ### Vector M-2 — известный реальный (история сессии) | Поле | Значение | |------|----------| | Mnemonic | `ranch basket resource enemy bridge spray holiday thing yellow round army mimic renew head test cradle piece public differ diamond connect leisure wrong ask` | | Montana address | **`2f8714b236118011647ec51d0ca6ad40d286bec7`** | **Cross-verification:** этот адрес независимо derived через Python `mnemonic.Mnemonic` + `hashlib.sha256` (см. §Cross-verification ниже) — byte-exact match. Доказывает что наш JS WebCrypto implementation детерминирован между platforms. ### Vector M-3 — текущий (если был восстановлен ранее) | Поле | Значение | |------|----------| | Mnemonic | `<28 hex chars> ...` (TBD при следующем создании) | | Montana address | `<40 hex>` | --- ## Cross-verification команда (Python) Аудитор может проверить независимо: ```python import hashlib import hmac from mnemonic import Mnemonic # python-mnemonic library def derive_montana_address(mnemonic_str): # Validate BIP39 + get seed m = Mnemonic("english") assert m.check(mnemonic_str), "invalid BIP39 mnemonic" seed = m.to_seed(mnemonic_str, passphrase="") # 64 bytes # Derive Montana address preimage = b"montana-v1:" + seed h = hashlib.sha256(preimage).digest() return h[:20].hex() # Vector M-2 m = "ranch basket resource enemy bridge spray holiday thing yellow round army mimic renew head test cradle piece public differ diamond connect leisure wrong ask" print(derive_montana_address(m)) # Expected: 2f8714b236118011647ec51d0ca6ad40d286bec7 ``` Если результат **не совпадает** с приведённым в Vector M-2 — это **fundamental bug** реализации (P0 critical). --- ## Compatibility verification Для каждого Vector M-1..M-3: - Mnemonic должен validate в `python-mnemonic`, `bitcoinjs/bip39`, `tweetnacl-js` - Seed должен byte-exact совпадать с PBKDF2 output этих библиотек - Montana address — наш специфический output, не совместим с другими wallets (см. `06-Восстановление.md` §5) --- ## Verification log (выполнено 2026-05-18) Cross-platform reproduction: ```python $ python3 -c " import hashlib from mnemonic import Mnemonic m = Mnemonic('english') mn = 'ranch basket resource enemy bridge spray holiday thing yellow round army mimic renew head test cradle piece public differ diamond connect leisure wrong ask' seed = m.to_seed(mn, passphrase='') h = hashlib.sha256(b'montana-v1:' + seed).digest() print(h[:20].hex()) " 2f8714b236118011647ec51d0ca6ad40d286bec7 ``` **Result match:** ✓ Python (`python-mnemonic` + stdlib `hashlib`) gives the identical address that our Android JS WebCrypto produces. Это закрывает следующие риски: - BIP39 mnemonic generation byte-exact compliance со стандартом - PBKDF2-HMAC-SHA512 implementation в WebCrypto byte-exact - SHA-256 implementation в WebCrypto byte-exact - Montana address derivation детерминирован между WebView Chromium и CPython **Не закрывает:** cross-Android-version determinism (требует физических устройств разных версий). См. `06-Восстановление.md` §4. --- ## Zero-entropy vector — также cross-verified ```python $ python3 -c " import hashlib seed_hex = 'bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8' seed = bytes.fromhex(seed_hex) h = hashlib.sha256(b'montana-v1:' + seed).digest() print(h[:20].hex()) " 0a4aeced1262c63ab0ca57dea1d2e1c893fa4b70 ``` **Pinned for regression test.** Любая будущая сборка должна давать тот же адрес для нулевого entropy mnemonic. Если расхождение — domain separator `"montana-v1:"` был случайно изменён, либо bit-packing в seed derivation сломался.