172 lines
8.2 KiB
Markdown
172 lines
8.2 KiB
Markdown
|
|
# 11. Phase 2 — TimeChain-Готовая интеграция (v6.6.0)
|
|||
|
|
|
|||
|
|
**Дата:** 2026-05-18 (продолжение работы после исходного аудит-пакета v6.5.0)
|
|||
|
|
|
|||
|
|
## Обзор изменений
|
|||
|
|
|
|||
|
|
Реализована **Phase 2** roadmap из `07-Известные-ограничения.md`. Часть P0/высоких findings закрыты, ВПН-балансы переведены на production Rust backend с криптографической аутентификацией heartbeat.
|
|||
|
|
|
|||
|
|
### Закрытые findings
|
|||
|
|
|
|||
|
|
| Finding | Статус | Доказательство |
|
|||
|
|
|---------|--------|----------------|
|
|||
|
|
| F-2 Heartbeat без cryptographic auth | **✅ Закрыто Ed25519 TOFU pinning + nonce-window replay protection** | `crates/mt-vpn-balance/src/main.rs` верификация через `ed25519-dalek`; Android клиент подписывает через BouncyCastle Ed25519 |
|
|||
|
|
| CF-2 Regex JSON парсер | **✅ Закрыто Rust типизированным `serde_json`** | весь backend в strong typed Rust |
|
|||
|
|
| CF-5 balances.json race | **✅ Закрыто `tokio::sync::Mutex` единый writer** | atomic state.json через `tokio::fs::rename` |
|
|||
|
|
| CF-7 silent JSON swallow | **✅ Закрыто axum `Json<T>` extractor** | malformed → 400 авто |
|
|||
|
|
| F-7 (частично) BIP39 без shielding | Ed25519 секрет вычислен от seed через SHA-256 domain separator — детерминирован, не покидает устройство | derived через `MontanaBridge.setSignerSeed()` |
|
|||
|
|
|
|||
|
|
### Открытые findings (уменьшение severity)
|
|||
|
|
|
|||
|
|
| Finding | Старая severity | Новая severity | Reason |
|
|||
|
|
|---------|-----------------|----------------|--------|
|
|||
|
|
| F-4 SPOF Moscow | Блокер mainnet | **Высокий** (нужна replication) | Rust backend атомарен, persistence файл `/var/lib/mt-vpn-balance/state.json`; replication на узлы остаётся Phase 3 |
|
|||
|
|
| F-reality-pq | Низкий | Низкий | Не изменилось — upstream xray задача |
|
|||
|
|
|
|||
|
|
### Новые findings от Phase 2
|
|||
|
|
|
|||
|
|
#### CF-Phase2-1 — Ed25519 НЕ post-quantum (нарушает [I-1])
|
|||
|
|
|
|||
|
|
**Severity:** средний (acknowledged явно в коде).
|
|||
|
|
|
|||
|
|
**Поверхность:** `crates/mt-vpn-balance/src/main.rs` использует `ed25519-dalek` для signature verification. Ed25519 уязвим к Shor.
|
|||
|
|
|
|||
|
|
**Принятие риска:**
|
|||
|
|
- Falcon-512 JNI binding для Android — отдельный milestone M-VPN-3
|
|||
|
|
- Pure-Kotlin Falcon реализаций не существует production-ready
|
|||
|
|
- Альтернатива (pure-Rust на устройстве через JNI) — отдельная инженерная работа
|
|||
|
|
|
|||
|
|
**Closure path (Phase 4 M-VPN-3):**
|
|||
|
|
- Заменить `ed25519-dalek` на `pqcrypto-falcon` в backend
|
|||
|
|
- Прокинуть Falcon-512 в Android через NDK + JNI wrapper
|
|||
|
|
- Обновить deriveAddr → включить публичный ключ Falcon в адрес
|
|||
|
|
|
|||
|
|
**Cost estimate:** 2-3 недели.
|
|||
|
|
|
|||
|
|
#### CF-Phase2-2 — TOFU pinning не имеет revocation
|
|||
|
|
|
|||
|
|
**Severity:** средний.
|
|||
|
|
|
|||
|
|
**Поверхность:** при первом heartbeat backend пинит pubkey. Если устройство утеряно/скомпрометировано — атакующий с украденным seed может присылать valid heartbeats навсегда.
|
|||
|
|
|
|||
|
|
**Closure path:**
|
|||
|
|
- Окно для revocation: подписать message "revoke" с владельческим pubkey → backend помечает аккаунт revoked
|
|||
|
|
- Recovery flow: timeout ≥ 90 дней inactive → разрешить повторное TOFU
|
|||
|
|
|
|||
|
|
**Cost estimate:** 1 неделя.
|
|||
|
|
|
|||
|
|
#### CF-Phase2-3 — Replay через нестрого монотонный nonce
|
|||
|
|
|
|||
|
|
**Severity:** низкий.
|
|||
|
|
|
|||
|
|
**Поверхность:** `nonce_ms` — UNIX timestamp клиента. Backend проверяет монотонность (last_nonce_ms < new_nonce_ms) + okno 30s. Если на устройстве сбился час в прошлое — heartbeats не пройдут до синхронизации.
|
|||
|
|
|
|||
|
|
**Mitigation:** Android `System.currentTimeMillis()` обычно NTP-синхронизирован. Окно ±30s покрывает дрифт.
|
|||
|
|
|
|||
|
|
**Closure path:** перейти на counter-based nonce (uint64 счётчик в state, инкрементируется на client). Phase 3.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Архитектурный апдейт
|
|||
|
|
|
|||
|
|
### До Phase 2 (v6.5.0)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Android → Reality → Helsinki haproxy → Cascade exit → montana.quest:443 (Moscow nginx)
|
|||
|
|
↓
|
|||
|
|
gunicorn (Flask) ← /api/vpn/heartbeat
|
|||
|
|
↓
|
|||
|
|
balances.json (file LOCK_EX)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Phase 2 (v6.6.0)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Android (v6.6.0)
|
|||
|
|
↓ BIP39 mnemonic → PBKDF2 seed → SHA-256 domain "montana-ed25519-v1:" → Ed25519 secret
|
|||
|
|
↓ Каждый heartbeat: signature_hex = Ed25519.sign(secret, "montana-heartbeat-v1:" || address || nonce_ms)
|
|||
|
|
↓ POST {address, nonce_ms, pubkey, signature}
|
|||
|
|
Reality cascade → exit → Moscow nginx:443
|
|||
|
|
↓ proxy_pass http://127.0.0.1:5009
|
|||
|
|
mt-vpn-balance (Rust, axum + tokio + ed25519-dalek)
|
|||
|
|
↓ Verify Ed25519 signature against pinned pubkey (TOFU at first hb)
|
|||
|
|
↓ Verify nonce_ms in ±30s window AND > last_nonce
|
|||
|
|
↓ Atomic state mutation under tokio::sync::Mutex
|
|||
|
|
↓ Persistence: state.json with atomic rename
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Verification log
|
|||
|
|
|
|||
|
|
### Server-side (Rust backend)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
$ ssh montana-moscow 'curl -s http://127.0.0.1:5009/api/vpn/stats'
|
|||
|
|
{
|
|||
|
|
"wallets": 7,
|
|||
|
|
"total_juno": 34.16235,
|
|||
|
|
"total_seconds": 34162.35,
|
|||
|
|
"active_now": 1,
|
|||
|
|
"signed_accounts": 1,
|
|||
|
|
"rate_per_second": 0.001
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`signed_accounts: 1` подтверждает что минимум один клиент сейчас отправляет Ed25519-signed heartbeats и backend верифицирует подпись.
|
|||
|
|
|
|||
|
|
### Client-side (Pixel 9 Pro XL)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
$ adb logcat -d -s MontanaVPN MontanaBridge
|
|||
|
|
MontanaBridge: ed25519 signer initialized
|
|||
|
|
MontanaJS: signer initialized, pubkey=41780d09d41058cb (truncated)
|
|||
|
|
MontanaVPN: hb: 200 via=true node=helsinki bal=3.535794 ...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Pubkey `41780d09d41058cb…` детерминирован от BIP39 seed конкретного кошелька — recovery на другом устройстве даст тот же pubkey.
|
|||
|
|
|
|||
|
|
### Unit tests Rust backend
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
$ cargo test -p mt-vpn-balance
|
|||
|
|
running 5 tests
|
|||
|
|
test tests::test_address_validation ... ok
|
|||
|
|
test tests::test_build_message_deterministic ... ok
|
|||
|
|
test tests::test_credited_arithmetic_overflow_safe ... ok
|
|||
|
|
test tests::test_ed25519_signing_roundtrip ... ok
|
|||
|
|
test tests::test_exit_node_label ... ok
|
|||
|
|
|
|||
|
|
test result: ok. 5 passed; 0 failed; 0 ignored
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Что осталось до полного closure
|
|||
|
|
|
|||
|
|
| Задача | Phase | Estimated |
|
|||
|
|
|--------|-------|-----------|
|
|||
|
|
| Replication state на 3 узла Montana | M-VPN-1 (продолжение) | 3 дня |
|
|||
|
|
| Falcon-512 JNI замена Ed25519 | M-VPN-3 | 2-3 недели |
|
|||
|
|
| Новый opcode `0x06 VpnHeartbeat` в Montana Protocol v35.26 | M-VPN-2 | 2-3 недели (включая spec patch + mt-account tests) |
|
|||
|
|
| Encrypted seed через user passcode | Phase 2 | 1 неделя |
|
|||
|
|
| Backup verify screen | Phase 2 | 1 день |
|
|||
|
|
| Automated tests recovery determinism | Phase 2 | 2 дня |
|
|||
|
|
| CI integration | Phase 2 | 2 дня |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Обновлённая оценка готовности
|
|||
|
|
|
|||
|
|
| Слой | v6.5.0 | v6.6.0 | Mainnet target |
|
|||
|
|
|------|--------|--------|----------------|
|
|||
|
|
| Криптография heartbeat | ноль | Ed25519 TOFU | Falcon-512 (PQ) |
|
|||
|
|
| Backend production | Flask MVP | **Rust axum** | Replicated на узлы |
|
|||
|
|
| Atomic concurrency | LOCK_EX flock | **tokio::sync::Mutex** | Consensus-driven |
|
|||
|
|
| State persistence | balances.json | **state.json + tokio::fs atomic** | TimeChain validator state |
|
|||
|
|
| Tests | 0 | **5 Rust unit tests** | 50+ tests, integration, e2e |
|
|||
|
|
| Replication | нет | нет | rsync daily (Phase 3) |
|
|||
|
|
| Sybil resistance | нет | TOFU pin + Ed25519 nonce | Falcon + consensus |
|
|||
|
|
|
|||
|
|
**Готовность к mainnet:** ~60% (было ~40%). Phase 3 closure cost: 4-5 недель.
|