WalletSeedSource
Single source of truth for the wallet's BIP-39 seed.
Every Kuira ecosystem consumer that needs the seed — WalletPanelViewModel, BBoardViewModel, Kicks's MatchManager, future agent runtimes — injects this @Singleton and calls ensureSeedReady. They all observe the same seed, the same biometric prompt cadence, and the same dev override.
Bootstrap contract:
Dev-seed escape hatch (debug only) — when
local.propertiesdefineskuira.dev.seed, decode + return without touching the vault or the passkey. See module-level KDoc inbuild.gradle.kts.Sigil gate — no passkey forged ⇒ SigilRequiredException. Consumers translate this to whatever UI affordance they own (
WalletStatus.SigilRequiredin the panel, a "forge sigil" screen in custom dApps, etc.). Throwing here is defense-in-depth — the host UI should also gate.Cache hit — SeedVault holds a seed AND the
seedIsPrfDerivedflag is set ⇒ biometric prompt to decrypt, return the cached PRF-derived seed.Cache miss OR legacy unflagged vault ⇒ wipe the legacy entry (decision B — legacy random seeds are abandoned, not migrated), run ONE passkey PRF authentication to derive the new seed, store in the vault, set the flag, return.
Caller MUST wipe the returned ByteArray once the SDK builder has copied it (typically in a finally block).
Constructors
Functions
Pre-warm SeedVault with a PRF output the caller already derived in a multi-purpose ceremony — used by SigilSession to collapse "sign in + first wallet refresh" to one biometric.
Returns the wallet's BIP-39 seed, deriving it from the user's passkey via PRF if not already cached. See class-level KDoc for the full bootstrap contract.