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.
A group-framing-code (also called count-code or group-code) is a special CESR framing code that delineates groups of primitives by specifying the count of elements, enabling self-framing grouping, pipelined stream processing, and hierarchical composition of cryptographic primitives in both text and binary domains.
A group-framing-code is a specialized encoding element within CESR (Composable Event Streaming Representation) that serves as a structural delimiter for organizing multiple primitives into cohesive, processable units. Unlike simple framing codes that delineate individual primitives, group-framing-codes provide counting mechanisms that specify how many primitives or nested groups follow, enabling parsers to extract entire groups atomically from a stream.
The primary purposes of group-framing-codes are:
Group-framing-codes are fundamental to CESR's composability property—the ability to convert concatenated primitives en masse between text and binary domains without loss. As stated in the CESR specification: "Self-framing grouping using Count Codes is one of the primary advantages of composable encoding."
The most critical implementation requirement is maintaining 24-bit boundary alignment for all group-framing-codes. This ensures composability—the ability to convert concatenated groups between text and binary domains without loss.
Alignment Formula:
pad_size = (3 - (count_bytes mod 3)) mod 3
This formula must be applied consistently across all implementations. Failure to maintain alignment breaks composability and makes streams non-interoperable.
Implementations must support dynamic code table loading based on CESR version codes. The active version determines:
Parsers should start with a default version and switch versions when encountering version count codes in the stream.
The recommended parser architecture separates concerns:
This modular design enables efficient stream processing and supports the cold start problem solution.
Implementations must support hierarchical composition through recursive parsing:
def parse_group(stream, position):
# Parse group code
group_info = parse_group_code(stream[position:])
position += group_info['code_length']
elements = []
for i in range(group_info['count']):
# Check if next element is a group code
if is_group_code(stream[position:]):
# Recursive call for nested group
nested_group, new_position = parse_group(stream, position)
elements.append(nested_group)
position = new_position
else:
# Parse primitive
primitive, new_position = parse_primitive(stream, position)
elements.append(primitive)
position = new_position
return {'type': group_info['type_code'], 'elements': elements}, position
Group-framing-codes follow CESR's general primitive structure but with specialized semantics:
Text Domain Structure:
[Type Code][Count Value]
Binary Domain Structure:
[Type Bytes][Count Bytes]
The group-framing-code is prepended to the group it describes, making the entire structure self-framing. A parser encountering a group-framing-code knows:
Group-framing-codes consist of three logical components:
1. Group Type Indicator
The type indicator specifies what kind of elements the group contains:
The type indicator is encoded in the leading character(s) of the code, using CESR's code table system.
2. Count Encoding
The count value can be encoded in multiple ways depending on the expected group size:
The count encoding must maintain CESR's 24-bit alignment constraint. For example, if the raw count requires 2 bytes, it must be padded to 3 bytes (24 bits) before Base64 encoding to 4 characters in the text domain.
3. Alignment Padding
To satisfy CESR's composability requirements, group-framing-codes include implicit padding:
ps = (3 - (N mod 3)) mod 3 where N is the raw count byte lengthGroup-framing-codes encode the following logical fields:
Type Field:
-A (small count group), -0A (large count group)Count Field:
Implicit Pad Field:
Group-framing-codes use CESR's dual-domain encoding:
Text Domain Encoding:
ps = (3 - (count_bytes mod 3)) mod 3ps zero bytes to raw count valueExample for count value 5 (1 byte):
Raw count: 0x05 (1 byte)
Pad size: (3 - (1 mod 3)) mod 3 = 2
Padded: 0x000005 (3 bytes)
Base64: AAAF (4 characters)
With type code '-A': -AAAAF (6 characters total)
Binary Domain Encoding:
Example for same count value 5:
Raw count: 0x05 (1 byte)
Pad size: 2
Padded: 0x000005 (3 bytes)
With type code 0xD0: 0xD0000005 (4 bytes total, but type code may be 1 byte)
Raw Domain Representation:
In the raw domain, group-framing-codes are represented as tuples:
(type_code_text, raw_count_integer)
Example:
("-A", 5)
This representation separates metadata (type code) from the actual count value used in parsing logic.
Alignment Constraint:
All group-framing-codes must satisfy the 24-bit alignment requirement:
4k characters where k is a positive integer3k bytes where k is a positive integerCount Range Constraints:
The maximum count value depends on the encoding scheme:
The CESR specification allows for multiple count code types to optimize for different use cases—small groups use compact codes, large groups use extended codes.
Nesting Depth Constraints:
While CESR supports hierarchical composition, implementations may impose practical limits:
Encoding a Group-Framing-Code:
The process of creating a group-framing-code involves:
Determine Group Type: Select the appropriate type code based on the elements being grouped (e.g., signature group, digest group, nested group)
Count Elements: Calculate the number of primitives or sub-groups in the group
Calculate Pad Size: Apply the formula ps = (3 - (count_bytes mod 3)) mod 3
Encode Count Value:
ps zero bytes to the raw countPrepend Type Code: Add the type code characters/bytes to the encoded count
Verify Alignment: Ensure the total length is a multiple of 4 characters (text) or 3 bytes (binary)
Example Creation Process:
# Pseudo-code for creating a group-framing-code
def create_group_code(group_type, element_count):
# Determine count byte length
count_bytes = element_count.to_bytes((element_count.bit_length() + 7) // 8, 'big')
# Calculate pad size
pad_size = (3 - (len(count_bytes) % 3)) % 3
# Prepend pad bytes
padded_count = b'\x00' * pad_size + count_bytes
# Base64 encode for text domain
encoded_count = base64.urlsafe_b64encode(padded_count).decode('ascii')
# Prepend type code
group_code = group_type + encoded_count
return group_code
Group-framing-codes are immutable once created. Modifying a group requires:
This immutability is essential for CESR's cryptographic integrity—changing a group-framing-code invalidates any signatures or digests computed over the stream.
Incremental Group Building:
For applications that build groups incrementally:
This approach avoids the need to reserve space for the count or perform stream rewrites.
Parsing a Group-Framing-Code:
The Parside parser processes group-framing-codes through these steps:
Validation Checks:
Robust parsers perform several validation checks:
count elements after the codeError Handling:
Parsing failures can occur due to:
Parsers should implement graceful error handling, potentially using escrow mechanisms to buffer incomplete groups until more data arrives.
Group-framing-codes are used throughout the KERI ecosystem:
1. KERI Event Messages
Key Event Logs (KELs) use group-framing-codes to organize:
Example KEL structure:
[Event Data]
[Group Code: 3 signatures]
[Signature 1]
[Signature 2]
[Signature 3]
[Group Code: 2 seals]
[Seal 1]
[Seal 2]
2. ACDC Credentials
Authentic Chained Data Containers (ACDCs) use group-framing-codes for:
3. IPEX Protocol
Issuance and Presentation Exchange (IPEX) uses group-framing-codes to bundle:
4. Transaction Event Logs (TELs)
TELs use group-framing-codes for:
Creation Phase:
Transmission Phase:
Reception Phase:
count elements from the streamProcessing Phase:
Group-framing-codes interact with several related CESR structures:
1. Primitive Codes
Individual primitives have their own framing codes that specify type and size. Group-framing-codes organize these primitives into higher-level structures.
2. Count Codes
The terms "group-framing-code" and "count code" are often used interchangeably. Technically, count codes are a subset of framing codes specifically designed for grouping.
3. Version Codes
CESR version codes specify which code table to use when parsing. Group-framing-codes are interpreted according to the active version.
4. Opcode Structures
Opcodes are a proposed extension to CESR that would enable stack-based virtual machine operations on groups. Group-framing-codes would serve as operands for these opcodes.
5. Attachment Structures
In KERI, group-framing-codes are often used in attachment sections of messages, where they organize signatures, receipts, and other supplementary data.
One of the most powerful features of group-framing-codes is support for nested groups:
[Outer Group Code: 2 groups]
[Inner Group Code: 3 signatures]
[Signature 1]
[Signature 2]
[Signature 3]
[Inner Group Code: 2 digests]
[Digest 1]
[Digest 2]
This hierarchical structure enables:
The Parside parser handles nested groups through recursive descent:
Group-framing-codes enable efficient pipelining:
Multiplexing:
[Stream]
[Group A: 5 elements]
[Group B: 3 elements]
[Group C: 7 elements]
A multiplexer can combine multiple groups into a single stream, with each group maintaining its self-framing property.
De-multiplexing:
A de-multiplexer reads the stream sequentially:
This architecture supports high-bandwidth applications where multiple data flows are interleaved in a single stream.
The cold start problem occurs when a parser begins reading a stream mid-transmission without knowing where primitive boundaries are. Group-framing-codes solve this through the sniffable property:
This makes CESR streams robust to transmission errors and partial data reception.
Parsing Efficiency:
Encoding Overhead:
Domain Conversion:
Implementing a group-framing-code parser requires:
count times to extract elementsImplementing a group-framing-code encoder requires:
Unit Tests:
Integration Tests:
Performance Tests:
Group-framing-codes are a foundational element of CESR's architecture, enabling self-framing grouping, hierarchical composition, and efficient stream processing. Their design reflects careful consideration of composability constraints, parsing efficiency, and protocol extensibility. Understanding group-framing-codes is essential for implementing KERI protocols and building applications on the CESR encoding framework.
Implementations should impose reasonable nesting depth limits to prevent stack overflow attacks.
Robust implementations must handle:
The escrow mechanism can buffer incomplete groups until more data arrives, enabling graceful handling of partial stream reception.
Single-Pass Parsing:
Group-framing-codes enable one-pass stream processing without backtracking. Implementations should:
Batch Domain Conversion:
The composability property allows en masse conversion between text and binary domains:
# Convert entire group without parsing elements
def convert_group_to_binary(text_group):
# Base64 decode the entire group
binary_group = base64.urlsafe_b64decode(text_group)
return binary_group
This is significantly faster than converting individual primitives.
Alignment Tests:
Test all three pad sizes (0, 1, 2) to ensure correct alignment:
def test_alignment():
for count in [1, 2, 3, 4, 5, 100, 1000]:
code = create_group_code(count)
assert len(code) % 4 == 0, f"Text code not aligned: {code}"
Round-Trip Tests:
Verify composability through round-trip conversion:
def test_round_trip():
text_group = create_text_group()
binary_group = text_to_binary(text_group)
recovered_text = binary_to_text(binary_group)
assert text_group == recovered_text
Nested Group Tests:
Test hierarchical composition with multiple nesting levels:
def test_nested_groups():
outer_group = create_group([
create_group([primitive1, primitive2]),
create_group([primitive3, primitive4, primitive5])
])
parsed = parse_group(outer_group)
assert len(parsed['elements']) == 2
assert len(parsed['elements'][0]['elements']) == 2
assert len(parsed['elements'][1]['elements']) == 3
Count Validation:
Always validate that count values are within reasonable bounds:
MAX_GROUP_SIZE = 1000000 # Implementation-defined limit
if count > MAX_GROUP_SIZE:
raise ValueError(f"Group count {count} exceeds maximum {MAX_GROUP_SIZE}")
Nesting Depth Limits:
Enforce maximum nesting depth to prevent stack overflow:
MAX_NESTING_DEPTH = 10
def parse_group(stream, position, depth=0):
if depth > MAX_NESTING_DEPTH:
raise ValueError(f"Nesting depth {depth} exceeds maximum {MAX_NESTING_DEPTH}")
# ... parsing logic
Stream Length Validation:
Verify that the stream contains enough data for the counted elements:
expected_length = position + (count * element_size)
if len(stream) < expected_length:
raise ValueError(f"Stream truncated: expected {expected_length} bytes, got {len(stream)}")
Implementations in different languages must produce identical encodings for the same logical groups. This requires:
Cross-implementation test suites should verify interoperability by exchanging encoded groups and validating parsing results.