Skip to content

rfc-005 · draft · 2026-05

RFC-005: Asymmetric upgrade for the operational log.

RFC-004 v1 uses shared-secret HMAC. That works in a single-operator-single-key world. The day a sociedad-IA delegates verification to a third party (regulator, auditor, counterpart) without sharing its key, asymmetric signatures (Ed25519) become necessary. RFC-005 specifies the additive migration path.

Status: Draft. Author: Nazareno Clemente (naza@helloastro.co). Discussion: github.com/ar-agents/ar-agents/discussions. License: CC-BY-4.0.

Companions: RFC-004 (v1 HMAC operational-log spec — the base this builds on), RFC-003 (envelope that benefits most from asymmetric).

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 · Why upgrade

RFC-004 v1 specifies HMAC-SHA256 with a shared symmetric secret. Three audiences hit limits with that scheme:

  • Regulators.They want to verify entries offline without trusting the operator's verify endpoint. With symmetric HMAC, the operator must either share the key (kills the security boundary) or provide a server-side verify endpoint the regulator trusts (a single point of control). Asymmetric flips this: the operator publishes a public key, anyone can verify, no secret leaves the operator.
  • Cross-jurisdictional counterparts (RFC-003). A Wyoming DAO LLC verifying an AR sociedad-IA's envelope needs the AR public key, not the shared secret. RFC-003 v1 punts on this; RFC-005 closes it.
  • Future-proofing key rotation.Today, rotating the HMAC secret invalidates every old entry's signature unless the operator carefully re-signs. With asymmetric + key-id, old entries stay verifiable under the old public key even after rotation.

2 · Algorithm choice

Ed25519 (RFC 8032). Reasons:

  • Tiny keys (32 bytes) and signatures (64 bytes). Won't bloat the entry shape meaningfully.
  • Universally available in Web Crypto, Node >= 12, every modern crypto library. Same as the HMAC story.
  • Deterministic by construction — same input + same key always produces the same signature. Maps onto RFC-004 § 3 (canonical- JSON + HMAC is deterministic) without surprise.
  • Battle-tested. Used by every cryptocurrency, every modern SSH server, every commit-signing flow.

Not P-256. Available everywhere but less determinism guarantees + larger sigs. Not RSA. Large keys, slower verify, no determinism. Not SLH-DSA (post-quantum). Too early for v2; revisit in v3 when post-quantum signatures stabilize.

3 · Additive entry shape

v2-conformant entries carry BOTH the v1 hmac field AND a new signature field. Verifiers check whichever they can:

interface OperationalLogEntry_v2 extends OperationalLogEntry_v1 {
  // v1 field (unchanged): symmetric HMAC, computed as before.
  hmac: string | null;

  // v2 additive field: asymmetric signature.
  // Format: { keyId, alg, value }
  // - keyId: stable identifier for the public key (e.g. "ar-sociedad-key-2026-05")
  // - alg:   "ed25519"
  // - value: base64url-encoded 64-byte signature
  signature?: {
    keyId: string;
    alg: "ed25519";
    value: string;
  };
}

Both fields are computed over the same canonical-JSON of the entry, with BOTH the hmac and signature fields stripped before signing. Stripping rule: remove the field if present, regardless of value.

Why additive.Migration is messy. Operators can't flip overnight. Verifiers running v1-only code shouldn't break. The additive shape lets v1 + v2 coexist for as long as needed.

4 · Key publication

Operators publish their public keys at:

GET /.well-known/sociedad-ia/keys

{
  "keys": [
    {
      "keyId": "ar-sociedad-key-2026-05",
      "alg": "ed25519",
      "publicKey": "MCowBQYDK2VwAyEA...",       // base64url, SubjectPublicKeyInfo DER
      "validFrom": "2026-05-01T00:00:00Z",
      "validUntil": null                         // null = currently active
    },
    {
      "keyId": "ar-sociedad-key-2025-12",
      "alg": "ed25519",
      "publicKey": "MCowBQYDK2VwAyEA...",
      "validFrom": "2025-12-01T00:00:00Z",
      "validUntil": "2026-04-30T23:59:59Z"      // rotated out
    }
  ]
}

Properties:

  • Keys ROTATE; old keys stay published indefinitely so historical entries remain verifiable.
  • Entries reference the keyId they were signed under; verifiers look it up in the keys list.
  • The keys endpoint is public, cacheable (15 min TTL recommended), and SHOULD be served from a stable origin (the sociedad-IA's canonical domain, not a behind-auth path).

5 · Verification flow

  1. Fetch the entry (e.g. from GET /api/audit/{sessionId}).
  2. Strip hmac + signature fields. Canonical-JSON-stringify (RFC-004 § 3 algorithm).
  3. If signature present: fetch the key from /.well-known/sociedad-ia/keys, find by keyId, verify Ed25519 against the canonical form.
  4. If signature absent + hmac present: fall back to v1 HMAC verification (if the verifier has access to the shared secret, e.g. for self-audit).
  5. If both absent: the entry is unsigned. v1 + v2 production: fatal misconfiguration.

6 · Migration timeline

A sociedad-IA upgrading from v1 to v2 follows this path:

  • Day 0. Generate an Ed25519 keypair. Publish the public key at /.well-known/sociedad-ia/keys. Keep the private key in the operator's secrets manager.
  • Day 0 → N. Library starts emitting entries with BOTH hmac AND signature. Verifier endpoint accepts both.
  • Day N (after audit retention period). Optional: drop hmac from new entries. Old entries still verifiable via stored signatures + the rotated-out keys. Most operators will keep both fields indefinitely; the cost is 100 bytes per entry.

7 · Test vectors (published)

RFC-005 v1 conformance vectors are live at /test-vectors/rfc-005-v1.json. The dataset includes:

  • A fixed Ed25519 keypair (private + public, base64url + SPKI/PKCS8 DER). The same keypair is published at /.well-known/sociedad-ia/keys (public key only).
  • 3 sample entries with their canonical-JSON form + signature.valuebase64url-exact expected output, cross-validated against Node's crypto.sign(null, msg, privateKey).
  • Mutation-detection vector showing that changing output.pong from 1 to 2 produces a different signature.

The reference implementation lives at apps/landing/src/lib/ed25519.ts in github.com/ar-agents/ar-agents; conformance proof at apps/landing/test/rfc-005-vectors.test.ts (7 vitest tests, all passing).

8 · Open questions

  • Hardware key support.Should operators be encouraged to keep the Ed25519 private key in a hardware token (YubiKey, TPM)? Verification doesn't care, but key custody is a real risk surface. RFC-005 v1 doesn't mandate; v1.1 may add SHOULD.
  • Key transparency.Append-only proof that the operator hasn't equivocated about their public key (Certificate Transparency-style). Probably out of scope for v1; RFC-007 candidate.
  • Cross-jurisdictional key registry. Should the AR registry, Wyoming registry, etc. publish a federated index of public keys? Centralization risk vs. enforcement utility — same trade-off as RFC-004 § 11.
  • Post-quantum readiness. Ed25519 is not post-quantum-safe. When NIST finalizes SLH-DSA + ML-DSA, RFC-005 v2 will add a second signature field for parallel PQ signing during the transition period.

9 · Compatibility summary

Operator emitsv1 verifierv2 verifierResult
hmac only✓ (falls back)OK
signature only✗ (no field)v1 cannot verify
Both✓ (uses hmac)✓ (prefers signature)OK (recommended)
NeitherFatal in production

10 · Implementation status

As of 2026-05-11, the following have shipped:

  • ✓ Reference implementation primitives in apps/landing/src/lib/ed25519.ts: signEntryAsymmetric, verifyEntryAsymmetric, fetchPublicKey. Behind AUDIT_ED25519_PRIVATE_KEY env var.
  • /.well-known/sociedad-ia/keys endpoint published with one demo Ed25519 key.
  • ✓ Test vectors published at /test-vectors/rfc-005-v1.json with byte-exact expected signatures cross-validated against Node's native Ed25519. 7 vitest tests passing.
  • /certifierextended with check #7a ("RFC-005 keys endpoint advertises Ed25519 public keys"). Weight 5. Pass if >=1 key advertised; skip if endpoint 404s (v1 HMAC-only is OK).
  • Integration into the live appendAudit flow — SHIPPED, VERIFIED LIVE. Production entries on the reference deployment now carry both hmac + signature (RFC-005 § 3 wire shape). When AUDIT_ED25519_PRIVATE_KEY is set in Vercel env, every appendAudit call computes both. Confirmed by a live /api/play session: 3-of-3 entries reported signedAsymmetricVerified: 3 alongside verified: 3, tampered: 0.
  • HMAC strip rule fix (round 22 finding): the original signEntry stripped only hmac; the dual-sign integration revealed that signature also needs to be stripped before canonical-JSON so HMAC-and-Ed25519 are computed over the same input space. Now: both strip both. 4 new regression tests in audit.test.ts.
  • ◐ Public review period via GitHub Discussions — open, no fixed end date for v1 finalization.

Comments + counter-proposals welcome.