Skip to Content
DocsBasicsFingerprinting

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

  1. Deep clone the input using structuredClone
  2. Canonicalize — recursively sort all object keys alphabetically and sort string arrays
  3. SerializeJSON.stringify with no whitespace or replacer
  4. 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