Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions docs/adr/ADR-0011-canonical-json-and-version-compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# ADR-0011 — Canonical JSON and Version Compatibility

- **Status:** Proposed; acceptance blocked by D-006 and D-023
- **Date:** 2026-08-10
- **Decision owner:** Protocol maintainer (`@chefmrfrizzle`)
- **Required reviewer:** Independent interoperability/security reviewer

## Context

Valoris needs stable bytes before it can safely define content identifiers or
signatures. Ordinary JSON is not stable enough: parsers can differ on duplicate
names, unsafe numbers, Unicode, and negative zero, and a schema's validator
dialect is not the same thing as a protocol release.

This proposal is based on [RFC 8785](https://www.rfc-editor.org/rfc/rfc8785.html),
its [verified errata](https://www.rfc-editor.org/errata/rfc8785),
[RFC 7493](https://www.rfc-editor.org/rfc/rfc7493.html),
[JSON Schema Draft 2020-12](https://json-schema.org/draft/2020-12/json-schema-core.html),
and [Semantic Versioning 2.0.0](https://semver.org/). RFC 8785 is informational,
so this ADR must identify the exact Valoris profile rather than imply standards
status it does not have.

## Proposed decision

### Strict input profile

A hash-critical Valoris JSON object would be eligible for canonicalization only
after a strict parser and the exact referenced schema establish all of the
following:

1. Input is UTF-8 JSON without a byte-order mark.
2. Object member names are unique. Duplicate-name rejection happens before a
language runtime can overwrite or merge values.
3. Strings contain valid interoperable Unicode and are preserved as parsed;
canonicalization performs no Unicode normalization.
4. A strict decoder maps each JSON number token to binary64 using the exact
conversion and rounding behavior required by the canonicalization profile.
The source number token is retained through validation so implementations
can test boundary and alias cases before discarding it.
5. Negative zero is rejected, implementing verified RFC 8785 erratum 7920.
6. Exact integers outside `[-9007199254740991, 9007199254740991]`, quantities
whose meaning depends on their source spelling, and decimal quantities whose
domain cannot tolerate binary64 rounding use schema-defined strings, not
JSON numbers.
7. The object conforms to an immutable, explicitly identified schema resource.
8. Unknown fields fail unless the schema defines an explicit extension point.
Hash-critical processors do not silently drop or reinterpret extensions.

Canonical output would use the RFC 8785 transformation: ECMAScript-compatible
primitive serialization, recursive object-property sorting by UTF-16 code
units, array order preserved, no insignificant whitespace, and UTF-8 encoding.

Canonicalization commits to the parsed numeric value, not to the original JSON
number spelling. Equivalent spellings such as `1`, `1.0`, and `1e0` are therefore
expected to converge. The protocol cannot determine a sender's "intended"
value after parsing. Any domain that needs lexical fidelity, decimal arithmetic,
units-preserving quantities, or exact values outside the safe integer range must
use a schema-defined string form. Golden vectors must expose rounding aliases
on both sides of every admitted boundary.

The exact canonicalization-profile identifier is not selected by this ADR. It
must be carried in, or unambiguously bound by, any content-identifier or
signature context so the same bytes cannot be reinterpreted under another
profile.

### Version dimensions

Four values have different jobs and must not be conflated:

- `$schema` identifies the JSON Schema dialect used by a schema document;
- `$id` gives an immutable identity to a schema resource;
- `protocol_version` identifies the Valoris protocol interpretation;
- `schema_version` identifies the canonical object's schema release.

Those field names are conceptual until schemas are designed. No consumer may
resolve a floating `latest` schema when verifying historical evidence.

Valoris would apply Semantic Versioning to a documented public compatibility
surface with stricter hash-history rules:

- **Major:** any incompatible interpretation, required-field, canonical-byte,
commitment-scope, or verification change.
- **Minor:** an explicitly backward-compatible capability added at a declared
extension point. Existing canonical objects retain their original bytes and
meaning, but an older verifier does not infer that it can accept a newer minor
object.
- **Patch:** editorial clarification or correction that does not change the set
of accepted instances, canonical bytes, field meaning, or verification
result. A behavioral fix requires a new schema resource and non-patch release.

Every producer declares an exact emitted version. Every verifier declares the
exact versions it accepts. Compatibility is an explicit matrix, not lexical
version comparison or best-effort parsing. Unknown major versions, unknown
critical extensions, missing historical schemas, and ambiguous downgrades fail
closed.

Semantic Versioning labels are release metadata, not proof of wire
compatibility. The compatibility matrix is authoritative for each producer,
consumer, object type, extension point, and verification operation. A newer
minor release can be backward-compatible for producers while still requiring an
older security verifier to reject objects containing semantics it cannot
evaluate.

### Historical interpretation

Released schema resources and canonicalization profiles are immutable. A new
release may deprecate an old profile for new issuance while retaining a bounded,
auditable verifier capable of interpreting historical objects under their
original rules. Migration creates a new object and an explicit relationship to
its predecessor; it never changes the predecessor's bytes or identity.

Historical interpretability is not current acceptability. A verifier must
report separately that an old object parses and verifies under its original
profile and whether current policy still trusts that profile for the requested
operation. Deprecated code paths must be isolated and unavailable for new
issuance.

## Required evidence before acceptance

1. Golden vectors cover nested sorting, array preservation, escaping, UTF-8,
UTF-16 ordering, duplicate names, invalid Unicode, negative zero, equivalent
number spellings, binary64 rounding aliases, numeric boundaries, unsafe
integers, and schema/version mismatches.
2. At least two independently maintained language implementations produce the
same bytes or the same rejection for every vector.
3. A compatibility matrix demonstrates major, minor, patch, extension,
downgrade, and historical-resolution behavior.
4. An independent reviewer approves the parser boundary, numeric domain,
canonicalization profile, and denial-of-service limits.
5. ADR-0012 supplies non-ambiguous domain separation and commitment scope before
any content identifier or signature is implemented.

## Consequences

- Hash-critical input becomes deliberately narrower than ordinary JSON.
- Some convenient native numeric values must be represented by typed strings.
- Implementations need a strict pre-parser rather than trusting default JSON
decoding behavior.
- Historical verification requires an immutable schema/profile archive.
- Additive evolution is possible only through designed extension points.

## Alternatives not selected

- **Raw producer bytes:** preserves formatting accidents and does not give
semantic interoperability.
- **Default language JSON serializer:** property order, number rendering, and
invalid-input handling differ across runtimes.
- **Floating schema URLs:** make historical meaning depend on mutable state.
- **Normalize Unicode before hashing:** changes author-provided code points and
can make distinct inputs collapse unexpectedly.
- **CBOR as an immediate replacement:** may be evaluated later, but would not
remove the need to specify numeric, version, and commitment semantics.

## Non-goals

This ADR does not define JSON schemas, choose hash or signature algorithms,
define identifier wire syntax, implement canonicalization, or approve any
security or scientific policy.
158 changes: 158 additions & 0 deletions docs/adr/ADR-0012-content-identifiers-and-signature-suite-agility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# ADR-0012 — Content Identifiers and Signature-Suite Agility

- **Status:** Proposed; every cryptographic choice is `BLOCKED_UNVERIFIED` under D-007 and D-017
- **Date:** 2026-08-10
- **Decision owner:** Protocol maintainer (`@chefmrfrizzle`)
- **Required reviewer:** Independent cryptography reviewer

## Context

Valoris must avoid identifiers whose algorithm or canonicalization assumptions
are implicit, and signatures whose names omit security-relevant parameters.
Content identity, event identity, signer identity, and authorization are
different claims.

The proposal follows the agility principles in
[RFC 7696 / BCP 201](https://www.rfc-editor.org/rfc/rfc7696.html), the move to
fully specified algorithm identifiers in
[RFC 9864](https://www.rfc-editor.org/rfc/rfc9864.html), the named-information
model and limitations in [RFC 6920](https://www.rfc-editor.org/rfc/rfc6920.html),
and the protected-metadata pattern in
[RFC 9421](https://www.rfc-editor.org/rfc/rfc9421.html). It does not adopt any
one of those wire formats.

## Proposed decision

### Distinct identifier classes

The protocol would assign different types and namespaces to:

- **content identifier:** commitment to canonical object content;
- **event identifier:** identity of an occurrence in an event source;
- **key identifier:** lookup hint for a specific verification key;
- **actor/controller identifier:** identity used in authorization policy;
- **delegation identifier:** immutable reference to an authority grant.

Software must not compare, substitute, or infer authority across these classes.
A content identifier demonstrates only a digest relationship to declared bytes;
it is not proof of authorship, permission, freshness, or confidentiality.

### Self-describing content commitment

A content identifier's interpreted structure would bind, without ambiguous
concatenation:

1. a Valoris content-identifier profile and version;
2. an object domain/type and schema version;
3. a canonicalization profile;
4. a digest algorithm/profile identifier that fixes every parameter, including
whether truncation is permitted and the exact output length;
5. a canonical identifier encoding; and
6. the digest value.

The digest preimage would use explicit domain separation for the Valoris
protocol, object type, schema version, and canonicalization profile. The exact
framing, wire grammar, digest algorithm, digest length, truncation policy, and
text/binary encoding are all `BLOCKED_UNVERIFIED`. They must be frozen by golden
vectors and reviewed before an identifier is emitted. Digest length is never an
attacker-selected runtime option: a permitted length belongs to a separately
registered profile.

Objects cannot contain their own content identifier inside the bytes used to
derive that identifier. References, signatures, and envelope fields require an
explicit commitment-scope table so there is no circular or accidental omission.

### Fully specified signature suites

A signature-suite identifier would identify every security-relevant choice,
including algorithm parameters and the signature-envelope profile. It may not
be a generic label whose concrete operation is inferred from key type. A key is
bound to its permitted suite, controller, purpose, and lifecycle state.

Verification-affecting metadata—including suite, key identifier, signer or
controller, content identifier, canonicalization profile, protocol context,
creation time, expiry when present, nonce when present, and purpose—must be
inside the protected commitment. The exact envelope remains
`BLOCKED_UNVERIFIED`.

An envelope parser would reject duplicate signature labels, duplicate protected
parameters, unprotected copies of protected parameters, ambiguous key lookup,
and signatures that can be moved between envelope positions or object types.
The acceptance policy must identify the exact signature set and threshold
required for the operation; "at least one valid signature" is not a safe
default.

Verifiers use an application policy allowlist. Unknown, ambiguous, deprecated
for the relevant time, or context-incompatible suites fail closed. There is no
opportunistic negotiation or fallback to a weaker algorithm.

Algorithm or suite selection is bound to the protected evidence and to an
independently obtained verifier policy version. A signer cannot authorize a new
algorithm merely by naming it in signed content. If algorithm information is
available from the envelope, key, registry, or policy in more than one place,
every resolved value must agree or verification fails.

### Transition and deprecation

Algorithm registry entries are immutable. A policy may stop new signing with a
suite while retaining historical verification long enough to interpret existing
evidence. A transition may require dual signatures or dual content commitments,
but the acceptance rule, cutover times, and downgrade protections must be
explicit. Two digests do not become the same identifier merely because a
migration relates them.

Transition evidence must itself resist stripping. If policy requires both an
old and a new suite, removing either signature or its required-suite declaration
causes failure. If policy accepts either suite during a window, that exact
window and policy version must be external to attacker-controlled content and
auditable. A weak historical signature cannot satisfy a current-operation gate
merely because it remains parseable.

Emergency deprecation, key rotation, compromise handling, cryptoperiods,
retention, and verification after retirement belong to the key-lifecycle policy
required by D-017. [NIST SP 800-57 Part 1 Rev. 5](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final)
and the current final [SP 800-131A Rev. 2](https://csrc.nist.gov/pubs/sp/800/131/a/r2/final)
must be considered at decision time. The draft Rev. 3 is a watch item, not an
accepted basis.

## `BLOCKED_UNVERIFIED` choices

No choice is made for:

- digest algorithm, output length, multihash/CID use, identifier encoding, or
wire grammar;
- signature algorithm, parameter set, key format, key identifier derivation,
random-number requirements, or hardware-key policy;
- signature envelope, countersignature, timestamp authority, nonce strategy,
transparency mechanism, or revocation-status format;
- mandatory-to-implement suite set, transition window, dual-signature rule, or
historical-verification lifetime.

## Required evidence before acceptance

1. A threat model covers collision, second-preimage, algorithm confusion,
downgrade, key substitution, parser differential, replay, and compromised
key scenarios.
2. Cross-language vectors cover domain separation, every committed field,
malformed prefixes, wrong or truncated lengths, duplicate parameters,
signature reordering/stripping, unknown suites, and transition cases.
3. Independent cryptography review approves the exact constructions and key
lifecycle.
4. At least two implementations verify the same positive and negative vectors.
5. Deprecation and emergency-rotation exercises preserve historical evidence
without permitting new use of a retired suite.

## Alternatives not selected

- **Bare hex digest:** omits algorithm, profile, type, and encoding context.
- **Algorithm inferred from digest length:** ambiguous and unsafe for migration.
- **Generic algorithm names interpreted from the key:** creates algorithm
confusion and prevents precise policy.
- **Single forever algorithm:** removes a safe migration path.
- **Runtime algorithm negotiation:** adds downgrade risk to deterministic
verification.

## Non-goals

This ADR authorizes no cryptographic implementation, production key, signing
service, schema, worker, payment mechanism, or accepted security policy.
Loading
Loading