Knowledge Base

Browse the concepts behind Truestamp. Follow the links between concepts, or search across everything.

Proof Bundle Wire Format

The self-describing JSON and CBOR wire format of a Truestamp proof bundle, the named type registry, the subject with its claims, metadata and witnesses, block maps that carry their own metadata, the block path, external commitments, the signing key event, and why nothing opaque travels.

Overview

A proof bundle is the receipt you download when you timestamp something with Truestamp. It is a single small file that anyone can check for themselves, without asking Truestamp whether it is real. That is the whole point: you do not have to trust us, because the file carries its own evidence. Everything after this section is the technical, field-by-field reference for developers who build software that reads or writes these files.

What a bundle proves is a submission window. Its subject is a submitted item, an entropy observation, or a Truestamp block. An item bundle shows the item was submitted after the public records its fingerprint commits to, and every bundle shows its subject sits in a Truestamp block that was later committed to a transaction on a public blockchain. It does NOT prove when the underlying content was originally created, and it does not prove who authored it. For the exact timing rules see verify a proof.

Under the hood, a bundle is a compact, self-contained artifact that lets a verifier reconstruct the cryptographic chain from the subject out to the public-blockchain transaction, without ever contacting a Truestamp server. Every bundle shares one top-level schema discriminated by a type name, carries a single Ed25519 signature over a fixed-width binary payload, and serializes to two interchangeable encodings: a human-readable JSON form and a compact binary CBOR form (CBOR is a standardized binary encoding for the same data JSON holds). This concept is the field reference for that wire format. It does not walk through the verification steps (see verify a proof) or the proof lifecycle (see the proof lifecycle).

Two properties shape everything below. First, nothing opaque travels: every hash a verifier meets is recomputed from bytes the bundle carries, so the bundle holds the metadata maps themselves and carries no metadata hash and no block hash anywhere. Second, the keys are long and readable, and nothing cryptographic depends on a key name: the signature covers a fixed binary payload, and every hash is computed over decoded values.

The bundle is designed to be verifiable offline. The external calls a verifier can make are to the public blockchains (Stellar Horizon, a Bitcoin node) when confirming the commitment transactions exist, and to the original public sources (the NIST beacon, Stellar, Bitcoin) when confirming a witness or an entropy subject. None of them is a Truestamp server. Trusting the signing key does need one out-of-band fetch of Truestamp’s published keyring, or a carried signing key event, but neither is fetched per verification. A bundle carries everything else it needs inline.

Top-level structure

Every bundle is a single map (JSON object or CBOR map) with these top-level keys. The type name selects the subject type and determines which of the optional keys are present.

Key Type Presence Meaning
version integer always Format version. Currently always 1.
type string always Subject type name (see the type registry below).
generated_at string always ISO 8601 generation timestamp, truncated to whole seconds.
public_key string always Base64 Ed25519 public key of the proof signer, 32 bytes, standard base64 with padding.
signature string always Base64 Ed25519 signature over the proof payload, 64 bytes, standard base64 with padding.
subject map absent for block and beacon The subject being attested.
inclusion_proof string absent for block and beacon Base64url (no padding) Merkle inclusion proof of the subject hash into block.merkle_root.
block map always The block that contains the subject.
block_path array of block maps optional The blocks between the head block and the containing block, oldest first.
commitments array always, non-empty External commitments to public blockchains, at least one entry.
signing_key_event map optional The ledger block that introduced the key that signed this bundle.

Key order carries no meaning. Canonicalization is applied only to the individual maps that are hashed, never to the bundle as a whole, so a bundle may present its top-level keys in any order and still verify.

The non-empty commitment invariant

commitments is required and MUST contain at least one entry. A bundle with no external commitment would resolve only to Truestamp’s own signature chain, which contradicts the promise of offline verifiability without trusting Truestamp. A subject whose block has not yet been committed to a public blockchain cannot produce a bundle: generation fails until the next epoch commit lands.

The subject

subject is present for item and entropy subjects and absent for the two block-like types, where the block is its own subject.

Key Presence Meaning
id always Subject id: a 26-character ULID for an item, a UUIDv7 for an entropy observation.
claims item subjects The claims map exactly as submitted, hashed under prefix 0x11.
entropy entropy subjects The captured source payload, hashed under prefix 0x21.
metadata always The subject’s metadata map, hashed under 0x12 (item) or 0x22 (entropy, always the empty map).
signing_key_id always 8 lowercase hex characters identifying the key that signed the subject, bound into the composite preimage as its four raw bytes.
witnesses optional, item subjects only Witness name to witness detail.

The composite subject hash binds the id, the data hash, the metadata hash, and the signing key id, under prefix 0x13 for an item and 0x23 for an entropy observation. The metadata hash in that preimage is derived from the carried metadata map rather than read from the bundle.

An item’s metadata map holds exactly one key, witnesses, whose entries name the public records the item’s fingerprint committed to at submission:

"metadata": {
"witnesses": {
"block": "<hex hash of the head block at submission>",
"entropy_stellar": "<hex hash of the newest captured Stellar observation>",
"entropy_nist": "<hex hash of the newest captured NIST observation>",
"entropy_bitcoin": "<hex hash of the newest captured Bitcoin observation>"
}
}

block is always present. Each entropy_* key is present only when that source had captured at least one observation by the time the item was submitted, and is absent otherwise, never null. An entropy subject’s metadata is always the empty map: the captured payload is itself the subject, so it witnesses nothing.

Block maps

The same five-key shape appears everywhere a block appears: the top-level block, each block_path entry, signing_key_event.block, and the block witness inside subject.witnesses.

Key Meaning
id Block id (UUIDv7).
previous_block_hash Hex SHA-256 hash of the preceding block.
merkle_root Hex SHA-256 Merkle root of the block.
metadata The block’s metadata map, hashed under prefix 0x33. The empty map for an ordinary block; a key-event block carries {"key_event": {...}}.
signing_key_id 8 lowercase hex characters identifying the key that signed the block.

A block hash is derived under prefix 0x32 from the id, previous block hash, Merkle root, metadata hash, and signing key id. The block hash itself is never carried anywhere in a bundle, so a bundle cannot lie about it: a verifier recomputes it, and the metadata hash it needs is recomputed from the carried metadata map.

The block path

block_path appears only when the item’s head block (the block whose hash subject.metadata.witnesses.block names) is not the containing block’s direct predecessor, and only when the block witness was asked for. It is ordered oldest first: block_path[0].previous_block_hash equals the head block hash, each following entry’s previous_block_hash equals the hash of the entry before it, and block.previous_block_hash equals the hash of the last entry. Each entry is an ordinary block map. The path carries the ledger-position claim of the block witness and nothing else; no witness hash depends on it.

External commitments

Each entry in commitments records one public-blockchain commitment of the block hash into an epoch Merkle root, and carries the epoch Merkle proof (epoch_proof, base64url, no padding) that walks the block hash up to that root. An epoch Merkle root is the single hash that summarizes a batch of Truestamp block hashes; that one root value is what actually gets written to the public blockchain, and the epoch proof shows this block belongs under it.

The chain is named in chain, and the value written on chain is in epoch_merkle_root on both chains. There is one root key, not one per chain, so nothing dispatches on which key happens to be present.

Key Presence Chains Meaning
chain required both "stellar" or "bitcoin".
epoch_merkle_root required both Hex 32-byte epoch Merkle root: the Stellar transaction memo, or the Bitcoin OP_RETURN payload.
epoch_proof required both Base64url Merkle proof: block hash to the epoch Merkle root.
transaction_hash confirmation both Hex 32-byte transaction hash or txid.
network optional both public or testnet (Stellar); mainnet, testnet, or regtest (Bitcoin).
timestamp optional both ISO 8601: the Stellar ledger close time, or the Bitcoin block header time.
ledger optional Stellar Ledger sequence number.
block_height confirmation Bitcoin Block height.
txoutproof optional Bitcoin Hex txoutproof (partial Merkle tree).
raw_transaction optional Bitcoin Hex raw transaction.
block_merkle_root optional Bitcoin Hex 32-byte Bitcoin block Merkle root.

Presence is graded by consequence, in three tiers, and only the first is a rejection. Required means the whole bundle is rejected without it: lacking the chain name, the epoch proof, or the epoch root, the entry cannot enter the epoch-proof walk or the signed epoch-root list at all. Confirmation means the field is needed only to look the transaction up on the public chain: without it that chain’s confirmation step has nothing to query and is reported skipped, exactly as a network failure is. Optional means its absence narrows what the confirmation step can establish and is never a failure.

What an absent optional field does

Truestamp legitimately emits entries that omit optional fields, so a verifier that treats them as required rejects real bundles. The Bitcoin offline payload txoutproof, raw_transaction, and block_merkle_root is the case that matters in practice, and each field’s absence skips exactly the checks that consume it:

  • an absent txoutproof skips the txoutproof parse, the partial-Merkle-tree walk, the check that the txid is in the matched transaction set, and the cross-check of block_merkle_root against the txoutproof header;
  • an absent raw_transaction skips the OP_RETURN extraction and the txid recomputation;
  • an absent block_merkle_root skips the cross-check of the recorded block Merkle root against the txoutproof header;
  • an entry carrying none of the three carries no offline Bitcoin evidence at all, and its Bitcoin commitment is reported skipped.

An absent network on its own never skips a confirmation step: a Stellar entry with no network still resolves to the non-public Horizon instance, while a verifier must not guess a Bitcoin network. An absent transaction_hash (either chain) or block_height (Bitcoin) leaves the confirmation step with nothing to query, so it is likewise skipped, never failed.

Witnesses

A witness is a public record that existed before the submission and that the subject’s composite fingerprint commits to. Witnesses open the submitted-after edge of the submission window; commitments, their mirror image, close the submitted-before edge.

subject.metadata.witnesses names each witness by its hash, and is what the fingerprint commits to. subject.witnesses carries the underlying detail so a verifier can rehash it and confirm the match. The two are independent: the metadata map is fixed at submission and always travels, while which details ride along is chosen when the bundle is generated.

Name Committed in item metadata Detail carried How it is checked What a confirmed witness establishes
block yes the head block map recompute the block hash (0x32) and compare it with the committed value the head block existed, and the containing block’s ledger position follows from it
entropy_stellar yes the observation’s payload map hash the payload under 0x21 and compare submitted after that ledger’s close time
entropy_nist yes the observation’s payload map hash the payload under 0x21 and compare submitted after that pulse’s publication time
entropy_bitcoin yes the observation’s payload map hash the payload under 0x21 and compare submitted after that block header’s time, read conservatively
signing_key_event no, carried at the top level the key-event block and its own commitments recompute the block hash, then walk each epoch proof the signing key was introduced by a publicly committed key event

No witness introduces a new byte prefix: the block witness reuses the block-hash prefix and every entropy witness reuses the entropy prefix. See the byte-prefix registry.

Witnesses are selectable, and the choice never touches a hash

Which witness details ride in a bundle is a generation argument. A download offers a complete file, carrying every witness so the file stands alone, and a compact file carrying none. The API’s witnesses argument takes the same choice, plus any subset.

Selecting witnesses cannot change a hash or the signature. The signed payload covers the subject hash, the block hash, and the epoch roots; the subject’s metadata hash covers subject.metadata (which holds the witness hashes the fingerprint commits to), not subject.witnesses (which holds the details). A compact bundle therefore verifies under exactly the same signature as the complete one, and a verifier reports each committed witness as committed but not carried. Because the metadata map always travels, even a compact bundle names every witness by hash.

Unknown witness names never break a bundle

A verifier hashes subject.metadata exactly as carried, so a witness name it does not recognize cannot change any digest it computes. An unrecognized name, whether it appears in subject.metadata.witnesses or in subject.witnesses, is reported as a visible skip and never fails a proof. Names are permanent: a name is never renamed and never reused, and a new kind of witness claims a new name. Those two rules together are what let the witness registry grow without a format version bump.

The signing key event

signing_key_event is optional and carried at the top level, because it witnesses the proof’s signature rather than the submission. It holds the ledger block whose metadata records the key event that introduced the signing key, plus that block’s own public-chain commitments:

"signing_key_event": {
"block": {
"id": "...",
"previous_block_hash": "...",
"merkle_root": "...",
"metadata": {
"key_event": {
"type": "genesis",
"key_id": "f2c39df9",
"sequence": 0,
"public_key": "<base64>",
"prerotation_commitment": null
}
},
"signing_key_id": "..."
},
"commitments": [ "...this block's own commitments, same shape as above..." ]
}

type is genesis, rotation, or emergency_rotation. A verifier confirms that key_event.public_key equals the bundle’s public_key and that key_event.key_id equals the key id derived from it, recomputes the block hash from the carried map, and walks each commitment’s epoch proof to its recorded root. The event rides along only when that key-event block has at least one external commitment, so a bundle either carries a chain-checkable key event or carries none at all. See Ed25519 signatures for how this sits alongside the pinned keyring.

The type registry

One unified registry names subject types and commitment chains, namespaced by decade. Names travel on the wire because a name is readable and a stray integer is not; the frozen integer code travels inside the signed payload. Both halves are permanent: a name is never renamed or reused, and a code is never renumbered or reassigned.

Name Code Where it appears
block 10 type; the code is emitted in the signed payload
beacon 11 type; the code is emitted in the signed payload
item 20 type; the code is emitted in the signed payload
entropy_nist 30 type; the code is emitted in the signed payload
entropy_stellar 31 type; the code is emitted in the signed payload
entropy_bitcoin 32 type; the code is emitted in the signed payload
stellar 40 commitments[].chain; the code is reserved and never on the wire
bitcoin 41 commitments[].chain; the code is reserved and never on the wire

The decades are meaningful: 10-19 block-like subjects, 20-29 item subjects, 30-39 entropy sources, 40-49 external commitment chains, 50 and above reserved.

Block-like subjects

Both block and beacon share the same structural shape: no subject, no inclusion_proof, block present, commitments non-empty. For these the block is the subject, so there is no intra-block Merkle inclusion step and no witness map. The two are cryptographically distinct only through the type code inside the signed payload, so a beacon signature does not verify as a plain block signature and vice versa, even for the same block. That gives a verifier a self-describing discriminator without relying on a filename or out-of-band metadata.

The signature payload

Every bundle carries exactly one Ed25519 signature computed over SHA256(0x61 || payload), where payload is a fixed-width, big-endian binary layout. The leading 0x61 is a domain prefix: a fixed one-byte tag prepended before hashing so that this hash can never collide with a hash computed for a different purpose in the system. Each kind of hash uses its own prefix (see domain-separated hashing).

offset size field
------ ---- -----
0 1 v version, uint8, currently always 1
1 2 t type code, uint16 big-endian (the registry integer for `type`)
3 4 kid signing-key id of the proof signer, derived from public_key
7 8 ts_ms generated_at in milliseconds since the Unix epoch, uint64 big-endian
15 32 subject_hash raw bytes
47 32 block_hash raw bytes
79 2 N count of epoch roots, uint16 big-endian
81 32*N epoch_roots concatenated raw epoch roots, in commitments array order

Three properties make this payload the tamper-evidence root for the whole bundle:

  • The t value in the payload is the registry integer for the bundle’s type name. Changing type changes the pre-image and fails the signature check. This is what makes block and beacon cryptographically distinct.
  • The kid in the payload identifies the key that signed the proof and is derived at verification time from the supplied public_key (SHA256(0x51 || public_key) truncated to 4 bytes), not read from any signing_key_id in the bundle. Under steady state all three match; under legitimate key rotation the signer’s key id may differ from the block or subject keys, and that is allowed.
  • The epoch roots are the epoch_merkle_root of each commitment entry, concatenated in array order. Reordering or altering commitments changes the payload.

For block-like subjects, subject_hash == block_hash: the same 32 bytes fill both slots. That degenerate case is intentional and harmless.

JSON and CBOR encodings

A bundle serializes to one of two interchangeable encodings that encode the same logical bundle and pass through the same verification.

The JSON form is human-readable. Hash-type fields are lowercase hex strings; public_key and signature are standard base64; the Merkle proofs inclusion_proof and epoch_proof are base64url with no padding.

The CBOR form (RFC 8949) is the compact binary form. The whole bundle is wrapped in the CBOR self-describing tag 55799 (the three bytes 0xd9 0xd9 0xf7), so a stream parser can detect the format from its prefix.

One rule decides which fields become CBOR byte strings: a field is a byte string when it is a member of a length-prefixed hash preimage or is raw cryptographic material. Everything else keeps its natural CBOR type, and every map that is canonicalized before hashing stays in the JSON value space, hex strings included, so that its bytes canonicalize identically in both encodings.

Field JSON CBOR
public_key base64 string byte string (32 bytes)
signature base64 string byte string (64 bytes)
every signing_key_id hex string (8 chars) byte string (4 bytes)
every previous_block_hash, merkle_root hex string (64 chars) byte string (32 bytes)
epoch_merkle_root, transaction_hash, block_merkle_root hex string (64 chars) byte string (32 bytes)
subject.claims, subject.entropy JSON object CBOR map, JSON value space
subject.metadata (witness hashes included) JSON object CBOR map, JSON value space
every block metadata, including in block_path and the key event JSON object CBOR map, JSON value space
every subject.witnesses.entropy_* payload JSON object CBOR map, JSON value space
inclusion_proof, epoch_proof base64url string text string, unchanged
txoutproof, raw_transaction hex string text string, unchanged
version, ledger, block_height numbers numbers
ids, type, chain, network, timestamps text strings text strings

The block witness inside subject.witnesses is an ordinary block map, so its hash fields follow the block rule and become byte strings, while its metadata stays in the JSON value space like every other hashed map.

The Merkle proofs and the Bitcoin hex fields stay text strings in CBOR, and none of the four is ever decoded from a byte string. A byte string in inclusion_proof or epoch_proof rejects the bundle; one in txoutproof or raw_transaction leaves the checks that consume it with nothing to read, so they report skipped.

Offline verifiability

The bundle is self-contained by design. A verifier reconstructs the full chain using only the bundle contents:

  • The subject data, the metadata map, and the signing key id regenerate the subject hash for non-block-like subjects.
  • The inclusion proof walks the subject hash up to block.merkle_root.
  • The block fields, with the metadata hash derived from the carried metadata map, regenerate the block hash.
  • Each epoch_proof walks the block hash up to an epoch Merkle root that equals the on-chain value in epoch_merkle_root.
  • Each carried witness rehashes to the value subject.metadata.witnesses commits to, which is what binds the witness to the fingerprint.
  • The signature, the public key, and the reconstructed payload confirm Truestamp signed exactly this bundle.

Confirming that the commitment transactions exist on Stellar or Bitcoin, and re-fetching a witness or an entropy subject from its own public source, are the steps that reach the network, and all of them are optional: a verifier can run fully offline and simply mark those checks as skipped. Tampering with any signed input breaks verification.

Nothing opaque travels

A bundle carries no hash it does not also carry the preimage for. Carrying a metadata hash on its own would leave a verifier holding a 32-byte value it could not independently recompute, so the bundle carries the maps and every hash a verifier meets is derived from bytes in the file:

  • subject.metadata is the preimage of the subject’s metadata hash, so the witnesses that open the submitted-after edge are readable rather than hidden behind a digest;
  • every block map carries its own metadata, so the block metadata hash and then the block hash are both derived rather than trusted;
  • no block hash appears anywhere in the bundle, so there is nothing for a bundle to assert about a value a verifier must compute.

The practical consequence is that both edges of the submission window are reachable from the file. The submitted-before edge rests on the commitment transaction carrying an epoch root that covers this block. The submitted-after edge rests on the witnesses: their hashes always travel inside subject.metadata, and a complete bundle also carries the underlying records, so a verifier can rehash each one and then re-fetch it from NIST, Stellar, or Bitcoin to pin the published time the edge rests on.

Integers in subject data must stay inside the safe range

Subject data is canonicalized with JCS before it is hashed, and RFC 8785 defines every JSON number by parsing it into an IEEE-754 double. An integer outside the range a double represents exactly therefore canonicalizes differently depending on the verifier: Truestamp emits it verbatim, while a JavaScript, Go, or Python verifier reads a rounded value back and derives a different digest. Such a proof is cryptographically sound but not portably verifiable, and a verifier that does not notice will report a valid proof as failed.

RFC 8785 states the bound in Appendix B as a SHOULD: integers should lie within -9007199254740991 to 9007199254740991, that is plus or minus 2^53 - 1, which is JavaScript’s Number.MAX_SAFE_INTEGER. Truestamp enforces it at submission: an Item whose claims carry an integer outside that range is rejected, with an error naming the offending key. Send a larger value as a string instead.

Floats are unaffected and are not restricted. A float is already a double, so every implementation reads back the same value, and the canonical form is determined by ECMA-262’s number-to-string rules that RFC 8785 adopts.

The rule applies to every map a verifier canonicalizes, which includes the metadata maps and the carried witness payloads. Entropy observation payloads are captured verbatim from NIST, Stellar, and Bitcoin, so Truestamp does not control their contents; a client reading one should be prepared for the same limit.

Nesting depth is limited to 32 levels

Truestamp’s verifier refuses a bundle nested more than 32 levels deep, the bundle object itself counting as the first level and every map and list inside it as one more, whichever encoding it arrives in. The check runs before anything in the bundle is canonicalized, because the cost of canonicalizing grows quickly with depth, and it stops at the first level past the limit. The refusal is a rejection of the whole bundle as malformed, not a failed step. A bundle Truestamp issues stays well inside the limit: its deepest part, an item’s claims metadata, is itself limited to 10 levels of nesting at submission.

Versioning

version is the format version, and it is 1. Version 1 is the first published format, and the layout described in this concept is what it means.

A bundle carrying a top-level v or t key, where this layout carries version and type, is a short-key pre-publication draft and is not supported. A verifier that receives one rejects the whole bundle as unsupported_layout and should tell the holder to regenerate the proof; no verifier, page, or document keeps a second code path for that shape. Regenerating a proof for a subject that is still committed produces the published layout.

version is a hard compatibility boundary that governs how the format may evolve:

  • A breaking change to the bundle schema or to the signature payload bumps version to a new integer. A bundle carrying a different version is a different format, and a verifier written for 1 should not attempt to parse or verify it.
  • Non-breaking additions do NOT bump version. New type names, new witness names, and new optional fields can all appear within version 1, because the registries only ever claim unused names and never renumber, reuse, or rename an existing entry.

Unfamiliar input comes in three kinds, handled three different ways, and a verifier must not merge them:

  • An unrecognized type is a hard rejection (invalid_subject_type). type selects the subject’s shape (whether subject and inclusion_proof are present) and the byte-prefix family used to derive the subject hash. A verifier that has never seen the name cannot derive the subject hash at all, so “a bundle whose signed inputs still verify” is not a state it can reach. It must reject before producing any step results, must not infer a shape from whichever keys happen to be present, and in particular must NOT treat an unknown type as block-like.
  • An unrecognized witness name is a visible skip. The fingerprint is derived by hashing the metadata map exactly as carried, so a name the verifier does not know changes none of its arithmetic and can never fail a proof.
  • An unrecognized optional field inside a known structure is ignored. A field a verifier never reads cannot change a digest it does compute; a verifier that surfaces it should do so as a skip or an informational result, never as a failure.

See verify a proof for how each outcome is reported.

Example (JSON, item subject)

An item bundle committed to both Stellar and Bitcoin, carrying all four witnesses and a signing key event. Hash, key, and proof values are truncated with an ellipsis for readability; on the wire they are full-length hex or base64 strings.

{
"version": 1,
"type": "item",
"generated_at": "2026-07-24T12:00:00Z",
"public_key": "IVL40Zt5HSRFMkLhXy6rbLfP…",
"signature": "BfZua6JEboOJUVHvC/IcEfzBQazK…",
"subject": {
"id": "01KY9ZWEX0248J48HK6D248NAN",
"claims": {
"name": "Appendix D worked example",
"hash": "b47cc0f104b62d4c7c30bcd6…",
"hash_type": "sha256"
},
"metadata": {
"witnesses": {
"block": "f6912793a49f289affc65a95…",
"entropy_bitcoin": "e358c850958e1f1e8ad4c60c…",
"entropy_nist": "0a5eb1a1721a463924404929…",
"entropy_stellar": "8a7e002361b83a4e05e09150…"
}
},
"signing_key_id": "f2c39df9",
"witnesses": {
"block": {
"id": "019f93fd-c670-7001-8000-000000000001",
"previous_block_hash": "a3b8c9d0e1f2a3b4c5d6e7f8…",
"merkle_root": "dcbf10256899ea68cbe0c112…",
"metadata": {},
"signing_key_id": "f2c39df9"
},
"entropy_stellar": {
"closed_at": "2026-07-24T11:58:10Z",
"hash": "9c9c9c9c9c9c9c9c9c9c9c9c…",
"sequence": 51234501
},
"entropy_nist": {
"pulse": {
"chainIndex": 1,
"pulseIndex": 2847559,
"outputValue": "abababababababababababab…",
"timeStamp": "2026-07-24T11:58:00.000Z",
"version": "2.0"
}
},
"entropy_bitcoin": {
"hash": "cdcdcdcdcdcdcdcdcdcdcdcd…",
"height": 870455,
"time": 1784894100
}
}
},
"inclusion_proof": "AgEBpL3mm9F5EfSMUULiCpl0Zlv-…",
"block": {
"id": "019f93ff-2600-7c30-8000-000000000c30",
"previous_block_hash": "f6912793a49f289affc65a95…",
"merkle_root": "7c40e8809aafdbc946bdc514…",
"metadata": {},
"signing_key_id": "f2c39df9"
},
"commitments": [
{
"chain": "stellar",
"epoch_merkle_root": "f5c2df8d5fdc24b0aef14c7a…",
"epoch_proof": "AgIjXul3dz0rfPIe4Aocilj…",
"transaction_hash": "5e5e5e5e5e5e5e5e5e5e5e5e…",
"network": "public",
"timestamp": "2026-07-24T12:00:12Z",
"ledger": 51234567
},
{
"chain": "bitcoin",
"epoch_merkle_root": "d1526bd295f222761a81bef1…",
"epoch_proof": "AQFI0ilW7XcA0GN7vG-R5V7…",
"transaction_hash": "7a7a7a7a7a7a7a7a7a7a7a7a…",
"network": "mainnet",
"timestamp": "2026-07-24T12:40:00Z",
"block_height": 870456
}
],
"signing_key_event": {
"block": {
"id": "019f93c8-3780-70a0-8000-0000000000a0",
"previous_block_hash": "96118892a96ced7df9875cca…",
"merkle_root": "e3b0c44298fc1c149afbf4c8…",
"metadata": {
"key_event": {
"type": "genesis",
"key_id": "f2c39df9",
"sequence": 0,
"public_key": "IVL40Zt5HSRFMkLhXy6rbLfP…",
"prerotation_commitment": null
}
},
"signing_key_id": "f2c39df9"
},
"commitments": [
{
"chain": "stellar",
"epoch_merkle_root": "5ee58a111980722fb7bf2cb4…",
"epoch_proof": "AQH-9oSs8vQTJbZXE4TSRmj…",
"transaction_hash": "3f3f3f3f3f3f3f3f3f3f3f3f…",
"network": "public",
"timestamp": "2026-07-24T11:00:14Z",
"ledger": 51230004
}
]
}
}

The compact variant of the same bundle drops subject.witnesses, signing_key_event, and block_path, and keeps everything else, including subject.metadata. A block-like bundle drops subject and inclusion_proof entirely and keeps version, type, generated_at, public_key, signature, block, and commitments.

Citations

  1. RFC 8949: Concise Binary Object Representation (CBOR). Defines the CBOR encoding and the self-describing tag 55799 used by the compact binary bundle.
  2. RFC 8785: JSON Canonicalization Scheme (JCS). Canonical byte form of every hashed map: subject data, metadata, and witness payloads.
  3. RFC 6962: Certificate Transparency. Source of the Merkle leaf and internal-node hashing the inclusion and epoch proofs walk.
  4. RFC 8610: Concise Data Definition Language (CDDL). The schema language Truestamp uses to specify and validate the CBOR wire form.