Skip to content
Concepts

Canonicalization

How Vitrified turns a submission into a deterministic byte sequence so leaf identifiers reproduce exactly across clients and runtimes.

Canonicalization

A submission's leaf identifier must reproduce exactly across SDKs, runtimes, and re-submissions — otherwise verifiers can't reconstruct the leaf from the original inputs. Vitrified pins canonicalization to JCS (JSON Canonicalization Scheme, RFC 8785) so any conformant JSON canonicalizer produces the same bytes.

The rule

leaf_sha256 = SHA-256(JCS(submission_envelope))

Where submission_envelope is a JSON object containing the artifact hash, the declared metadata schema, and the metadata payload. The exact field order in your source code doesn't matter; JCS sorts keys lexicographically, normalizes number encoding, and uses a single, deterministic UTF-8 serialization.

What JCS guarantees

  • Key ordering. Object keys are sorted lexicographically by their Unicode code-point sequence.
  • Number normalization. Numbers serialize to the shortest IEEE-754 form. 1.0, 1, and 1e0 all canonicalize to 1.
  • String normalization. Strings serialize as UTF-8 with the minimum set of escapes required by JSON. No optional whitespace.
  • No insignificant whitespace. No spaces between tokens.
  • No ambiguity. For any JSON value, the canonical byte sequence is unique.

Reference implementations

The canonicalization implementations live in this repository and ship in every SDK:

Both implementations are tested against the shared test vectors at spec/canonicalization/test-vectors/ on every commit, so cross-language drift is a CI failure.

What Vitrified does not canonicalize

Vitrified never canonicalizes the bytes of your artifact. The canonicalization rule applies only to the submission envelope — the JSON wrapper containing the hash and metadata. Your artifact bytes are exactly what you hashed; nothing on the wire transforms them.

Canonicalization helpers for artifact-side normalization (CRLF vs. LF, BOM stripping, JSON re-serialization of your own JSON artifacts) exist in the SDK as explicit function calls you choose to invoke. They are never applied silently.

See also

Was this page helpful?