Overview
Challenge keys are a critical component of Muun’s recovery system. They are password-derived keys that enable secure, server-independent wallet recovery through the emergency kit.What are challenge keys?
Challenge keys are cryptographic keys derived from user-memorable secrets (recovery code or password) using strong key derivation functions. They serve two primary purposes:- Encrypt wallet backup data in the emergency kit
- Enable decryption during wallet recovery without server access
Key derivation
Challenge private key generation
Challenge keys are derived using scrypt, a memory-hard key derivation function that resists brute-force attacks:libwallet/challenge_keys.go
input: User’s recovery code or password as bytessalt: 8-byte random salt for key derivation- Returns: ECDSA private key on the secp256k1 curve
Scrypt parameters are tuned to require significant memory and computation, making dictionary attacks impractical even with specialized hardware.
Version evolution
Muun supports multiple challenge key versions: Version 2 (Legacy)- 136-byte encoded format
- Salt stored only in second key
- Supported for backward compatibility
- 147-byte encoded format
- Salt included in all encrypted keys
- Improved security and recovery reliability
libwallet/challenge_keys.go
Challenge key operations
Signing challenges
Challenge keys can sign arbitrary data to prove knowledge of the recovery secret:libwallet/challenge_keys.go
- Recovery code setup verification
- Password change operations
- Server authentication during recovery
Decrypting wallet keys
The primary use of challenge keys is decrypting the encrypted private key from the emergency kit:libwallet/challenge_keys.go
Encrypted private key format
Encrypted keys contain:libwallet/challenge_keys.go
Encryption process
- Generate ephemeral key pair: One-time keypair for ECDH
- Derive shared secret: ECDH between ephemeral private key and challenge public key
- Encrypt private key data: AES-256-CBC using shared secret
- Encode result: Base58 encoding with version and metadata
The ephemeral public key is included in the encrypted output, allowing the challenge private key to reconstruct the shared secret for decryption.
Challenge key lifecycle
Setup flow
- User creates recovery code
- Recovery code derives challenge private key
- Challenge public key sent to server
- Server encrypts user’s private key with challenge public key
- Encrypted key included in emergency kit PDF
Recovery flow
- User enters recovery code from emergency kit
- Recovery code derives same challenge private key
- Challenge private key decrypts encrypted user key
- Wallet reconstructs from decrypted key
Password change
When changing password/recovery code:- Derive new challenge key from new password
- Re-encrypt private keys with new challenge public key
- Update emergency kit with new encrypted keys
- Invalidate old challenge keys
Security properties
Brute-force resistance
Scrypt key derivation provides:- Memory hardness: Requires significant RAM (32+ MB)
- Time hardness: Configurable iteration count
- Parallelization resistance: Cannot efficiently parallelize
Offline recovery
Challenge keys enable fully offline recovery:- No server communication required
- Works even if Muun servers are unavailable
- User has complete control over recovery
Forward secrecy
Changing the recovery code generates new challenge keys:- Old encrypted data cannot be decrypted with new challenge key
- Requires re-encryption with new challenge public key
- Provides rotation capability for enhanced security
Best practices
For users
- Choose strong recovery codes: Use randomly generated codes
- Store emergency kit securely: Physical security is critical
- Never share recovery code: Equivalent to wallet private keys
- Test recovery process: Verify you can decrypt the emergency kit
For developers
- Validate challenge key versions: Handle both v2 and v3 formats
- Clear sensitive memory: Zero out passwords and keys after use
- Use constant-time operations: Prevent timing attacks
- Implement rate limiting: Limit password attempts
Common issues
Decryption failures
Symptom: “Failed to decrypt key” error Causes:- Incorrect recovery code entered
- Version mismatch (v2 vs v3 format)
- Corrupted encrypted key data
- Wrong network (mainnet vs testnet)
Salt missing errors
Symptom: “Salt required but not provided” Cause: Attempting to decrypt v3 format without salt Solution: Ensure salt is extracted and provided from encoded keyRelated documentation
Emergency Kit
Complete emergency kit system
Recovery
Wallet recovery process
Challenge Keys API
Challenge key API reference
Encryption API
Encryption and decryption APIs