montana/Android/Внешний-аудит/приложения/вектора-тестов-bip39.md
2026-05-18 22:11:45 +03:00

6.3 KiB
Raw Blame History

Приложение А. Тест-векторы 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:") `
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> <words>... (TBD при следующем создании)
Montana address <40 hex>

Cross-verification команда (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:

$ 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

$ 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 сломался.