- Purpose
This document defines how ledger payloads are transformed into canonical form before hashing.
Canonicalization guarantees:
Resolving locale, route permissions, and workspace projection.
Current scope: Guest
Category: 60_technical_specs | Version: v1.0.0
Owner: DOCUMENT_CUSTODIAN | Review cycle: 60 days
Approval authority: GOVERNANCE_ADMIN, COMPLIANCE_OFFICER
Documentation portal is read-only. Editing and mutation endpoints are disabled.
Kvary platform is originally created in Georgian. Where a Georgian version exists, Georgian is authoritative for platform UI, documentation, and legal interpretation.
Translations into other languages are provided for convenience. Some records may originate in other languages and carry their own source or legal locale for a specific flow, but where a Georgian version is available, the Georgian version prevails for platform-level wording and interpretation.
Metadata incomplete: Document ID, Version, Status, Owner Role, Last Review Date, Next Review Date, Change Log
This document defines how ledger payloads are transformed into canonical form before hashing.
Canonicalization guarantees:
Deterministic hashing
Replay consistency
Cross-node hash equality
Cryptographic immutability
If canonicalization differs across environments, the protocol is broken.
Hash(input) must be identical across:
OS
Runtime
Language version
Time
Node ordering
Developer machine
No implicit behavior allowed.
Canonicalization applies to:
GovernanceRecordV1
LedgerEntry
PolicyV1
Settlement payload metadata
KES commitments
Any structure used to compute:
payloadHash
entryHash
versionHash
policyHash
All object keys MUST be sorted lexicographically (UTF-16 code unit order).
Example:
❌ Not allowed:
{ b: 2, a: 1 }
✅ Canonical:
{ a: 1, b: 2 }
Sorting must be recursive.
3.2 Arrays
Arrays must:
Preserve order exactly as provided
Never be auto-sorted
Never be deduplicated
Never be mutated
Array order is semantically meaningful.
3.3 Undefined Values
Rules:
Undefined properties MUST be removed.
Null values MUST be preserved.
Empty string "" MUST be preserved.
Empty object {} MUST be preserved.
3.4 Number Handling
Rules:
No floats in governance-critical hashes.
Monetary values MUST be stringified integers.
Decimals stored separately.
No scientific notation.
No implicit conversion.
Example:
❌ 1.23 ✅ value: "123", decimals: 2
3.5 Boolean Handling
Must remain:
true false
Never converted to string.
3.6 String Encoding
UTF-8
No trimming
No normalization
No lowercasing
No whitespace mutation
Exact byte equality required.
Pseudo-spec:
Remove undefined properties recursively.
Sort object keys lexicographically.
Preserve array order.
Preserve types exactly.
JSON.stringify without spacing.
Hash with fixed algorithm (SHA-256 unless protocol changes).
Example:
canonicalString = JSON.stringify(sortedObject) hash = SHA256(canonicalString)
No pretty print. No spacing. No custom replacers. No runtime-dependent formatting.
Computed from canonicalized payload only.
payloadHash = hash(canonical(payload))
5.2 entryHash
Computed from canonicalized entry:
entryHash = hash({ id, previousHash, payloadHash, payload })
Key ordering must also apply here.
KES versionHash MUST be computed from:
Canonical commitments payload only.
Never from:
LedgerEntry
Metadata
Decision hashes
Execution outputs
Version hash must represent pure contract definition.
PolicyHash must be computed from canonical PolicyV1.
If policyHash changes due to non-semantic ordering differences → canonicalization is broken.
Replaying the same ledger MUST produce:
Same payloadHash
Same entryHash
Same versionHash
Same policyHash
Across machines.
Across time.
Across environments.
The following are strictly forbidden:
Date.now() inside canonicalized payload
Random UUID generation
Environment-dependent data
Locale formatting
Floating-point monetary math
Object key insertion-order dependency
Implicit JSON.stringify key ordering
Using Map without conversion
Canonicalization function must:
Have no side effects
Not mutate input
Not depend on global state
Not depend on runtime configuration
Not read external files
It must be pure and deterministic.
If:
SettlementIntent canonicalization differs from KES canonicalization → entire governance replay integrity fails.
All domains must share the same canonicalization engine.
Single source of truth implementation.
If canonicalization algorithm ever changes:
GOVERNANCE_RULES_VERSION must bump
All dependent hashes must be versioned
Migration rules must be documented
Replay compatibility must be preserved
Changing canonicalization without versioning = protocol fork.
Before release:
Cross-platform hash equality test required
Snapshot test required
Deterministic replay test required
JSON fuzz tests recommended
Hash is law. Canonical form defines hash. Therefore canonicalization defines law.