feat: BIP-39 master seed for unified key derivation

Replace fragmented random key generation with a single 24-word BIP-39
mnemonic that deterministically derives all node keys: Ed25519 (DID),
secp256k1 (Nostr/Bitcoin), BIP-84 xprv (Bitcoin Core), and LND aezeed
entropy. New onboarding flow: seed generate → word verification → identity
naming. Restore path enabled via 24-word entry. Includes seed RPC handlers,
mock backend support, LND/Bitcoin Core wallet-from-seed integration, and
UI polish across settings and discover views.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-31 01:41:24 +01:00
co-authored by Claude Opus 4.6
parent 3d50fb9888
commit a8292ab622
50 changed files with 2200 additions and 258 deletions
+1 -1
View File
@@ -634,7 +634,7 @@ mod tests {
let frame = build_app_start("Archipelago");
assert_eq!(frame[3], CMD_APP_START);
let name = &frame[4..];
assert_eq!(std::str::from_utf8(name).ok_or_else(|| anyhow::anyhow!("invalid UTF-8 in app name"))?, "Archipelago");
assert_eq!(std::str::from_utf8(name).map_err(|e| anyhow::anyhow!("invalid UTF-8 in app name: {}", e))?, "Archipelago");
Ok(())
}
+24 -1
View File
@@ -158,6 +158,29 @@ impl SessionManager {
Ok(plaintext)
}
/// Store a ratchet session for a peer (in memory and on disk).
#[allow(dead_code)]
pub async fn store_session(&self, did: &str, state: RatchetState) -> Result<()> {
self.save_session_to_disk(did, &state).await?;
let mut sessions = self.sessions.write().await;
sessions.insert(did.to_string(), state);
Ok(())
}
/// Remove a ratchet session for a peer (from memory and disk).
#[allow(dead_code)]
pub async fn remove_session(&self, did: &str) -> Result<()> {
let mut sessions = self.sessions.write().await;
sessions.remove(did);
let path = self.session_path(did);
if path.exists() {
tokio::fs::remove_file(&path)
.await
.context("Failed to remove ratchet session file")?;
}
Ok(())
}
/// Get session info for a peer (for RPC status endpoint).
pub async fn session_info(&self, did: &str) -> Option<SessionInfo> {
let sessions = self.sessions.read().await;
@@ -205,7 +228,7 @@ mod tests {
let mgr = SessionManager::new(dir.path());
let root_key = [42u8; 32];
let (spk_secret, spk_public) = crypto::generate_x25519_ephemeral();
let (_spk_secret, spk_public) = crypto::generate_x25519_ephemeral();
let state = RatchetState::init_as_sender(root_key, &spk_public).unwrap();
let did = "did:key:z6MkTestSession";