Seed Phrase Generation and Recovery in Mobile Crypto Wallet
Seed phrase — only recovery point for entire wallet. If mnemonic generated with poor entropy or recovery yields different addresses — user loses fund access. Both scenarios happen in production.
Generation: Where Mistakes Happen
Most dangerous error — using pseudo-random source. Math.random() in JavaScript not cryptographically random. Date.now() as seed — catastrophe. For BIP-39 need exactly 128 bits (12 words) or 256 bits (24 words) cryptographically random entropy.
On iOS correct path — SecRandomCopyBytes:
var entropy = Data(count: 16) // 128 bits for 12 words
let result = entropy.withUnsafeMutableBytes {
SecRandomCopyBytes(kSecRandomDefault, 16, $0.baseAddress!)
}
guard result == errSecSuccess else { throw WalletError.entropyGeneration }
On Android — SecureRandom from java.security, not Random:
val entropy = ByteArray(16)
SecureRandom().nextBytes(entropy)
React Native: react-native-get-random-values polyfills crypto.getRandomValues(), which uses native CSPRNG. Without this package @noble/hashes and @scure/bip39 work on unsafe source.
Recovery and Compatibility
Recovery — input 12/24 words → same addresses. Bugs usually in text normalization: extra spaces, unicode spaces (NBSP instead of regular), case. bip39.validateMnemonic() should return false for such, but UI should normalize input before checking — trim() and replace(/\s+/g, ' ') mandatory.
Second source of incompatibility — passphrase. BIP-39 allows optional passphrase ("25th word"). MetaMask ignores it (empty string). Trezor supports. If your wallet silently passes empty passphrase, user recovering where they specified one — addresses differ. Must explicitly ask on recovery.
UX for Seed Confirmation
Show words in groups of 4, not all at once. After show — verification: random 3–4 words in random order, user taps in correct sequence. Don't allow clipboard copy by default — clipboard read by other apps. If copying allowed, clear clipboard after 60 seconds via UIApplication/ClipboardManager.
On Android 10+ ClipboardManager.clearPrimaryClip() — public API. On iOS < 16 no direct clearing, set clipboard to empty string.
Process
Implementation, testing on BIP-39 official vectors, seed confirmation UI, recovery with input normalization. Timeline — 3–5 days. If passphrase support and compatibility with specific external wallet needed — add day for testing.







