continuity-receipt (Rust)
Second, independent implementation of the Continuity Receipt verifier for
continuity-receipt/0.1-0.4 bundles and verification receipts (companion
v1), including the 0.4 agreement-binding rules. The Python implementation in ../continuity_receipt/ remains the
reference; this crate exists for the two-independent-implementations bar,
native embedding, and single-binary deployment.
It re-implements the pinned JCS subset (canon.rs), did:key Ed25519
verification (didkey.rs), and the full verification algorithm with the same
error codes, verdict precedence, and JSON output shape as
continuity_receipt.verify (verify.rs) and
continuity_receipt.verification (verification.rs).
Install
The crate tracks continuity-receipt/0.1-0.3 bundles; the Python
implementation in this repository remains the reference. Publication
runbook: PUBLISH.md.
Run
The binary prints the same JSON shape as the Python CLI (verdict, errors,
provisional_reasons, insufficient_reasons, summary) and exits 0 iff the
verdict is TRUSTED, else 1.
Selective disclosure
continuity-receipt-disclose mirrors continuity_receipt/disclose.py
(redact / verify / reveal / check):
The gate-key file is the raw 32-byte Ed25519 seed. Redaction re-signs the
modified receipt and every receipt after it, so the signer must be the
chain's issuer; redacting a cross-checked field (for example spend_cap)
fails closed to UNTRUSTED because a commitment cannot prove the claim.
Verification receipts
continuity-receipt-verify-receipt mirrors
continuity_receipt/verification.py: shape and consistency checks
(error_codes equals the codes in errors; the verdict equals the class
implied by the errors/reasons), the Ed25519 signature over the canonical view
minus sig, optional bundle-digest and issuer-revocation checks.
Exit 0 iff the receipt is valid. --revocations reads a local revocation
document (the Python CLI also accepts URLs).
OpenTimestamps anchors
continuity-receipt-anchor mirrors continuity_receipt/anchor.py: replay a
detached .ots proof from the file digest and verify a Bitcoin attestation
against a supplied 80-byte block header by exact merkle-root equality.
Statuses verified / unverified / mismatch / invalid with the same
machine codes as Python; exit 0 iff verified. Header chain validation is
out of scope by design (../ANCHORING.md): the header is trusted input, not a
substitute for proof-of-work or confirmation checks.
Tests
The vector runner reads ../vectors/manifest.json and checks all 40 bundle
vectors against their expected verdict and error code; tests/verification.rs
does the same for the 21 verification-receipt vectors
(../vectors/verification/manifest.json), including consistency violations
and receipt digests. Malformed-bundle smoke cases
(empty object, non-object, missing receipts) are included so the verifier
returns structured errors instead of panicking. tests/disclose.rs covers
redaction, tail re-signing, refusal cases, and commitment recomputation
against the frozen vectors. tests/fuzz_corpus.rs mutates every vector
(deterministic seed) plus synthetic malformed shapes and byte truncations:
every case must yield a structured verdict with coded errors and never
panic. Set CR_FUZZ_CORPUS_DIR=<dir> to write the generated corpus to disk.
tests/anchor.rs covers synthetic proofs (LEB128 varuints, reverse/prepend,
truncation, keccak refusal) and the five real .ots fixtures, including the
published keccak negative case.
The Python↔Rust differentials run in CI after cargo build:
Intentional, documented differences from Python
- Floats and canonicalization failures produce a structured
malformed(or the relevant check's) error instead of a Python exception/traceback. - Invalid JSON input to the CLI prints a structured
malformedresult and exits1instead of raising. - Non-list
anchors/revocationsvalues and other deeply malformed shapes are failed closed with the corresponding structured error where Python would raise. disclose redactadditionally accepts repeatable--salt <path>=<hex>for reproducible commitments; the Python CLI always randomizes salts.disclose verifydoes not accept--revocationsuntil the Rust revocation-list loader lands; external lists remain Python-only. The verification-receipt CLI accepts local revocation documents (no URLs).anchor verifyhuman (non---json) output prints attestations as compact JSON rather than Python dict reprs; the--jsonshape is identical.