Key Generation
Every Decentrl identity starts with three cryptographic keys — each with a distinct purpose and blast radius.
Every identity in Decentrl is built on three independent cryptographic keys, generated entirely on the user's device. No server is involved. No seed phrase is required. The keys are the identity.
Formal spec: DCTRL-0002 — Cryptographic Operations defines the exact key structure, encoding formats, and algorithms.
The Three Keys
| Key | Type | Purpose | Scope |
|---|---|---|---|
| Signing key | Ed25519 | Authentication, signatures, DID control | Identity lifetime, published in DID |
| Pre-key | X25519 | Bootstrapping new contracts (async first contact) | Rotatable, published in DID |
| Storage key | AES-256 | Self-encryption of stored events | Identity lifetime, local only, never shared |
Signing Key (Ed25519)
The signing key is the root of your identity. Every command you send, every event you publish, and every contract you sign carries an Ed25519 signature computed with this key. Signatures are computed over canonical JSON — deep-sorted keys, UTF-8 encoded — ensuring deterministic verification.
If someone has your DID, they can extract your public signing key and verify that a message genuinely came from you.
Pre-key (X25519)
The pre-key enables strangers to initiate encrypted contact. When Alice wants to establish a communication contract with Bob, she uses Bob's public pre-key (embedded in his DID) to encrypt the contract request. Only Bob can decrypt it.
The pre-key is rotatable. Once a contract is established, the pre-key's job is done — the contract uses its own ephemeral keys. Rotating the pre-key doesn't affect existing contracts.
Storage Key (AES-256)
The storage key encrypts events stored on your mediator. It never leaves your device and is never shared with anyone — not even your mediator. When you receive an event, you decrypt it with the contract's root secret, then re-encrypt it with your storage key before storing.
This means your mediator holds only ciphertext it cannot decrypt.
Key Separation
The three-key design limits blast radius. Compromising one key doesn't compromise the others:
- Signing key compromised — attacker can impersonate you, but cannot decrypt any existing conversation. There's no encryption key to derive from the signing key. Remediation: rotate the signing key, re-establish contracts.
- Pre-key compromised — attacker can read new contract requests addressed to you, but existing contracts are unaffected (they use independent ephemeral keys). Remediation: rotate the pre-key in your DID.
- Storage key compromised — requires physical device access. Attacker can read your stored events but cannot impersonate you or intercept live traffic. Equivalent to someone copying your local database.
- Contract ephemeral key compromised — only that one contract is affected. All other contracts, stored data, and authentication remain secure.
In Code
import { generateIdentityKeys } from '@decentrl/crypto'
const keys = generateIdentityKeys()
// {
// signing: { publicKey: Uint8Array, privateKey: Uint8Array } Ed25519
// encryption: { publicKey: Uint8Array, privateKey: Uint8Array } X25519
// storageKey: Uint8Array AES-256
// }Keys are Uint8Array internally and serialized as base64 strings for persistence. The signing and encryption public keys are encoded as base58btc multibase strings when embedded in DIDs.