148 lines
6.3 KiB
Markdown
148 lines
6.3 KiB
Markdown
# Приложение А. Тест-векторы 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> <words>...` (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 сломался.
|