Skip to main content

Module attest

Module attest 

Source
Expand description

Provenance attestation — turning “we have a trace” into “we have evidence” (SPEC.md §6.5, ADR 0010).

A Provenance link carries a digest. A digest is tamper-evident only to a party that already trusts whoever recorded it: it proves the bytes did not change since someone wrote that number down, and says nothing about who wrote it or whether they were entitled to. For a host reading its own cache that is enough. For the auditor asking “prove this citation is what the provider actually served,” it is not — the digest and the frame it describes were produced by the same unauthenticated party, so a provider that fabricates a frame simply fabricates a matching digest.

A signature closes that gap, and it is the only thing that does. This module defines the three constructions that make a frame’s provenance verifiable offline, by a third party, with no network and no trust in the host that stored it:

  1. A provenance chain hash (provenance_chain_head) — a hash chain over a frame’s ordered Provenance links, folded source-first, so no link can be inserted, removed, reordered, or edited without changing the head.
  2. A frame commitment (frame_commitment) — the chain head bound to the frame’s full FrameId identity.
  3. A Merkle root (merkle_root) over a whole result set, with InclusionProofs, so one frame can be proven a member of a signed answer without disclosing its siblings.

ProvenanceAttestation is the detached Ed25519 signature over (1)–(3). It reaches a host on the frames envelope, in ContextQueryResult::frame_attestations and ContextQueryResult::result_attestationbeside the frames, never inside one (SPEC.md §6.5.5, F6/F11).

§Why the frame identity is inside the signed preimage

Signing a bare chain head would be a forgery primitive, not a defense. Two frames citing the same source share a chain head, so a signature over the head alone can be lifted from an innocuous frame and stapled onto a fabricated one: the signature verifies, the evidence is invented. The signed preimage therefore commits to (provider_id, frame_id, content_digest) — the whole FrameId triple — and the chain head. A signature binds to one frame served by one provider, or it binds to nothing.

§Why the encoding is length-prefixed rather than canonical JSON

The lifecycle profile’s record_hash canonicalizes with RFC 8785 (JCS), which is the right choice there: a record’s hash covers a whole open-ended JSON document. A provenance chain is a fixed list of six optional strings, and for that shape JCS is a liability — it makes every implementation depend on a conforming JSON canonicalizer, whose number formatting and Unicode escaping rules are exactly where cross-language implementations silently disagree.

This module encodes the typed fields directly, each length-prefixed (SPEC.md §6.5.1). Length prefixing is not decoration: naive concatenation is ambiguous, and a chain with uri: "ab", range: "c" would otherwise hash identically to one with uri: "a", range: "bc" — a collision an adversary chooses, not one they have to find. A four-byte big-endian length in front of every field makes the encoding injective, and any language can produce it from the typed fields with no library at all.

§Cryptography is optional; the preimage rule is not

Hashing and signature verification live behind the off-by-default attestation feature, so contextgraph-types keeps its “zero dependencies beyond serde” promise for the pure wire consumer. ProvenanceAttestation itself is a wire type and always compiles — a host must be able to parse, relay, and store an attestation it has not been built to check, exactly as it relays a frame kind it does not recognize.

The protocol defines the preimage; it does not define your signing backend. frame_commitment and merkle_root are public so a provider holding keys in an HSM, a KMS, or a hardware token signs the bytes itself and never hands this crate a secret. sign_frame_attestation exists for providers and tests that are content to sign in-process.

Structs§

FrameAttestation
What a result set says about one frame’s attestation — the wire carrier that keeps a ProvenanceAttestation beside the frame it covers (SPEC.md §6.5.5, F11).
InclusionProof
A proof that one frame commitment is a leaf of a signed merkle_root (SPEC.md §6.5.3).
InclusionStep
One step of a Merkle InclusionProof: the sibling hash, and which side it sits on.
ProvenanceAttestation
A detached attestation binding one frame’s provenance to a signing identity (SPEC.md §6.5).

Enums§

AttestationVerdict
The outcome of checking a ProvenanceAttestation (SPEC.md §6.5.4).

Constants§

ALGORITHM_ED25519
The signature algorithm this revision defines. algorithm is a string, not an enum, precisely so a post-quantum successor is an additive change rather than a new major family — see ProvenanceAttestation::algorithm.
MAX_INCLUSION_PATH_STEPS
The longest inclusion path this crate will walk (SPEC.md §6.5.3).

Functions§

digest_string
Render 32 raw bytes as this protocol’s sha256:<hex> digest string.
encode_provenance_link
The canonical encoding of one provenance link (SPEC.md §6.5.1).
frame_commitment
The commitment binding one frame’s identity to its provenance chain (SPEC.md §6.5.2) — the preimage a single-frame attestation signs.
inclusion_proof
Build an InclusionProof for leaf_index within commitments. None if the index is out of range.
merkle_root
The Merkle root over a set of frame commitments (SPEC.md §6.5.3).
provenance_chain_head
The head of a frame’s provenance hash chain (SPEC.md §6.5.2).
public_key_for
The public key matching a signing seed, as raw bytes — the form verify_frame_attestation accepts.
result_set_commitments
Every frame of a result set paired with its commitment, in the protocol’s canonical FrameId order (SPEC.md §6.3, §6.5.3).
result_set_root
The Merkle root a provider signs to attest a whole answer (SPEC.md §6.5.3, F12).
root_from_proof
Recompute a Merkle root from a leaf commitment and its proof.
sign_commitment
Sign an arbitrary commitment (a frame commitment or a Merkle root).
sign_frame_attestation
Sign a frame’s commitment in-process, for providers content to hold key material in memory.
verify_commitment
Verify a detached attestation over an already-computed commitment — a merkle_root for a result set, or a frame_commitment.
verify_frame_attestation
Verify a detached attestation over a single frame (SPEC.md §6.5.4).
verify_frame_inclusion
Verify that a frame was a leaf of a signed result-set root (SPEC.md §6.5.3, F13).