Cbor-core 0.6.0: A deterministic CBOR::Core encoder/decoder

⚓ Rust    📅 2026-04-14    👤 surdeus    👁️ 3      

surdeus

cbor-core is a Rust implementation of the CBOR::Core profile, as specified in draft-rundgren-cbor-core-25.

Its central type is an owned Value that can be built, inspected, modified, encoded to bytes, and decoded back. Encoding is always deterministic (shortest integer and float forms, sorted map keys), and the decoder rejects non-canonical input. NaN payloads, including signaling NaNs, are preserved bit-for-bit through round-trips.

The Value API is shaped around CBOR itself, so all CBOR data items, including tagged values, simple values and arbitrary map keys, stay directly reachable. For the familiar serialize/deserialize pattern the optional serde feature adds Serialize/Deserialize for Value together with to_value and from_value.

Notable features

  • Strict adherence to CBOR::Core draft. All test vectors from Appendix A pass, including rejection of non-deterministic encodings.
  • Full support for CBOR diagnostic notation (Section 2.3.6) in both directions:
    Debug prints it, and FromStr parses it.
  • No mandatory dependencies. The core crate is self-contained.
    Optional features add integration with serde, chrono, time, half (for f16), num-bigint, crypto-bigint, and rug.
  • Map and array access by &str and &[u8] keys without allocating a temporary on the heap for the comparison, via a ValueKey type used by get, get_mut, remove, contains, and Index/IndexMut.
  • Decoder hardening: bounded recursion depth, capped declared lengths, and a per-call allocation budget, so malformed input cannot exhaust memory or blow the stack.

Quick taste

Diagnostic notation is often the shortest way to write a literal CBOR
value:

use cbor_core::Value;

let cert: Value = r#"{
    "iss": "https://issuer.example",
    "sub": "user-42",
    "iat": 1700000000,
    "cnf": {
        "kty": "OKP",
        "crv": "Ed25519",
        "x":   h'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
    },
    "scope": ["read", "write"]
}"#.parse().unwrap();

assert_eq!(cert["cnf"]["crv"].as_str().unwrap(), "Ed25519");

let bytes = cert.encode();
assert_eq!(Value::decode(&bytes).unwrap(), cert);

Links

Status and origin

The API is not yet stable. Names and signatures may still change before a 1.0, but the encoding layer and test-vector coverage are settled.

The crate grew out of a side discussion in this users.rust-lang.org thread.

Feedback, bug reports, and PRs are welcome.

License: MIT.

1 post - 1 participant

Read full topic

🏷️ Rust_feed