| Internet-Draft | SAIHM Protocol | May 2026 |
| Jackson | Expires 28 November 2026 | [Page] |
This document defines the Sovereign AI Horizontal Memory (SAIHM) protocol, a memory layer for AI agents that supports post-quantum identity binding, public-chain audit anchoring, per-cell encryption with wallet-derived keys, revocable sharing contracts, and cryptographic right-to-erasure aligned with Article 17 of EU Regulation 2016/679 (GDPR).¶
SAIHM is the memory-layer protocol companion to the Model Context Protocol (MCP). MCP standardizes how AI agents reach tools and contextual data sources; SAIHM standardizes how AI agents persist, share, and erase memory across sessions, models, and vendors.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 28 November 2026.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.¶
This document is published through the Independent Submission Stream of the RFC Series, as defined in [RFC4846] and described in [RFC8730]. It is not an Internet Standard, and it has not been reviewed for, nor does it necessarily reflect, the rough consensus of the IETF community.¶
The Model Context Protocol [MCP], donated to the Agentic AI Foundation [AAIF] under the Linux Foundation on 9 December 2025, defines how an AI agent reaches external tools and contextual data sources. MCP solves the tool-access layer of the agent stack. It does not standardize how an agent persists memory across sessions, models, or vendors. Here, "memory" refers to the holder's content-addressable cells (Section 2.1), identified by their content (cellId), not the bytes of an addressable memory in the computer-architecture sense (Section 1.3).¶
Production AI agents today rely on one of several non-portable approaches: a local file system, a vendor-specific session log, or a vector database. None of these provides post-quantum identity binding, public-chain audit, cryptographic erasure aligned with Article 17 of GDPR [GDPR], or wallet-bound sovereignty that prevents an operator from reading cell content.¶
This document specifies the Sovereign AI Horizontal Memory (SAIHM) protocol. SAIHM is a memory-layer protocol that an MCP-capable agent may attach to gain durable, sovereign, revocably-shareable, cryptographically-erasable memory. The protocol is operator-agnostic, vendor-agnostic, and chain-agnostic. Where a public-chain audit anchor is named, it is named as a reference-deployment property, not as a protocol mandate.¶
This document defines:¶
This document does NOT define:¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
A conformant SAIHM implementation depends on the following external substrates. Where a substrate is itself an IETF or NIST normative reference, it appears in the Normative References. Where a substrate is selected per deployment, the deployment is responsible for stating which selection it uses.¶
A SAIHM cell is the tuple:¶
<cellId, holderId, kekVersion, tier, cellNonce, ciphertext, signature, timestamp>¶
32-byte content-addressable identifier. cellId MUST be computed as¶
cellId = SHA-256( kekVersion_be32 ||
cellNonce ||
ciphertext )
¶
where:¶
The output is the raw 32-byte SHA-256 digest. For transport on the MCP tool surface, cellId is conveyed as a lowercase hexadecimal string of length 64.¶
Including kekVersion and cellNonce in the derivation ensures that the same plaintext encrypted under a different KEK generation or with a different per-cell nonce produces a distinct cellId, eliminating cross-KEK and cross-nonce collisions.¶
At read time, implementations MUST recompute cellId from the cell's kekVersion, cellNonce, and ciphertext fields and MUST reject any cell whose stored cellId does not match the recomputation. Because cellNonce is a public field, this recomputation is the integrity check that prevents an operator from substituting cellNonce after the holder's signature is computed.¶
Holder identity is derived from a wallet seed via the canonical HKDF chain:¶
identityKey = HKDF(salt = "MPS-PQC-KEY-GEN-v1",
IKM = walletSeed,
info = "MPS-AGENT-IDENTITY-v1",
L = 64 bytes)
¶
identityKey is then used as the seed for ML-DSA-65 keypair generation per [FIPS204]. The public component is holderId; the private component MUST NOT leave the holder's machine.¶
Every SAIHM operation MUST be authenticated by an ML-DSA-65 signature over the operation's canonical envelope. Verification MUST follow [FIPS204] using the public holderId.¶
For each cell, the holder derives a per-cell DEK:¶
DEK = HKDF(salt = KEK_v,
IKM = identityKey,
info = cellNonce || "MPS-CELL-DEK-v1",
L = 32 bytes)
¶
where KEK_v is the current KEK generation and cellNonce is a per-cell 16-byte random value. The DEK is used directly with the AEAD cipher to encrypt the cell payload.¶
KEK rotation is versioned. An operator MAY rotate the KEK under operator-defined policy; rotation does not invalidate existing cells because each cell carries its kekVersion. Implementations MUST verify the kekVersion at read time and reject cells whose KEK has been revoked.¶
For each operation (write, read, share, revoke, erase) the protocol emits a receipt:¶
<receiptId, cellId, operation, holderId, signature, timestamp>¶
The receipt is anchored on a public chain offering transactional finality and public-record properties. Anchoring MUST produce a chain-reachable identifier sufficient to reproduce the receipt independently.¶
Reference deployment: COTI V2 mainnet, chain ID 2632500, block explorer https://mainnet.cotiscan.io. Implementations MAY use any public chain offering equivalent finality and public-record properties. The chain choice is a deployment decision; this protocol does not mandate one.¶
The erase operation is atomic at the cryptographic layer:¶
Because the operator never held the DEK (Section 2.3), the ciphertext at rest is computationally meaningless from the moment of DEK destruction. Erasure is irreversible by the operator.¶
The blacklist is a public, append-only set of cellIds. An entry is added to the blacklist when, and only when, the operator anchors an erasure receipt for that cellId on the audit chain. Each erasure receipt's payload carries the cellId of the erased cell; the act of anchoring a valid erasure receipt is the act of adding the cellId to the blacklist.¶
The blacklist construct is mandatory: every successful saihm_forget operation MUST result in (i) destruction of the DEK by the holder, (ii) anchoring of an erasure receipt by the operator, and (iii) inclusion of the erased cellId in the blacklist by virtue of (ii).¶
The blacklist is reproducible from the audit chain by any observer: scan all anchored receipts whose operation field equals "FORGET" and project the cellId field. Operators MAY publish a cached, queryable form of the blacklist for latency-sensitive consumers; the cached form MUST be reproducible from the chain.¶
Implementations MUST consult the blacklist on every saihm_recall and MUST NOT return any cell whose cellId is blacklisted, regardless of whether the requesting party is the original holder, a TEMPORARY grantee, a PERMANENT grantee, or a SYNDICATE grantee. The protocol does not prescribe a particular index structure (e.g., Bloom filter, sorted set, on-chain Merkle accumulator); implementations choose one matching their scale and latency requirements.¶
In the Model Context Protocol [MCP], a "tool" is a function: a named operation with typed inputs and typed outputs that an MCP host runtime exposes to the model. The eight SAIHM tools defined below are functions in this sense; each subsection gives the tool's signature in TypeScript-like notation, followed by its pre-conditions, behavior, post-conditions, and error returns.¶
SAIHM exposes the protocol entirely through MCP using eight tools. Each tool MUST authenticate the caller with an ML-DSA-65 signature (Section 2.2) over the tool's canonical request envelope.¶
The tool surface is intentionally bounded at eight. The bound is a design constraint imposed by this specification, not an upper limit imposed by MCP. The motivation is that a small, fixed tool surface is easier for agent runtime authors and security reviewers to audit, version, and reason about than an open-ended tool list.¶
Protocol evolution within this bounded surface proceeds through three mechanisms:¶
A future major revision of this protocol MAY add or remove tools. Within this revision, the surface is fixed at eight.¶
Return value (an object with the following fields):¶
IEEE 754 binary64 in the closed interval [0.0, 1.0]. Byzantine Fault Score Index: the fraction of audit-chain receipts that match a corresponding holder-side tool-call event, computed over the same 30-day rolling window. Formally,¶
bfsi = 1 - (M / R)¶
where R is the count of operator-anchored receipts on the audit chain attributed to the holder over the window, and M is the count of those receipts for which no corresponding tool-call event is attested in the holder's local event log. When R = 0 (no operator receipts attributed to the holder in the window), bfsi is defined as 1.0 by convention; this signals absence of fault evidence rather than positive integrity, and the bfsi_R field (below) discloses the underlying R = 0 to the holder. bfsi is not opaque; the inputs (R, M, and the window boundary) MUST be exposed to the holder through the same saihm_status call under the fields bfsi_window_start_ts, bfsi_R, and bfsi_M, so that any holder or auditor can reproduce the computation.¶
A bfsi below the operator's published operator-integrity threshold (the reference deployment publishes 0.99 as the threshold) is a signal to the holder that operator integrity is degrading and is grounds for migration to another operator.¶
The full CBOR schema for the saihm_status return appears in Section 4.¶
This protocol defines a governance hook (saihm_governance_propose, saihm_governance_vote) but does not mandate a single governance form. The set of governance scopes is itself governance-mutable, so a deployment is free to evolve its governance policy without revising this protocol.¶
Every deployment MUST publish its governance form, comprising at least the following parameters, at a stable URL referenced from the deployment's saihm_status output:¶
The reference governance form, used by the reference deployment, has the following values for the parameters above:¶
Sybil-resistance note: the reference governance form above is hardened against Sybil attack by the soul-bound, non-transferable nature of the governance SBTs and by the requirement that SBTs be earned through demonstrated SAIHM protocol use rather than purchased or transferred. A party that spawns N wallets to multiply identity gains at most the minimum SBT yield per wallet (the floor that issuance policy permits for a newly active holderId); a long-standing legitimate holder accumulates SBTs over time at a rate that this Sybil strategy cannot match without performing equivalent legitimate protocol activity, by construction. Deployments that need a different Sybil-resistance posture (for example, identity attestation, KYC, or proof-of-stake at scale) MAY substitute an alternative governance form, subject to constraints (i)-(iii) below.¶
Implementations MAY substitute alternative governance forms (for example, stake-weighted, multi-signature board, or DAO-contract governance) so long as¶
SAIHM uses Concise Binary Object Representation (CBOR) [RFC8949] for cell payloads and receipts, and JSON-RPC 2.0 over the MCP transport for tool calls. All timestamps appearing in CBOR-encoded payloads MUST be CBOR unsigned integers (CBOR major type 0); no SAIHM emitter or parser is permitted to clamp to a signed 32-bit window (Section 2.1).¶
A canonical cell payload (CBOR diagnostic notation):¶
{1: h'...cellId...',
2: h'...holderId...',
3: 1,
4: "FILECOIN",
5: h'...cellNonce-16-bytes...',
6: h'...ciphertext...',
7: h'...signature...',
8: 1747526400}
¶
The integer keys correspond to fields defined in Section 2.1: 1=cellId, 2=holderId, 3=kekVersion, 4=tier, 5=cellNonce, 6=ciphertext, 7=signature, 8=timestamp.¶
A canonical receipt (CBOR diagnostic notation):¶
{1: h'...receiptId...',
2: h'...cellId...',
3: "REMEMBER",
4: h'...holderId...',
5: h'...signature...',
6: 1747526400}
¶
For erasure receipts (operation = "FORGET"), the receipt payload's cellId field carries the cellId added to the blacklist (Section 2.6).¶
A canonical saihm_status return (CBOR diagnostic notation):¶
{"prs": 0.997,
"bfsi": 1.0,
"bfsi_window_start_ts": 1745020800,
"bfsi_R": 0,
"bfsi_M": 0,
"shards": {"FILECOIN": 42},
"contracts": [
{"contractId": h'...32-bytes...',
"mode": "TEMPORARY",
"granteeIds": [h'...32-bytes...'],
"expiresAt": 1747612800}
],
"governance": [
{"propId": h'...32-bytes...',
"scope": "kek-rotation-cadence",
"opens_ts": 1747000000,
"closes_ts": 1748209600,
"tally_for": 1240,
"tally_against": 18,
"tally_abstain": 5}
]}
¶
For each tool call that mutates state (saihm_remember, saihm_forget, saihm_share, saihm_revoke_share, saihm_governance_propose, saihm_governance_vote), the operator MUST emit a receipt anchored on the audit chain.¶
The receipt MUST include the operation type, the cellId (or contractId, or propId), the holderId, and the timestamp.¶
The receipt MUST NOT include cell plaintext, the DEK, or the wallet seed.¶
Receipts for erasure (saihm_forget) MUST also include the tombstone identifier and the cellId added to the blacklist (Section 2.6).¶
Read-only tool calls (saihm_recall, saihm_status) MAY emit receipts under operator policy; receipts for read-only calls MUST NOT include cell plaintext.¶
ML-DSA-65 [FIPS204] is the protocol's authentication primitive. ML-DSA-65 is a NIST-selected post-quantum digital signature algorithm in the FIPS-204 family. An adversary with a cryptographically relevant quantum computer cannot forge SAIHM signatures.¶
Implementations MUST use the FIPS-204 parameter set named ML-DSA-65. Implementations SHOULD include the kekVersion in every signed envelope so that key-rotation events are themselves signed.¶
The wallet seed and the derived identity key MUST NOT leave the holder's machine. The protocol does not provide key escrow. A holder who loses the wallet seed loses access to their cells; the operator cannot recover access on behalf of the holder.¶
This is intentional. The operator's inability to recover the wallet seed is the same property that prevents the operator from reading cell content.¶
Cryptographic erasure (Section 2.6) provides stronger evidence than logical (soft) deletion. Because the DEK is destroyed at the holder side, ciphertext at rest is computationally meaningless to any party, including the operator.¶
Backups and replicas store only ciphertext. DEK destruction propagates erasure semantics to every copy of the ciphertext, anywhere, automatically. An operator MUST NOT cache the DEK.¶
The protocol assumes an honest-but-curious operator: the operator is expected to provide storage and transport honestly but MAY attempt to learn cell content.¶
Against an honest-but-curious operator:¶
Against a malicious operator (one that deviates from the protocol), additional measures (e.g., threshold-replicated storage, multi-chain receipt anchoring) may be advisable but are out of scope for this protocol layer.¶
The saihm_forget operation provides cryptographic-grade evidence of erasure aligned with Article 17 of Regulation (EU) 2016/679 [GDPR]. The DEK is destroyed; a tombstone is published; the cellId is blacklisted; and a receipt is anchored on chain.¶
Article 17 requires erasure "without undue delay". saihm_forget is atomic at the cryptographic layer; there is no operator-side deletion queue that could fail to drain.¶
The audit log records cellId, holderId, operation, and timestamp. It MUST NOT record cell plaintext, the DEK, or the wallet seed. An auditor observing the chain learns when and by whom each operation was performed, but not the content of any cell.¶
Receipts anchored on chain are public. Holders SHOULD treat the existence of a cell (cellId, holderId, timestamp) as publicly observable. Where the existence of a record is itself sensitive, holders SHOULD use additional countermeasures outside the scope of this protocol (e.g., pseudonymous holder identities, batched-operation timing).¶
This document has no IANA actions.¶
The reference SAIHM deployment runs on the COTI V2 Helium mainnet (chain ID 2632500). Protocol implementations MAY anchor receipts on any public chain offering equivalent transactional finality and public-record properties. The chain choice is a deployment decision; the protocol does not mandate one.¶
The reference deployment publishes:¶
This appendix walks through the canonical SAIHM cell lifecycle with concrete, illustrative values. All cryptographic inputs labelled "TEST" are derived from a well-known test wallet seed and MUST NOT be used for production cells.¶
The canonical lifecycle saihm_remember -> saihm_recall -> saihm_share -> saihm_revoke_share -> saihm_forget, with the actor (holder agent, operator, public chain) and the message at each hop:¶
Holder agent Operator Public chain
============ ======== ============
| | |
| saihm_remember | |
| (envelope, sig) | |
|-------------------->| |
| | persist ciphertext |
| | to storage tier |
| |---------------------->|
| | write receipt |
| | anchored (txid) |
| |<----------------------|
| cellId | |
|<--------------------| |
| | |
| saihm_recall | |
| (envelope, sig) | |
|-------------------->| |
| cells[] | |
| (ciphertext) | |
|<--------------------| |
| (decrypt locally) | |
| | |
| saihm_share | |
| (cellId, grantee, | |
| mode) | |
|-------------------->| |
| | contract + |
| | share receipt |
| |---------------------->|
| | anchored (txid) |
| |<----------------------|
| contractId | |
|<--------------------| |
| | |
| saihm_revoke_share | |
| (contractId) | |
|-------------------->| |
| | contractRevocation + |
| | revoke receipt |
| |---------------------->|
| | anchored (txid) |
| |<----------------------|
| revocationId | |
|<--------------------| |
| | |
| saihm_forget | |
| (cellId) | |
| [holder destroys | |
| DEK locally] | |
|-------------------->| |
| | erasure receipt + |
| | tombstone + |
| | cellId blacklisted |
| |---------------------->|
| | anchored (txid) |
| |<----------------------|
| tombstone | |
|<--------------------| |
¶
The following values are derived from a labelled test wallet seed and are intended only to demonstrate the HKDF, AEAD, SHA-256, and CBOR derivations defined in the body of this document. Any FIPS-204-conformant ML-DSA-65 implementation, RFC 5869 HKDF implementation, and RFC 5116 AEAD implementation will reproduce these values from the inputs given.¶
Test wallet seed (32 bytes, hex), derived as SHA-256("SAIHM-TEST-VECTOR-001-DO-NOT-USE-IN-PRODUCTION"):¶
walletSeed (TEST) = f068b8db8484d33bdbedd154bf5bf28e11fba330b79469e23595d6f738d7f5c6¶
HKDF identity derivation (Section 2.2):¶
identityKey =
HKDF(salt = "MPS-PQC-KEY-GEN-v1",
IKM = walletSeed,
info = "MPS-AGENT-IDENTITY-v1",
L = 64 bytes)
=
fdf786da8cb1f074393f9ad6dec1671e08085540e95c8463c9f2e15f437bbc5a
2c267aeaf355e79d8968cc21846cdff7e16f498437de3d6b1fd290703eeed9c2
¶
holderId (32 bytes, hex), presented as the test holder's protocol-level identifier:¶
holderId (TEST) = ab4f746fd1520d2736854559d6751969ae9127f5dbc607d7298acbf1afb1f588¶
KEK generation: kekVersion = 1.¶
Per-cell nonce (16 bytes, hex):¶
cellNonce = 25bd74b827789faacad8ffb7593c2359¶
Cell plaintext:¶
plaintext = "Hello, SAIHM. This is a test memory cell."¶
DEK derivation (Section 2.3):¶
DEK =
HKDF(salt = KEK_v (4-byte big-endian of kekVersion=1),
IKM = identityKey,
info = cellNonce || "MPS-CELL-DEK-v1",
L = 32 bytes)
=
a1e54f730c6c7a1048ae436c9d2b179821c6eddd7841f41e36215285f3ffd07a
¶
AEAD encryption (AES-256-GCM, [NIST-SP-800-38D]) using the first 12 bytes of cellNonce as the GCM IV in this test vector; the protocol does not prescribe an AEAD-IV derivation, and deployments select one:¶
ciphertext (57 bytes, including 16-byte GCM tag) = 595b0b9f77a8d95f29c5affa151bbcc18fdc3f7e5223792627919ee2d52f2bf2 4933c35de4c1755559bee818ef54b48a388bcdd2e4a30fbde8¶
cellId derivation (Section 2.1):¶
cellId =
SHA-256( kekVersion_be32 || cellNonce || ciphertext )
=
d851960a5b7754c5884c96bef5d615e666c8ad006e4ceebe028cd85aae8e7c2f
¶
timestamp = 1747526400 (UTC 2025-05-18T00:00:00Z; encoded as 8 bytes big-endian when used in signature concatenation).¶
signature: ML-DSA-65 ([FIPS204]) over (cellId || holderId || kekVersion_be32 || timestamp_be64). The signature is 3309 bytes; the first 32 bytes are shown for illustration, and the full signature is reproducible from a FIPS-204-conformant ML-DSA-65 implementation given the test wallet seed above:¶
signature (first 32 of 3309 bytes) = dba1109b3d53e17290914cdb2e639c6cdad37aff8184537ba9b2c05c7fe8a994 ... (3277 more bytes) ...¶
The canonical CBOR encoding of the example cell, per the schema in Section 4:¶
{1: h'd851960a5b7754c5884c96bef5d615e666c8ad006e4ceebe028cd85aae8e7c2f',
2: h'ab4f746fd1520d2736854559d6751969ae9127f5dbc607d7298acbf1afb1f588',
3: 1,
4: "FILECOIN",
5: h'25bd74b827789faacad8ffb7593c2359',
6: h'595b0b9f77a8d95f29c5affa151bbcc18fdc3f7e5223792627919ee2
d52f2bf24933c35de4c1755559bee818ef54b48a388bcdd2e4a30fbde8',
7: h'dba1109b3d53e17290914cdb2e639c6cdad37aff8184537ba9b2c05c
7fe8a994 ... (3277 more bytes; 3309 total)',
8: 1747526400}
¶
Byte-level CBOR encoding (with one line of commentary per field; ML-DSA-65 signature bytes elided for brevity):¶
A8 # map(8)
01 # unsigned(1) // key=1 (cellId)
58 20 # bytes(32)
d851960a5b7754c5884c96bef5d615e666c8ad006e4ceebe028cd85aae8e7c2f
02 # unsigned(2) // key=2 (holderId)
58 20 # bytes(32)
ab4f746fd1520d2736854559d6751969ae9127f5dbc607d7298acbf1afb1f588
03 # unsigned(3) // key=3 (kekVersion)
01 # unsigned(1) // value = 1
04 # unsigned(4) // key=4 (tier)
68 # text(8)
46494c45434f494e // "FILECOIN"
05 # unsigned(5) // key=5 (cellNonce)
50 # bytes(16)
25bd74b827789faacad8ffb7593c2359
06 # unsigned(6) // key=6 (ciphertext)
58 39 # bytes(57)
595b0b9f77a8d95f29c5affa151bbcc18fdc3f7e5223792627919ee2d52f2bf2
4933c35de4c1755559bee818ef54b48a388bcdd2e4a30fbde8
07 # unsigned(7) // key=7 (signature)
59 0CED # bytes(3309)
dba1109b3d53e17290914cdb2e639c6cdad37aff8184537ba9b2c05c7fe8a994
... (3277 more signature bytes; elided for brevity) ...
08 # unsigned(8) // key=8 (timestamp)
1A 68292300 # unsigned(1747526400)
¶
The corresponding write receipt (operation = "REMEMBER"), per the schema in Section 4:¶
{1: h'(32-byte receiptId, anchored on chain at txid)',
2: h'd851960a5b7754c5884c96bef5d615e666c8ad006e4ceebe028cd85aae8e7c2f',
3: "REMEMBER",
4: h'ab4f746fd1520d2736854559d6751969ae9127f5dbc607d7298acbf1afb1f588',
5: h'(3309-byte ML-DSA-65 signature over receipt envelope)',
6: 1747526400}
¶