Loading vLEI.wiki
Fetching knowledge base...
Fetching knowledge base...
This comprehensive explanation has been generated from 35 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.
An append-only event log is a verifiable data structure where new events can be appended to the end but existing events are immutable, providing a tamper-evident chronological record. In KERI, this structure forms the foundation of Key Event Logs (KELs) that record cryptographically signed key management events in an ordered, verifiable sequence.
An append-only event log is a fundamental data structure pattern characterized by two essential properties:
This pattern creates a verifiable chronological record where the complete history of events is preserved and any tampering becomes cryptographically detectable. The append-only property is not merely a software convention but a cryptographically enforced guarantee through hash chaining and digital signatures.
Within the KERI protocol, append-only event logs serve as the primary data structure for establishing and maintaining cryptographic proof of control authority over identifiers. The Key Event Log (KEL) implements this pattern to record all key management events for an Autonomic Identifier (AID).
The append-only property provides several critical security guarantees:
d field with a fixed-length dummy value before hashingAppend-only event logs in KERI follow a backward and forward chained structure:
Backward chaining occurs through digest chaining, where each event includes a cryptographic digest (hash) of the previous event. This creates an immutable chain where:
According to Document 12, the digest chaining mechanism ensures that "each event is cryptographically bound to previous events," creating what the specification terms duplicity evidence - a structure that enables detection of conflicting log versions.
Forward chaining is implemented through pre-rotation, where each establishment event includes a cryptographic commitment (digest) to the next set of rotation keys. This forward commitment:
An append-only event log in KERI consists of several essential components:
1. Event Entries
Each entry in the log is a key event - a serialized data structure containing:
v): Protocol version and serialization formati): The AID this log belongs tos): Monotonically increasing integerd): SAID of the event itselft): Inception, rotation, or interactionp): Backward chain link2. Event Types
KERI defines three primary event types within the append-only structure:
icp): The first and only event that creates an identifier, establishing initial key staterot): Establishment events that change the authoritative key setixn): Non-establishment events that anchor external data without changing keysAs Document 7 explains, events are organized into two subsequences:
3. Cryptographic Binding
The append-only structure is cryptographically enforced through multiple mechanisms:
KERI append-only event logs support multiple serialization formats through CESR (Composable Event Streaming Representation):
All formats must preserve insertion-ordered field maps to ensure canonical serialization. As Document 10 specifies, "reproducible serialization is essential for SAID computation" and "round-trip serialization/deserialization must not alter field order."
The standard field structure for events in an append-only log follows the KERI event message format:
{
"v": "KERI10JSON00011c_",
"t": "icp",
"d": "EXq5YqaL6L48pf0fu7IUhL0JRaU2_RxFP0AL43wYn148",
"i": "EXq5YqaL6L48pf0fu7IUhL0JRaU2_RxFP0AL43wYn148",
"s": "0",
"kt": "1",
"k": ["DaU6JR2nmwyZ-i0d8JZAoTNZH3ULvYAfSVPzhzS6b5CM"],
"nt": "1",
"n": ["EZ-i0d8JZAoTNZH3ULvaU6JR2nmwyYAfSVPzhzS6b5CM"],
"bt": "0",
"b": [],
"c": [],
"a": []
}
Field semantics:
v: Version string encoding protocol, serialization, and sizet: Event type (icp=inception, rot=rotation, ixn=interaction)d: Self-addressing identifier (SAID) of this eventi: Identifier prefix (matches d for inception)s: Sequence number (0 for inception, increments for each event)kt: Current signing thresholdk: Current signing key listnt: Next signing threshold (for pre-rotation)n: Next key digest list (pre-rotation commitments)bt: Witness thresholdb: Witness identifier listc: Configuration traitsa: Anchored data sealsEvents are encoded using CESR primitives that provide:
Self-framing: Each primitive includes type and size information, enabling stream parsing without external schema knowledge.
Composability: Groups of primitives can be converted between text and binary domains without loss, as Document 15 explains: "Converting a group of concatenated primitives from text (T) to binary (B) domain produces the same result as converting each primitive individually and then concatenating."
Qualified cryptographic primitives: All cryptographic material (keys, digests, signatures) includes prepended derivation codes that specify the algorithm used:
E: Ed25519 public keyD: Blake3-256 digest0B: ECDSA secp256k1 signatureThis self-describing encoding enables algorithm agility - the ability to support multiple cryptographic algorithms within the same log structure.
Sequence number constraints:
Digest constraints:
Key constraints:
Event size:
Inception Process:
Creating an append-only event log begins with the inception event, which establishes the identifier and initial key state. According to Document 12, this process involves:
The inception event is unique and immutable - there can be only one inception event per identifier, and it cannot be changed after creation. This provides the cryptographic root of trust for the entire log.
Example inception workflow:
# Generate random seed
seed = generate_entropy(256) # 256 bits of entropy
# Derive initial key pair
private_key = derive_private_key(seed, algorithm='Ed25519')
public_key = derive_public_key(private_key)
# Derive next (pre-rotated) key pair
next_private_key = derive_private_key(seed, index=1)
next_public_digest = hash(derive_public_key(next_private_key))
# Create inception event
event = {
'v': 'KERI10JSON00011c_',
't': 'icp',
's': '0',
'kt': '1',
'k': [encode_key(public_key)],
'nt': '1',
'n': [encode_digest(next_public_digest)],
'bt': '0',
'b': [],
'c': [],
'a': []
}
# Compute SAID
event['d'] = compute_said(event)
event['i'] = event['d'] # For inception, i == d
# Sign event
signature = sign(serialize(event), private_key)
Appending Events:
The append-only property means that updates occur only through appending new events, never modifying existing ones. The two types of updates are:
1. Rotation Events (changing key state):
def create_rotation_event(kel, current_keys, next_keys):
# Get previous event
previous_event = kel[-1]
# Create rotation event
rotation = {
'v': 'KERI10JSON00011c_',
't': 'rot',
'i': previous_event['i'], # Same identifier
's': str(int(previous_event['s']) + 1), # Increment sequence
'p': previous_event['d'], # Previous event digest
'kt': '1',
'k': [encode_key(k) for k in current_keys],
'nt': '1',
'n': [encode_digest(hash(k)) for k in next_keys],
'bt': '0',
'b': [],
'c': [],
'a': []
}
# Compute SAID
rotation['d'] = compute_said(rotation)
# Sign with PREVIOUS keys (proving control)
signatures = [sign(serialize(rotation), k) for k in previous_keys]
return rotation, signatures
2. Interaction Events (anchoring data):
def create_interaction_event(kel, current_keys, anchored_data):
previous_event = kel[-1]
interaction = {
'v': 'KERI10JSON00011c_',
't': 'ixn',
'i': previous_event['i'],
's': str(int(previous_event['s']) + 1),
'p': previous_event['d'],
'a': [{
'd': compute_digest(anchored_data)
}]
}
interaction['d'] = compute_said(interaction)
signatures = [sign(serialize(interaction), k) for k in current_keys]
return interaction, signatures
Immutability Enforcement:
The append-only property is enforced through multiple mechanisms:
Log Verification Process:
Verifying an append-only event log involves multiple validation steps:
1. Structural Validation:
def verify_log_structure(kel):
# Check inception is first
if kel[0]['t'] != 'icp':
raise ValidationError("First event must be inception")
# Verify sequence numbers
for i, event in enumerate(kel):
if int(event['s']) != i:
raise ValidationError(f"Sequence number mismatch at index {i}")
# Verify digest chain
for i in range(1, len(kel)):
if kel[i]['p'] != kel[i-1]['d']:
raise ValidationError(f"Digest chain broken at index {i}")
return True
2. Cryptographic Validation:
def verify_event_signatures(event, signatures, key_state):
# Serialize event for signature verification
serialized = serialize(event)
# Get current authoritative keys from key state
current_keys = key_state['k']
threshold = int(key_state['kt'])
# Verify sufficient valid signatures
valid_sigs = 0
for sig in signatures:
for key in current_keys:
if verify_signature(serialized, sig, key):
valid_sigs += 1
break
if valid_sigs < threshold:
raise ValidationError(f"Insufficient signatures: {valid_sigs} < {threshold}")
return True
3. Key State Validation:
As Document 16 explains, key state validation ensures that:
4. Duplicity Detection:
The append-only structure enables ambient duplicity detection - the ability for any observer to detect conflicting versions of the log:
def detect_duplicity(kel1, kel2):
# Find first point of divergence
for i in range(min(len(kel1), len(kel2))):
if kel1[i]['d'] != kel2[i]['d']:
return {
'duplicitous': True,
'sequence': i,
'event1': kel1[i],
'event2': kel2[i]
}
# Check for truncation
if len(kel1) != len(kel2):
return {
'duplicitous': True,
'type': 'truncation',
'length1': len(kel1),
'length2': len(kel2)
}
return {'duplicitous': False}
Append-only event logs are the foundational data structure of KERI, used in multiple contexts:
1. Key Event Logs (KELs):
The primary use case is the KEL, which records all key management events for an identifier. As Document 1 establishes, KELs provide:
2. Key Event Receipt Logs (KERLs):
A KERL extends the KEL by including witness receipts - signatures from designated witnesses that attest to having observed specific events. According to Document 5, KERLs:
3. Transaction Event Logs (TELs):
The TEL applies the append-only pattern to credential lifecycle management:
As Document 7 explains, TELs provide "cryptographic proof of registry state by reference to the corresponding controlling KEL."
Creation Phase:
Active Phase:
Recovery Phase:
If key compromise is detected:
The append-only structure ensures that even compromised keys cannot erase the evidence of compromise - the entire history remains verifiable.
Archival Phase:
For long-term preservation:
Relationship to Blockchains:
As Document 1 notes, blockchains are a well-known example of append-only logs where:
However, KERI's append-only logs differ fundamentally:
Relationship to Certificate Transparency:
Certificate Transparency (CT) also uses append-only logs, as Document 35 describes:
KERI extends these concepts by:
Relationship to Event Sourcing:
The append-only event log pattern is also used in event sourcing architectures:
KERI applies these principles to key management:
Witnesses:
Witnesses interact with append-only logs by:
Watchers:
Watchers operate in "promiscuous mode" to:
Validators:
Validators use append-only logs to:
OOBI (Out-Of-Band Introduction):
OOBI enables discovery of append-only logs by:
Tamper Evidence:
The append-only structure provides strong tamper evidence through:
Non-Repudiation:
Controllers cannot deny events they have signed because:
Forward Integrity:
Pre-rotation provides forward integrity by:
Post-Quantum Security:
As Document 18 explains, the append-only structure with pre-rotation provides post-quantum security:
Storage Requirements:
Verification Performance:
Network Efficiency:
vs. Mutable Databases:
Traditional mutable databases (CRUD model) differ fundamentally:
As Document 3 explains, the RUN model (Read, Update, Nullify) provides:
vs. Blockchain Ledgers:
Blockchains provide global append-only logs but with significant differences:
KERI's approach provides:
vs. Certificate Transparency Logs:
CT logs share the append-only property but differ in:
KERI provides: