Repository navigation
refactor(canonical): delegate JCS number and string writing to serde_json_canonicalizer - #202
Merged
graywolf336 merged 2 commits intoSep 28, 2026
Conversation
…ectors Replace the hand-written RFC 8785 walker in atomic-canonical/src/jcs.rs with a call into serde_json_canonicalizer. Member ordering and string escaping were already correct; number formatting was not. Section 3.2.2.3 requires the ECMAScript Number::toString algorithm, and serde_json's formatter crosses between decimal and exponent notation at different magnitudes and writes negative zero as -0.0, so two conforming implementations hashed the same logical document to different digests. The delegate formats through ryu_js, which is the variant the section names, and serializes through an explicit heap stack rather than the call stack. canonicalize keeps its signature, so no call site changes anywhere in the workspace. Eleven measured cases are pinned as fixtures under atomic-canonical/tests/vectors/ with a harness in tests/jcs_vectors.rs. Three conformance cases this entry point cannot decide are recorded in atomic-canonical/tests/vectors/INGEST-BOUNDARY.md rather than tested here: a repeated object member is gone before canonicalize is reached, and RFC 8785 admits both an integer past 2^53 and a fractional number. All of them want a strict decoder on the raw bytes at the boundary where documents arrive.
The Format job runs cargo fmt --all -- --check, which rejected two statements in atomic-canonical/tests/jcs_vectors.rs. No behaviour change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The file atomic-canonical/src/jcs.rs says it is the single canonicalization entry point, so the whole change is one dependency line and one file. Canonicalization now runs through
serde_json_canonicalizer, and canonicalize keeps its signature, so no call site in the workspace moves.Member ordering by UTF-16 code units and string escaping were already right; number formatting was not. Section 3.2.2.3 defers to the ECMAScript Number::toString algorithm, and the formatter in serde_json is not that algorithm. I measured each divergence on dev at bcbe2c5, re-measured after the change, and pinned eleven as fixtures under atomic-canonical/tests/vectors/.
devnumber-decimal-below-exponent-threshold0.0000011e-6number-decimal-2pow682951479051793528300002.9514790517935283e+20number-decimal-9999999999999997000009999999999999997000009.999999999999997e+20number-decimal-9999999999999999000009999999999999999000001e+21number-negative-small-decimal-0.0000033333333333333333-3.3333333333333333e-6number-negative-zero0-0.0number-exponent-9.999999999999997e229.999999999999997e+229.999999999999996e+22number-exponent-1.0000000000000001e231.0000000000000001e+231e+23number-exponent-9.999999999999997e-79.999999999999997e-79.999999999999995e-7number-rounded-to-its-double90071992547409929007199254740993depth-at-the-cap-is-canonicalizedFour further cases want a strict decoder on the wire bytes instead, and atomic-canonical/tests/vectors/INGEST-BOUNDARY.md lists each with its id for a follow-up. The fixtures come from https://github.com/probityai/agent-evidence-vectors, and the decoder that closes those four is https://github.com/probityai/jcs-admit.