Skip to content

chain: COSE-signed checkpoints and the conformance suite#421

Closed
damienrch wants to merge 5 commits into
mainfrom
provetrail-freeze-bytes
Closed

chain: COSE-signed checkpoints and the conformance suite#421
damienrch wants to merge 5 commits into
mainfrom
provetrail-freeze-bytes

Conversation

@damienrch

Copy link
Copy Markdown

Four commits that were made directly on local main and never reviewed. Moved onto a branch so they land through a PR.

  • 0cb28a5 feat(catalog): pin token v0.1.2 and solana-signer v0.1.1
  • 518995f chain: sign checkpoints under COSE algorithm -19 and the vendor-tree media type
  • 9baa8b3 chain/conformance: run-record vectors are L2, per the tier definition
  • 2c9561c chain: harden the reference verifier and complete the conformance suite
  • e3e9aa5 chain/conformance: pin the empty-string ruling with a vector

Task: 0a671767-3e9b-44ee-9a56-2298f94825e0

…media type

RFC 9864 (Oct 2025) deprecated the polymorphic EdDSA identifier (-8) in
favour of fully-specified Ed25519 (-19), and RFC 6838 s3.1 makes unfaceted
application/provetrail-* names unobtainable outside the standards tree, so
the checkpoint protected header now carries alg -19 and
application/vnd.provetrail.checkpoint+cbor. The signature bytes are
unchanged Ed25519.

go-cose v1.3.0 predates RFC 9864 and its NewSigner/NewVerifier reject -19,
so ed25519CoseSigner/ed25519CoseVerifier carry the label themselves; Sign1
sign/verify only compare the header algorithm against the signer's, so no
fork of the library is needed.

Conformance crypto vectors regenerated in one event (go test
./chain/conformance -update); this is the single pre-freeze byte change the
Provetrail v0.1.0 gate allows.
The crypto.run.* vectors were tagged L3 while CONFORMANCE.md placed
run-record root integrity at L2, where the tier definition (Merkle-leaf
integrity over carried bytes) puts it. Retag the five run vectors L2 and
keep event_proof and consistency at L3 as the standalone transparency
proofs. Manifest-only regeneration; no vector bytes changed.
Verifier hardening, no wire-byte changes:
- decodeCheckpoint enforces payload canonicality (re-encode and compare)
  and a full SHA-256 root; checkpointPayload refuses to sign a short root.
- VerifyRun refuses an empty record with record.empty before the size
  comparison, so a signed size-0 checkpoint cannot make emptiness pass.
- VerifyEventProof names record.index_out_of_range for an index outside
  the signed size and merkle.missing_node for a path shorter than the
  tree shape requires (delivered length computed via Rehash).
- toCanonical enforces the closed actor category (enc.invalid_actor).
- Tree.Root returns the RFC 6962 empty root for an empty tree, matching
  its own documentation.

Conformance suite grows 34 -> 64 vectors: structural schema and boundary
coverage (seq gaps, ints beyond 2^53, unicode keys, bstr payloads,
full-envelope rejects) and the crypto mutant matrix (checkpoint header and
payload axes, run-container framing axes, operational proof codes).
SPEC Section 8.2 rules that required string fields are encoded even when
empty, as zero-length text strings. valid.empty_strings.01 pins the ruling.
gofumpt and gofmt disagree about alignment when a map key is a wide rune,
and the lint gate follows gofumpt. Whitespace only.
@ion-alpha-dev

Copy link
Copy Markdown
Collaborator

Opened under the wrong identity. Reopening from the workspace account.

@github-actions github-actions Bot locked and limited conversation to collaborators Jul 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants