12 min read
How Label 309 Works
Label 309 writes a Proof of Existence into Cardano transaction metadata: a content hash first, plus optional signatures, sealed payloads, recipient key slots, and Merkle batches. Here is how each layer works and how anyone verifies it.

Label 309 defines how a Proof-of-Existence record is
written into Cardano transaction metadata. At its core, a record commits one or
more content hashes to Cardano under metadata label 309. The block time of that
transaction becomes the public witness that those exact bytes existed no later
than that moment. Everything else the record can carry — signatures, storage
URIs, encrypted payloads, recipient key slots, Merkle roots, a pointer to an
earlier record — is optional metadata about that one claim.
The design goal is simple to state: a proof should be independently verifiable. Checking the basic claim should not require trusting CardanoWall, a publisher's website, a private database, or a certificate authority — only the public chain and, for content claims, the original bytes.
Label 309 is an open standard. It has been submitted to the Cardano CIP process as a Metadata-category proposal and is under review by the CIP editors; the metadata label itself is the durable on-chain identifier, and the web app, CLI, and SDKs are reference implementations of it rather than the standard. If you want the broader picture first, start with what Proof of Existence actually is.
What is stored on the blockchain under label 309?
A Label 309 record lives in Cardano transaction metadata under integer label
309. Exactly one record per transaction; a verifier ignores every other
metadata label.
The record body is encoded as canonical CBOR — a deterministic binary format, so two implementations expressing the same logical record emit byte-identical bytes. Cardano caps any single metadata string at 64 bytes, and a serialized record is usually larger than that. So the body is transported as one CBOR array of small byte-string chunks whose in-order concatenation is the record body. A verifier concatenates the chunks back together before it validates anything. That is the only chunking the format performs.
That transport detail matters to implementers, but the idea underneath is plain:
- The transaction carries metadata label
309. - The value under that label reassembles into one Label 309 record.
- The record commits to content hashes, Merkle roots, or both.
- Optional fields add signatures, encrypted-payload material, storage URIs, and a replacement pointer.
This is not a free-form note field. The record has a strict, closed shape, which is exactly what lets different implementations produce and verify the same bytes.
Why is the content hash the primary claim?
Because Proof of Existence is a claim about exact bytes, and a hash is the fingerprint of exact bytes.
The content hash is the primary claim in Label 309; every other field is metadata
about it. For a simple file proof, an item carries a hashes map that pairs a
named hash algorithm — for example sha2-256 or blake2b-256 — with a raw
32-byte digest. To check the proof, a verifier recomputes the digest from the
original file and compares it against the digest in the record.
If the bytes match, the proof passes. Change one byte and the digest changes, so the proof fails.
This is why the claim stays small even when the content is large or private. The record never needs the file. It needs the fingerprint.
What are items, uris, and enc?
items are the per-content commitments in a record. Each item is one content
claim. The only required part is a non-empty hashes map; the rest is optional.
An item can carry:
hashes— the required map of hash algorithm to raw digest;uris— optional content-addressed locations such asar://…(Arweave) oripfs://…(IPFS);enc— an optional encryption envelope for a sealed (encrypted) record.
The key idea is that uris are not the proof. The hash is the proof. A URI is
a retrieval hint or a storage commitment that helps a verifier find bytes to
check. A hash-only record with no URI is a complete, valid proof. A record with a
URI can help retrieve public content or ciphertext. A sealed record keeps the
plaintext encrypted off chain while still proving when it existed.
Why only ar:// and ipfs://?
Label 309 v1 restricts storage URIs to content-addressed schemes — Arweave and
IPFS — and rejects everything else, including https://. That restriction is
deliberate, not temporary.
A normal https:// URL depends on DNS, TLS, server behavior, redirects, and
whatever happens to be hosted at that address later. A content-addressed URI is
different: the address itself is derived from the content (an IPFS CID is a
multihash of the bytes; an Arweave transaction id commits to the data under
Arweave consensus). So a verifier can confirm "the bytes I fetched are the bytes
the producer committed to" without trusting the storage gateway, DNS, or a
certificate authority. The fetched bytes still have to match the on-chain
commitment; the storage layer is never a source of truth on its own.
What do signatures prove — and what don't they?
A Label 309 record can carry an optional top-level sigs array. Each entry is a
detached COSE_Sign1 signature over the record body with the sigs field removed.
In plain terms, a signer vouches for the whole record at once: every item, every
hash, every URI, every sealed envelope, every Merkle root, the supersedence
pointer, and any extension fields.
Signing is additive. A record without a signature still proves existence. A record with a valid signature also shows that a specific key stood behind the record:
- hash-only: these bytes existed by this public time;
- signed: these bytes existed by this public time, and this key vouched for the record.
The precision matters, because a signature proves less than people often assume. A verified signature does not prove that the same key paid for or submitted the Cardano transaction, that it chose the block time, or that it belongs to any named real-world person. It proves that the key signed the record body — nothing more. Render it as "signed by this key", never as "published by this key". That narrow, honest meaning is what makes a signed proof portable across different apps and gateways. Authorship is always optional, and a signature a verifier cannot check (an unsupported algorithm, an unresolvable key) never invalidates the existence claim — signatures fail softly; existence does not.
What is a sealed record?
A sealed record keeps content confidential while still proving when it existed.
In a sealed Label 309 record, the item still commits to the plaintext hash —
never the ciphertext. The plaintext is encrypted, and the ciphertext lives at a
content-addressed URI (ar://… or ipfs://…), never on chain. The on-chain
record carries an encryption envelope holding the material a chosen key holder
needs to recover the content-encryption key. The chain does not contain the
plaintext, and it does not publish a recipient list.
For a recipient, verification adds a few steps:
- Fetch the record from Cardano.
- Fetch the ciphertext from content-addressed storage.
- Try to open a matching key slot locally.
- Decrypt the ciphertext if a slot opens.
- Recompute the plaintext hash and compare it against the on-chain commitment.
Because the on-chain digest binds the plaintext, a sealed proof preserves the exact original file and keeps it private. A few honest limits come with that: a sealed record proves timing and integrity, not anonymity, and a recipient who decrypts can always choose to leak the plaintext afterward.
How do recipients work without a recipient field?
Recipients work through receive keys and trial-decryption, not a readable addressee field.
If a sender knows a recipient's receive address (an X25519 public key, optionally a hybrid post-quantum one), the sender can build a sealed record with a key slot that recipient can open. The recipient's public key never appears as a readable field in the record. The recipient's software watches the public stream of Label 309 records and locally tries to decrypt candidate slots; if a slot opens, the record belongs in that recipient's inbox.
This is why a CardanoWall inbox is not an ordinary server-side mailbox. The gateway exposes a recipient-blind feed of records; the client finds the ones it can decrypt. The server never needs to know who the recipient is or decrypt anything on their behalf. (See how to receive sealed records for the recipient side in practice.)
There are still metadata limits worth being clear about. The record never publishes plaintext or a recipient column, and the slot order is shuffled before publication so it carries no signal. But the count of slots is visible, and timing, payment trails, and operational mistakes can reveal information that the record format itself cannot hide.
How does one record cover thousands of files?
If you need to prove that a thousand files existed, you should not need a thousand
Cardano transactions. Label 309 supports Merkle batching: hash the files, build a
Merkle tree over the ordered list of hashes, and publish a single 32-byte root in
the record's merkle array. Alongside the root, the record carries a leaf count,
which binds the on-chain root to the exact size of the off-chain list.
Later you can prove that one specific file or event was in the batch by showing:
- the file (or its leaf hash);
- an inclusion proof — the sibling hashes along the path to the root;
- the Merkle root anchored in the Label 309 record.
The verifier folds the inclusion proof back up to a root and accepts it only if the recomputed root equals the published root, byte for byte. Every undisclosed leaf stays private — the root reveals nothing about the leaves it commits to.
This is the scaling layer for CI/CD artifacts, compliance logs, AI outputs, dataset manifests, release folders, and evidence bundles. It gets its own treatment in one record for thousands of files.
What does the supersedes pointer do?
supersedes is an optional 32-byte pointer to an earlier Label 309 record, by its
transaction hash. It lets a newer record say "this replaces or updates that
earlier record."
The earlier record is not deleted and not invalidated. Cardano is append-only, so both records remain independently verifiable forever. The pointer is just a link; it carries no reason field. The human meaning of the replacement — a correction, a revised manifest, an updated evidence package — belongs in the new content or the application layer, not in the metadata. The value of the pointer is that it works with no vendor database row and no proprietary record id.
How does verification work?
Verification is layered. Label 309 defines three verifier roles, each a strict extension of the one before it:
- Structural validator — a pure function over the record bytes. It confirms canonical CBOR, schema shape, field types, required fields, algorithm identifiers, and URI rules. It performs no network I/O, verifies no signatures, and decrypts nothing.
- Public verifier — starts from a Cardano transaction reference. It fetches
the raw transaction from an explorer the verifier itself chooses, binds those
bytes to the requested transaction hash, confirms label
309is present, reassembles the record, runs structural validation, checks confirmation depth, and verifies the signatures it supports. If content bytes are available, it can recompute public content hashes. It does not decrypt. - Recipient verifier — everything the public verifier does, plus its own private key to open sealed payloads and recompute plaintext hashes.
One subtlety keeps verification honest: a public verifier reads the raw
transaction CBOR, not an explorer's JSON view of the metadata. A JSON
projection is lossy — it discards map-key order and the bytes-versus-text
distinction — so re-encoding from it would break every signature on a conforming
record. And because settlement on Cardano is probabilistic, a record that is only
a block or two deep is reported as pending rather than valid until it has
enough confirmations behind it.
This structure keeps the trust model clean. A basic verifier needs no CardanoWall account; a public proof checks without a publisher server; a sealed proof decrypts locally, in the key holder's hands. The verify a Label 309 record walkthrough shows the public-verifier path end to end.
Where does the gateway fit?
The gateway publishes records. It is not the root of trust.
A Label 309 gateway handles the parts that are genuinely hard to run yourself: it quotes the price, uploads ciphertext to storage, builds and submits the Cardano transaction, waits for confirmation, indexes records, manages balances, and exposes an API. CardanoWall uses this gateway model to make publishing practical for ordinary users and developers.
But a proof is not trusted because a gateway says it exists. It is trusted because the record is on chain, the bytes validate, the signatures check, and the hashes recompute. That is the line between a hosted service and a proof standard: the service helps you publish; the standard lets anyone verify, with the gateway fully out of the trust path.
The minimal mental model
Think of Label 309 as a small, layered record:
itemsprove that exact content bytes existed by a public time.sigslet keys vouch for the record, optionally.enclets encrypted content stay private but recoverable.- recipient key slots let specific key holders open sealed content.
merklelets one record stand in for a very large batch.- verification runs on public data and local keys — never on vendor trust.
That layering is why CardanoWall can be a web app, an API, a CLI, a desktop app, or a self-hosted gateway — while the proof format stays the same. The product can change; the proof stays verifiable.
One thing it is worth being honest about throughout: a Label 309 proof shows that specific bytes existed by a public time, and that they have not changed since. It does not prove who authored the content, who owns it, or whether anything it says is true. For where that line falls, see what a proof does not prove.
Further reading
- What is Proof of Existence?
- Verify a Label 309 record
- One record for thousands of files
- What a proof does not prove
- The Label 309 standard: label309.org
- The open-source SDKs and CLI: github.com/cardanowall
- The Cardano CIP submission (under review): CIPs PR #1205