Specification for blob encoding in Lithoglyph’s ABI and storage layers.
Status: PROPOSED (resolves Q-ABI-BLOBS-001)
Chosen Encoding: CBOR (Concise Binary Object Representation)
Rationale:
| Criteria | Cap’n Proto | Protobuf | CBOR | MsgPack |
|---|---|---|---|---|
Schema Required |
Yes |
Yes |
No |
No |
Zero-Copy Access |
Yes |
No |
No |
No |
Self-Describing |
No |
No |
Yes |
Yes |
Deterministic |
Partial |
No (map ordering) |
Yes (with constraints) |
No (map ordering) |
Zig Support |
Poor |
Good (prost) |
Excellent (zig-cbor) |
Good |
Forth Support |
None |
None |
Feasible |
Feasible |
Factor Support |
None |
None |
Feasible |
Feasible |
Complexity |
High |
Medium |
Low |
Low |
Human Debugging |
Hard |
Hard |
Easier |
Easier |
-
Schema-optional: Works without code generation
-
Self-describing: Values carry type information
-
Deterministic: With CBOR canonicalization rules (RFC 8949 §4.2)
-
Wide support: Implementations in Zig, Factor, Forth, Lean 4, Elixir
-
Standards-based: IETF RFC 8949
-
Extensible: Tagged types for custom semantics
-
Requires schema compilation for every type
-
Poor Zig tooling (no mature library)
-
No Forth/Factor implementations
-
Overkill for PoC phase
-
Map key ordering is non-deterministic (Google’s implementation)
-
Requires proto files and code generation
-
More complex than needed for PoC
Lithoglyph REQUIRES deterministic CBOR encoding:
-
Integer encoding: Use smallest representation
-
Map key ordering: Lexicographic by encoded key bytes
-
No indefinite lengths: All lengths must be definite
-
Float encoding: Use smallest representation (half/single/double)
-
No duplicate keys: Maps must have unique keys
Lithoglyph uses CBOR tags for domain-specific types:
| Tag | Type | Description |
|---|---|---|
0 |
RFC 3339 datetime |
Timestamps (standard CBOR) |
32 |
URI |
Resource identifiers (standard CBOR) |
55799 |
Self-described CBOR |
Optional wrapper (standard CBOR) |
39001 |
Lithoglyph Block Reference |
Reference to a block by ID |
39002 |
Lithoglyph Document ID |
Document identifier |
39003 |
Lithoglyph Collection Name |
Collection identifier |
39004 |
Lithoglyph Provenance |
Provenance payload |
39005 |
Lithoglyph Actor |
Actor information |
39006 |
Lithoglyph PROMPT Score |
PROMPT evidence score |
39007 |
Lithoglyph Functional Dependency |
FD encoding for normalizer |
39008 |
Lithoglyph Proof |
GQLdt proof blob |
|
Note
|
Tags 39001-39999 are in the "first come first served" range per RFC 8949. |
Document: {"claim": "Inflation at 10%", "source": "ONS", "score": 85}
CBOR (diagnostic notation):
{
"claim": "Inflation at 10%",
"source": "ONS",
"score": 39006(85) // Tagged PROMPT score
}
CBOR (hex):
A3 # map(3)
65 636C61696D # "claim"
70 496E666C6174696F6E... # "Inflation at 10%"
66 736F75726365 # "source"
63 4F4E53 # "ONS"
65 73636F7265 # "score"
D9 9866 18 55 # tag(39006) + unsigned(85)All blobs passed through Form.Bridge follow this structure:
pub const LithBlob = struct {
data: [*]const u8,
len: usize,
encoding: BlobEncoding,
};
pub const BlobEncoding = enum(u8) {
cbor = 0, // Default for PoC
cbor_compressed = 1, // LZ4-compressed CBOR
reserved = 255,
};Error blobs use a standard structure:
CBOR (diagnostic notation):
{
"code": 1001,
"message": "Document not found",
"details": {
"collection": "evidence",
"document_id": "doc_abc123"
},
"provenance": {...}
}All CBOR blobs MUST have deterministic text rendering for audit:
-
Use CBOR diagnostic notation as base
-
Expand Lithoglyph-specific tags to human-readable form
-
Timestamps rendered as ISO 8601
-
Document IDs rendered with collection context
-
Provenance rendered with actor name
-
Payloads > 512 bytes: Optional LZ4 compression
-
Journal entries: Compress if forward + inverse > 1024 bytes
-
Blocks: Compress based on block type and size
Use zig-cbor library:
const cbor = @import("cbor");
pub fn encode_document(doc: Document) ![]u8 {
var encoder = cbor.Encoder.init(allocator);
try encoder.encodeMap(doc);
return encoder.finish();
}Minimal CBOR implementation:
: encode-uint ( n -- ) \ Encode unsigned integer
dup 24 < if emit exit then
dup 256 < if 24 emit emit exit then
\ ... etc
;Use cbor vocabulary:
USING: cbor ;
: encode-document ( doc -- bytes )
>cbor ;Golden test vectors in test-vectors/encoding/:
-
simple_document.cbor- Simple document encoding -
simple_document.txt- Canonical text rendering -
provenance.cbor- Full provenance encoding -
tagged_types.cbor- All Lithoglyph-specific tags -
deterministic_map.cbor- Map with ordered keys -
compressed_document.lz4- LZ4-compressed CBOR
-
RFC 8949: Concise Binary Object Representation (CBOR)
-
RFC 8610: Concise Data Definition Language (CDDL)