Auditable Real-time Inference Architecture (ARIA)
When an AI system makes a decision that matters, there is usually no way to check afterwards what it actually did. This records each decision so it can be independently verified later, without exposing the model itself.
Summary
- Why
- Operators of high-stakes AI systems keep their own audit logs, which they can alter or delete before anyone inspects them, so there is no way for an outside party to independently confirm which model produced a given output and when.
- What
- BRC-122 (ARIA) is a BSV application-layer standard that uses a pre-commitment transaction and a sealing transaction to let anyone independently verify which AI model produced a given output and at what time.
- How
- An operator broadcasts an EPOCH_OPEN transaction committing to model hashes and system state before running a batch of inferences, then broadcasts an EPOCH_CLOSE transaction containing a Merkle root of all the inference records once the batch finishes, and anyone can later verify both transactions and recompute the…
What this lets you do
- Publish a pre-commitment of model versions before running inference
- Seal a batch of inferences with a Merkle root after the fact
- Let anyone verify which model produced which output at what time, without trusting the operator
- Detect record tampering, deletion, or fabrication after the fact
- Chain epochs together so each batch links to the one before it
Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.
Reference for an AI
Everything an assistant needs to answer questions about BRC-122 accurately, including what it depends on.
The specification
Abstract
This document specifies the Auditable Real-time Inference Architecture (ARIA) protocol, a BSV application-layer standard for cryptographic accountability of AI inference systems operating in production. ARIA enables independent, post-hoc verification of which AI model produced which output at what time — without requiring access to the operator's systems or trust in the operator's claims.
The protocol uses a pre-commitment scheme: before any inference executes, the operator publishes an OP_RETURN transaction on BSV committing to the exact model versions and system state that will be used. After the inference batch completes, a second transaction seals the batch with a Merkle root of all records. The two transactions are cryptographically linked, making retroactive fabrication of records computationally infeasible.
Motivation
Production AI systems that make high-stakes decisions — medical triage, credit scoring, content moderation, judicial risk assessment — currently offer no externally verifiable record of their behavior. Audit logs are mutable; operators can alter, delete, or fabricate records before a regulatory inspection. Independent verification requires cooperation from the auditee.
The EU AI Act (Regulation (EU) 2024/1689), effective from 2026, mandates for high-risk AI systems (Annex III):
- Automatic event logging with sufficient granularity to identify the inputs that led to each output (Art. 12.1)
- Traceability across the AI system's lifecycle (Art. 12.2)
- Capacity for post-hoc verification of the system's outputs (Art. 12.3)
No open technical standard currently addresses all three requirements simultaneously with an economically viable implementation. ARIA fills this gap.
BSV is uniquely suited for this protocol. Its unbounded OP_RETURN capacity (100 KB+), fees of approximately $0.0001 per transaction, and Teranode-scale throughput make it economically viable to commit every epoch of a real-time inference system — costing approximately $2.10/year for a system processing 1.5-second epochs continuously, compared to $13M–$315M/year on Ethereum.
Specification
1. Terminology
| Term | Definition |
|---|---|
| Epoch | A time interval or batch of inferences bounded by an EPOCH_OPEN and EPOCH_CLOSE transaction pair. |
| EPOCH_OPEN | BSV transaction that commits the model versions and system state before inference begins. |
| EPOCH_CLOSE | BSV transaction that seals the epoch with a Merkle root of all inference records. |
| AuditRecord | A structured record representing a single inference event within an epoch. |
| Merkle root | SHA-256 root of the RFC 6962 Merkle tree of all AuditRecord hashes in an epoch. |
| canonical JSON | A deterministic JSON serialization defined in §5 of this specification. |
| record hash | SHA-256 of the canonical JSON serialization of an AuditRecord. |
| operator | The entity deploying and operating an AI system. |
| verifier | Any party performing independent verification of an epoch or record. |
2. Transaction Format
ARIA data is embedded in BSV transactions using a standard OP_RETURN output with the following script format:
OP_FALSE OP_RETURN PUSH4(0x41524941) PUSHDATA(<json_bytes>)
0x00 0x6A 0x04 0x41 0x52 0x49 0x41 <varint> <utf-8 json>
- OP_FALSE (
0x00): Marks the output as provably unspendable per the standard OP_FALSE OP_RETURN pattern. - OP_RETURN (
0x6A): Standard OP_RETURN opcode. - PUSH4 (
0x04) followed by0x41524941(b'ARIA'): 4-byte application identifier. - PUSHDATA: Standard Bitcoin script pushdata encoding of the JSON payload bytes.
- Payloads ≤ 75 bytes: direct length byte.
- Payloads 76–255 bytes:
OP_PUSHDATA1(0x4C) + 1-byte length. - Payloads 256–65535 bytes:
OP_PUSHDATA2(0x4D) + 2-byte little-endian length. - Payloads > 65535 bytes:
OP_PUSHDATA4(0x4E) + 4-byte little-endian length.
- JSON payload: UTF-8 encoded JSON object. MUST NOT contain whitespace outside string values.
A transaction MAY contain multiple outputs. Verifiers MUST inspect all outputs and use the first that matches the ARIA prefix.
3. EPOCH_OPEN Payload Schema
{
"aria_version": "1.0",
"type": "EPOCH_OPEN",
"epoch_id": "ep_<unix_timestamp_ms>_<sequence_4digits>",
"system_id": "<registered_system_identifier>",
"model_hashes": {
"<model_id>": "sha256:<64_hex_chars>"
},
"state_hash": "sha256:<64_hex_chars>",
"timestamp": 1742848200,
"nonce": "<32_hex_chars>"
}
Field definitions:
| Field | Type | Required | Description |
|---|---|---|---|
aria_version | string | ✓ | Protocol version. MUST be "1.0" for this specification. |
type | string | ✓ | MUST be "EPOCH_OPEN". |
epoch_id | string | ✓ | Unique epoch identifier. Format: ep_<unix_ms>_<seq>. MUST be monotonically increasing within a system_id. |
system_id | string | ✓ | Unique identifier for the AI system. SHOULD match the identifier registered in an ARIA-compatible registry. |
model_hashes | object | ✓ | Mapping from model_id strings to "sha256:<hex>" hashes of the serialized model files. MUST include all models that will execute in this epoch. |
state_hash | string | ✓ | "sha256:<hex>" of the canonical JSON of the system's operational state (configuration, thresholds, routing rules). MUST NOT include personally identifiable information. |
timestamp | integer | ✓ | Unix timestamp (seconds) at which the epoch opened. MUST be less than the timestamp implied by the BSV block containing EPOCH_CLOSE. |
nonce | string | ✓ | 16 cryptographically random bytes encoded as 32 lowercase hex characters. Prevents replay attacks on identical consecutive states. |
Constraints:
epoch_iduniqueness is scoped tosystem_id. Two different systems MAY share an epoch_id.model_hashesvalues MUST use lowercase hex and the"sha256:"prefix.- The EPOCH_OPEN transaction MUST be broadcast and confirmed (or at minimum in the mempool with a valid txid) before any AuditRecord for that epoch is created.
4. AuditRecord Schema
An AuditRecord represents a single inference event. AuditRecords are stored locally by the operator and are NOT individually broadcast to BSV. Their hashes are committed collectively via the Merkle root in EPOCH_CLOSE.
{
"aria_version": "1.0",
"record_id": "rec_<epoch_id>_<sequence_6digits>",
"epoch_id": "ep_<...>",
"model_id": "<must_be_key_in_EPOCH_OPEN_model_hashes>",
"input_hash": "sha256:<64_hex_chars>",
"output_hash": "sha256:<64_hex_chars>",
"confidence": 0.95,
"latency_ms": 47,
"sequence": 0,
"metadata": {
"decision_class": "triage_priority_1",
"custom": {}
}
}
Field definitions:
| Field | Type | Required | Description |
|---|---|---|---|
aria_version | string | ✓ | MUST be "1.0". |
record_id | string | ✓ | Unique record identifier within the epoch. |
epoch_id | string | ✓ | MUST match the epoch_id in the corresponding EPOCH_OPEN. |
model_id | string | ✓ | MUST be a key present in model_hashes of the corresponding EPOCH_OPEN. |
input_hash | string | ✓ | "sha256:<hex>" of the canonical JSON of the inference input after PII removal. |
output_hash | string | ✓ | "sha256:<hex>" of the canonical JSON of the inference output. |
confidence | float | null | ✗ | Model confidence score [0, 1]. RECOMMENDED when available. |
latency_ms | integer | ✗ | Inference duration in milliseconds. Default 0. |
sequence | integer | ✓ | Zero-based index of this record within the epoch. MUST be unique within an epoch. Determines leaf order in the Merkle tree. |
metadata | object | ✗ | Arbitrary key-value pairs for domain-specific context. |
PII handling: Operators MUST identify and remove personally identifiable information fields from the input before computing input_hash. The set of PII fields is operator-defined and SHOULD be documented in the system registration. Output data is considered accountability-relevant and SHOULD NOT be PII-filtered unless legally required.
5. EPOCH_CLOSE Payload Schema
{
"aria_version": "1.0",
"type": "EPOCH_CLOSE",
"epoch_id": "ep_<...>",
"prev_txid": "<64_hex_chars_of_EPOCH_OPEN_txid>",
"records_merkle_root": "sha256:<64_hex_chars>",
"records_count": 42,
"duration_ms": 1498
}
Field definitions:
| Field | Type | Required | Description |
|---|---|---|---|
aria_version | string | ✓ | MUST be "1.0". |
type | string | ✓ | MUST be "EPOCH_CLOSE". |
epoch_id | string | ✓ | MUST match the epoch_id in the corresponding EPOCH_OPEN. |
prev_txid | string | ✓ | BSV txid of the corresponding EPOCH_OPEN transaction. This is the cryptographic link that makes the chain verifiable. |
records_merkle_root | string | ✓ | "sha256:<hex>" Merkle root of all AuditRecord hashes in this epoch, ordered by sequence. For an empty epoch (zero records), MUST be "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" (SHA-256 of the empty byte string). |
records_count | integer | ✓ | Number of AuditRecords in this epoch. |
duration_ms | integer | ✗ | Epoch duration in milliseconds. |
6. AuditRecord Hash Algorithm
The hash of an AuditRecord is the SHA-256 of its canonical JSON serialization. The following fields are included in the canonical form, in this exact order:
{
"aria_version": "1.0",
"confidence": <float_or_null>,
"epoch_id": "<string>",
"input_hash": "<string>",
"latency_ms": <integer>,
"metadata": <object>,
"model_id": "<string>",
"output_hash": "<string>",
"record_id": "<string>",
"sequence": <integer>
}
Note: keys are sorted alphabetically. This matches the canonical JSON rules in §7.
The hash is computed as:
record_hash = "sha256:" + hex(SHA-256(canonical_json_bytes))
where canonical_json_bytes is the UTF-8 encoding of the canonical JSON string (no whitespace).
7. Canonical JSON Serialization
All hashes in ARIA use a deterministic JSON serialization to ensure cross-implementation reproducibility.
Rules:
- No whitespace: No spaces, tabs, or line breaks outside string values.
- Alphabetically sorted keys: Object keys sorted by Unicode code point, recursively at all nesting levels.
- Float representation: IEEE 754 double-precision. Trailing zeros removed. No scientific notation unless the magnitude requires it (exponent ≥ 17 or ≤ -4). Up to 17 significant digits.
- Null: Serialized as
null. - NaN and Infinity: MUST NOT appear in canonical data. Implementations MUST reject inputs containing NaN or Infinity values.
- Array order: Preserved as-is. Arrays are NOT sorted.
- String encoding: UTF-8. Unicode escape sequences (
\uXXXX) are permitted for non-ASCII characters. - Boolean:
true/false(lowercase).
8. Merkle Tree Construction
ARIA uses a SHA-256 Merkle tree with second-preimage attack protection following RFC 6962 (Certificate Transparency):
leaf_hash(data) = SHA-256(0x00 || data)
internal_hash(l, r) = SHA-256(0x01 || l || r)
Where || denotes byte concatenation and data is the raw SHA-256 digest bytes (32 bytes) of a record hash string decoded from hex.
Construction algorithm:
- Sort all AuditRecord hashes by their
sequencefield (ascending). - Compute leaf hashes: for each record hash
h, computeleaf = SHA-256(0x00 || bytes.fromhex(h[7:]))whereh[7:]strips the"sha256:"prefix. - Build the tree bottom-up. If a level has an odd number of nodes, duplicate the last node.
- The root of the tree with a single leaf is
leaf_hash(record_hash). - The root of an empty tree is
SHA-256(b"").
Merkle proof format:
A Merkle proof for a leaf is a list of (sibling_hash, position) tuples where position is "left" or "right", indicating which side the sibling is on relative to the path to the root.
9. Epoch Lifecycle
Operator side BSV
───────────────────────────────── ──────────────────────────
1. Prepare model_hashes
2. Compute state_hash
3. Generate nonce
4. Broadcast EPOCH_OPEN ──────────► txid_open confirmed/mempool
5. [EPOCH_OPEN txid available]
6. Execute inferences
7. Create AuditRecord per inference
8. Persist records to local storage
9. Compute Merkle root
10. Broadcast EPOCH_CLOSE ────────► txid_close confirmed/mempool
(prev_txid = txid_open)
Anti-backdating guarantee: Because EPOCH_OPEN is broadcast before inferences begin, and BSV blocks include timestamps, no operator can claim a different model version or system state was in effect at decision time. The commitment is public and immutable.
10. Verification Algorithm
Given open_txid and optionally close_txid, a verifier MUST perform the following checks:
Epoch verification:
- Fetch the transaction at
open_txidand extract the ARIA payload. - Verify
payload.type == "EPOCH_OPEN". - If
close_txidis not provided, locate it by searching for an EPOCH_CLOSE transaction whoseprev_txid == open_txid. Implementations MAY use a local index or require the caller to supplyclose_txidexplicitly. - Fetch the transaction at
close_txidand extract the ARIA payload. - Verify
payload.type == "EPOCH_CLOSE". - Verify
close_payload.prev_txid == open_txid. If this check fails, the epoch is TAMPERED. - Verify
close_payload.epoch_id == open_payload.epoch_id. If this check fails, the epoch is TAMPERED.
Record verification (in addition to epoch verification):
- Reconstruct the AuditRecord from the provided record data.
- Verify
record.epoch_id == open_payload.epoch_id. If this fails, the record is TAMPERED. - Verify
record.model_id ∈ open_payload.model_hashes. If this fails, the record is TAMPERED. - If local storage is available: reconstruct the Merkle tree from all stored records for this epoch and verify that the record's hash is a member (Merkle proof). Verify the reconstructed root matches
close_payload.records_merkle_root. If this fails, the record is TAMPERED.
11. Verification Result
Implementations MUST produce a structured verification result with at minimum:
| Field | Type | Description |
|---|---|---|
valid | boolean | True if all checks passed. |
tampered | boolean | True if a cryptographic inconsistency was detected. |
epoch_id | string | Epoch identifier from EPOCH_OPEN. |
system_id | string | System identifier from EPOCH_OPEN. |
model_id | string | null | Model identifier (record verification only). |
model_version | string | null | SHA-256 of the committed model file. |
decided_at | datetime | null | Datetime from EPOCH_OPEN timestamp. |
records_count | integer | Number of records from EPOCH_CLOSE. |
merkle_root | string | Merkle root from EPOCH_CLOSE. |
error | string | null | Human-readable error message if not valid. |
12. ZK Extension (Optional)
Implementations MAY include a zk field in the EPOCH_CLOSE payload to provide zero-knowledge proof evidence and EU AI Act regulatory claims. When present, the zk field MUST conform to the following schema.
12.1 ZKPayload
{
"zk_enabled": true,
"claims_count": 3,
"all_claims_satisfied": true,
"statement_hash": "sha256:<64_hex_chars>",
"claims": [<ClaimResult>, ...],
"aggregate_proof": <AggregateProof | null>
}
The statement_hash commits to the epoch's regulatory state:
statement_hash = SHA256(canonical_json({
"epoch_id": <str>,
"claims": [{"claim_type": ..., "params": ..., "satisfied": ...}, ...],
"aggregate_digest": <str | "">
}))
12.2 ClaimResult
{
"claim_type": "confidence_percentile",
"params": {"p": 99, "threshold": 0.85},
"satisfied": true,
"evidence_hash": "sha256:<64_hex_chars>",
"human_description": "99th percentile confidence 0.912 ≥ 0.85",
"eu_ai_act_reference": "Art. 9 §7 — accuracy and robustness requirements",
"detail": null
}
Standard claim_type values and their EU AI Act mapping:
claim_type | Article |
|---|---|
confidence_percentile | Art. 9 §7 |
model_unchanged | Art. 9 §4 |
no_pii_in_inputs | Art. 10 §3 + GDPR Art. 9 |
output_distribution | Art. 12 §1 |
latency_bound | Art. 14 §2 |
record_count_range | Art. 12 §1 |
all_models_registered | Art. 11 |
The evidence_hash is computed as:
evidence_hash = SHA256(canonical_json({"evidence": sorted(str(v) for v in values)}))
where values is the set of data values used to evaluate the claim (e.g., the list of confidence scores for confidence_percentile).
12.3 AggregateProof
{
"proofs_merkle_root": "sha256:<64_hex_chars>",
"n_proofs": 42,
"aggregation_scheme": "merkle",
"aggregate_digest": "sha256:<64_hex_chars>"
}
proofs_merkle_root: Merkle root of per-record ZK proof digests.aggregation_scheme:"merkle"(production),"nova"(future),"plonk_recursive"(future).aggregate_digest: SHA-256 of the raw aggregate bytes (the bytes themselves are NOT embedded on-chain due to size constraints).
12.4 Proving tiers
Implementations MAY use any of the following proving tiers:
| Tier | Method | Suitable for |
|---|---|---|
full_zk | Halo2/KZG circuit (EZKL) | ONNX models ≤ 10M params |
commitment | HMAC-SHA256 keyed commitment | Any model size |
tee | Intel SGX remote attestation | 1B+ parameter models |
The tier is a per-proof attribute stored locally. Only the aggregate Merkle root is committed on-chain.
Security Considerations
What ARIA guarantees
-
Pre-commitment immutability: Once EPOCH_OPEN is confirmed in a BSV block, the committed
model_hashesandstate_hashcannot be altered. Any claim that a different model version was used is verifiably false. -
Merkle root tamper detection: Any modification to any single record in an epoch — adding, removing, or altering — invalidates the Merkle root. This is detectable without access to all records (Merkle proof suffices).
-
Chronological ordering: The BSV block timestamp of EPOCH_OPEN provides an external lower bound on the inference time. EPOCH_CLOSE must reference EPOCH_OPEN via
prev_txid, establishing a directed chain. -
Operator key compromise does not alter history: A compromised private key can create new fraudulent epochs but cannot alter already-confirmed transactions.
What ARIA does NOT guarantee
-
Input/output correctness: ARIA commits hashes of inputs and outputs, not the inputs/outputs themselves. An operator could hash a different input than the actual one. ARIA cannot detect this without access to the original data.
-
Model quality or safety: ARIA verifies which model produced an output. It does not verify that the model is safe, accurate, or unbiased.
-
Real-time tamper detection: ARIA detects tampering during post-hoc verification, not in real time.
-
BSV network availability: If BSV becomes unavailable, epochs cannot be committed. Implementations MUST queue epochs and retry.
Threat model
| Threat | ARIA defense | Residual risk |
|---|---|---|
| Operator fabricates records after the fact | prev_txid chain + Merkle root is immutable on BSV | None — detectable |
| Operator claims different model version | model_hashes in EPOCH_OPEN is immutable | None — detectable |
| Operator alters a single record | Merkle root mismatch | None — detectable |
| Operator hashes wrong input | Not detectable without original data | Requires regulatory access to raw logs |
| Key compromise, new fraudulent epochs | New epochs have different epoch_id / timestamps | Detectable by auditors monitoring epoch history |
| BSV chain reorganisation | Uses SPV confirmation (6+ blocks for high-stakes use) | Mitigated by waiting for confirmations |
Test Vectors
Canonical JSON
Input object:
{"b": 2, "a": 1, "c": {"z": 3, "x": 1}}
Canonical form: {"a":1,"b":2,"c":{"x":1,"z":3}}
SHA-256: a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3
(This is the hash of the canonical string above, encoded as UTF-8.)
AuditRecord hash
Given:
{
"aria_version": "1.0",
"record_id": "rec_ep_1742848200000_0001_000000",
"epoch_id": "ep_1742848200000_0001",
"model_id": "triage",
"input_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"output_hash": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"confidence": null,
"latency_ms": 0,
"sequence": 0,
"metadata": {}
}
Canonical JSON (keys sorted, no whitespace):
{"aria_version":"1.0","confidence":null,"epoch_id":"ep_1742848200000_0001","input_hash":"sha256:aaaa...","latency_ms":0,"metadata":{},"model_id":"triage","output_hash":"sha256:bbbb...","record_id":"rec_ep_1742848200000_0001_000000","sequence":0}
Merkle root (2 records)
Leaf 0 hash (64 hex chars): h0
Leaf 1 hash (64 hex chars): h1
leaf0 = SHA-256(0x00 || bytes.fromhex(h0[7:]))
leaf1 = SHA-256(0x00 || bytes.fromhex(h1[7:]))
root = SHA-256(0x01 || leaf0 || leaf1)
OP_RETURN script
For payload {"type":"EPOCH_OPEN"} (21 bytes UTF-8):
00 6a 04 41524941 15 7b2274797065223a22455043...
00= OP_FALSE6a= OP_RETURN04 41524941= PUSH4 +ARIA15= direct length byte (21)7b...= UTF-8 JSON bytes
Reference Implementation
The canonical reference implementation of BRC-122 is the aria-bsv Python package, available at:
https://github.com/JuanmPalencia/aria-bsv
The reference implementation includes:
aria/core/hasher.py— canonical JSON and SHA-256 hashingaria/core/merkle.py— RFC 6962 Merkle tree with second-preimage protectionaria/core/record.py— AuditRecord schema and hash algorithmaria/core/epoch.py— EpochManager: EPOCH_OPEN / EPOCH_CLOSE lifecyclearia/verify.py— Independent Verifier with WhatsOnChain integrationaria/auditor.py— High-level InferenceAuditor (5-line integration API)aria/zk/— ZK extension: tiered prover, EU AI Act claims DSL, proof aggregation, EpochStatement
Copyright
This BRC is placed in the public domain. Authors waive all copyright and related rights.