Blog · engineering

How MintID declares the bytes behind a ten-second proof

If two implementations hash the binding of a ten-second presentation over different bytes, a valid proof fails or a wrong one passes. MintID now declares its rule: RFC 8785 canonicalization, then SHA-256. It cites every digest as a typed reference and hashes Merkle-tree entries as raw bytes. This rule is recorded as bIP-0003. It leaves the bytes unchanged for existing integrations and follows an individual IETF submission on SCITT payload binding.

Updated 2026-10-04: profile availability and headings.

MintID now names its canonicalization algorithm, cites every digest with a type, and prepares its verdicts so anyone can check them.

A MintID presentation lives for ten seconds. In that window a verifier sends a signed challenge. The holder answers with a zero-knowledge proof bound to that exact challenge, and the verifier decides. One 32-byte digest folds in everything about the binding: the origin, the verifier key, the nonce, the policy, and the finalized block. If two implementations compute that digest over different bytes, a valid proof fails. Worse, a proof made for one challenge can pass for another.

So the exact bytes matter.

Multi-language SDKs need an explicit byte format

Until now the rule was implicit: “the JSON our reference implementation emits”, with sorted keys and no whitespace. That worked because one language wrote it. A second language now has to reproduce that JSON byte for byte in our verifier SDKs in other languages, so the rule must be explicit.

MintID canonicalizes JSON with RFC 8785, then hashes it with SHA-256

MintID now declares its canonicalization algorithm. We canonicalize every JSON object we hash, sign, or cite by digest with the JSON Canonicalization Scheme of RFC 8785, then hash it with SHA-256. We use the vocabulary of a recent IETF document, Canonicalization Declaration for SCITT Signed Statements (draft-mih-sokolov-scitt-payload-binding). This document is an individual submission circulated on the SCITT working group’s list. In that vocabulary the algorithm is called jcs, and digests are cited as typed digest references. A typed digest reference says what kind of object it points at and how the digest was made. We hash every entry in a Merkle tree or a transparency log as raw bytes, never as hexadecimal text. Each rule prevents a specific failure mode.

Existing integrations do not need to change. For the payloads MintID sends, the declared rule produces the exact same bytes as the previous one. Every frozen conformance vector is unchanged. Implementers working in Go, TypeScript, or PHP can now build against an RFC. They do not need to match our Python reference code.

Verifiers can publish verdicts that a third party can timestamp and check later

A MintID verifier can also publish its verification decisions for others to check. For example, an x402 explorer that re-checks a seller’s human-backing every few hours could publish its own signed verdict: “human-backed at this assurance level, verified at this time, re-checked every N hours.” The same draft describes how to package that statement as a COSE signed statement (RFC 9052) with a content-derived identifier. A transparency service can then issue a receipt for the statement. With that receipt, any third party can later verify that the verdict existed, unchanged, at that time. MintID does not run or need a transparency service. Verifying a MintID claim carries no protocol fee, and anyone can recompute a verdict’s inputs against the chain. A receipt adds independent, time-stamped evidence on top. Our x402 profile now records this packaging as the shape our published verdicts will take.

The proof and the chain stay exactly as they were

The zero-knowledge proof itself is a binary object, so it is not canonicalized as JSON. The rule covers the data that the proof is bound to. No on-chain logic changes. No new field carries anything about a holder. Typed references point at public objects only: a status root, an issuer’s public definition, a challenge.

The profile is recorded in bIP-0003

Clear byte-level rules let independent implementations interoperate. Anyone can check a result without trusting the operator or a single reference codebase. The profile is recorded as bIP-0003 and is available on request. Where an RFC already exists, we adopt it. The draft we align with is an individual submission, and we will track it as it evolves.

References

What changed for existing MintID integrations?
Nothing changed for existing integrations. For the payloads MintID actually sends, the declared rule (RFC 8785 canonicalization followed by SHA-256) produces the same bytes as the previous implicit rule. Every frozen conformance vector is unchanged. An implementer in another language can now build against an RFC. They do not need to match the Python reference implementation.
Does MintID implement SCITT?
No. MintID adopts the parts that already stand on RFCs: RFC 8785 for canonicalization, RFC 9052 for COSE signed statements, and RFC 9995 for the hash-envelope shape. MintID cites the SCITT payload-binding draft as an alignment target. That draft is an individual IETF submission (version 05, September 2026). It is not a standard, and MintID makes no claim about its future.
What is a typed digest reference?
A typed digest reference cites a digest together with the kind of object it points at and how the digest was computed. That includes the canonicalization algorithm and the hash. A bare 32-byte value can be mistaken for the digest of the wrong object or the wrong bytes. A typed reference prevents that mistake.
Does this touch the zero-knowledge proof?
No. The proof is a binary object, so it is not canonicalized as JSON. The rule covers what the proof is bound to: the challenge, the policy, and the chain state. It does not cover the proof itself. No on-chain logic changes, and no new field carries anything about a holder. Typed references point at public objects only.

Build a verifier client in another language

The bytes are now specified for anyone implementing a MintID verifier client in another language. Tell us if any part of the profile is unclear.