YinkoShield

Knowledge Center / Evidence architecture / evidence architecture · 2026·03

Forward chaining — three independent invariants for drop, edit, replay

Forward chaining is what links the records of the Local Evidence Ledger into a sequence whose integrity a verifier can check without coordinating with the device's clock or the operator's pipeline. Each record references its predecessor by hash, by sequence number, and by boot epoch. Drop, edit, reorder, and replay each break at least one of these three invariants — independently and additively.

[ forward chaining · three independent invariants ] intact chain boot_id = 0xab12 · seq monotonic · prev_hash matches seq=3 prev=ok seq=4 prev=ok seq=5 prev=ok seq=6 prev=ok seq=7 prev=ok all three invariants hold dropped event boot_id = 0xab12 (same epoch) · seq gap · prev_hash mismatch seq=3 prev=ok seq=4 prev=ok seq=5 missing seq=6 prev≠hash(4) seq=7 prev=ok two of three invariants flag the drop // what the verifier checks — independent and additive prev_hash prev_hash(N+1) == hash(N) detects: edit, replay, splice monotonic seq seq(N+1) == seq(N) + 1 detects: drop, reorder single boot_id boot_id stable within epoch detects: cross-boot replay
The verifier does not need a clock or coordination with the operator's pipeline. Three local invariants — prev_hash, seq, boot_id — independently surface drop, edit, reorder, and replay.

1. The three invariants

Each evidence record carries three header fields that participate in the chain:

  • prev_hash — the SHA-256 [2] hash of the previous record’s full serialised body, including its own header. The chain invariant is prev_hash(N+1) == hash(N).
  • seq — a monotonically increasing 64-bit counter, scoped to the current boot epoch. The invariant is seq(N+1) == seq(N) + 1.
  • boot_id — an opaque identifier for the current device boot, generated at TRP initialisation, stable for the duration of the boot, and reseeded on each subsequent boot. The invariant is that boot_id is constant within a contiguous block of records and changes only at boundaries the ledger explicitly marks.

These are independent. A verifier can check each one in isolation; each one closes a different attack class.

2. What each invariant detects

  • prev_hash detects edit, splice, and replay across a chain. An edited record’s hash no longer matches the next record’s reference. A spliced sub-chain from a different ledger fails to attach because the public-key context and the predecessor hash diverge. A naive replay of a previously-seen record sequence fails to attach to the verifier’s most-recently-seen tip.
  • seq detects drop and reorder. Removing record N leaves a gap in the sequence that cannot be reconstructed without producing a new chain — and that new chain would be a fork the verifier detects against the public-key context.
  • boot_id detects cross-boot replay. An attacker who captures the ledger contents from one boot cannot present them as evidence from a later boot — the boot_id field changed, and any submission must declare its boot epoch. For boot_id to be load-bearing the operator anchors it to a hardware-rooted boot epoch via platform attestation: on Android, Key Attestation [4] exposes the RootOfTrust block including verifiedBootHash and bootPatchLevel, which the operator records at bootstrap and cross-checks against subsequent submissions; on iOS, App Attest binds to a per-device root key established by the Secure Enclave. Without that anchor a compromised runtime could mint arbitrary boot_id values; with it, a fabricated boot_id fails the attestation-derived cross-check.

The chain integrity additionally rests on the per-record signature covered in self-signing-devices: without each record being signed by the device’s hardware-backed key, an attacker with raw-storage access could re-hash an entire chain consistently from a chosen prefix. The signature is what makes that re-hash cryptographically infeasible.

The three checks together — combined with the per-record signature and the operator pinning the most-recent-seen (boot_id, seq) per device — close the four canonical sequence-attack classes (drop, edit, reorder, replay) without any coordination beyond the ledger contents themselves, the device’s signing key, and the operator’s bootstrap-time attestation record.

3. Why the verifier needs no clock

A naïve approach to forward integrity uses timestamps and a trusted clock. Timestamps are useful as observation metadata but not load-bearing for chain integrity here. The chain is sequenced by the device’s own counter; the verifier’s job is to confirm the counter is monotonic and the hashes link.

This matters in three operational contexts:

  • Offline operation. The device may produce evidence while disconnected from the operator. The chain is intact; submission is delayed; the verifier still checks the same invariants when the records arrive.
  • Sovereignty. No third-party clock service is in the trust path. Time-source choice is left to the operator (or none at all).
  • Cross-jurisdictional submission. A regulator in one jurisdiction can verify records produced in another without resolving a shared time authority.

Haber and Stornetta’s original time-stamping construction [3] established the principle that sequential linking provides tamper-evidence checkable from the chain structure itself, independent of external clock attestation — though their construction used a trusted third-party timestamping service rather than a device-local chain as deployed here.

4. What forward chaining does not do

Forward chaining gives the verifier high confidence about the sequence of recorded events. It does not establish that the events were the only events, or that the recorded events correspond to ground truth. The TRP’s job is observation fidelity (covered under /architecture/runtime-coherence); the chain’s job is preservation fidelity. The two combine; they do not substitute for one another.

5. Operator-side use

When an operator’s verifier sees a submission, the chain check is fast — linear in the number of records, no I/O, no external calls. Operators typically run the chain check first before any policy evaluation: a broken chain is a verification failure, not a verdict input. A broken chain surfaces under the code.integrity signal class (the established taxonomy class for tampering-with-records observations) so downstream policy can index on it, but no operator policy makes a positive decision from a broken chain. Forward chaining is one of the structural properties Execution Evidence Infrastructure (EEI) — the device-identity infrastructure layer for banking and payments — publishes to the verifier; sequence integrity composes with the per-record signature and the platform-attestation anchor to deliver chain coherence the operator can check locally.

6. Cross-references

7. External references

[1] IETF. RFC 7515 — JSON Web Signature. datatracker.ietf.org/doc/html/rfc7515. Cited 2026-03-16.

[2] NIST. FIPS 180-4 — Secure Hash Standard (SHS). csrc.nist.gov/pubs/fips/180-4/upd1/final. Cited 2026-03-16.

[3] Haber, S. & Stornetta, W. How to Time-Stamp a Digital Document. Journal of Cryptology, Vol. 3, No. 2, pp. 99–111, 1991, Springer. DOI 10.1007/BF00196791. Cited 2026-03-16.

[4] AOSP. Android Key Attestation — RootOfTrust block, verifiedBootHash, bootPatchLevel. source.android.com/docs/security/features/keystore/attestation. Cited 2026-03-16.