Canonicalization
ALX uses recursive-json-sort-v1 to convert supported ALX values into deterministic UTF-8 bytes. Block identity derivation hashes these bytes, so conforming implementations produce identical canonical bytes and identical hashes from equivalent inputs.
Canonical Rules
Canonical output contains no whitespace between tokens. Each input type has one canonical representation:
| Input | Canonical Representation |
|---|---|
null | null |
| Boolean | true or false |
| Safe integer | Decimal digits; -0 becomes 0, and 1.0 becomes 1 |
| Finite non-integer number | Shortest round-trip decimal form produced by JavaScript JSON.stringify() |
| String | Double-quoted UTF-8, escaped as described below |
| Array | Elements in original order |
| Object | Keys sorted by UTF-16 code units |
String Escaping
Strings keep every character as UTF-8 except three groups: " is escaped as \", \ as \\, and control characters U+0000 to U+001F as \b, \t, \n, \f, \r, or \u00XX with lowercase hexadecimal digits. Non-ASCII characters and / are never escaped.
Input Requirements
Canonicalization accepts ALX values: null, booleans, valid Unicode strings, supported finite IEEE 754 binary64 numbers, arrays, and objects with unique string keys. Raw JSON parsing, including duplicate-member rejection, happens before canonicalization.
Unicode code points are preserved without normalization. Composed and decomposed forms of the same character produce different canonical bytes and different hashes.
Canonicalization Constraints
Canonicalization rejects every other input. Rejected input has no canonical bytes and no protocol identity.
| Rejected input | Error identifier |
|---|---|
undefined, including sparse array elements and object properties whose value is undefined | ALX_CANONICALIZATION_UNSUPPORTED_TYPE |
BigInt | ALX_CANONICALIZATION_BIGINT |
Symbol | ALX_CANONICALIZATION_SYMBOL |
Non-finite numbers (NaN, Infinity, -Infinity) | ALX_CANONICALIZATION_NON_FINITE |
| Unsafe integers, outside -(2^53 - 1) to 2^53 - 1 | ALX_CANONICALIZATION_UNSAFE_INTEGER |
| Strings or object keys containing an unpaired UTF-16 surrogate | ALX_CANONICALIZATION_INVALID_UNICODE |
| Cyclic structures | ALX_CANONICALIZATION_CYCLIC |
| Unsupported value types, such as functions, dates, maps, and class instances | ALX_CANONICALIZATION_UNSUPPORTED_TYPE |
Block Identity
contentHash hashes a domain tag followed by the canonical bytes of content. blockHash hashes a domain tag followed by the canonical bytes of {"content": …, "parentHashes": […]}, with parentHashes normalized first. Block validation repeats both derivations and compares the results with the recorded hashes. See Block Identity for the domain tags and hash format.