This specification defines the canonical form for ZLAR Governed Action Receipts and audit trail entries. All implementations that produce or verify signatures over ZLAR JSON structures must follow this specification.
This specification adopts RFC 8785 (JSON Canonicalization Scheme) with a constrained schema that eliminates its known failure modes. Any ZLAR-canonical JSON is also RFC 8785-canonical.
ZLAR uses JSON structures signed with Ed25519 over their SHA-256 hash. For signatures to verify across implementations (bash, Node.js, Python, Go, Rust), every implementation must produce byte-identical canonical output for the same logical data.
The canonical form is computed by:
ZLAR canonical form applies to JSON structures that conform to these type restrictions:
true, false)null)Rationale: Floating-point serialization is the primary source of cross-language canonicalization failures. JavaScript's JSON.stringify(100.0) produces "100". Python's json.dumps(100.0) produces "100.0". Eliminating floats from the schema eliminates this entire vulnerability class.
Object keys must be sorted recursively at all nesting levels by Unicode code point order. For the constrained ZLAR schema (ASCII-only keys), this is identical to lexicographic byte order, UTF-16 code unit order (RFC 8785), and ASCII alphabetical order.
Integers must be serialized as decimal digits with no leading zeros, no trailing zeros, no decimal point, and no exponent notation. Negative zero must serialize as 0.
Strings follow standard JSON escaping (RFC 8259). All non-ASCII characters must be output as literal UTF-8 bytes, not escaped to \uXXXX. This matches JavaScript's JSON.stringify() and RFC 8785.
| Language | Recommended Implementation |
|---|---|
| Node.js/TypeScript | canonicalize npm package (erdtman) or recursive key-sort + JSON.stringify |
| Python | rfc8785 package (Trail of Bits) or recursive key-sort + json.dumps(ensure_ascii=False, separators=(',',':')) |
| Go | gowebpki/jcs |
| Java | titanium-jcs or erdtman/java-json-canonicalization |
| Rust | serde_json_canonicalizer (not serde_jcs — confirmed UTF-16 sorting bug) |
| Bash | jq -S -c '.' (valid for ZLAR-constrained structures only) |
28 test vectors are published at tests/fixtures/canonicalization-vectors.json. Verified across Node.js, Python, and bash/jq. Implementations must produce byte-identical output for every vector.
Permanent URL: https://zlar.ai/specs/canonicalization
Source: docs/canonicalization-spec.md
License: Apache 2.0 — ZLAR Inc.