feat: encrypted seed export to Nostr + Blossom (WalletExport)#894
Draft
DavidGershony wants to merge 1 commit into
Draft
feat: encrypted seed export to Nostr + Blossom (WalletExport)#894DavidGershony wants to merge 1 commit into
DavidGershony wants to merge 1 commit into
Conversation
Adds an opt-in cloud backup of the wallet seed under a user-chosen Recovery Passphrase. Two-layer envelope: inner = AES-256-GCM keyed by Argon2id(passphrase) → HKDF outer = NIP-44 v2 self-encryption to a passphrase-derived backup npub The encrypted blob is uploaded to ≥2 of 4 Blossom servers (BUD-02 kind-24242 auth signed by the passphrase-derived nsec, content verified by SHA-256). A kind 30078 manifest event under the same npub makes the backup discoverable from the passphrase alone — no account, no username. Recovery: passphrase → derive npub → query relay for manifest → fetch blob from any healthy Blossom server → AEAD-decrypt seed. SDK: - Angor.Sdk.WalletExport.Crypto: Argon2id, AES-GCM, HKDF-derived secp256k1 backup keys, NIP-44 self-ECDH envelope. Secrets zeroed on dispose. - Angor.Sdk.WalletExport.Blossom: BUD-02 upload + content-hash verified download + HEAD existence probe. - CloudBackupService / BackupRecoveryService: orchestration. - WalletCloudBackupService: persists CloudBackupRecord onto EncryptedWallet for status + passive health checks. Tests: - 25 unit tests cover KDF determinism + NFC, AEAD tamper rejection + AAD enforcement, key-triple derivation + domain separation + zero-on-dispose, and full two-layer roundtrip including wrong-passphrase + unrelated-keys rejection. UI (design app): - Settings → new Cloud Backup card with enable/refresh/verify/ disable actions. ViewModel surface is ready; passphrase-entry modal XAML is a follow-up (existing wipe-data modal is the template). DI wired in both Avalonia and design composition roots; webapp NetworkConfiguration extended with GetDefaultBackupServerUrls(). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Opt-in cloud backup of the wallet seed protected by a user-chosen Recovery Passphrase. Two layers of encryption (NIP-44 outer + AES-256-GCM inner with Argon2id KDF), encrypted blob stored on ≥2 of 4 Blossom servers, kind 30078 manifest event makes it discoverable from the passphrase alone — no account, username, or email.
passphrase → Argon2id → HKDF → (backup_sk, backup_pk, K_inner). Seed JSON encrypted withK_inner, uploaded to Blossom (BUD-02 kind-24242 auth signed bybackup_sk, server hash verified). Manifest NIP-44-encrypted tobackup_pkand published as a parameterized-replaceable kind 30078 under the same npub.backup_pk→ query relays for the manifest → fetch blob from any healthy Blossom server → AEAD-decrypt → seed in hand.What's in this PR
Angor.Sdk.WalletExport.Crypto— Argon2id (OWASP m=64MiB/t=3/p=1), AES-256-GCM, HKDF domain-separated secp256k1 backup keys, NIP-44 self-ECDH envelope. Secrets zeroed on dispose.Angor.Sdk.WalletExport.Blossom— BUD-02 upload + content-hash-verified download + HEAD existence probe.CloudBackupService,BackupRecoveryService,WalletCloudBackupService(wallet-store integration viaEncryptedWallet.CloudBackupfield).SettingsView.axaml:1038is the template.)INetworkConfiguration.GetDefaultBackupServerUrls()added across all three implementations.Threat model highlights
What's deferred (clean follow-ups)
OpenEnableBackupModal,ConfirmEnableBackupAsync, etc.). Copy the wipe-data modal as a template.AddWalletFlow.cs:13— callsIBackupRecoveryService.RecoverAsync(passphrase)then existingIWalletAppService.CreateWallet(...).backup_sk— needs a new platform-abstract secure-key store. v1 is more secure (passphrase required for refresh).net9.0(Avalonia) vsnet10.0(SDK) framework mismatch in the repo prevents that app from building; unrelated to this feature.Test plan
dotnet test src/sdk/Angor.Sdk.Tests --filter Angor.Sdk.Tests.WalletExport— all 25 unit tests pass🤖 Generated with Claude Code