Overview
Challenge keys are a critical component of Muun’s recovery system. They enable:- Recovery Code Protection: Deriving keys from user recovery codes
- Emergency Kit Encryption: Encrypting wallet keys for backup
- Secure Key Exchange: Encrypting keys between user and Muun servers
- Multi-Version Support: Handling legacy key formats (v2, v3)
Key Constants
Encoded Key Lengths
Key Serialization Versions
ChallengePrivateKey
Represents a private key derived from a recovery code for encrypting/decrypting wallet keys.Constructor
NewChallengePrivateKey
Creates a challenge private key from an input (recovery code) and salt using scrypt.The recovery code or input material (typically user-provided)
The salt for scrypt key derivation (8 bytes)
The derived challenge private key
- Derive 32-byte key using
Scrypt256(input, salt) - Convert bytes to secp256k1 private key
- Return wrapped private key
Signing Methods
SignSha
Computes SHA-256 digest of payload and signs it with ECDSA.The data to sign (will be SHA-256 hashed)
DER-encoded ECDSA signature
Error if signing fails
Public Key Methods
PubKey
Returns the corresponding challenge public key.The public key derived from this private key
PubKeyHex
Returns the compressed public key as a hex string.Hex-encoded compressed public key (66 characters, 33 bytes)
Key Decryption Methods
DecryptRawKey
Decrypts an encrypted private key from a base58-encoded string.Base58-encoded encrypted key (from emergency kit)
The network configuration (mainnet, testnet, regtest)
The decrypted HD private key with birthday information
Error if decryption fails or key format is invalid
- Decode base58 string to
EncryptedPrivateKeyInfo - Decrypt using ECDH with challenge private key
- Extract raw private key and chain code
- Return master HD private key
DecryptKey
Decrypts an encrypted private key from decoded key info.The decoded encrypted key information
The network configuration
The decrypted key with birthday
Error if decryption fails
Decrypted Key Structure
The decrypted HD private key (master key at path “m”)
The key’s birthday as block height. Used for faster blockchain scanning. 0 for version 3 keys (birthday removed as it was unused).
ChallengePublicKey
Represents a public key derived from a challenge private key, used for encrypting wallet keys.Constructor
NewChallengePublicKeyFromSerialized
Creates a challenge public key from serialized bytes.Compressed public key bytes (33 bytes)
The parsed challenge public key
Error if key format is invalid
Key Encryption Methods
EncryptKey
Encrypts an HD private key for storage in emergency kit. Automatically detects version from muunPrivateKey.The HD private key to encrypt
The salt used for recovery code scrypt (8 bytes, or empty for zero-filled)
The key birthday (block height). Only used for v2 keys; ignored for v3.
The Muun private key (base58) - used to detect version (v2 or v3)
Base58-encoded encrypted key
Error if encryption fails or version is unrecognized
- Reads first byte of
muunPrivateKeyto determine format version - Encrypts using matching version (v2 or v3) for consistency
- V2: Includes birthday field
- V3: No birthday field (cleaner format)
Utility Methods
GetChecksum
Computes a checksum for the public key (for verification purposes).Hex-encoded checksum (last 8 bytes of SHA-256 hash)
- SHA-256 hash of compressed public key
- Take last 8 bytes
- Hex encode
Encrypted Key Information
EncryptedPrivateKeyInfo
Gomobile-compatible structure for encrypted key data using hex encoding.Decoding Functions
DecodeEncryptedPrivateKey
Decodes a base58-encoded encrypted key string.Base58-encoded encrypted key
Decoded key information
Error if format is invalid or version is unrecognized
- Version 2: Legacy format with birthday and optional salt
- Version 3: Modern format without birthday
Key Derivation
Scrypt256
TheScrypt256 function (referenced but not shown) derives a 256-bit key from input and salt.
Typical Parameters:
- N: CPU/memory cost parameter (e.g., 16384)
- r: Block size (e.g., 8)
- p: Parallelization (e.g., 1)
- Output: 32 bytes (256 bits)
Security Considerations
Recovery Code Strength
Salt Handling
- Modern Keys (v3): Always include 8-byte salt
- Legacy Keys (v2): May have zero-filled salt for very old keys
- Storage: Salt is stored with encrypted key (not secret)
Version Compatibility
- Backward Compatible: Can decrypt v2 and v3 keys
- Forward Compatible: New encryptions should use v3
- Version Detection: Automatically handled based on Muun key version
Best Practices
- Always provide salt when encrypting new keys
- Store version information with encrypted keys
- Test decryption immediately after encryption
- Validate checksums when comparing public keys
- Use birthday field (v2) for efficient blockchain scanning if needed
Complete Example
Recovery Workflow
Typical emergency recovery flow:- User has: Recovery code (8 words) + Emergency Kit PDF (with encrypted keys)
- Decode: Parse base58 encrypted keys from PDF
- Derive: Create challenge private key from recovery code + salt
- Decrypt: Decrypt both user key and Muun key
- Restore: Use decrypted keys to restore full wallet access