Key Registration
Deriving and registering protocol keys
Key Hierarchy#
Keys are derived deterministically from a wallet signature. This means keys are portable — you can recover them on any device by signing the same message with your Solana wallet.
Key Loss
If you lose access to your Solana wallet, you lose access to all funds in the anonymity pool. There is no recovery mechanism. Store your seed phrase securely.
Derivation#
The derivation uses a single signMessage call:
signature = wallet.signMessage("Mini Veil master keys")
masterSeed = SHA-256(signature)
spendingPriv = SHA-256("mini-veil-spending" || masterSeed) → 32 bytes
viewingPriv = SHA-256("mini-veil-viewing" || masterSeed) → 32 bytes
spendingPub = Ed25519.getPublicKey(spendingPriv) → 32 bytes
viewingPub = X25519.getPublicKey(viewingPriv) → 32 bytes
Extended Key Hierarchy#
The core SDK (@mini-veil/core — npm package coming soon) supports an extended hierarchy via generateVeilKeys(seed?):
L1 Ed25519 keypair (Solana key)
├── X25519 keypair
├── spendingKey (field element)
│ └── spendingBlinding (field element)
├── viewingKey (field element)
│ └── viewingBlinding (field element)
└── userCommitment = Poseidon(
Poseidon(l1Low, l1High),
Poseidon(
Poseidon(viewingKey, viewingBlinding),
Poseidon(spendingKey, spendingBlinding)
)
)
On-chain Registration#
Keys are registered on-chain via the register_keys instruction:
register_keys(
x25519_public_key: [u8; 32], // viewing public key
user_commitment: [u8; 32], // spending public key
)
This creates a KeyRegistry PDA at seed ["key-registry", owner] storing:
| Field | Size | Description |
|---|---|---|
| owner | 32 bytes | Wallet address |
| x25519_public_key | 32 bytes | X25519 viewing public key |
| user_commitment | 32 bytes | Ed25519 spending public key |
| bump | 1 byte | PDA bump seed |
Key Caching#
Once derived, keys are cached in localStorage under mini-veil-keys-{wallet_address} with the following fields:
spendingPrivKeyviewingPrivKeyspendingPubKeyviewingPubKeymixerSpendingKey(field element used for nullifier derivation)
Proactive Registration Check#
The dashboard performs a proactive key registration check with a 500ms debounced useEffect:
- Derive keys from wallet signature
- Check if
KeyRegistryPDA exists on-chain - Compare derived
userCommitmentagainst on-chain value - If mismatched or missing, prompt user to register
- Registration cost: ~0.005 SOL (5,000,000 lamports)
Key Usage#
| Key | Used For | |---|---| | Spending key | Nullifier derivation, ZK proof generation | | Viewing key (private) | Scanning stealth announcements, decrypting payments | | Viewing key (public) | Sender encrypts ephemeral key for recipient | | Spending public key | Recipient binds stealth address to this key |