Cryptographic Proof · WebCrypto SHA-256

Do not take our word for it.

How EqubFlow computes append-only hash chains so anyone can independently audit decision records.

In-browser verifier
Chain broken at entry #0

How hash chain verification works

Every decision record row contains a sequence number, timestamp, kind, plain-language reason, and the cryptographic hash of the previous row. By hashing each row deterministically using RFC 8785 JSON canonicalization, any modification to a single historical character invalidates all subsequent hashes.

  1. Canonical format: Each entry is canonicalized according to RFC 8785 (JCS). Keys are sorted lexicographically by UTF-16 code units, and whitespace is removed.
  2. Chained fingerprints: The hash of entry N is computed as SHA256(prevHash + canonicalJson(content)).
  3. Tamper evidence: Altering a single character in entry 2 invalidates its hash, which breaks the prevHash pointer of entry 3 and every entry that follows.

Implementation excerpt

packages/domain/src/decision-chain.ts
export function computeDecisionHash(
prevHash: string,
content: DecisionRecordContent
): string {
const canonical = canonicalJson(content);
return createHash('sha256').update(prevHash + canonical).digest('hex');
}

Golden Vector Test Case

Independent verification vector for third-party auditing tools:

verify.py
import hashlib, json
prev_hash = "0" * 64
content = {
"at": "2026-10-12T10:30:00Z",
"kind": "group_created",
"reason": "Circle of six created on Arc Testnet with 4 members.",
"seq": 1
}
# RFC 8785 canonical JSON: sorted keys, no whitespace
canonical = json.dumps(content, separators=(',', ':'), sort_keys=True)
record_hash = hashlib.sha256((prev_hash + canonical).encode('utf-8')).hexdigest()
print("Computed fingerprint:", record_hash)
Honest limit: A person who controls the signing key and the database could rebuild a consistent record. Publishing the latest fingerprint on Arc is what makes that visible. In this testnet version, fingerprints are logged on Arc Testnet.