# Hash chain

Kind

concept

For

developer · operator · governance

Verified against

@veritio/core@0.4.7 · veritio-json-v1

A Veritio record chain makes a later change, deletion, or reordering detectable. It does this with three separate invariants: deterministic bytes, gapless tenant-local sequence numbers, and a link to the preceding record hash.

## From an object to canonical bytes

[Section titled “From an object to canonical bytes”](#from-an-object-to-canonical-bytes)

Normal JSON serialization can vary when object keys were inserted in different orders. `veritio-json-v1` first normalizes the supported JSON domain and sorts object keys recursively, then serializes the result without insignificant whitespace.

```text
Host objects with different key insertion order
                    ↓ normalizeForJson
The same sorted JSON-compatible value
                    ↓ JSON.stringify
The same UTF-8 canonical byte sequence
                    ↓ SHA-256
The same digest
```

Undefined object properties are omitted, array holes become `null`, dates become ISO strings where SDK input permits them, and non-finite numbers fail instead of receiving an unstable representation.

## What the record hash covers

[Section titled “What the record hash covers”](#what-the-record-hash-covers)

`hashAuditRecord` removes only the stored `hash` field and hashes the canonical JSON of everything else in the record envelope. That includes the normalized event, sequence, previous hash, algorithm labels, append time, and idempotency-key hash.

For the first two records in one tenant:

```text
record 1
  sequence: 1
  previousHash: null
  hash: SHA-256(canonical record 1 without its hash field)

record 2
  sequence: 2
  previousHash: record 1.hash
  hash: SHA-256(canonical record 2 without its hash field)
```

Each tenant has independent verifier state. Two tenants may both have sequence `1`; their records must never be joined into one tenant chain.

## How verification walks the chain

[Section titled “How verification walks the chain”](#how-verification-walks-the-chain)

For each record in supplied order, `verifyAuditRecords` checks:

1.  `event.scope.tenantId` exists.
2.  `hashAlgorithm` is `sha256`.
3.  `canonicalization` is `veritio-json-v1`.
4.  `sequence` is exactly one greater than the last record for that tenant.
5.  `previousHash` matches the last verified hash for that tenant.
6.  The recomputed record hash matches the stored `hash`.

It stops at the first failure and reports the array index plus a stable reason.

## Mutation and deletion produce different evidence

[Section titled “Mutation and deletion produce different evidence”](#mutation-and-deletion-produce-different-evidence)

The executable [verification tutorial](/docs/start/verify-a-chain/) changes the second record and separately removes the first. Its checked output is:

verified tamper output

```json
{
  "changedRecord": {
    "ok": false,
    "index": 1,
    "reason": "hash_mismatch"
  },
  "droppedRecord": {
    "ok": false,
    "index": 0,
    "reason": "sequence_mismatch"
  }
}
```

Changing bytes without recomputing the envelope produces `hash_mismatch`. Starting with sequence `2` produces `sequence_mismatch`. Reordering or deleting a middle record can produce a sequence or previous-hash mismatch at the first surviving inconsistent record.

## Detection is not prevention

[Section titled “Detection is not prevention”](#detection-is-not-prevention)

The chain does not stop someone with write access from corrupting bytes. It makes the corruption detectable when verification runs. The append boundary still needs authorization, tenant isolation, expected-tip checks, idempotency conflict rejection, backups, and operational response.

A locally consistent chain can also be replaced in its entirety by an attacker controlling the whole store. Evidence commits, independently held exports, signatures where implemented, or external commitments can strengthen the ability to detect whole-history replacement.

## What a valid result proves

[Section titled “What a valid result proves”](#what-a-valid-result-proves)

`{ "ok": true }` means the supplied records are internally consistent under the declared protocol algorithms. It does not prove that the host recorded every relevant event or that an event’s original claim was truthful.

Continue with [Storage overview](/docs/storage/overview/) to understand which adapters can own authoritative ordering, or use the [verifier reference](/docs/reference/verifier/) to interpret each failure.

[Edit page](https://github.com/getveritio/veritio-website/edit/main/src/content/docs/docs/concepts/hash-chain.mdx)

Last updated: Aug 23, 2026

[Previous  
Audit events](/docs/concepts/audit-events/)[Next  
Evidence graph](/docs/concepts/evidence-graph/)

Veritio provides evidence support, not legal advice or automatic compliance.

This site uses cookieless, anonymous analytics (Umami) by default. With your consent, we also enable Google Analytics, which sets cookies and sends usage data to Google. [Privacy Policy](/legal/privacy/)
