<!-- markdown mirror of https://mintid.net/en/blog/declaring-how-we-hash — generated at build time -->

> MintID now names its canonicalization algorithm — RFC 8785 (JCS) then SHA-256 — cites every digest as a typed reference, and hashes anything logged in a Merkle tree as raw bytes. Published as bIP-0003 and aligned with an IETF individual submission on SCITT payload binding; byte-for-byte unchanged for existing integrations, and the shape our published verifier verdicts will take.

Blog · engineering

# Declaring how we hash: a small standard for the bytes behind a ten-second proof

MintID now names its canonicalization algorithm — RFC 8785 (JCS) then SHA-256 — cites every digest as a typed reference, and hashes anything logged in a Merkle tree as raw bytes. Published as bIP-0003 and aligned with an IETF individual submission on SCITT payload binding; byte-for-byte unchanged for existing integrations, and the shape our published verifier verdicts will take.

by Marc Miró i Rierola·published 2026-09-17·updated 2026-09-17·6 min read

_Why MintID now names its canonicalization algorithm, cites every digest with a type, and prepares its verdicts to be checked by anyone — without asking anyone to trust us._

A MintID [presentation](/en/technology) 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. Everything about the binding — which origin, which verifier key, which nonce, which policy, which finalized block — is folded into one 32-byte digest. If two implementations compute that digest over different bytes, a perfectly valid proof fails, or worse, a proof made for one challenge is accepted for another.

So the boring question matters: _which bytes, exactly?_

## The rule we had

Until now the answer was implicit: “the JSON our reference implementation emits” — sorted keys, no whitespace. It worked because one language wrote it. It stops working the moment a second language has to reproduce it byte for byte, which is precisely what our [verifier SDKs in other languages](/en/sdk/multi-language-clients) do.

## The rule we adopted

MintID now _declares_ its canonicalization algorithm. Every JSON object we hash, sign or cite by digest is canonicalized with the JSON Canonicalization Scheme of [RFC 8785](https://www.rfc-editor.org/rfc/rfc8785), then hashed with SHA-256. There is a name for that combination in a recent IETF document, _Canonicalization Declaration for SCITT Signed Statements_ ([`draft-mih-sokolov-scitt-payload-binding`](https://datatracker.ietf.org/doc/html/draft-mih-sokolov-scitt-payload-binding-05)), an individual submission circulated on the SCITT working group’s list, and we use its vocabulary: the algorithm is called `jcs`; digests are cited as _typed digest references_ — a reference says what kind of object it points at and how the digest was made; and anything placed in a Merkle tree or a transparency log is hashed as raw bytes, never as hexadecimal text. Small rules, each with a specific failure mode behind it.

> **What changed for existing integrations: nothing.** For the payloads MintID actually sends, the new rule produces the same bytes as the old one. Every frozen [conformance vector](/en/sdk/conformance) is unchanged. What changed is that an implementer in Go, TypeScript or PHP can now point at an RFC instead of at our Python.

## What it prepares

A MintID verifier does not only decide; it can _publish_. An [x402 explorer](/en/x402-pilot) that checks a seller’s human-backing every few hours publishes its own signed verdict: “human-backed at this assurance level, verified at this time, re-checked every N hours.” The same draft describes how such a statement should be packaged — a COSE signed statement ([RFC 9052](https://www.rfc-editor.org/rfc/rfc9052)) with a content-derived identifier — so that a transparency service can issue a receipt for it and any third party can later verify that the verdict existed, unchanged, at that time. MintID does not run a transparency service and does not need one: verification of a MintID claim is free and anyone can recompute a verdict’s inputs against the chain. A receipt adds independent, time-stamped evidence on top. Our [x402 profile](/en/blog/x402-web-bot-auth-identity-profile) now records this packaging as the shape our published verdicts will take.

## What it does not touch

The zero-knowledge proof itself is a binary object and is not canonicalized as JSON; the rule covers what the proof is _bound to_, not the proof. No on-chain logic changes. No new field carries anything about a holder: typed references point at public objects — a status root, an issuer’s public definition, a challenge — and nothing else.

## Why we bother

Identity infrastructure is judged on interoperability and on what can be verified without trusting the operator. Naming the algorithm is the cheapest possible investment in both. The profile is published in the repository as bIP-0003, and the draft we align with is an individual submission we will track as it evolves — we adopt what already stands on RFCs, and we say so.

### References

*   bIP-0003 — Canonicalization declaration and typed digest references — the MintID profile, published in the repository
*   [RFC 8785 — JSON Canonicalization Scheme (JCS)](https://www.rfc-editor.org/rfc/rfc8785)
*   [RFC 9052 — CBOR Object Signing and Encryption (COSE): Structures and Process](https://www.rfc-editor.org/rfc/rfc9052)
*   [RFC 9943 — An Architecture for Trustworthy and Transparent Digital Supply Chains (SCITT)](https://www.rfc-editor.org/rfc/rfc9943)
*   [RFC 9995 — COSE Hash Envelope](https://www.rfc-editor.org/rfc/rfc9995)
*   [draft-mih-sokolov-scitt-payload-binding-05 — Canonicalization Declaration for SCITT Signed Statements](https://datatracker.ietf.org/doc/html/draft-mih-sokolov-scitt-payload-binding-05) — individual submission, 11 September 2026

What changed for existing MintID integrations?

Nothing. 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. What changed is that an implementer in another language can now point at an RFC instead of at 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, RFC 9995 for the hash-envelope shape — and cites the SCITT payload-binding draft as an alignment target. That draft is an individual IETF submission (version 05, September 2026), not a standard, and MintID makes no claim about its future.

What is a typed digest reference?

A digest cited together with what kind of object it points at and how the digest was computed — 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 cannot.

Does this touch the zero-knowledge proof?

No. The proof is a binary object and is not canonicalized as JSON; the rule covers what the proof is bound to — the challenge, the policy, the chain state — not the proof itself. No on-chain logic changes, and no new field carries anything about a holder: typed references point at public objects only.

## Point at an RFC, not at our code

If you are implementing a MintID verifier client in another language, the bytes are now specified. Tell us where the profile is unclear.

[Verifier SDK](/en/sdk)[Talk to us](/en/contact)

---
Source: https://mintid.net/en/blog/declaring-how-we-hash · Declaring how we hash: a small standard for the bytes behind a ten-second proof — MintID blog
