Securing 2M+ accounts & $15B+ in assets, protected & secure·B5 Secure™ — per data-element authorization for .NET platforms·Now building on .NET 10

The Evidence Format and Offline Verifier

← Developers
Developers

Verify the evidence without trusting us.

A published format, a signed example export, and a verifier that is one Python file using only the standard library — no network, no configuration, no B5 dependency. Twenty-one checks. Then change one character and watch it refuse.

Published formatOffline verifiered25519 + HMAC9 attacks
Generally AvailableQ4 2026 Roadmap Extension

What is published today, and what is roadmap. The format specification, the verifier and both example exports are on this page and you can run them now. The in-product export that produces these files from a live B5 deployment is a Q4 2026 roadmap extension, which is what the badge above refers to. The format is deliberately independent of that schedule — an audit firm or SIEM vendor can build against it without B5 software.

The demo is three commands, and you run them

offline, no network
$ python3 b5verify.py ./example-export-ed25519
b5verify — ./example-export-ed25519

  ok  every record carries the required fields
  ok  every record hashes to its stated digest
  ok  the hash chain is unbroken
  ok  sequence numbers are contiguous and in order
  ok  the manifest's declared head is the last record's hash :: manifest 281e0ac6b700, actual 281e0ac6b700
  ok  the chain head is signed by the key the manifest names :: ed25519
  ok  every record states whether it was a simulation
  ok  NOTE: 1 of 5 records are shadow decisions and did not affect any response

VERIFIED — 21 checks passed.                                   # exit 0

$ sed -i 's/AC-77310/AC-99120/' example-export-ed25519/records.jsonl

$ python3 b5verify.py ./example-export-ed25519

 FAIL every record hashes to its stated digest :: [(2, 'ev-01J8ZA', 'stated 5a7c1ab486cd, computed 581ebbefff4f')]

VERIFICATION FAILED — 1 of 21 checks did not pass.              # exit 1

Exit 0 verified, 1 failed, 2 unreadable — so it composes into a pipeline. There is no hosted service to be up, no account to create, and nothing of ours to trust.

The chain, and the flaw the attack suite found

The most useful thing on this page, because it is an argument against our own first draft.

Each record’s digest is:

the binding
hash = SHA-256( canonical_body ‖ "\n" ‖ prev_hash ‖ "\n" ‖ sequence )

The first version of the format excluded the whole decision_evidence block from each record’s digest. That is reasonable on its face — a digest cannot cover itself — but it left prev_hash and sequence uncovered. A record’s hash therefore depended only on its own body.

So the chain could be relinked. Alter record 2, recompute its hash, re-point record 3’s prev_hash, and the chain verified cleanly. The head only moved if the last record changed, so the signature still passed. Tamper case 05 passed when it should have failed. Binding the linkage into the digest means a tamper is caught by that record’s own hash — and an attacker who recomputes it to hide the change then finds every subsequent hash must change too, which moves the head, which breaks the signature. There is no longer a repair that relinks cleanly.

A format specification that has not been attacked is a draft. This one would not have been found by writing the spec and admiring it.

Nine attacks, all rejected

Flip a denial to a permit

Caught by the record hash.

Delete a record mid-chain

Caught three independent ways — count, chain and sequence — deliberately, so repairing one is not enough.

Reorder two records

Caught by sequence and by the chain.

Tamper, then fix that record’s own hash

Breaks at the next record.

Re-chain after a tamper

Head moves; head signature fails.

Forge the head signature

Fails against the public key.

Move a record outside the window

Caught against the manifest window.

Strip the shadow flag

Rejected — shadow status is mandatory, not defaulted.

Re-chain an ed25519 export without the private key

Impossible by construction; that is the point of the second export.

Two example exports, and the honest reason for both

example-export

HMAC — deliberately forgeable

Signed with HMAC-SHA256 with the secret in the manifest, so it verifies using the standard library alone. That also makes it demonstrably forgeable, and we would rather say so than let you discover it.

example-export-ed25519

Public key only — production

The manifest carries the public key and nothing else. This is the shape a real export takes.

Shipping only the convenient one while claiming signatures protect the chain would be a claim the artefact itself contradicts. And when the signing library is absent the tool reports the signature check as SKIPPED, never as passed — a verifier that silently downgrades is worse than one that refuses.

example-export-ed25519/manifest.json
{
  "format": "b5-evidence/1",
  "generated_by": "B5 Security Platform 4.0.0.3",
  "tenant_uid": "t-8f21c0",
  "records": "records.jsonl",
  "record_count": 5,
  "window": {
    "start": 1785225600123,
    "end": 1785225605222
  },
  "canonicalisation": "JSON, sorted keys, separators (',',':'), UTF-8, with the decision_evidence block excluded from its own digest",
  "chain": {
    "uid": "chain-t-8f21c0",
    "head_hash": "281e0ac6b7008233b00a0edff683b19f0b1c4c30a6e48b7197953ac32fed8d28",
    "signing_key_uid": "key-2026-07-ed25519",
    "signature": "22VwTgPGqQxoRIfGb0w22Yg56hPjgeRH7wqSEipFy+d5J2Jm8EledjLCM9ea6g6gL709qRxfJPrnt/qIcdxCCA=="
  },
  "key": {
    "uid": "key-2026-07-ed25519",
    "alg": "ed25519",
    "public_b64": "hdTepOHcEpC9nRgdvrSf2eYbJgWFSsMM0JOg7xvDfBA=",
    "_note": "Public key only. The private key never leaves the signer."
  }
}

Give it to your auditor during the evaluation

Not after contracting. The format and the tool are yours to keep either way, and neither depends on us continuing to exist.

Developer Relations

Talk to a human.

Get architecture guidance, Test Mode access, integration review, or help choosing the right B5 identity and authorization pattern.

Scroll to Top