cardano-binary is the canonical CBOR toolkit used across the Cardano stack.
It mirrors the behaviour of the Haskell
cardano-binary
package so that ledger types, networking payloads, and test fixtures encode and
decode byte-for-byte the same way in Rust.
| Rust path | Purpose | Haskell source |
|---|---|---|
cardano_binary (crate root) |
Re-exports the high-level API surface (serialize, decode_full, nested helpers) |
Cardano.Binary |
serialize |
Canonical CBOR encoders, buffer reuse, semantic tag 24 helpers | Cardano.Binary.Serialize |
deserialize |
Total decoders, leftover detection, nested tag 24 decoders, legacy unsafe helpers | Cardano.Binary.Decode |
error |
Error type equivalent to Haskell DecoderError, capturing leftovers, tag mismatches, and IO failures |
Cardano.Binary.Decoder.Error |
Refer to HASKELL_MAPPING.md for the full symbol-by-symbol translation.
use cardano_binary::{decode_full, encode_nested_cbor, serialize};
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug)]
struct Demo {
id: u64,
tag: String,
}
let value = Demo { id: 7, tag: "hello".into() };
let bytes = serialize(&value)?;
let decoded: Demo = decode_full(&bytes)?;
assert_eq!(decoded, value);
let nested = encode_nested_cbor(&value)?;
let nested_decoded: Demo = cardano_binary::decode_nested_cbor(&nested)?;
assert_eq!(nested_decoded, value);- Canonical CBOR output – Deterministic encoding that satisfies RFC 8949 §4.2 (smallest integer form, definite lengths, sorted map keys, no duplicates).
- Nested CBOR helpers – Encode/Decode semantic tag 24 payloads used by the ledger and networking protocols.
- Leftover-aware decoding –
decode_fullreports trailing bytes throughBinaryError::Leftoverso deserialisation boundaries stay explicit. - Allocation-aware APIs –
serialize_into_vecandserialize_with_capacityreuse buffers for tight loops or pre-sizing. - Extensive parity testing – 86 tests covering golden vectors, Haskell cross-validation, property-based roundtrips, and fuzzed CBOR fragments.
The encoder enforces the canonical rules automatically, but collections need to
arrive in the right order. Prefer deterministic containers (BTreeMap, sorted
vectors) when serialising maps:
use std::collections::BTreeMap;
let mut map = BTreeMap::new();
map.insert("zebra", 1);
map.insert("apple", 2);
map.insert("mango", 3);
let bytes = serialize(&map)?; // Keys encode in byte-order: "apple", "mango", "zebra"If you work with Vec<(K, V)>, make sure to sort before encoding:
let mut entries = vec![("zebra", 1), ("apple", 2), ("mango", 3)];
entries.sort_by_key(|(key, _)| *key);
let canonical = serialize(&entries)?;Some protocol messages embed CBOR inside CBOR (tag 24). The helper functions wrap and unwrap the tagged payload while validating the structure:
let inner_bytes = vec![0x01, 0x02, 0x03];
let tagged = cardano_binary::encode_nested_cbor_bytes(&inner_bytes)?;
let roundtrip = cardano_binary::decode_nested_cbor_bytes(&tagged)?;
assert_eq!(roundtrip, inner_bytes);Errors differentiate between the wrong tag (BinaryError::NestedTag) and an
unexpected payload type (BinaryError::NestedPayload).
All APIs return Result<_, BinaryError>. Besides serialization/deserialization
wrappers around ciborium, notable cases include:
BinaryError::Leftover– exposes the label, leftover slice, and length so higher-level decoders can surface actionable messages.BinaryError::NestedTag– carries both the expected and observed tag IDs.BinaryError::NestedPayload– signals that the inner CBOR object was not a byte string.
Deprecated helpers (unsafe_deserialize*) mirror the historical Haskell API and
will be removed once downstream code migrates to fallible decoding.
cargo test -p cardano-binaryThe suite spans:
tests/cbor_compatibility.rs– coverage over CBOR major/minor types.tests/golden_tests.rs– fixed hex fixtures tied to the Haskell repository.tests/haskell_cross_validation.rs– roundtrips against Haskell outputs.tests/proptest_roundtrip.rs– property tests for structural types.
CI executes these alongside the rest of the workspace to guard byte-level parity.
cargo bench -p cardano-binary --bench cbor_benchCriterion benchmarks report throughput for representative payloads (small and
large structs, vector-heavy data, large maps). HTML reports live under
target/criterion/cbor_bench/.
cardano-base– feature flags and base types that often serialise through this crate.cardano-slotting– slot/epoch primitives with CBOR instances backed bycardano-binary.
Licensed under either of
- Apache License, Version 2.0, (LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE or http://opensource.org/licenses/MIT)
at your option.