Rust implementation of Convex CAD3 — the canonical wire and storage encoding for Convex lattice data values.
Status: early. The small primitive variants are landed; collections, blobs/strings, and the rest are next. The Java reference implementation lives at
Convex-Dev/convexunderconvex-core/src/main/java/convex/core/data/. Architectural design lives indocs/CELL_DESIGN.md.
CAD3 is a compact, self-describing, canonical binary encoding for immutable data values. Every value has exactly one valid byte representation, and the SHA3-256 hash of that encoding is the value's stable, decentralised identifier (the "value ID"). Larger values form Merkle DAGs via embedded child encodings or external value-ID references, enabling structural sharing, partial transmission, and arbitrary-size data structures inside fixed-size buffers.
See the CAD3 specification for full details.
| Tag(s) | Type | Notes |
|---|---|---|
0x00 |
nil |
single-byte encoding |
0x10–0x18 |
Long | signed i64, minimal-length two's complement |
0x1D |
Double | IEEE 754, canonical NaN |
0x30 |
String | UTF-8 (not enforced), leaf only — ≤ 4096 bytes |
0x31 |
Blob | arbitrary bytes, leaf only — ≤ 4096 bytes |
0x3C–0x3E |
Char | Unicode scalar, minimal-length |
0xB0–0xBF |
Byte flags | 0xB0 = CVM false, 0xB1 = CVM true |
0xEA |
Address | account index, VLQ payload |
Roadmap (in rough order): BigInt, Symbol, Keyword, Ref + Vector (forces tree form for large Blob/String), List, Map, Set, Index, signed data, records.
[dependencies]
cad3 = "0.0.1"use cad3::Cell;
use bytes::Bytes;
// Encoding — one canonical byte sequence per value
assert_eq!(Cell::Nil.encoding(), vec![0x00]);
assert_eq!(Cell::FALSE.encoding(), vec![0xB0]);
assert_eq!(Cell::Long(19).encoding(), vec![0x11, 0x13]);
assert_eq!(Cell::Char('A').encoding(), vec![0x3C, 0x41]);
assert_eq!(Cell::Address(128).encoding(), vec![0xEA, 0x81, 0x00]);
assert_eq!(Cell::string(Bytes::from_static(b"Hi")).encoding(),
vec![0x30, 0x02, b'H', b'i']);
assert_eq!(Cell::blob(Bytes::from_static(&[1,2,3])).encoding(),
vec![0x31, 0x03, 1, 2, 3]);
// Round trip
let cell = Cell::decode(&Cell::Long(42).encoding()).unwrap();
assert_eq!(cell, Cell::Long(42));
// Cheap sharing — cloning a heavy cell is one atomic refcount bump
let blob = Cell::blob(Bytes::from(vec![0xAB; 4096]));
let shared = blob.clone(); // no copy of the 4096 bytes; Arc bumped
// Value ID = SHA3-256 of the canonical encoding (cached on heavy cells)
let id = Cell::Long(42).value_id();
println!("value id = {id}");Requires Rust 1.75 or later.
cargo fmt --all
cargo clippy --all-targets -- -D warnings
cargo testLicensed under the Apache License, Version 2.0.