Title: Wallet creation + recovery (2-of-3, user+server+guard) Status: draft (superseded by cloud-backup decision, оставляем как архив) Owner: <ник> Goal: Описать опциональный флоу кошелька с recovery через 2/3 SSS: шард пользователя, E2E-зашифрованный шард на сервере, шард гварда. Сервер не способен восстановить без участия гварда/пользователя.
Decisions:
- Active:
wallet/decisions/decision-2026-01-17-cloud-backup-supersedes-sss.md(cloud backup заменяет этот флоу). - Archive:
wallet/decisions/decision-2026-01-13-recovery-2of3.md,wallet/decisions/decision-2026-01-14-sss-format-and-oob.md.
Open questions (если вернёмся к 2-of-3):
- Формат SSS-конверта: точный layout/AAD, тест-векторы, негативные тесты на подмену metadata.
- Протокол E2E: Noise/X3DH детали, double-wrapping S-shard (кто чей pubkey использует, ротация).
- UX гварда: OOB-канал, подтверждение/отклонение, таймауты, rate-limit попыток.
- Replay/abort: как инвалидировать старые recovery sessions, защита от re-play уведомлений гварду.
- Хранение и удаление: сроки retention S-shard ciphertext, когда подчистка, аудит действий.
- Device posture: требования к устройству гварда (TEE/KeyStore/SE, KDF параметры), политика при смене устройства.
- KYC/антириск: кто источник, какие сигналы, частота повторного KYC.
Roles:
- User (U) — владелец кошелька, генерирует сид, держит шард U.
- Server (S) — курьер шифртекста для шарда S; не имеет ключей к расшифровке.
- Guard (G) — доверенное лицо/устройство, держит шард G, подтверждает recovery, тревожит владельца.
- KYC provider — даёт сигнал допуска (не даёт ключи).
Invariants (must hold):
- Non-custodial: сервер не видит сид/приватные ключи; хранит только шифртекст шарда S и метаданные.
- SSS k=2, n=3 (classic Shamir): любые 2 из 3 восстанавливают секрет.
- Share binding: шарды всегда упакованы в аутентифицированную обёртку (AEAD) с
wallet_id/sss_profile_id/version/role/index(нельзя незаметно перемешать шарды между кошельками/сессиями). - E2E: шарды S и G всегда в шифре под ключи получателей; локальный KDF (Argon2id) + AES-GCM/ChaCha20-Poly1305.
- Recovery требует участия G (OOB подтверждение) и сессионного ключа U; KYC — только сигнал, не ключ.
- Таймауты сессий, аудит событий; без участия G и U сервер не способен инициировать/завершить recovery.
Terminology:
- OOB (out-of-band) подтверждение: гвард подтверждает recovery по независимому каналу (звонок/код/мессенджер/второе устройство), чтобы проверить запрос и тревожить владельца при атаке.
Flow A — обычный кошелёк (без шардов):
- U генерирует seed (12/24), локально шифрует бэкап (пароль→Argon2id→AES-GCM).
- Нет шардов, нет серверных копий. Потеря seed = невосстановимо.
Flow B — кошелёк с recovery 2/3: Creation:
- U генерирует seed локально.
- Split seed → classic Shamir SSS 2/3: U-shard, S-shard, G-shard.
- U-shard: хранится локально, шифруется паролем (Argon2id).
- S-shard: шифруется E2E под pubkey U_recovery и pubkey G (двойное обёртывание или гибрид), отправляется и хранится на сервере как шифртекст. Метаданные: wallet_id, sss_profile_id, sss_format_version, k/n, share_index, guard_id, статус.
- G-shard: хранится у гварда локально, шифруется паролем/био-гейтом + KDF.
Recovery (когда утеряно устройство U):
- U с новым устройством создаёт recovery session, публикует сессионный pubkey, проходит KYC (сигнал допуска/антириск).
- Сервер уведомляет G о запросе (push). G выполняет OOB проверку (звонок/мессенджер/код).
- G разблокирует G-shard (паскод+био), шифрует под сессионный pubkey U, отправляет по E2E.
- Сервер отдаёт S-shard шифртекст (у него нет ключей), U расшифровывает S-shard локально своим recovery key (который сервер не знает).
- U объединяет любые 2 из 3 (обычно G-shard + S-shard) → получает seed → импортирует кошелёк.
- Сессия закрывается, сессионные ключи стираются, событие аудита фиксируется.
Anti-abuse / внутренний атакующий:
- Сервер не имеет ключей для S-shard; без G участие невозможно завершить recovery.
- Любая попытка «тихого» запуска recovery требует G-активации, которая тревожит владельца.
- Rate-limit/таймаут recovery-сессий; логирование событий
recovery_requested,guard_approved/denied,recovery_completed/failed.
Риски и митигация (остаточные):
- Компрометация устройства G или слабый KDF → оффлайн-брут G-shard. Требуется жёсткий KDF/био-гейт и защитное хранилище (TEE/KeyStore/Secure Enclave).
- Социнжиниринг G: смягчать OOB-подтверждением и уведомлением владельца.
- Потеря и U-shard, и G-shard одновременно при недоступности S-shard → невосстановимо.