Loading vLEI.wiki
Fetching knowledge base...
Fetching knowledge base...
This comprehensive explanation has been generated from 79 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 version-string is the first field in any top-level KERI field map that specifies the protocol version, serialization format, and message size in a regex-parseable format, enabling self-framing behavior in serialization formats (JSON, CBOR, MGPK) that don't natively support it.
The version-string is a specially formatted string field that appears as the first element in KERI and ACDC data structures. It serves as a critical metadata header that enables parsers to correctly interpret the serialization format, protocol version, and message boundaries without requiring external context.
The version-string fulfills three essential functions in the KERI/ACDC ecosystem:
As Document 1 states, the version-string serves as a "workaround mechanism" to enable self-framing behavior in serialization formats that don't natively support it. This is critical because CESR requires all primitives to be self-framing for composability, but JSON, CBOR, and MGPK lack this property inherently.
Size Calculation: Always compute size over the compact serialization (no whitespace) of the message body. The size field must reflect the exact byte count that will be transmitted.
Field Ordering: The version-string MUST be the first field in the serialized structure. Parsers depend on this invariant for stream processing.
Hexadecimal Encoding: Use lowercase hexadecimal digits (0-9, a-f) for the size field. Pad with leading zeros to the required width (typically 6 digits).
Terminator: Always include the underscore terminator character. This provides an unambiguous end marker for the version-string.
Regex Patterns: Use robust regex patterns that validate the complete version-string structure, not just the leading characters. Reject malformed version-strings immediately.
Size Validation: Validate that the size field is within reasonable bounds before allocating buffers. Extremely large sizes may indicate attacks or corruption.
Stream Positioning: After reading a message, ensure the stream pointer is positioned exactly at the start of the next message. Off-by-one errors cause cascading parse failures.
Error Handling: Implement graceful error handling for:
Use JSON when:
Use CBOR when:
Use MessagePack when:
The version-string follows a regex-parseable format that encodes multiple pieces of information in a compact representation. According to Document 13, ACDC version strings follow the pattern:
ACDCvvSSSShhhhhh_
Where:
For KERI events, Document 11 shows version strings like KERI10JSON0000e6_, following a similar pattern:
KERIvvKKKKSSSSSS_
Where:
The version-string contains several critical components:
Protocol Identifier: The leading characters ("KERI" or "ACDC") immediately identify which protocol specification governs the message structure. This allows parsers to load the appropriate validation rules and field definitions.
Version Numbers: The version component enables protocol evolution while maintaining backward compatibility. Parsers can determine whether they support a given version and handle version-specific features appropriately.
Serialization Kind: The serialization indicator tells parsers which codec to use for deserialization. Common values include:
Size Information: The hexadecimal size field specifies the total byte count of the serialized message body. This is the critical component that enables self-framing behavior.
Terminator: The underscore character marks the end of the version-string, allowing parsers to distinguish it from the message body.
The version-string is always represented as a string type in the serialization format. In JSON, it appears as:
{
"v": "ACDC10JSON00011c_",
"d": "EAdXt3gIXOf2BBWNHdSXCJnFJL5OuQPyM5K0neuniccM",
...
}
The field label is consistently "v" across all KERI and ACDC structures. Document 37 confirms that the version string "must always appear first when present" in the field ordering.
The version-string uses ASCII-compatible characters exclusively, ensuring it can be parsed in both text and binary serialization formats without encoding ambiguity. The components are encoded as:
Protocol and Version: Plain ASCII text (e.g., "KERI10", "ACDC10")
Serialization Kind: ASCII text codes:
Size Field: Hexadecimal ASCII digits (0-9, a-f) representing the byte count. The use of hexadecimal allows compact representation of large sizes while maintaining ASCII compatibility.
Terminator: The underscore character "_" provides an unambiguous end marker.
The version-string has a fixed length determined by its format specification. For ACDC version strings following the ACDCvvSSSShhhhhh_ pattern:
For KERI version strings, the length varies based on the specific format but follows similar principles. Document 25 shows examples like KERI10JSON000188_ with 18 characters.
The size field constraint is particularly important. With 6 hexadecimal digits, the maximum representable size is 0xFFFFFF = 16,777,215 bytes (approximately 16 MB). This is sufficient for most KERI events and ACDC credentials while maintaining a compact version-string.
Creating a version-string involves several steps:
1. Determine Protocol and Version: Select the appropriate protocol identifier (KERI or ACDC) and version number based on the message type being created.
2. Choose Serialization Format: Select JSON, CBOR, or MGPK based on the use case:
3. Serialize Message Body: Serialize the complete message structure (excluding the version-string itself) using the chosen format.
4. Calculate Size: Compute the byte length of the serialized message body. This must be the exact byte count, not character count.
5. Format Size as Hexadecimal: Convert the byte count to hexadecimal and pad with leading zeros to the required width (typically 6 digits).
6. Construct Version-String: Concatenate all components in the specified order with the terminator.
7. Prepend to Message: Add the version-string as the first field in the serialized structure.
Document 13 emphasizes that the version-string must be computed over the compact serialization (no whitespace) to ensure consistent size calculation.
The version-string is immutable once a message is created. Any modification to the message body requires:
1. Reserialize: Serialize the modified message body
2. Recalculate Size: Compute the new byte length
3. Regenerate Version-String: Create a new version-string with the updated size
4. Replace: Substitute the new version-string for the old one
This immutability is critical for maintaining message integrity. In ACDC structures that use SAIDs, modifying the message body would invalidate the SAID, requiring recomputation of the entire cryptographic commitment chain.
Parsers must validate version-strings to ensure message integrity:
Format Validation:
Size Verification:
Protocol Compliance:
Document 6 describes how the sniffer component uses regex matching to locate version-strings in mixed-format streams, extracting the length information to determine message boundaries.
The version-string appears in multiple KERI ecosystem protocols:
KERI Key Event Messages: All key events (inception, rotation, interaction) include version-strings. Document 43 shows examples:
{"v":"KERI10JSON0000e6_","t":"icp","d":"EH7Oq9oxCgYa-nnNLvwhp9sFZpALILlRYyB-6n4WDi7w",...}
ACDC Credentials: All ACDC variants (compact, full, public, private) include version-strings. Document 29 demonstrates:
{"v":"ACDC10JSON00011c_","d":"EAdXt3gIXOf2BBWNHdSXCJnFJL5OuQPyM5K0neuniccM",...}
IPEX Messages: Issuance and Presentation Exchange protocol messages use version-strings. Document 12 shows IPEX exchange messages include version-strings in their structure.
TEL Events: Transaction Event Log events for credential registries include version-strings for self-framing.
The version-string participates in the complete message lifecycle:
Creation Phase: Generated during message construction as described above.
Transmission Phase: The version-string enables stream processing. Document 5 explains how Parside uses version-strings to parse streams:
This enables pipelined processing of concatenated messages without delimiters.
Reception Phase: Receivers validate the version-string to ensure:
Archival Phase: Version-strings enable format migration. Archives can identify message formats and versions, facilitating conversion to newer formats while preserving semantic content.
The version-string interacts with several related KERI/ACDC structures:
Version Code: Document 7 distinguishes version-code from version-string. The version-code is a CESR count code that specifies which CESR code tables are active in a stream section. The version-string, by contrast, is a field within a message that describes that specific message's format.
CESR Primitives: Version-strings enable non-CESR formats (JSON, CBOR, MGPK) to achieve self-framing properties required for CESR composability. Document 4 explains that CESR primitives are inherently self-framing, but JSON/CBOR/MGPK require version-strings to achieve this property.
Field Maps: The version-string is always the first field in field-maps. Document 37 establishes the normative field ordering with v first, followed by t (type), d (SAID), and other fields.
SAIDs: In structures using SAIDs, the version-string is included in the SAID computation. Document 13 specifies that the SAID is computed over the entire serialized structure including the version-string, binding the format metadata cryptographically to the content.
Implementing version-string parsing requires careful attention to several details:
Regex Patterns: Parsers should use robust regex patterns that match the expected format while rejecting malformed version-strings. The pattern should capture all components for validation.
Size Handling: The hexadecimal size field must be parsed correctly:
Stream Positioning: After reading the version-string and message body, the parser must position the stream pointer correctly for the next message. Off-by-one errors can cause catastrophic parsing failures.
Choosing the appropriate serialization format involves trade-offs:
JSON:
CBOR:
MessagePack (MGPK):
Document 15 emphasizes that CESR's composability property enables zero-cost switching between text and binary formats, allowing developers to use JSON during development and switch to CBOR/MGPK for production without code changes.
As protocols evolve, version-strings enable graceful migration:
Backward Compatibility: Parsers should support multiple version numbers, allowing older messages to be processed alongside newer ones.
Forward Compatibility: When encountering unknown versions, parsers should fail gracefully with informative error messages rather than crashing or producing incorrect results.
Version Negotiation: In interactive protocols, parties can exchange version-strings to negotiate a mutually supported version before beginning substantive communication.
Robust implementations must handle various error conditions:
Malformed Version-Strings: Detect and reject version-strings that don't match the expected format.
Unsupported Versions: Gracefully handle version numbers that aren't supported by the implementation.
Size Mismatches: Detect when the actual message size doesn't match the size field in the version-string, indicating truncation or corruption.
Serialization Errors: Handle cases where the message body can't be deserialized using the indicated format.
The version-string represents a potential attack surface:
Size Field Attacks: Malicious actors could craft version-strings with incorrect size fields to cause:
Implementations must validate size fields against reasonable bounds and available resources.
Format Confusion: Attackers might specify one serialization format in the version-string but provide data in a different format, potentially exploiting parser vulnerabilities.
Version Downgrade: In protocols that support multiple versions, attackers might force use of older, less secure versions through version-string manipulation.
In ACDC structures, the version-string is protected by the SAID mechanism. Any tampering with the version-string invalidates the SAID, making the attack detectable. However, in contexts where SAIDs aren't used, additional integrity protection (signatures, MACs) may be necessary.
Version-string parsing is on the critical path for message processing. Optimizations include:
Compiled Regex: Pre-compile regex patterns rather than compiling on each parse.
Direct Parsing: For performance-critical code, consider hand-written parsers that directly extract components without regex overhead.
Caching: Cache parsed version-string components when processing multiple messages with the same format.
Zero-Copy: Design parsers to avoid copying the message body, using the size field to create views into the original buffer.
Computing the size field efficiently is important for message generation:
Streaming Serialization: Some serialization libraries support streaming output, allowing size calculation during serialization rather than requiring a separate pass.
Size Estimation: For formats with predictable size characteristics, estimate the size and allocate buffers accordingly, adjusting if the estimate is incorrect.
Incremental Updates: When modifying messages, track size changes incrementally rather than reserializing the entire structure.
The version-string is a foundational element that enables interoperability across the KERI ecosystem:
Multi-Language Implementations: Version-strings provide a language-agnostic format specification, enabling implementations in Python (keripy), Rust (keriox), JavaScript/TypeScript (signify-ts), and other languages to interoperate seamlessly.
Protocol Layering: Version-strings enable clean protocol layering. KERI events can be embedded in ACDC credentials, which can be embedded in IPEX messages, with each layer having its own version-string for independent evolution.
Tooling: Version-strings enable generic tooling that can inspect, validate, and transform KERI/ACDC messages without protocol-specific knowledge, simply by parsing the version-string to determine format and structure.
The version-string, despite its apparent simplicity, is a critical architectural element that enables the KERI ecosystem's composability, interoperability, and evolvability.
Size Field Attacks: Validate size fields against maximum message sizes and available memory. Reject unreasonably large sizes before allocation.
Format Confusion: Verify that the message body actually uses the serialization format specified in the version-string. Don't blindly trust the format indicator.
Version Downgrade: In protocols supporting multiple versions, implement version negotiation carefully to prevent downgrade attacks.
Integrity Protection: In contexts without SAID protection, consider additional integrity mechanisms (signatures, MACs) to protect version-strings from tampering.
Compiled Regex: Pre-compile regex patterns at initialization rather than compiling on each parse operation.
Zero-Copy Parsing: Design parsers to create views into the original buffer rather than copying message bodies when possible.
Streaming Serialization: Use serialization libraries that support streaming output to calculate sizes during serialization rather than requiring separate passes.
Buffer Pooling: Reuse allocated buffers across multiple message parsing operations to reduce allocation overhead.
Format Validation: Test parsing of valid and invalid version-strings, including edge cases like maximum sizes and boundary conditions.
Size Accuracy: Verify that generated version-strings contain accurate size fields by deserializing and measuring the result.
Stream Processing: Test parsing of concatenated messages with various sizes and formats to ensure correct boundary detection.
Error Conditions: Test error handling for truncated messages, oversized messages, and format mismatches.
Cross-Format: Test round-trip conversion between JSON, CBOR, and MessagePack to verify format-independent semantics.
When integrating with existing KERI/ACDC libraries:
keripy (Python): Use the built-in serialization functions that automatically generate correct version-strings.
signify-ts (TypeScript): Follow the patterns in the vLEI training examples for credential creation with proper version-strings.
keriox (Rust): Use the SAID derive macro which handles version-string generation automatically when the version attribute is specified.
Custom Implementations: Study the reference implementations to understand subtle details like field ordering and size calculation edge cases.