Fingerprinting
The fingerprint function computes a deterministic SHA-256 hash of any JavaScript object.
import { fingerprint } from "@stacknet/lode";
const hash: string = fingerprint(obj);
// → "a3f8c2e9b4d1..." (64-character hex string)Algorithm
- Deep clone the input using
structuredClone - Canonicalize — recursively sort all object keys alphabetically and sort string arrays
- Serialize —
JSON.stringifywith no whitespace or replacer - Hash — SHA-256, output as lowercase hex
Canonicalization
The key insight of LODE fingerprinting is that the hash is computed on a canonical form, not on the raw input. This means:
Object keys are sorted
fingerprint({ b: 2, a: 1 }) === fingerprint({ a: 1, b: 2 })
// → true (same hash)String arrays are sorted
fingerprint({ tags: ["beta", "alpha"] }) === fingerprint({ tags: ["alpha", "beta"] })
// → true (same hash)Non-string arrays preserve order
fingerprint({ steps: [3, 1, 2] }) === fingerprint({ steps: [1, 2, 3] })
// → false (different hash — not all strings, so order matters)Nested objects are recursively sorted
fingerprint({
outer: { z: 1, a: 2 },
inner: { y: { c: 3, b: 4 } }
})
// Canonicalizes to: {"inner":{"y":{"b":4,"c":3}},"outer":{"a":2,"z":1}}Properties
- Deterministic — Same logical object always produces the same hash
- Order-independent — Key insertion order and string array order don’t affect the hash
- Collision-resistant — SHA-256 provides 256-bit security
- One-way — Cannot reconstruct the object from the hash
Use Cases
- Cache keys — Use the fingerprint as a cache key for compiled Vein binaries
- Content addressing — Reference configurations by their fingerprint instead of version numbers
- Change detection — Compare fingerprints to detect if a configuration has changed
- Audit logging — Record fingerprints to track which exact configuration was active at any point
Last updated on