<?xml version="1.0" encoding="utf-8"?>
<!-- xml2rfc v3 source per RFC 7991. Generate text or html using xml2rfc. -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     ipr="trust200902"
     docName="draft-saihm-memory-protocol-01"
     category="info"
     submissionType="independent"
     xml:lang="en"
     tocInclude="true"
     tocDepth="4"
     sortRefs="true"
     version="3">
  <front>
    <title abbrev="SAIHM Protocol">The Sovereign AI Horizontal Memory (SAIHM) Protocol</title>
    <seriesInfo name="Internet-Draft" value="draft-saihm-memory-protocol-01"/>
    <author fullname="Russell Jackson" initials="R." surname="Jackson">
      <organization>SAIHM (Sovereign AI Horizontal Memory)</organization>
      <address>
        <email>architect@saihm.coti.global</email>
        <uri>https://saihm.coti.global/</uri>
      </address>
    </author>
    <date year="2026" month="May" day="27"/>
    <area>art</area>
    <workgroup>Independent Submission</workgroup>
    <keyword>AI memory</keyword>
    <keyword>post-quantum signatures</keyword>
    <keyword>Model Context Protocol</keyword>
    <keyword>GDPR Article 17</keyword>
    <keyword>cryptographic erasure</keyword>
    <abstract>
      <t>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).</t>
      <t>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.</t>
    </abstract>
  </front>
  <middle>
    <section anchor="introduction"><name>Introduction</name>
      <t>This document is published through the Independent Submission
         Stream of the RFC Series, as defined in <xref target="RFC4846"/>
         and described in <xref target="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.</t>
      <section anchor="motivation"><name>Motivation</name>
        <t>The Model Context Protocol <xref target="MCP"/>, donated to the
           Agentic AI Foundation <xref target="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 (<xref target="cell-shape"/>),
           identified by their content (cellId), not the bytes of an
           addressable memory in the computer-architecture sense
           (<xref target="terminology"/>).</t>
        <t>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 <xref target="GDPR"/>, or
           wallet-bound sovereignty that prevents an operator from reading
           cell content.</t>
        <t>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.</t>
      </section>
      <section anchor="scope"><name>Scope</name>
        <t>This document defines:</t>
        <ul>
          <li>The cell shape (encrypted memory unit with canonical
              metadata).</li>
          <li>Identity binding using a post-quantum digital signature
              algorithm (ML-DSA-65, <xref target="FIPS204"/>).</li>
          <li>An encryption envelope deriving a per-cell DEK from the
              holder's wallet through a canonical HKDF chain
              <xref target="RFC5869"/>.</li>
          <li>An audit anchor profile, with a reference deployment on a
              public chain.</li>
          <li>Sharing contracts (temporary, permanent, syndicate).</li>
          <li>Cryptographic erasure semantics (DEK destruction +
              tombstone + content-address blacklist) aligned with GDPR
              Article 17.</li>
          <li>An MCP binding consisting of eight canonical tools.</li>
        </ul>
        <t>This document does NOT define:</t>
        <ul>
          <li>A specific blockchain (the protocol is chain-agnostic).</li>
          <li>Vector-database semantics (orthogonal).</li>
          <li>Agent runtime semantics (covered by MCP and runtime
              implementations).</li>
        </ul>
      </section>
      <section anchor="terminology"><name>Conventions and Terminology</name>
        <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
           "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
           "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
           "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>",
           "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and
           "<bcp14>OPTIONAL</bcp14>" in this document are to be
           interpreted as described in BCP 14
           <xref target="RFC2119"/> <xref target="RFC8174"/> when, and
           only when, they appear in all capitals, as shown here.</t>
        <dl>
          <dt>AEAD:</dt>
          <dd>Authenticated Encryption with Associated Data, as defined
              in <xref target="RFC5116"/>. SAIHM uses an AEAD cipher to
              encrypt cell payloads; AES-256-GCM
              (<xref target="NIST-SP-800-38D"/>) is
              <bcp14>RECOMMENDED</bcp14>.</dd>
          <dt>canonical request envelope:</dt>
          <dd>a CBOR map (<xref target="RFC8949"/>) carrying the inputs
              to a SAIHM tool call in a fixed key order. The envelope is
              the byte sequence over which the caller computes the
              ML-DSA-65 signature that authenticates the call. The fixed
              key order is enumerated in
              <xref target="wire-formats"/>.</dd>
          <dt>Cell:</dt>
          <dd>an encrypted memory unit, as defined in
              <xref target="cell-shape"/>.</dd>
          <dt>DEK:</dt>
          <dd>Data Encryption Key. A per-cell symmetric key derived via
              HKDF from the holder's identity key.</dd>
          <dt>HKDF:</dt>
          <dd>HMAC-based Extract-and-Expand Key Derivation Function, as
              defined in <xref target="RFC5869"/>.</dd>
          <dt>Holder:</dt>
          <dd>the natural person, organization, or autonomous agent that
              owns the wallet seed bound to a SAIHM cell.</dd>
          <dt>KEK:</dt>
          <dd>Key Encryption Key version identifier. A protocol-level
              counter that permits cryptographic agility through
              rotation without invalidating existing cells.</dd>
          <dt>MCP:</dt>
          <dd>the Model Context Protocol <xref target="MCP"/>. In MCP, a
              "tool" is a function: a named operation with typed inputs
              and typed outputs exposed by an MCP host runtime to a
              model. SAIHM exposes its protocol entirely as eight such
              functions (<xref target="tool-surface"/>).</dd>
          <dt>memory:</dt>
          <dd>the aggregate set of SAIHM cells
              (<xref target="cell-shape"/>) bound to a single holderId.
              SAIHM memory is content-addressable: each cell is
              identified by its cellId, and a holder's memory is the
              union of all cells whose holderId matches the holder,
              minus those for which an erasure receipt has been
              anchored. This is distinct from "memory" in the
              computer-architecture sense (a contiguous addressable byte
              store).</dd>
          <dt>memory-layer protocol:</dt>
          <dd>a network-protocol specification whose subject matter is
              the persistence, sharing, and erasure of memory belonging
              to a holder. A memory-layer protocol defines the
              encoding, authentication, integrity, and lifecycle of the
              at-rest data, without prescribing the application that
              produces or consumes it.</dd>
          <dt>ML-DSA:</dt>
          <dd>Module-Lattice-Based Digital Signature Algorithm, as
              specified in <xref target="FIPS204"/>. SAIHM authenticates
              every operation with an ML-DSA-65 signature.</dd>
          <dt>Operator:</dt>
          <dd>the entity providing storage, transport, and audit-anchor
              services to a holder. The operator <bcp14>MUST NOT</bcp14>
              have access to plaintext cell content.</dd>
          <dt>Receipt:</dt>
          <dd>a signed record of a SAIHM operation, anchored on a
              public chain.</dd>
          <dt>sentinel value:</dt>
          <dd>a designated in-band value that signals the absence of an
              ordinary value of the same type. In
              <xref target="sharing-contracts"/>, expiresAt = 0 is the
              sentinel signalling "no time bound". The sentinel
              preserves a flat representation of the contract tuple; a
              separate boolean flag field would carry the same
              information at the cost of an additional field. This
              document retains the sentinel for representational
              economy.</dd>
          <dt>storage tier:</dt>
          <dd>a named, operator-chosen persistence backend with stated
              durability and retention properties. The tier value
              ("FILECOIN" is the example given in the reference
              deployment) is deployment metadata; the protocol does not
              prescribe a particular tier, and tier names have no
              protocol semantics beyond serving as a hint to the
              operator-side storage router.</dd>
          <dt>UNIX epoch:</dt>
          <dd>the time reference defined in
              <xref target="IEEE-1003.1-2024"/> under "Seconds Since
              the Epoch". All SAIHM timestamps are encoded as unsigned
              integer seconds since the UNIX epoch.</dd>
          <dt>wallet seed:</dt>
          <dd>a high-entropy secret value held by the holder, from
              which the holder's identity key is derived
              (<xref target="identity-binding"/>). The wallet seed is
              generated, stored, and rotated by a wallet implementation
              external to this protocol; this document does not specify
              how the wallet seed is generated or stored.</dd>
        </dl>
      </section>
      <section anchor="substrate-prerequisites"><name>Substrate prerequisites</name>
        <t>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.</t>
        <ol type="(%c)">
          <li>A wallet implementation capable of producing a
              high-entropy secret of at least 256 bits, which the
              holder retains as the wallet seed
              (<xref target="identity-binding"/>). The protocol does
              not specify how the wallet seed is generated, stored, or
              rotated.</li>
          <li>An implementation of HKDF as defined in
              <xref target="RFC5869"/>, used for identity-key
              derivation and per-cell DEK derivation.</li>
          <li>An implementation of ML-DSA-65 conformant with
              <xref target="FIPS204"/>.</li>
          <li>An implementation of an AEAD cipher conformant with
              <xref target="RFC5116"/>. AES-256-GCM
              (<xref target="NIST-SP-800-38D"/>) is
              <bcp14>RECOMMENDED</bcp14>.</li>
          <li>An implementation of SHA-256
              (<xref target="FIPS180-4"/>) for cellId derivation.</li>
          <li>A CBOR codec conformant with <xref target="RFC8949"/>
              for cell and receipt encoding.</li>
          <li>A Model Context Protocol (MCP) host runtime exposing
              the SAIHM tool functions over the MCP transport.</li>
          <li>A public chain offering transactional finality and
              public-record properties, used for receipt anchoring.
              Per-deployment selection; the reference deployment uses
              COTI V2 (chain ID 2632500). Implementations
              <bcp14>MAY</bcp14> choose any chain offering equivalent
              properties.</li>
          <li>A storage tier exposing PUT, GET, and DELETE semantics
              over an opaque ciphertext blob. Per-deployment
              selection; the reference deployment uses a Filecoin
              tier.</li>
        </ol>
      </section>
    </section>

    <section anchor="architecture"><name>Architecture</name>
      <section anchor="cell-shape"><name>Cell shape</name>
        <t>A SAIHM cell is the tuple:</t>
        <artwork align="left">
&lt;cellId, holderId, kekVersion, tier, cellNonce, ciphertext,
 signature, timestamp&gt;
        </artwork>
        <dl>
          <dt>cellId:</dt>
          <dd>
            <t>32-byte content-addressable identifier. cellId
               <bcp14>MUST</bcp14> be computed as</t>
            <artwork align="left">
cellId = SHA-256( kekVersion_be32 ||
                  cellNonce       ||
                  ciphertext )
            </artwork>
            <t>where:</t>
            <ul empty="true">
              <li>kekVersion_be32 is kekVersion encoded as a 4-byte
                  big-endian unsigned integer;</li>
              <li>cellNonce is the 16-byte cellNonce defined in
                  <xref target="encryption-envelope"/>;</li>
              <li>ciphertext is the AEAD output, including the
                  authentication tag;</li>
              <li>|| denotes octet concatenation.</li>
            </ul>
            <t>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.</t>
            <t>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.</t>
            <t>At read time, implementations <bcp14>MUST</bcp14>
               recompute cellId from the cell's kekVersion,
               cellNonce, and ciphertext fields and
               <bcp14>MUST</bcp14> 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.</t>
          </dd>
          <dt>holderId:</dt>
          <dd>32-byte holder identity, derived from the holder's
              wallet seed (<xref target="identity-binding"/>).</dd>
          <dt>kekVersion:</dt>
          <dd>32-bit unsigned integer identifying the KEK generation
              in force at write time.</dd>
          <dt>tier:</dt>
          <dd>short ASCII string naming the operator's storage
              tier (e.g., "FILECOIN").</dd>
          <dt>cellNonce:</dt>
          <dd>16-byte per-cell random value, used both in DEK
              derivation (<xref target="encryption-envelope"/>) and
              in cellId derivation (above). cellNonce is a public
              field, transmitted with the cell to permit the cellId
              recomputation check above.</dd>
          <dt>ciphertext:</dt>
          <dd>cell payload encrypted with the per-cell DEK under an
              AEAD cipher. AES-256-GCM is
              <bcp14>RECOMMENDED</bcp14>.</dd>
          <dt>signature:</dt>
          <dd>ML-DSA-65 signature over the concatenation
              (cellId || holderId || kekVersion_be32 ||
              timestamp_be64). When timestamp appears in any
              concatenated byte sequence over which a signature is
              computed, it <bcp14>MUST</bcp14> be encoded as 8 bytes
              in big-endian order (timestamp_be64).</dd>
          <dt>timestamp:</dt>
          <dd>64-bit unsigned integer. UTC seconds since the UNIX
              epoch as defined in <xref target="IEEE-1003.1-2024"/>
              ("Seconds Since the Epoch"). Implementations
              <bcp14>MUST NOT</bcp14> use a 32-bit signed
              representation. A 32-bit signed encoding of UNIX time
              overflows at 03:14:07Z on 19 January 2038;
              implementations encountering values produced by such
              an encoding <bcp14>MUST</bcp14> treat the affected
              receipts as malformed. The 64-bit unsigned
              representation supports values up to 2^64 - 1 seconds
              since the epoch, exceeding any practical time horizon
              by many orders of magnitude.</dd>
        </dl>
      </section>
      <section anchor="identity-binding"><name>Identity binding (ML-DSA-65)</name>
        <t>Holder identity is derived from a wallet seed via the
           canonical HKDF chain:</t>
        <artwork align="left">
identityKey = HKDF(salt = "MPS-PQC-KEY-GEN-v1",
                   IKM  = walletSeed,
                   info = "MPS-AGENT-IDENTITY-v1",
                   L    = 64 bytes)
        </artwork>
        <t>identityKey is then used as the seed for ML-DSA-65 keypair
           generation per <xref target="FIPS204"/>. The public
           component is holderId; the private component
           <bcp14>MUST NOT</bcp14> leave the holder's machine.</t>
        <t>Every SAIHM operation <bcp14>MUST</bcp14> be authenticated
           by an ML-DSA-65 signature over the operation's canonical
           envelope. Verification <bcp14>MUST</bcp14> follow
           <xref target="FIPS204"/> using the public holderId.</t>
      </section>
      <section anchor="encryption-envelope"><name>Encryption envelope (HKDF chain)</name>
        <t>For each cell, the holder derives a per-cell DEK:</t>
        <artwork align="left">
DEK = HKDF(salt = KEK_v,
           IKM  = identityKey,
           info = cellNonce || "MPS-CELL-DEK-v1",
           L    = 32 bytes)
        </artwork>
        <t>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.</t>
        <t>KEK rotation is versioned. An operator <bcp14>MAY</bcp14>
           rotate the KEK under operator-defined policy; rotation
           does not invalidate existing cells because each cell
           carries its kekVersion. Implementations
           <bcp14>MUST</bcp14> verify the kekVersion at read time and
           reject cells whose KEK has been revoked.</t>
      </section>
      <section anchor="audit-anchor"><name>Audit anchor (public chain)</name>
        <t>For each operation (write, read, share, revoke, erase) the
           protocol emits a receipt:</t>
        <artwork align="left">
&lt;receiptId, cellId, operation, holderId, signature, timestamp&gt;
        </artwork>
        <t>The receipt is anchored on a public chain offering
           transactional finality and public-record properties.
           Anchoring <bcp14>MUST</bcp14> produce a chain-reachable
           identifier sufficient to reproduce the receipt
           independently.</t>
        <t>Reference deployment: COTI V2 mainnet, chain ID 2632500,
           block explorer https://mainnet.cotiscan.io. Implementations
           <bcp14>MAY</bcp14> use any public chain offering equivalent
           finality and public-record properties. The chain choice is
           a deployment decision; this protocol does not mandate
           one.</t>
      </section>
      <section anchor="sharing-contracts"><name>Sharing contracts</name>
        <t>A holder <bcp14>MAY</bcp14> share a cell with a grantee
           through a signed sharing contract:</t>
        <artwork align="left">
&lt;contractId, cellId, granteeId, mode, expiresAt, holderSignature&gt;
        </artwork>
        <t>mode is one of:</t>
        <dl>
          <dt>TEMPORARY:</dt>
          <dd>revocable; expiresAt <bcp14>MUST</bcp14> be no later
              than timestamp + 86400 seconds (24 hours).</dd>
          <dt>PERMANENT:</dt>
          <dd>revocable; expiresAt <bcp14>MUST</bcp14> be the
              sentinel value 0 (no time bound).</dd>
          <dt>SYNDICATE:</dt>
          <dd>
            <t>A single sharing contract that names an ordered list
               of granteeIds rather than a single granteeId. The
               contract is atomic in two senses: all listed
               grantees gain access in a single signed event, and a
               single counter-signed contractRevocation removes
               access for every listed grantee simultaneously.
               expiresAt <bcp14>MAY</bcp14> be 0 (no time bound) or
               a future timestamp.</t>
            <t>SYNDICATE validation by the operator:</t>
            <ol type="(%c)">
              <li>The operator <bcp14>MUST</bcp14> verify the
                  holder's ML-DSA-65 signature over the full
                  contract, including the full grantee list.</li>
              <li>On saihm_recall by an entity X, the operator
                  <bcp14>MUST</bcp14> include cells from any active
                  SYNDICATE contract whose grantee list contains
                  X's holderId.</li>
              <li>On contractRevocation, the operator
                  <bcp14>MUST</bcp14> cease serving the cell to
                  every member of the grantee list from the moment
                  the revocation is anchored on chain.</li>
            </ol>
            <t>SYNDICATE use cases include sharing the memory of a
               multi-party deliberation (e.g., a deal syndicate or
               an incident-response team) with a fixed grantee
               set, where per-grantee TEMPORARY contracts would
               multiply administration cost and where issuing the
               same memory N times under N TEMPORARY contracts
               would multiply the anchored-receipt cost.</t>
          </dd>
        </dl>
        <t>Revocation is performed via a counter-signed
           contractRevocation anchored on chain. Once anchored, the
           revocation takes effect immediately; subsequent recall
           attempts by the grantee <bcp14>MUST</bcp14> be rejected
           by the operator.</t>
      </section>
      <section anchor="cryptographic-erasure"><name>Cryptographic erasure</name>
        <t>The erase operation is atomic at the cryptographic layer:</t>
        <ol>
          <li>The holder destroys the DEK for the target cell.</li>
          <li>A tombstone is emitted, carrying cellId and a
              timestamp.</li>
          <li>The cell's cellId is added to a public blacklist (see
              below).</li>
          <li>An audit receipt is anchored on chain.</li>
        </ol>
        <t>Because the operator never held the DEK
           (<xref target="encryption-envelope"/>), the ciphertext at
           rest is computationally meaningless from the moment of
           DEK destruction. Erasure is irreversible by the
           operator.</t>
        <t>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.</t>
        <t>The blacklist construct is mandatory: every successful
           saihm_forget operation <bcp14>MUST</bcp14> 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).</t>
        <t>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 <bcp14>MAY</bcp14> publish a cached,
           queryable form of the blacklist for latency-sensitive
           consumers; the cached form <bcp14>MUST</bcp14> be
           reproducible from the chain.</t>
        <t>Implementations <bcp14>MUST</bcp14> consult the
           blacklist on every saihm_recall and
           <bcp14>MUST NOT</bcp14> 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.</t>
      </section>
    </section>

    <section anchor="tool-surface"><name>Tool surface (MCP binding)</name>
      <t>In the Model Context Protocol <xref target="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.</t>
      <t>SAIHM exposes the protocol entirely through MCP using
         eight tools. Each tool <bcp14>MUST</bcp14> authenticate
         the caller with an ML-DSA-65 signature
         (<xref target="identity-binding"/>) over the tool's
         canonical request envelope.</t>
      <t>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.</t>
      <t>Protocol evolution within this bounded surface proceeds
         through three mechanisms:</t>
      <ol type="(%i)">
        <li>KEK rotation: an operational change in which the same
            eight tools continue to operate under a new KEK
            generation (<xref target="encryption-envelope"/>).
            Existing cells remain readable so long as their
            kekVersion has not been revoked.</li>
        <li>Governance vote: a protocol-level parameter change
            proposed via saihm_governance_propose
            (<xref target="tool-governance-propose"/>) and
            ratified via saihm_governance_vote
            (<xref target="tool-governance-vote"/>). The set of
            governance scopes is itself governance-mutable.</li>
        <li>Parameter changes within existing tool signatures:
            new sharing-contract modes
            (<xref target="sharing-contracts"/>), new governance
            scopes (<xref target="tool-governance-propose"/>), or
            new payload fields are introduced by extending the
            typed input of an existing tool, not by adding a new
            tool.</li>
      </ol>
      <t>A future major revision of this protocol
         <bcp14>MAY</bcp14> add or remove tools. Within this
         revision, the surface is fixed at eight.</t>

      <section anchor="tool-remember"><name>saihm_remember</name>
        <dl>
          <dt>Signature:</dt>
          <dd>saihm_remember(content: string) -&gt; cellId</dd>
          <dt>Pre-conditions:</dt>
          <dd>Caller is the holder. The holder's wallet seed is
              locally available to the holder-side runtime. The
              caller has constructed a canonical request envelope
              and signed it with the holder's ML-DSA-65 identity
              key.</dd>
          <dt>Behavior:</dt>
          <dd>The holder derives a per-cell DEK
              (<xref target="encryption-envelope"/>), encrypts
              content under an AEAD cipher to produce ciphertext,
              computes cellId (<xref target="cell-shape"/>),
              signs the canonical envelope, and submits the cell
              to the operator. The operator persists the
              ciphertext to the holder-named storage tier and
              anchors a write receipt on the audit chain
              (<xref target="audit-anchor"/>).</dd>
          <dt>Post-conditions:</dt>
          <dd>A cell with the returned cellId is retrievable via
              saihm_recall. A write receipt for cellId is
              anchored on the audit chain.</dd>
          <dt>Errors:</dt>
          <dd>"no_wallet_seed", "envelope_signature_invalid",
              "operator_storage_unavailable",
              "operator_chain_unavailable", "rate_limited".</dd>
        </dl>
      </section>

      <section anchor="tool-recall"><name>saihm_recall</name>
        <dl>
          <dt>Signature:</dt>
          <dd>saihm_recall(query?: string) -&gt; cells[]</dd>
          <dt>Pre-conditions:</dt>
          <dd>Caller is the holder, or a grantee under an active
              sharing contract that names the caller's
              holderId.</dd>
          <dt>Behavior:</dt>
          <dd>The operator returns ciphertexts for all cells
              whose holderId matches the caller, plus
              ciphertexts from active sharing contracts naming
              the caller (<xref target="sharing-contracts"/>).
              Cells whose cellId is on the public blacklist
              (<xref target="cryptographic-erasure"/>) are
              omitted. The caller decrypts client-side and
              applies the optional query filter after
              decryption. query <bcp14>MUST NOT</bcp14> be
              transmitted to the operator.</dd>
          <dt>Post-conditions:</dt>
          <dd>The returned cell set reflects the operator's view
              at recall time. Blacklisted cells
              <bcp14>MUST NOT</bcp14> appear in the returned
              set.</dd>
          <dt>Errors:</dt>
          <dd>None beyond transport faults.</dd>
        </dl>
      </section>

      <section anchor="tool-forget"><name>saihm_forget</name>
        <dl>
          <dt>Signature:</dt>
          <dd>saihm_forget(cellId: string) -&gt; tombstone</dd>
          <dt>Pre-conditions:</dt>
          <dd>Caller is the holder of the named cell. The
              caller's wallet seed is locally available.</dd>
          <dt>Behavior:</dt>
          <dd>The holder destroys the per-cell DEK for cellId.
              The operator anchors an erasure receipt on the
              audit chain, emits a tombstone, and adds cellId to
              the public blacklist
              (<xref target="cryptographic-erasure"/>). After
              saihm_forget returns success, the cell content
              <bcp14>MUST</bcp14> be computationally
              non-recoverable by any party, including the
              operator.</dd>
          <dt>Post-conditions:</dt>
          <dd>cellId appears on the public blacklist. The DEK
              for cellId is destroyed; the ciphertext at rest is
              computationally meaningless. Subsequent
              saihm_recall calls <bcp14>MUST NOT</bcp14> return
              the cell.</dd>
          <dt>Errors:</dt>
          <dd>"not_holder", "cell_not_found", "already_erased",
              "operator_chain_unavailable".</dd>
        </dl>
      </section>

      <section anchor="tool-status"><name>saihm_status</name>
        <dl>
          <dt>Signature:</dt>
          <dd>saihm_status() -&gt; { prs, bfsi, bfsi_R, bfsi_M,
              bfsi_window_start_ts, shards, contracts,
              governance }</dd>
          <dt>Pre-conditions:</dt>
          <dd>Caller is the holder.</dd>
          <dt>Behavior:</dt>
          <dd>The operator computes the dashboard fields per the
              schema specified in this subsection (and
              CBOR-encoded in
              <xref target="wire-formats"/>).</dd>
          <dt>Post-conditions:</dt>
          <dd>The returned dashboard reflects operator-recorded
              state at the time of call. The bfsi inputs
              (bfsi_R, bfsi_M, bfsi_window_start_ts) are
              sufficient for the caller to reproduce the bfsi
              computation.</dd>
          <dt>Errors:</dt>
          <dd>None beyond transport faults.</dd>
        </dl>
        <t>Return value (an object with the following fields):</t>
        <dl>
          <dt>prs:</dt>
          <dd>IEEE 754 binary64 in the closed interval
              [0.0, 1.0]. Process Reliability Score: the
              fraction of the operator's expected tool-call
              returns delivered within the operator's published
              SLA window, computed over a rolling 30-day
              window.</dd>
          <dt>bfsi:</dt>
          <dd>
            <t>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,</t>
            <artwork align="left">
bfsi = 1 - (M / R)
            </artwork>
            <t>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)
               <bcp14>MUST</bcp14> 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.</t>
            <t>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.</t>
          </dd>
          <dt>bfsi_window_start_ts:</dt>
          <dd>Unsigned integer, UNIX epoch seconds. The start
              of the rolling 30-day window over which bfsi
              (and prs) is computed.</dd>
          <dt>bfsi_R:</dt>
          <dd>Unsigned integer. The count of operator-anchored
              receipts on the audit chain attributed to the
              holder over the window.</dd>
          <dt>bfsi_M:</dt>
          <dd>Unsigned integer. The count of those receipts
              for which no corresponding tool-call event is
              attested in the holder's local event log.</dd>
          <dt>shards:</dt>
          <dd>a CBOR map keyed by tier name, value = unsigned
              integer count of cells stored under that
              tier.</dd>
          <dt>contracts:</dt>
          <dd>a CBOR array of objects, each with fields
              contractId (32-byte hex), mode (string enum:
              "TEMPORARY" | "PERMANENT" | "SYNDICATE"),
              granteeIds (array of 32-byte hex), expiresAt
              (unsigned integer, UNIX epoch seconds).</dd>
          <dt>governance:</dt>
          <dd>a CBOR array of objects, each with fields propId
              (32-byte hex), scope (string), opens_ts
              (unsigned integer), closes_ts (unsigned
              integer), tally_for (unsigned integer),
              tally_against (unsigned integer), tally_abstain
              (unsigned integer).</dd>
        </dl>
        <t>The full CBOR schema for the saihm_status return
           appears in <xref target="wire-formats"/>.</t>
      </section>

      <section anchor="tool-share"><name>saihm_share</name>
        <dl>
          <dt>Signature:</dt>
          <dd>saihm_share(cellId: string,
              granteeAgentId: string | string[],
              mode: "TEMPORARY" | "PERMANENT" | "SYNDICATE")
              -&gt; contractId</dd>
          <dt>Pre-conditions:</dt>
          <dd>Caller is the holder of cellId.</dd>
          <dt>Behavior:</dt>
          <dd>The holder emits a signed sharing contract
              granting access per the mode semantics
              (<xref target="sharing-contracts"/>). For
              SYNDICATE mode, granteeAgentId is an array; for
              TEMPORARY and PERMANENT, granteeAgentId is a
              single value.</dd>
          <dt>Post-conditions:</dt>
          <dd>The named grantee(s) gain saihm_recall access to
              cellId per the mode's lifecycle. A share receipt
              is anchored on the audit chain.</dd>
          <dt>Errors:</dt>
          <dd>"not_holder", "cell_not_found", "invalid_mode",
              "syndicate_grantees_empty",
              "operator_chain_unavailable".</dd>
        </dl>
      </section>

      <section anchor="tool-revoke-share"><name>saihm_revoke_share</name>
        <dl>
          <dt>Signature:</dt>
          <dd>saihm_revoke_share(contractId: string) -&gt;
              revocationId</dd>
          <dt>Pre-conditions:</dt>
          <dd>Caller is the holder party to the contract named
              by contractId.</dd>
          <dt>Behavior:</dt>
          <dd>The holder emits a counter-signed
              contractRevocation. The operator ceases serving
              cell access to the contract's grantee(s) from the
              moment the revocation is anchored on chain.</dd>
          <dt>Post-conditions:</dt>
          <dd>The revocation is anchored on the audit chain.
              Subsequent saihm_recall by the grantee(s)
              <bcp14>MUST NOT</bcp14> return the cell under
              this contract.</dd>
          <dt>Errors:</dt>
          <dd>"not_holder", "contract_not_found",
              "already_revoked",
              "operator_chain_unavailable".</dd>
        </dl>
      </section>

      <section anchor="tool-governance-propose"><name>saihm_governance_propose</name>
        <dl>
          <dt>Signature:</dt>
          <dd>saihm_governance_propose(scope: string,
              payload: object) -&gt; propId</dd>
          <dt>Pre-conditions:</dt>
          <dd>Caller satisfies the deployment's
              eligibility-to-propose predicate
              (<xref target="governance-form"/>). scope is one
              of the deployment's declared proposal
              scopes.</dd>
          <dt>Behavior:</dt>
          <dd>The caller submits a signed proposal. The
              operator anchors the proposal receipt on the
              audit chain. The voting window opens.</dd>
          <dt>Post-conditions:</dt>
          <dd>A proposal with propId is published; it accepts
              saihm_governance_vote calls for the deployment's
              voting window duration.</dd>
          <dt>Errors:</dt>
          <dd>"ineligible_proposer", "unknown_scope",
              "operator_chain_unavailable".</dd>
        </dl>
      </section>

      <section anchor="tool-governance-vote"><name>saihm_governance_vote</name>
        <dl>
          <dt>Signature:</dt>
          <dd>saihm_governance_vote(propId: string,
              vote: "FOR" | "AGAINST" | "ABSTAIN") -&gt;
              voteReceipt</dd>
          <dt>Pre-conditions:</dt>
          <dd>Caller satisfies the deployment's
              eligibility-to-vote predicate
              (<xref target="governance-form"/>). propId names
              an open proposal.</dd>
          <dt>Behavior:</dt>
          <dd>The caller submits a signed vote. The operator
              anchors the vote receipt on the audit chain. The
              proposal's tally updates.</dd>
          <dt>Post-conditions:</dt>
          <dd>The vote is anchored. The proposal's tally on
              the audit chain reflects the vote per the
              deployment's vote-weight function. Vote tallies
              <bcp14>MUST</bcp14> be reproducible from the
              audit chain.</dd>
          <dt>Errors:</dt>
          <dd>"ineligible_voter", "proposal_not_found",
              "proposal_closed",
              "operator_chain_unavailable".</dd>
        </dl>
      </section>

      <section anchor="governance-form"><name>Governance form</name>
        <t>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.</t>
        <t>Every deployment <bcp14>MUST</bcp14> publish its
           governance form, comprising at least the following
           parameters, at a stable URL referenced from the
           deployment's saihm_status output:</t>
        <ol type="(%c)">
          <li>Eligibility to propose: the predicate over a
              holderId that determines whether the holder may
              submit a proposal.</li>
          <li>Eligibility to vote: the predicate over a holderId
              that determines whether the holder may cast a
              vote.</li>
          <li>Vote weight: the function mapping a holderId to a
              non-negative real number, contributing to the
              tally.</li>
          <li>Threshold: the predicate over a tally that
              determines whether a proposal passes.</li>
          <li>Voting window: the duration in seconds during
              which saihm_governance_vote calls are accepted
              for a given propId.</li>
          <li>Proposal scopes: the enumeration of permitted
              scope values for saihm_governance_propose.</li>
        </ol>
        <t>The reference governance form, used by the reference
           deployment, has the following values for the
           parameters above:</t>
        <ol type="(%c)">
          <li>Eligibility to propose: any holderId for which at
              least one saihm_remember receipt has been
              anchored on the audit chain.</li>
          <li>Eligibility to vote: same as (a).</li>
          <li>Vote weight: the holderId's balance of governance
              soul-bound tokens (SBTs) at the moment the
              proposal is anchored. SBTs are non-transferable,
              non-purchasable tokens minted to a holderId in
              exchange for verified, on-chain SAIHM protocol
              activity. The exact issuance schedule (which
              protocol events mint how many SBTs, at what
              cadence, and up to what cap) is deployment
              policy and is published at the deployment's
              governance URL.</li>
          <li>Threshold: (tally_for &gt; tally_against) AND
              (tally_for + tally_against &gt;= 0.10 * sum of
              all eligible SBT balances at proposal anchor
              time).</li>
          <li>Voting window: 1209600 seconds (14 days) from
              anchoring of the proposal receipt.</li>
          <li>Proposal scopes: enumerated at
              https://saihm.coti.global/governance.</li>
        </ol>
        <t>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)
           <bcp14>MAY</bcp14> substitute an alternative
           governance form, subject to constraints (i)-(iii)
           below.</t>
        <t>Implementations <bcp14>MAY</bcp14> substitute
           alternative governance forms (for example,
           stake-weighted, multi-signature board, or
           DAO-contract governance) so long as</t>
        <ol type="(%i)">
          <li>the saihm_governance_propose and
              saihm_governance_vote tool signatures remain
              unchanged;</li>
          <li>vote outcomes are reproducible from the audit
              chain; and</li>
          <li>the parameters (a)-(f) above are published at a
              stable URL referenced from saihm_status.</li>
        </ol>
      </section>
    </section>

    <section anchor="wire-formats"><name>Wire formats</name>
      <t>SAIHM uses Concise Binary Object Representation (CBOR)
         <xref target="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
         <bcp14>MUST</bcp14> be CBOR unsigned integers (CBOR major
         type 0); no SAIHM emitter or parser is permitted to clamp
         to a signed 32-bit window
         (<xref target="cell-shape"/>).</t>
      <t>A canonical cell payload (CBOR diagnostic notation):</t>
      <artwork align="left">
{1: h'...cellId...',
 2: h'...holderId...',
 3: 1,
 4: "FILECOIN",
 5: h'...cellNonce-16-bytes...',
 6: h'...ciphertext...',
 7: h'...signature...',
 8: 1747526400}
      </artwork>
      <t>The integer keys correspond to fields defined in
         <xref target="cell-shape"/>: 1=cellId, 2=holderId,
         3=kekVersion, 4=tier, 5=cellNonce, 6=ciphertext,
         7=signature, 8=timestamp.</t>
      <t>A canonical receipt (CBOR diagnostic notation):</t>
      <artwork align="left">
{1: h'...receiptId...',
 2: h'...cellId...',
 3: "REMEMBER",
 4: h'...holderId...',
 5: h'...signature...',
 6: 1747526400}
      </artwork>
      <t>For erasure receipts (operation = "FORGET"), the receipt
         payload's cellId field carries the cellId added to the
         blacklist (<xref target="cryptographic-erasure"/>).</t>
      <t>A canonical saihm_status return (CBOR diagnostic
         notation):</t>
      <artwork align="left">
{"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}
 ]}
      </artwork>
    </section>

    <section anchor="receipt-semantics"><name>Receipt and audit semantics</name>
      <t>For each tool call that mutates state (saihm_remember,
         saihm_forget, saihm_share, saihm_revoke_share,
         saihm_governance_propose, saihm_governance_vote), the
         operator <bcp14>MUST</bcp14> emit a receipt anchored on
         the audit chain.</t>
      <t>The receipt <bcp14>MUST</bcp14> include the operation
         type, the cellId (or contractId, or propId), the
         holderId, and the timestamp.</t>
      <t>The receipt <bcp14>MUST NOT</bcp14> include cell
         plaintext, the DEK, or the wallet seed.</t>
      <t>Receipts for erasure (saihm_forget)
         <bcp14>MUST</bcp14> also include the tombstone identifier
         and the cellId added to the blacklist
         (<xref target="cryptographic-erasure"/>).</t>
      <t>Read-only tool calls (saihm_recall, saihm_status)
         <bcp14>MAY</bcp14> emit receipts under operator policy;
         receipts for read-only calls <bcp14>MUST NOT</bcp14>
         include cell plaintext.</t>
    </section>

    <section anchor="security"><name>Security considerations</name>
      <section anchor="security-pq"><name>Post-quantum identity</name>
        <t>ML-DSA-65 <xref target="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.</t>
        <t>Implementations <bcp14>MUST</bcp14> use the FIPS-204
           parameter set named ML-DSA-65. Implementations
           <bcp14>SHOULD</bcp14> include the kekVersion in every
           signed envelope so that key-rotation events are
           themselves signed.</t>
      </section>
      <section anchor="security-key-custody"><name>Sovereign key custody</name>
        <t>The wallet seed and the derived identity key
           <bcp14>MUST NOT</bcp14> 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.</t>
        <t>This is intentional. The operator's inability to
           recover the wallet seed is the same property that
           prevents the operator from reading cell
           content.</t>
      </section>
      <section anchor="security-erasure"><name>Cryptographic erasure properties</name>
        <t>Cryptographic erasure
           (<xref target="cryptographic-erasure"/>) 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.</t>
        <t>Backups and replicas store only ciphertext. DEK
           destruction propagates erasure semantics to every
           copy of the ciphertext, anywhere, automatically. An
           operator <bcp14>MUST NOT</bcp14> cache the DEK.</t>
      </section>
      <section anchor="security-threat-model"><name>Operator threat model</name>
        <t>The protocol assumes an honest-but-curious operator:
           the operator is expected to provide storage and
           transport honestly but <bcp14>MAY</bcp14> attempt to
           learn cell content.</t>
        <t>Against an honest-but-curious operator:</t>
        <ul>
          <li>Cell plaintext is never accessible to the
              operator (encryption-before-egress + per-cell
              DEK).</li>
          <li>Cell signatures are reproducible from public
              keys, so the operator cannot inject forged
              cells.</li>
          <li>Receipt validity is verifiable against the
              public chain, so the operator cannot rewrite the
              audit trail.</li>
        </ul>
        <t>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.</t>
      </section>
    </section>

    <section anchor="privacy"><name>Privacy considerations</name>
      <section anchor="privacy-art17"><name>GDPR Article 17 alignment</name>
        <t>The saihm_forget operation provides
           cryptographic-grade evidence of erasure aligned with
           Article 17 of Regulation (EU) 2016/679
           <xref target="GDPR"/>. The DEK is destroyed; a
           tombstone is published; the cellId is blacklisted;
           and a receipt is anchored on chain.</t>
        <t>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.</t>
      </section>
      <section anchor="privacy-minimization"><name>Minimization</name>
        <t>The audit log records cellId, holderId, operation,
           and timestamp. It <bcp14>MUST NOT</bcp14> 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.</t>
      </section>
      <section anchor="privacy-audit-content"><name>Audit log content</name>
        <t>Receipts anchored on chain are public. Holders
           <bcp14>SHOULD</bcp14> treat the existence of a cell
           (cellId, holderId, timestamp) as publicly
           observable. Where the existence of a record is
           itself sensitive, holders <bcp14>SHOULD</bcp14> use
           additional countermeasures outside the scope of this
           protocol (e.g., pseudonymous holder identities,
           batched-operation timing).</t>
      </section>
    </section>

    <section anchor="iana"><name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>
  </middle>

  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <reference anchor="FIPS180-4" target="https://csrc.nist.gov/pubs/fips/180-4/upd1/final">
          <front>
            <title>Secure Hash Standard (SHS)</title>
            <author>
              <organization>National Institute of Standards and Technology</organization>
            </author>
            <date year="2015" month="August"/>
          </front>
          <seriesInfo name="FIPS" value="PUB 180-4"/>
        </reference>
        <reference anchor="FIPS204" target="https://csrc.nist.gov/pubs/fips/204/final">
          <front>
            <title>Module-Lattice-Based Digital Signature Standard</title>
            <author>
              <organization>National Institute of Standards and Technology</organization>
            </author>
            <date year="2024" month="August"/>
          </front>
          <seriesInfo name="FIPS" value="PUB 204"/>
        </reference>
        <reference anchor="IEEE-1003.1-2024" target="https://standards.ieee.org/ieee/1003.1/7700/">
          <front>
            <title>IEEE Standard for Information Technology--Portable Operating System Interface (POSIX(TM)) Base Specifications, Issue 8</title>
            <author>
              <organization>IEEE</organization>
            </author>
            <date year="2024" month="June"/>
          </front>
          <seriesInfo name="IEEE Std" value="1003.1-2024"/>
        </reference>
        <reference anchor="NIST-SP-800-38D" target="https://csrc.nist.gov/pubs/sp/800/38/d/final">
          <front>
            <title>Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC</title>
            <author initials="M." surname="Dworkin" fullname="Morris Dworkin"/>
            <date year="2007" month="November"/>
          </front>
          <seriesInfo name="NIST" value="SP 800-38D"/>
        </reference>
        <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author initials="S." surname="Bradner" fullname="Scott Bradner"/>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        <reference anchor="RFC5116" target="https://www.rfc-editor.org/info/rfc5116">
          <front>
            <title>An Interface and Algorithms for Authenticated Encryption</title>
            <author initials="D." surname="McGrew" fullname="David McGrew"/>
            <date year="2008" month="January"/>
          </front>
          <seriesInfo name="RFC" value="5116"/>
          <seriesInfo name="DOI" value="10.17487/RFC5116"/>
        </reference>
        <reference anchor="RFC5869" target="https://www.rfc-editor.org/info/rfc5869">
          <front>
            <title>HMAC-based Extract-and-Expand Key Derivation Function (HKDF)</title>
            <author initials="H." surname="Krawczyk"/>
            <author initials="P." surname="Eronen"/>
            <date year="2010" month="May"/>
          </front>
          <seriesInfo name="RFC" value="5869"/>
          <seriesInfo name="DOI" value="10.17487/RFC5869"/>
        </reference>
        <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author initials="B." surname="Leiba"/>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
        <reference anchor="RFC8949" target="https://www.rfc-editor.org/info/rfc8949">
          <front>
            <title>Concise Binary Object Representation (CBOR)</title>
            <author initials="C." surname="Bormann"/>
            <author initials="P." surname="Hoffman"/>
            <date year="2020" month="December"/>
          </front>
          <seriesInfo name="STD" value="94"/>
          <seriesInfo name="RFC" value="8949"/>
          <seriesInfo name="DOI" value="10.17487/RFC8949"/>
        </reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="AAIF" target="https://aaif.io/">
          <front>
            <title>Agentic AI Foundation</title>
            <author>
              <organization>Linux Foundation</organization>
            </author>
            <date year="2025" month="December" day="9"/>
          </front>
        </reference>
        <reference anchor="EU-AI-ACT" target="https://eur-lex.europa.eu/eli/reg/2024/1689/oj">
          <front>
            <title>Regulation (EU) 2024/1689 of the European Parliament and of the Council of 13 June 2024 (Artificial Intelligence Act)</title>
            <author>
              <organization>European Parliament and Council</organization>
            </author>
            <date year="2024" month="June"/>
          </front>
        </reference>
        <reference anchor="GDPR" target="https://eur-lex.europa.eu/eli/reg/2016/679/oj">
          <front>
            <title>Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016 (General Data Protection Regulation)</title>
            <author>
              <organization>European Parliament and Council</organization>
            </author>
            <date year="2016" month="April"/>
          </front>
        </reference>
        <reference anchor="ISO-27001">
          <front>
            <title>ISO/IEC 27001:2022 Information security management systems --- Requirements</title>
            <author>
              <organization>ISO/IEC</organization>
            </author>
            <date year="2022" month="October"/>
          </front>
        </reference>
        <reference anchor="ISO-42001">
          <front>
            <title>ISO/IEC 42001:2023 Information technology --- Artificial intelligence --- Management system</title>
            <author>
              <organization>ISO/IEC</organization>
            </author>
            <date year="2023" month="December"/>
          </front>
        </reference>
        <reference anchor="MCP" target="https://modelcontextprotocol.io/">
          <front>
            <title>Model Context Protocol Specification</title>
            <author>
              <organization>Anthropic</organization>
            </author>
            <date year="2025" month="November" day="25"/>
          </front>
          <refcontent>Donated to the Agentic AI Foundation under the Linux Foundation on 9 December 2025</refcontent>
        </reference>
        <reference anchor="NIST-AI-RMF" target="https://nvlpubs.nist.gov/nistpubs/ai/NIST.AI.100-1.pdf">
          <front>
            <title>AI Risk Management Framework 1.0</title>
            <author>
              <organization>National Institute of Standards and Technology</organization>
            </author>
            <date year="2023" month="January"/>
          </front>
          <seriesInfo name="NIST AI" value="100-1"/>
        </reference>
        <reference anchor="RFC4846" target="https://www.rfc-editor.org/info/rfc4846">
          <front>
            <title>Independent Submissions to the RFC Editor</title>
            <author initials="J." surname="Klensin"/>
            <author initials="D." surname="Thaler"/>
            <date year="2007" month="July"/>
          </front>
          <seriesInfo name="RFC" value="4846"/>
          <seriesInfo name="DOI" value="10.17487/RFC4846"/>
        </reference>
        <reference anchor="RFC8730" target="https://www.rfc-editor.org/info/rfc8730">
          <front>
            <title>Independent Submission Editor Model</title>
            <author initials="N." surname="Brownlee"/>
            <author initials="R." surname="Hinden"/>
            <date year="2020" month="February"/>
          </front>
          <seriesInfo name="RFC" value="8730"/>
          <seriesInfo name="DOI" value="10.17487/RFC8730"/>
        </reference>
      </references>
    </references>

    <section anchor="appendix-deployment" numbered="true" toc="default">
      <name>Reference deployment</name>
      <t>The reference SAIHM deployment runs on the COTI V2 Helium
         mainnet (chain ID 2632500). Protocol implementations
         <bcp14>MAY</bcp14> 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.</t>
      <t>The reference deployment publishes:</t>
      <ul>
        <li>npm reference implementation: @saihm/mcp-server (Apache
            2.0).</li>
        <li>Block explorer for chain receipts:
            https://mainnet.cotiscan.io.</li>
        <li>Crosswalks to NIST AI RMF
            <xref target="NIST-AI-RMF"/>, ISO/IEC 42001
            <xref target="ISO-42001"/>, ISO/IEC 27001
            <xref target="ISO-27001"/>, EU AI Act
            <xref target="EU-AI-ACT"/>, GDPR Article 17
            <xref target="GDPR"/>, and MCP
            <xref target="MCP"/> at
            https://saihm.coti.global/standards.</li>
      </ul>
    </section>

    <section anchor="appendix-worked-example" numbered="true" toc="default">
      <name>Worked example</name>
      <t>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
         <bcp14>MUST NOT</bcp14> be used for production cells.</t>

      <section anchor="appendix-seq-diagram"><name>Lifecycle sequence diagram</name>
        <t>The canonical lifecycle saihm_remember -&gt;
           saihm_recall -&gt; saihm_share -&gt;
           saihm_revoke_share -&gt; saihm_forget, with the
           actor (holder agent, operator, public chain) and
           the message at each hop:</t>
        <artwork align="left"><![CDATA[
 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         |                       |
      |<--------------------|                       |
]]></artwork>
      </section>

      <section anchor="appendix-crypto-values"><name>Cryptographic example values</name>
        <t>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.</t>

        <t>Test wallet seed (32 bytes, hex), derived as
           SHA-256("SAIHM-TEST-VECTOR-001-DO-NOT-USE-IN-PRODUCTION"):</t>
        <artwork align="left">
walletSeed (TEST) =
  f068b8db8484d33bdbedd154bf5bf28e11fba330b79469e23595d6f738d7f5c6
        </artwork>

        <t>HKDF identity derivation
           (<xref target="identity-binding"/>):</t>
        <artwork align="left">
identityKey =
  HKDF(salt = "MPS-PQC-KEY-GEN-v1",
       IKM  = walletSeed,
       info = "MPS-AGENT-IDENTITY-v1",
       L    = 64 bytes)
       =
  fdf786da8cb1f074393f9ad6dec1671e08085540e95c8463c9f2e15f437bbc5a
  2c267aeaf355e79d8968cc21846cdff7e16f498437de3d6b1fd290703eeed9c2
        </artwork>

        <t>holderId (32 bytes, hex), presented as the test
           holder's protocol-level identifier:</t>
        <artwork align="left">
holderId (TEST) =
  ab4f746fd1520d2736854559d6751969ae9127f5dbc607d7298acbf1afb1f588
        </artwork>

        <t>KEK generation: kekVersion = 1.</t>

        <t>Per-cell nonce (16 bytes, hex):</t>
        <artwork align="left">
cellNonce =
  25bd74b827789faacad8ffb7593c2359
        </artwork>

        <t>Cell plaintext:</t>
        <artwork align="left">
plaintext =
  "Hello, SAIHM. This is a test memory cell."
        </artwork>

        <t>DEK derivation
           (<xref target="encryption-envelope"/>):</t>
        <artwork align="left">
DEK =
  HKDF(salt = KEK_v (4-byte big-endian of kekVersion=1),
       IKM  = identityKey,
       info = cellNonce || "MPS-CELL-DEK-v1",
       L    = 32 bytes)
       =
  a1e54f730c6c7a1048ae436c9d2b179821c6eddd7841f41e36215285f3ffd07a
        </artwork>

        <t>AEAD encryption (AES-256-GCM,
           <xref target="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:</t>
        <artwork align="left">
ciphertext (57 bytes, including 16-byte GCM tag) =
  595b0b9f77a8d95f29c5affa151bbcc18fdc3f7e5223792627919ee2d52f2bf2
  4933c35de4c1755559bee818ef54b48a388bcdd2e4a30fbde8
        </artwork>

        <t>cellId derivation
           (<xref target="cell-shape"/>):</t>
        <artwork align="left">
cellId =
  SHA-256( kekVersion_be32 || cellNonce || ciphertext )
       =
  d851960a5b7754c5884c96bef5d615e666c8ad006e4ceebe028cd85aae8e7c2f
        </artwork>

        <t>timestamp = 1747526400 (UTC 2025-05-18T00:00:00Z;
           encoded as 8 bytes big-endian when used in
           signature concatenation).</t>

        <t>signature: ML-DSA-65 (<xref target="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:</t>
        <artwork align="left">
signature (first 32 of 3309 bytes) =
  dba1109b3d53e17290914cdb2e639c6cdad37aff8184537ba9b2c05c7fe8a994
  ... (3277 more bytes) ...
        </artwork>
      </section>

      <section anchor="appendix-cbor-walkthrough"><name>CBOR encoding walkthrough</name>
        <t>The canonical CBOR encoding of the example cell, per
           the schema in <xref target="wire-formats"/>:</t>
        <artwork align="left">
{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}
        </artwork>
        <t>Byte-level CBOR encoding (with one line of commentary
           per field; ML-DSA-65 signature bytes elided for
           brevity):</t>
        <artwork align="left"><![CDATA[
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)
]]></artwork>
        <t>The corresponding write receipt (operation =
           "REMEMBER"), per the schema in
           <xref target="wire-formats"/>:</t>
        <artwork align="left">
{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}
        </artwork>
      </section>
    </section>
  </back>
</rfc>
