content-addressable
Content addressing for Rust and Python: derive an address from data so anyone with the bytes and address can verify that they match.
The crate uses IPLD content identifiers (CIDs) with BLAKE3. The Python package binds the Rust core, so both languages produce the same identifier when a value encodes to the same canonical DAG-CBOR bytes.
Use the right identity
ContentId identifies canonical DAG-CBOR values. RawContentId identifies
bytes without interpreting them. Both use CIDv1 and a 32-byte BLAKE3 digest,
but their codecs differ and make them distinct identities even for the same
digest. Compare typed CIDs, never bare digests. Emit base32-lower CID text.
Before constructing a ContentId from untrusted bytes, check that they are
canonical DAG-CBOR.
ContentId::from_canonical_bytes assumes this without checking. Use checked
construction or checked decoding to validate canonicality; typed checked
decoding also catches fields the target type discards.
See identity and decoding for construction APIs, checked reads, presentation forms, foreign CIDs, and the Python tag-42 link limitation.
Installation
Rust (1.85 or later):
[]
= "0.1.0"
Python:
Import the Python package as content_addressable.
Rust quick start
Implement canonical_form to give your type the ContentAddressable trait
methods content_id, verify, and ensure_content_id:
use ;
use Serialize;
let record = Record ;
let id = record.content_id?; // a CIDv1 (DAG-CBOR + BLAKE3)
assert!; // self-certifying: re-derive and compare
println!; // "bafyr4i…" — the canonical text form
# Ok::
verify returns Ok(false) on a mismatch. ensure_content_id returns
Err(ContentError::VerificationFailed).
Python quick start
Call content_id on a native Python value. Python exposes neither the Rust
ContentAddressable trait nor its verify method.
# A value's content id (CIDv1, DAG-CBOR + BLAKE3). Key order is irrelevant.
=
=
assert # base32-lower multibase text
assert == 64 # 64-char bare-digest-hex
assert
# Canonical bytes round-trip; equal values -> equal bytes -> equal ids.
=
assert ==
assert ==
assert == # order-independent
# Parse an id back from its text / binary forms.
assert ==
assert ==
# Wrap an already-computed 32-byte BLAKE3 digest with NO re-hash.
assert ==
assert == 32 # the raw BLAKE3 hash
ContentId supports equality and hashing for use as a dict key or set
member.
Stability and optional features
The core contracts are stable throughout 0.1.x, with
one documented exception in 0.1.2
for Rust trait-method name resolution. See the stability contract
for frozen bytes, APIs, and compatibility details.
All unstable-* features are off by default and may change:
unstable-store: verified storage operations and an in-memory backend.unstable-legacy: parsers for legacy identifier formats.unstable-migration: records of identity changes.
See experimental features for examples and storage guarantees.
Development
See RELEASING.md for tag-driven releases.