ADR 0009: Cryptographic suite succession and cross-suite evidence longevity
Copy Markdown View Source- Status: accepted
- Date: 2026-08-05
Context
The current contract-major's cryptographic suite is BAP1-Ed25519-SHA256 (EdDSA over Ed25519, SHA-256
digests, RFC 8785 JCS canonical bytes, the BAP1-* domain separators). It is a named suite, not
"the" algorithm set — successor suites follow BAP<contract-major>-<signature>-<digest> (registries.md).
ADR 0006 §2 committed to two
design directions in charter prose:
- The anticipated successor signature family is ML-DSA (FIPS 204), with a hybrid Ed25519 + ML-DSA composite posture to be evaluated when the successor suite is defined.
- Long-retention evidence under a frozen signature algorithm outlives the algorithm's trustworthiness; the committed solution is cross-suite countersignature, where "boundary anchors of a current suite countersign archives of an earlier suite ... attesting 'verified complete under suite A at time T'" and "trust freshness comes from the newest countersignature, not from the original signature surviving cryptanalysis" (standards-track.md § Evidence longevity).
ADR 0006 §2 committed to the DIRECTION; this ADR carries the MECHANISM to ADR-quality design. The
design-adversarial pass on BAP-11 (Challenge 1, blocking) defeated the first mechanism draft — a
ba+suite-transition chaining key/suite identity — because it solves KEY succession, not ALGORITHM
break: if the original suite's signature algorithm is broken, the original boundary anchors (which
bind the chain hash) and transitions are forgeable, and a key/suite-identity chain attests a forgery.
The charter's "trust freshness ... not from the original signature surviving cryptanalysis" requires
a content-covering re-attestation: a current-suite key signing the archive's CONTENT, independent
of the original signatures. This ADR specifies that primitive.
Activation of any of this is a successor-contract-major concern; the current major stays single-suite and the closed profile rejects every reserved name this ADR introduces.
Decision
1. Suite-naming scheme (ADR-grade; refines ADR 0006 §2)
The suite-naming scheme is BAP<contract-major>-<signature>-<digest>. The current suite is
BAP1-Ed25519-SHA256; a successor suite binds its own domain separators, alg values, and fixed
widths under its own contract-major. The kid/thumbprint indirection at the key-locator boundary is
already key-type independent, so trusted-key resolution survives suite succession unchanged. This is
the scheme registries.md § Cryptographic suites carries; this ADR records
it as an ADR-grade decision (ADR 0006 §2 named it in charter prose).
2. ML-DSA successor path (named, not constant-bearing)
The anticipated successor signature family is ML-DSA (FIPS 204). The three parameter sets are ML-DSA-44 (NIST security category 2), ML-DSA-65 (category 3), and ML-DSA-87 (category 5). This ADR names the family and the parameter-set/security-category mapping; it does NOT cite byte sizes or select a parameter set — those belong to the successor suite's own ADR at its definition, gated by the deprecation-prerequisites rule (published profile + corpus + two independent passing implementations, standards-track.md § Parallel-version support).
A hybrid Ed25519 + ML-DSA composite posture is FLAGGED for evaluation when the successor suite is defined. It is NOT specified here: a composite changes frozen wire bytes, which is a contract-major change, and the composite's value is a migration-window optimization (a single archive remains directly verifiable during the overlap without re-attestation), not the only path to evidence longevity (the content-countersignature below solves signature-family break on its own; digest- primitive break requires the successor suite to bind a fresh digest, named in § 3). The deferral is on the wire-freeze barrier, not "speculative design."
3. The content-covering countersignature mechanism (the core)
The mechanism binds the archive's CONTENT DIGEST under a current-suite key, independent of the original suite's signatures. ADR 0004 already computes the archive's SHA-256 content digest over every raw byte ("hashes every raw byte, and compares the raw SHA-256 digest in constant time"). That digest IS the archive's content identity. A cross-suite content countersignature is a current-suite key signing a closed statement binding that digest, attesting "verified complete."
A successor major defines a ba+suite-attestation typ (reserved now in
registries.md) with:
- a closed payload binding: the archive's chain identity, the sequence range covered, the archive's SHA-256 content digest, the original suite identity under which the archive was verified, the attestation time, and the attesting key's identity;
- a typed, suite-parameterized key binding (NOT "one extra field" — the design-adversarial
Challenge 3): the current major's fingerprint is RFC 7638 OKP over
{"crv":"Ed25519","kty":"OKP","x":...}(lib/bounded_authority_protocol/v1/jwk.ex); an ML-DSA key has no OKP JWK form, so a successor suite defines its own canonical key preimage + thumbprint. The payload carries the suite identity so the verifier knows which fingerprint construction applies to which key; - signed by the attesting current-suite key.
The reserved claim name ba_sut (suite-attestation) carries the payload binding
(registries.md).
Verification of aged evidence (the charter's two-part rule, corrected)
- Content integrity re-attested (load-bearing): the caller supplies a currently-trusted suite's
public key + the
ba+suite-attestationcountersignature over the archive. The verifier re-derives the archive's content digest (ADR 0004's exact byte-walk), compares it to the countersigned digest in constant time, and verifies the countersignature under the current key. This step does NOT depend on the original suite's signatures — it covers the content. - Original-suite verification as historical record (the algorithm-break class): the archive MAY
still verify under its original suite's rules (anchors, transitions, row hashes) when those
signatures are still trusted, preserving the issuance provenance. Under signature-family break
of the original suite (e.g. Ed25519 broken, SHA-256 still trusted), step 1 alone suffices for
trust: the archive's content digest D (SHA-256 over the FULL archive bytes, including the signed
anchors/transitions/rows per ADR 0004's
hash_chunks) COVERS the original signatures — they are bytes within the hashed content — so a current key's signature over D re-attests the complete archive byte-for-byte, and an Ed25519-break attacker cannot alter any archive byte without changing D nor forge the current-key countersignature. The original signatures become historical record, not the trust root. (Under digest-primitive break — SHA-256 itself compromised — step 1 does NOT suffice, because D is the broken digest; see the failure-class enumeration below for the hash-agility gap and the successor-major fresh-digest requirement.) (Note: no original-suite signature signs D itself — the anchors sign the chain hash, the transitions sign key succession — so the relationship is "D covers the signatures," not "the signatures cover D.")
Failure classes the mechanism closes (including algorithm break — Challenge 2)
"Algorithm break" splits into two sub-classes with different closures, because the content digest
D the countersignature binds IS the original suite's SHA-256 (anchored_export_codec.ex:706) — a
named member of BAP1-Ed25519-SHA256. The mechanism as specified (countersigning the existing
digest D) closes signature-family break fully; digest-primitive break requires the successor suite
to bind a FRESH successor-suite digest, named honestly below rather than overclaimed.
- Signature-family break of the original suite (the load-bearing class — e.g. Ed25519 broken): an attacker forges every original-suite signature (anchors that bind the chain hash, transitions, row commitments). CLOSED by the content-covering countersignature — trust rests on the current key's signature over the content digest, re-derived and compared in constant time, NOT on the original signatures. (SHA-256 is presumed unbroken in this sub-class; the break is the signature primitive.)
- Digest-primitive break (NOT closed by re-signing the existing digest — hash-agility gap): if
the reason for suite succession is SHA-256's compromise (second-preimage/collision resistance
lost), an attacker presents a colliding archive with the same digest D and inherits the legitimate
current-key countersignature — the constant-time digest comparison passes on forged content. The
mechanism as specified does NOT close this sub-class, because it binds D (the original suite's
digest). A successor major that anticipates digest break MUST bind a FRESH successor-suite digest
of the raw archive bytes (hash-agile: the countersignature signs
H_succ(raw_archive_bytes), not the inherited D, and binds the digest algorithm in the payload). This is a successor-major mechanism detail; this ADR names the gap honestly rather than claiming the whole "algorithm break" class is closed. (NIST's collision-resistance guidance for signature applications applies: the digest bound by a countersignature must be one the verifier still trusts.) - Content-digest mismatch (signature-family-break regime, SHA-256 trusted): a countersignature over digest D presented with an archive whose re-derived digest is D'. CLOSED by the constant-time digest comparison (ADR 0004's mechanism) — under the signature-family-break regime where SHA-256 remains collision-resistant.
- Compromise of the attesting current-suite key: a rogue
K_curcan countersign arbitrary archives (including ones carrying forged original-suite signatures). This is the trust-root risk the caller manages by supplying the trusted current key — it is a key-custody/trust-decision, not a verifier bypass (the verifier only accepts keys the caller declared trusted). The mitigation is operational (the caller's trusted-key set), exactly as ADR 0004's caller supplies the trusted current key for the historical-key chain. - Suite-downgrade: the caller supplies the trusted current suite, so a downgrade (a weaker suite claimed as "current" to bypass a stronger suite's deprecation) is a caller trust-decision, not a verifier bypass.
- Suite-mismatch: the attestation's
original_suitefield must match the archive's original suite. ADR 0004's archive carries no explicit suite field (the suite is implicit in theBAP1-*prefix/alg/fixed widths); a successor major derives the archive's original suite from those markers (the prefix byteBAP1-ARCHIVE\0, the anchoralg/typ, the fixed widths) and the verifier requires the attestation'soriginal_suiteto equal the derived value. The successor major's ADR specifies the exact derivation. - Attesting-key validity window: only the generic
valid_from <= attestation_time < valid_beforecheck transfers from ADR 0004 (a single key's interval), NOT ADR 0004's positional anti-cycling / no-fingerprint-cycle rules — those govern an ordered transition CHAIN, and the attestation is deliberately NOT a chain link. The attesting key's interval is checked against the attestation time; ordering across multiple attestations is the successor major's concern.
Alternatives considered
- A
ba+suite-transitionchaining key/suite identity (the original BAP-11 draft). Rejected (design-adversarial Challenge 1): it solves key succession, not algorithm break. If the original suite breaks, the original anchors/transitions are forgeable, and the chain attests a forgery. The content-covering countersignature is required. - Re-sign archives under the new suite. Rejected: it destroys the original evidence's byte-identity (the archive's value IS that it is the original bytes), and requires the new-suite key to see every old archive. The content countersignature preserves the original bytes and adds a layered attestation over their digest.
- No mechanism ("re-verify under the old suite if you still trust it"). Rejected: that is the status quo's failure mode — long-retention evidence's trustworthiness expires before its retention period.
Consequences
- A successor major implementing evidence longevity implements the
ba+suite-attestationtyp as a content-covering countersignature, NOT a key/suite-identity chain. The reservedba+suite-attestationtyp andba_sutclaim are REJECTED by the current major's closed profile — the rejection evidence is the CODE's closed typ set{ba+cap, dpop+jwt, ba+chain-anchor, ba+key-transition}(compact_jws.ex:117,149-150,runtime.ex:280,boundary_anchor_codec.ex:92,key_transition_codec.ex:124) and closed claim set, neither of which admits the reserved names. (The unchanged conformance corpus atagreed=259is CONSISTENT with this — it exercises the closed code sets — but is not itself the rejection proof for names that live in docs only, since the corpus verifies code behavior, not docs reservations.) - Activation is a successor-contract-major decision. The current major's wire profile, bounds, and verdicts are unchanged.
- The hybrid Ed25519 + ML-DSA composite is a successor-suite-ADR concern (wire-freeze barrier), not this ADR's.
- The ML-DSA family + parameter-set/security-category mapping is named; the successor suite's ADR selects a parameter set and cites byte sizes.