rfc-006 · draft · 2026-05

RFC-006: Hash-chained ledger + external anchoring profile.

RFC-004 makes each entry tamper-evident. It does not prove the set of entries is complete and ordered, nor defend the log when the adversary is the operator. RFC-006 is the profile that does both, and it stays RFC-004-checkable by a normative projection, so raising the floor does not fork the standard.

Status: Draft. Author: Nazareno Clemente (naza@naza.ar). Discussion: github.com/ar-agents/ar-agents/discussions. License: CC-BY-4.0. DOI: pending Zenodo deposit.

Companions: RFC-001 (liability + governance taxonomy), RFC-004 (operational-log spec, the base this profile extends), RFC-005 (Ed25519 asymmetric upgrade).

Reference implementation: Vultur @vultur/core/{audit,anchor}.ts (the live producer). Independent verifier: tools/arg-verify/arg-verify.mjs in github.com/ar-agents/ar-agents (chain, project, vectors, zero dependency, offline).

Not an IETF RFC. These specs are open-source drafts authored by an independent developer (Nazareno Clemente). The “RFC” naming follows the IETF style (numbered, versioned, status, CC-licensed) but does not imply IETF, IRTF, or any standards-body endorsement. The documents are technical proposals open to public comment at github.com/ar-agents/ar-agents/discussions. For citation in legislation, link to a specific commit hash or tagged release on GitHub, not to the canonical /rfcs/{n} URL. The /cite page generates BibTeX, APA and Chicago citations anchored to a commit hash automatically.

1 · The gap RFC-006 fills

RFC-004 §4 specifies an append-only, per-entry HMAC-signed log and, in §11, explicitly leaves open whether stores that allow random-access overwrite need a Merkle-chain to give the same guarantee, plus anti-equivocation. A sociedad-IA (umbrella nickname; the legal figure is the Sociedad Automatizada, art. 14 of the Anteproyecto de Ley General de Sociedades, whose art. 263 requires publicly-verifiable digital records) handling real value wants strictly more than per-entry tamper-evidence:

  • Insertion / deletion / reordering detection, not just per-record mutation detection. A per-entry HMAC proves this record was not edited; it does not prove the set of records is complete and ordered.
  • A guarantee against the operator itself.A per-entry HMAC is computed with the operator's key; the operator can re-sign a rewritten history. The log must be defensible even when the adversary is the sociedad-IA.

RFC-006 delivers both: a linked HMAC hash-chain plus an external anchor sub-chain. It is a strict superset of RFC-004: every RFC-006 ledger projects, by the normative deterministic map in §5, onto RFC-004-conformant entries, so a regulator holding only RFC-004 and the published RFC-004 tooling can verify an RFC-006 producer with no new software.

2 · Canonical-JSON (normative, inherited)

RFC-006 uses the RFC-004 §3 canonical-JSON function verbatim: keys sorted lexicographically at every level, arrays positional, primitives via JSON.stringify. The reference producer's canonicalize() (JSON.stringify(sort(v))) is a conformant implementation; arg-verify reimplements the §3 form clean-room and the two agree on every published vector.

3 · Chain link (normative)

The unit of an RFC-006 ledger is a link, not a free-standing entry.

interface ChainLinkPayload {
  seq:        number;            // 1-based, contiguous, no gaps
  prevHash:   string;            // hash of link seq-1; "GENESIS" for seq 1
  societyId:  string | null;     // tenant; null = global ledger
  actor:      string;            // who/what initiated
  action:     string;            // the operation that produced the effect
  meta:       unknown;           // operation detail; null if none
  ts:         string;            // ISO-8601 UTC, server clock at write time
}

hash_n = HMAC_SHA256( AUDIT_SECRET,
           canonical({ seq, prevHash, societyId, actor, action,
                       meta: meta ?? null, ts }) )      // lowercase hex
prevHash_1 = "GENESIS"
prevHash_n = hash_{n-1}        (n > 1)

hash_n is raw lowercase hex (no sha256:prefix, that is RFC-004's per-entry convention, not the chain convention). meta is normalized to null when absent before canonicalization so sign and verify agree. The only permitted mutation primitive is append; TTL-purge for RFC-004 §7 retention is the sole destructive exception and it purges whole prefixes, never interior links.

4 · Chain verification (normative)

4.1 Contiguous chain (full integrity). For an ordered slice from genesis or a known checkpoint, assert for every i: (1) seq_i == seq_{i-1} + 1 (contiguity, detects deletion / reordering); (2) prevHash_i == hash_{i-1} (linkage, detects insertion / deletion); (3) hash_i == HMAC(secret, canonical(payload_i)) (authenticity, detects mutation, including deeply-nested mutation). A passing slice proves the records are unmutated and complete and ordered.

4.2 Per-record (non-contiguous slice). For a filtered view (one society pulled from a global chain), contiguity cannot hold; assert only check (3) per record and label the result recordsOnly: true.

5 · RFC-004 projection (normative, the conformance bridge)

An RFC-006 producer is RFC-004-conformant by construction via this deterministic projection P. Given chain link L:

id         := `${L.ts}-${L.hash.slice(0,8)}`
sessionId  := if   typeof L.societyId === "string"
                   && /^[A-Za-z0-9_-]{8,64}$/.test(L.societyId)
              then L.societyId
              else if L.societyId == null  then "GLOBAL-LEDGER"
              else "soc-" + base64url(sha256(String(L.societyId))).slice(0,16)
ts         := L.ts
tool       := L.action
governance := (L.meta is object && L.meta.governance ∈ RFC-004 §6 enum)
              ? L.meta.governance : "audit-logged"
input      := { actor: L.actor, seq: L.seq, meta: L.meta ?? null }
output     := (omitted)
hmac       := "sha256:" + HMAC_SHA256( PROJECTION_SECRET,
                            canonical(P(L) without `hmac`) )

Properties (all machine-checked by arg-verify project / arg-verify vectors):

  • Determinism. P is a pure function of L. Same chain produces the same entries.
  • RFC-004 validity. P(L) is a well-formed OperationalLogEntry; verifyEntry(P(L), PROJECTION_SECRET) per RFC-004 §3 returns true.
  • Injectivity. input.seq plus id (which embeds hash) make P collision-free, preserving chain order and identity.
  • Lossy-but-declared. governance defaults to audit-logged when the producer did not carry an explicit class in meta.governance. This is the only lossy point and it fails safe (toward the more-liability class, never toward mocked-upstream).

PROJECTION_SECRET MAY equal AUDIT_SECRET or be a separate RFC-004 signing key; the projection is a view, the native chain (§3-4) remains the stronger guarantee. A regulator running RFC-004 tooling (arg-verify entry P(L).json --secret PROJECTION_SECRET) gets a green check with zero RFC-006 awareness.

6 · External anchoring (normative)

Periodically the producer checkpoints the chain head into an anchor; anchors form their own HMAC-signed chain:

interface AnchorBody {
  seq:        number;      // 1-based, contiguous
  headSeq:    number;      // chain head seq at checkpoint time
  headHash:   string;      // chain head hash at checkpoint time
  prevAnchor: string;      // previous anchor signature; "GENESIS" for seq 1
  ts:         string;      // ISO-8601 UTC
}
signature_n  = HMAC_SHA256( AUDIT_SECRET, canonical(AnchorBody_n) )  // hex
prevAnchor_n = signature_{n-1}

The anchor chain SHOULD be mirrored to an external notaryoutside the operator's control (an append-only third party, timestamping authority, or public log). The operator then cannot retroactively rewrite or backdate history without invalidating every anchor issued since the divergence point, and the external mirror is evidence the operator cannot suppress. This is the §1 guarantee against the operator itself.

7 · Asymmetric attestation (normative, aligns RFC-005)

When an RFC-006 producer publishes a signed compliance attestation over the chain head, RFC-006 requires RFC-005 wire conventions so a single verifier works everywhere: Ed25519 value base64url-unpadded (not standard base64); public key set at /.well-known/sociedad-ia/keys as the RFC-005 §4 JSON with keyId + rotation; each signature carries a keyId resolvable in that set. The reference producer currently emits base64 + an embedded key at /api/audit/pubkey; RFC-006 §7 is the normative target and the gap is a pure encoding/endpoint change tracked in CONFORMANCE.md.

8 · Verification interface (extends RFC-004 §5)

  • GET /api/audit/verify, contiguous-chain verification result.
  • GET /api/audit/anchor, the anchor chain for §6 verification.
  • GET /api/audit/{slug}/attestation, the §7 attestation.
  • GET /api/audit/{slug}/bundle, the §8 export bundle: chain slice + RFC-004 entries + attestation, the artifact a regulator downloads and verifies offline.
  • A projection export emitting P(L) so a regulator runs RFC-004 tooling unchanged. RFC-006 v1.1 normative-izes the exact route; v1 requires only that such an export exists and is documented.

These endpoints are live on this deployment: every durable audit entry also lands as a link in the global hash chain, the head is sealed into the signed anchor chain, and any society slice exports as a bundle verifiable offline with node arg-verify.mjs bundle <file>, no trust in this server required. The implementation is conformance-tested in CI against the frozen vectors below.

9 · Conformance test vectors

/test-vectors/rfc-006-v1.json contains, with byte-exact deterministic outputs: a genesis-rooted 3-link chain (expected hash per link); a mutated copy that MUST fail at the mutated seq; a deletion copy that MUST fail on contiguity/linkage; a 2-anchor chain; and the exact P(L) object and RFC-004 hmac for every link. A library claims RFC-006 conformance iff it reproduces every value and the projected entries pass RFC-004 §3 verifyEntry. Run:

node tools/arg-verify/arg-verify.mjs vectors
# RFC-004: 10 PASS · RFC-005: 4 PASS · RFC-006: 12 PASS
# ALL VECTORS PASS, the published /arg standard is independently reproducible.

10 · Decision request

  • RFC-004 v1 remains the minimum operational-log floor.
  • RFC-006 v1 is the recommended profile for any sociedad-IA handling real value, regulated activity, or third-party funds. An RFC-006 producer is RFC-004-conformant via the §5 projection, so citing RFC-006 does not fork the standard, it raises the floor while staying RFC-004-checkable.
  • Suggested legislative language: the operational log MUST satisfy RFC-004 v1; producers handling [regulated thresholds] MUST satisfy RFC-006 v1.

11 · Open questions

  • Projection route (v1.1). Normative path + content-type for the §8 projection export.
  • Anchor cadence (v1.1). MUST-anchor interval and minimum external-notary properties (append-only proof, independence).
  • meta.governance enforcement. Should v1.1 make it MUST (lossless projection) rather than SHOULD?
  • Key transparency. RFC-005 §8 carries over; anti-equivocation for the §7 key set is an RFC-007 candidate.
  • Cross-chain reciprocity. Whether an RFC-003 envelope wrapping an RFC-006 ledger carries native links or the §5 projection.

12 · Compliance with companions

RFC-001 §9 → RFC-006 §3-4. Append-only + signed; RFC-006 strengthens to chain-linked + anchored.

RFC-004 → RFC-006 §5. Every RFC-006 ledger is an RFC-004 log via the normative projection; no client breakage.

RFC-005 → RFC-006 §7. Asymmetric attestations on an RFC-006 ledger MUST use RFC-005 encoding / endpoint / keyId.

Comments + counter-proposals welcome via GitHub Discussions. This is a draft; v1 finalization pins every test-vector value (already byte-exact in /test-vectors/rfc-006-v1.json).