Skip to main content
Canonical Serializer (Python reimplementation). Reproduces packages/crypto/src/CanonicalSerializer.ts byte-for-byte, for already-JSON-decoded input, as the independent-language proof requested by the PQC audit’s Layer 5 (“deterministic serialization … Node.js, plus at least one other language”). This module deliberately does NOT reconstruct Date objects from ISO strings before re-serializing: an Execution Trust Record read from a JSON file (or an API response) already has every timestamp as a plain string — CanonicalSerializer.ts’s own Date-handling branch only matters on the TypeScript signing side, which starts from real Date objects. Re-serializing already-JSON-decoded primitives sidesteps the much harder problem of reproducing Date.prototype.toISOString() exactly and is sufficient for verification, since the signer already turned every Date into its canonical string form before ever hashing or signing it. Two concrete cross-language pitfalls this module corrects for — found empirically while writing it, not assumed:
  • JSON.stringify’s default separators are compact (no space after ”,” or ”:”); Python’s json.dumps defaults to ”, ” and ”: ”. Left uncorrected, every object/array would serialize to different bytes in Python than in Node, and no signature would ever verify.
  • JSON.stringify does not escape non-ASCII characters by default; Python’s json.dumps defaults to ensure_ascii=True, which \uXXXX- escapes them. Same effect: different bytes for any string containing non-ASCII content.
Known, narrow limitation: key sorting uses Python’s default string ordering (Unicode code point order), while CanonicalSerializer.ts sorts by JavaScript’s default string ordering (UTF-16 code unit order). These are identical for every key actually used in this codebase’s real payloads (all ASCII identifiers) and for the entire Basic Multilingual Plane; they diverge only for object keys containing astral-plane Unicode characters (code points above U+FFFF), which does not occur anywhere in this system’s real payloads today.

canonical_serialize

Serializes an already-JSON-decoded value into the same canonical UTF-8 bytes CanonicalSerializer.ts would produce for the equivalent JavaScript value.