Loading vLEI.wiki
Fetching knowledge base...
Fetching knowledge base...
This comprehensive explanation has been generated from 66 GitHub source documents. All source documents are searchable here.
Last updated: October 7, 2025
This content is meant to be consumed by AI agents via MCP. Click here to get the MCP configuration.
Note: In rare cases it may contain LLM hallucinations.
For authoritative documentation, please consult the official GLEIF vLEI trainings and the ToIP Glossary.
A derivation code is a compact, prepended character sequence in CESR encoding that specifies the cryptographic algorithm, key type, or operation used to derive a cryptographic primitive, enabling self-describing, composable representations of keys, digests, and signatures without external information.
A derivation code is a prepended metadata indicator in KERI's Composable Event Streaming Representation (CESR) that encodes the cryptographic algorithm, key type, digest function, or signature scheme used to generate a cryptographic primitive. This code transforms raw cryptographic material into a qualified primitive that is self-describing and independently verifiable.
Formally, a derivation code is a fixed-length character sequence (in text domain) or byte sequence (in binary domain) that:
Derivation codes solve a fundamental problem in cryptographic systems: how to know which algorithm was used to generate a piece of cryptographic material. When a verifier receives a public key, signature, or digest, they must know:
Traditional systems solve this through:
KERI's derivation codes embed this information directly in the identifier or primitive itself, creating truly portable, self-contained cryptographic objects.
Derivation codes are classified into three primary categories in CESR:
Derivation codes do not perform cryptographic operations themselves—they are metadata indicators that specify which algorithms were used. Common derivation codes include:
Public Key Algorithms:
B: Ed25519 non-transferable prefix public verification key (44 characters)D: Ed25519 public verification key (44 characters)1AAA: ECDSA secp256k1 non-transferable prefix (48 characters)1AAC: Ed448 non-transferable prefix (80 characters)Digest Algorithms:
E: Blake3-256 digest (44 characters)F: Blake2b-256 digest (44 characters)H: SHA3-256 digest (44 characters)I: SHA2-256 digest (44 characters)0D: Blake3-512 digest (88 characters)0F: SHA3-512 digest (88 characters)Signature Algorithms:
0B: Ed25519 signature (88 characters)0C: ECDSA secp256k1 signature (88 characters)1AAE: Ed448 signature (152 characters)Derivation codes themselves provide no cryptographic security—they are plaintext metadata. However, they enable critical security properties:
Cryptographic Agility: Systems can support multiple algorithms simultaneously without breaking changes. New algorithms can be added by defining new derivation codes.
Algorithm Binding: The derivation code creates an immutable binding between the algorithm specification and the cryptographic material. Changing the code invalidates the primitive.
Verification Determinism: Verifiers can deterministically select the correct algorithm without ambiguity or negotiation.
Post-Quantum Readiness: New post-quantum algorithms can be integrated by defining new derivation codes without protocol changes.
Derivation codes implicitly encode the expected size of cryptographic material:
Single-character codes (e.g., B, E, F):
Two-character codes (e.g., 0B, 0D, 0F):
Four-character codes (e.g., 1AAA, 1AAC):
The 24-bit alignment constraint is fundamental: all CESR primitives must be integer multiples of 4 Base64 characters (24 bits) in text domain and 3 bytes (24 bits) in binary domain. This ensures composability—the ability to convert concatenated primitives between domains without losing structure.
CESR encoding transforms raw cryptographic material into qualified primitives through a precise process:
Step 1: Determine Pad Size
Given raw material of N bytes, calculate pad size:
ps = (3 - (N mod 3)) mod 3
For a 32-byte Ed25519 public key:
ps = (3 - (32 mod 3)) mod 3 = (3 - 2) mod 3 = 1
Step 2: Prepend Lead Bytes
Prepend ps zero bytes to the raw material:
padded = [0x00] * ps + raw_bytes
For 32-byte key with ps=1:
padded = [0x00] + [32 bytes of key material] = 33 bytes
Step 3: Base64 Encode
Encode the padded bytes using Base64 URL-safe encoding:
encoded = base64_url_safe_encode(padded)
This produces 44 characters (33 bytes * 8 bits / 6 bits per Base64 char = 44).
Step 4: Replace Lead Characters with Derivation Code
The first ps Base64 characters result from the lead bytes and contain no information from the raw material. Replace these with the derivation code:
qualified = derivation_code + encoded[ps:]
For Ed25519 with code B:
qualified = 'B' + encoded[1:] = 'BF5pxRJP6THrUtlDdhh07hJEDKrJxkcR9m5u1xs33bhp'
Text Domain (T):
[A-Z, a-z, 0-9, -, _]BF5pxRJP6THrUtlDdhh07hJEDKrJxkcR9m5u1xs33bhpBinary Domain (B):
[0x04, 0x17, 0xa7, ...] (33 bytes total)Raw Domain (R):
(derivation_code, raw_bytes)('B', [0x17, 0xa7, 0x1c, ...]) (32 raw bytes)Derivation codes follow specific structural patterns:
Single-character codes (most common):
B, D, E, F, H, ITwo-character codes (larger primitives):
0 (zero)0B, 0D, 0E, 0F, 0GFour-character codes (specialized algorithms):
1 (one)1AAA, 1AAB, 1AAC, 1AAD, 1AAEInception Events (icp):
Derivation codes appear in multiple fields:
{
"v": "KERI10JSON000188_",
"t": "icp",
"d": "ELvaU6Z-i0d8JJR2nmwyYAZAoTNZH3UfSVPzhzS6b5CM",
"i": "ELvaU6Z-i0d8JJR2nmwyYAZAoTNZH3UfSVPzhzS6b5CM",
"s": "0",
"kt": "1",
"k": ["DKrJxkcR9m5u1xs33F5pxRJP6T7hJEbhpHrUtlDdhh0"],
"n": ["ELvaU6Z-i0d8JJR2nmwyYAZAoTNZH3UfSVPzhzS6b5CM"]
}
d field: SAID with E derivation code (Blake3-256 digest)i field: AID prefix with E code (self-addressing identifier)k array: Current signing key with D code (Ed25519 public key)n array: Next key digest with E code (Blake3-256 of pre-rotated key)Rotation Events (rot):
Similar structure with updated keys:
{
"v": "KERI10JSON000190_",
"t": "rot",
"d": "EY6jnekRK0M3GzKd7N0xH6fMJk2EqPjLkEcvXqhJRkqw",
"i": "ELvaU6Z-i0d8JJR2nmwyYAZAoTNZH3UfSVPzhzS6b5CM",
"s": "1",
"p": "ELvaU6Z-i0d8JJR2nmwyYAZAoTNZH3UfSVPzhzS6b5CM",
"kt": "1",
"k": ["DNewKeyMaterialAfterRotation123456789012345678"],
"n": ["ENextKeyDigestForSubsequentRotation1234567890"]
}
p field: Prior event digest with E codek and n values with appropriate derivation codesInteraction Events (ixn):
Minimal structure for anchoring:
{
"v": "KERI10JSON000138_",
"t": "ixn",
"d": "EAnchoredDataDigest123456789012345678901234",
"i": "ELvaU6Z-i0d8JJR2nmwyYAZAoTNZH3UfSVPzhzS6b5CM",
"s": "2",
"p": "EY6jnekRK0M3GzKd7N0xH6fMJk2EqPjLkEcvXqhJRkqw",
"a": ["ESealedDataDigest1234567890123456789012345"]
}
a array: Anchored data seals with E codesSelf-Certifying Identifiers:
The most fundamental usage is in AID prefixes:
BF5pxRJP6THrUtlDdhh07hJEDKrJxkcR9m5u1xs33bhp
Breakdown:
B: Derivation code indicating Ed25519 non-transferableF5pxRJP6THrUtlDdhh07hJEDKrJxkcR9m5u1xs33bhp: Base64-encoded public keyVerification process:
BSelf-Addressing Identifiers:
For self-addressing AIDs:
ELvaU6Z-i0d8JJR2nmwyYAZAoTNZH3UfSVPzhzS6b5CM
Breakdown:
E: Derivation code indicating Blake3-256 digestLvaU6Z-i0d8JJR2nmwyYAZAoTNZH3UfSVPzhzS6b5CM: Base64-encoded digestVerification process:
Ei field with dummy charactersWitness Receipts:
Witness signatures use indexed signature codes:
-CAB
0BAAAAAAAAAAAAAAAAAAAAAA
BJq7UABlttINuWJh1Xl2lkqZG4NTdUdqnbFJDa6ZyxCC
0BSignatureBytes1234567890123456789012345678901234567890123456789012345678901234
Breakdown:
-CAB: Count code indicating 2 indexed signatures follow0B: Indexed signature derivation code (Ed25519)Public Key Verification:
Digest Verification:
SAID Verification:
# charactersDerivation codes qualify various types of cryptographic material:
Keys: Public keys (B, D, 1AAA), private keys (A, J), encryption keys (C, O)
Digests: Hash outputs (E, F, G, H, I, 0D, 0E, 0F, 0G)
Signatures: Signature values (0B, 0C, 1AAE)
Salts/Seeds: Random values (0A, A)
For multi-signature scenarios, derivation codes include index information:
Siger (indexed signature): Combines signature with index indicating which key signed
Cigar (un-indexed signature): Signature without index for single-sig scenarios
Both use the same underlying derivation codes but with different framing.
Special derivation codes indicate groups of primitives:
-CAB: Count code for 2 indexed signatures
-CAC: Count code for 3 indexed signatures
-GAB: Group code for event source seals
These enable pipelined streaming where multiple primitives are processed as a unit.
Concatenated Streams:
Multiple qualified primitives can be concatenated:
BKey1234567890123456789012345678901234567890EDigest1234567890123456789012345678901234560BSignature123456789012345678901234567890123456789012345678901234567890123456789012
Parsing:
B → 44-character Ed25519 key followsE → 44-character Blake3-256 digest follows0B → 88-character Ed25519 signature followsNested Structures:
ACDC credentials contain multiple qualified primitives:
{
"v": "ACDC10JSON000197_",
"d": "ECredentialSAID1234567890123456789012345",
"i": "EIssuerAID123456789012345678901234567890",
"s": "ESchemaID1234567890123456789012345678901",
"a": {
"d": "EAttributeBlockSAID123456789012345678901",
"name": "Alice"
}
}
Each d, i, s field contains a qualified primitive with derivation code.
Implementations must maintain code tables mapping derivation codes to:
The CESR specification defines multiple code tables:
Small Fixed Raw Size Table: Single-character codes for 32-byte primitives Large Fixed Raw Size Table: Two-character codes for 64-byte primitives Variable Raw Size Tables: Four-character codes for variable-length primitives
Cold Start Parsing:
When beginning to parse a CESR stream:
Stream Processing:
For continuous streams:
Unknown Codes:
If a derivation code is not recognized:
Length Mismatches:
If primitive length doesn't match code specification:
Invalid Base64:
If Base64 decoding fails:
Code Lookup:
Use hash tables or switch statements for O(1) code lookup:
CODE_TABLE = {
'B': {'algorithm': 'Ed25519', 'length': 44, 'pad': 1},
'E': {'algorithm': 'Blake3-256', 'length': 44, 'pad': 1},
'0B': {'algorithm': 'Ed25519-Sig', 'length': 88, 'pad': 2},
# ...
}
Batch Processing:
Process groups of primitives together when count codes indicate batches:
if code == '-CAB': # 2 indexed signatures
signatures = parse_batch(stream, count=2, type='indexed_sig')
verify_batch(signatures)
Zero-Copy Parsing:
Where possible, avoid copying data:
# Instead of:
key_bytes = stream[1:44].decode('base64')
# Use views:
key_view = memoryview(stream)[1:44]
Derivation codes enable seamless algorithm upgrades:
Adding New Algorithms:
Deprecating Algorithms:
Post-Quantum Transition:
When quantum computers threaten current algorithms:
This approach ensures KERI remains secure even as cryptographic landscape evolves.
Implementations MUST maintain accurate code tables mapping derivation codes to algorithm specifications. The CESR specification defines multiple tables that must be synchronized:
Code tables must specify for each code:
All CESR primitives MUST maintain 24-bit boundary alignment:
Pad size calculation: ps = (3 - (N mod 3)) mod 3 where N is raw byte length.
Implement cold start parsing capability:
Do NOT attempt to parse primitives with unknown derivation codes—reject immediately.
Unknown Codes: Reject primitives with unrecognized derivation codes. Do not attempt to parse or skip.
Length Mismatches: If extracted primitive length doesn't match code specification, reject as corrupted.
Invalid Base64: If Base64 decoding fails, reject primitive and indicate encoding error.
Design code table systems to support:
Code Lookup: Use hash tables or switch statements for O(1) derivation code lookup.
Batch Processing: When count codes indicate groups, process primitives in batches for efficiency.
Zero-Copy Parsing: Where possible, use memory views to avoid copying data during parsing.
Algorithm Binding: The derivation code creates an immutable binding between algorithm specification and cryptographic material. Changing the code invalidates the primitive.
Verification Determinism: Always use the algorithm specified by the derivation code—never substitute or negotiate alternatives.
Deprecation Policy: Continue supporting deprecated codes for verification of historical data, but prevent new issuance.
Implementations should test:
All KERI implementations MUST:
This ensures that KERI identifiers and events are portable across implementations.