Decentralized trust (KERI and ToIP)
Companion Memory is a personal memory bank holding messages, photos, financial documents, health records, and private communications. Building federated peer-to-peer interactions across such sensitive archives requires an identity and trust architecture that eliminates centralized intermediaries, third-party token brokers, and single points of surveillance.
To achieve this, Companion Memory implements the Trust Over IP (ToIP) dual-stack architecture using Key Event Receipt Infrastructure (KERI).
Why traditional identity models fail personal memory
Existing identity architectures create unacceptable failure modes when applied to private personal memory:
flowchart TD
subgraph Centralized["1. Centralized Identity (OAuth / OIDC / Google / Apple)"]
CentralServer["Centralized identity provider"]
CentralServer -->|Issues bearer tokens| Box1["Companion A"]
CentralServer -->|Revokes / suspends account| Box2["Companion B"]
style CentralServer fill:#f87171,color:#fff
end
subgraph Blockchain["2. Public Ledger DIDs (did:ion, did:cheqd, did:indy)"]
Chain["Public blockchain / distributed ledger"]
Chain -->|Gas fees, slow confirmation| Box3["Companion C"]
Chain -->|Public metadata correlation| Box4["Companion D"]
style Chain fill:#fbbf24,color:#000
end
subgraph KERI["3. Autonomic Identity (KERI / ToIP)"]
BoxA["Companion A<br/>did:keri:D..."] <-->|Direct pairwise P2P verification<br/>No ledger, zero cloud broker| BoxB["Companion B<br/>did:keri:D..."]
style BoxA fill:#34d399,color:#000
style BoxB fill:#34d399,color:#000
end| Identity model | The fatal flaw for personal memory |
|---|---|
| Centralized OIDC / OAuth | Surveillance and dependency. A centralized token server (such as Google, Apple, or Companion Portal) knows every time Companion A communicates with Companion B, can revoke access at will, and can suffer outages that paralyze peer communication. |
| Public Blockchain DIDs | Cost, latency, and permanent correlation. Every key rotation costs gas fees and takes minutes to confirm. Worse, public ledgers permanently record transaction timestamps and transaction graphs, creating permanent correlation trails that violate privacy rights. |
Domain-based DIDs (did:web) | DNS and CA vulnerability. If a domain expires, changes hands, or experiences a DNS hijacking, the owner’s entire identity and historical trust graph is severed or compromised. |
| Autonomic Identity (KERI) | Sovereign, ledgerless, and secure. Identity is rooted directly in the controller’s cryptographic keys. Rotations are recorded in lightweight, pairwise Key Event Logs (KEL). No cloud server, blockchain, or domain authority is needed. |
KERI core primitives
KERI operates on the principle that identity should be autonomic—self-contained and self-governing.
flowchart LR
subgraph KEL["Key Event Log (KEL)"]
direction LR
ICP["Inception Event (icp)<br/>Keys: K0<br/>Next commitment: H(K1)"] --> ROT1["Rotation Event (rot)<br/>Reveals: K1<br/>Next commitment: H(K2)"]
ROT1 --> ROT2["Rotation Event (rot)<br/>Reveals: K2<br/>Next commitment: H(K3)"]
ROT2 --> IXN["Interaction Event (ixn)<br/>Anchors grant SAID<br/>Keys unchanged"]
end1. Autonomic Identifiers (AIDs)
An AID is a decentralized identifier that self-certifies its controller:
- Basic identifier (
did:keri:D...): For single-key edge devices (such as a local Companion Hub), the AID is the Ed25519 public key itself, encoded in Composable Event Streaming Representation (CESR). - Self-addressing identifier (
did:keri:E...): For personas and appliances with rotatable keys, the identifier is the cryptographic digest of the inception event (icp). The identifier never changes, even when private keys are rotated.
2. Key Event Logs (KEL)
An entity’s history is recorded in an immutable, append-only Key Event Log:
icp(Inception): Establishes the AID, the initial signing key, the pre-rotation hash, and configuration parameters.rot(Rotation): Rotates the signing authority to a new key pair while simultaneously establishing a commitment to the subsequent key pair.ixn(Interaction): Seals and anchors external data (such as standing grant SAIDs) without changing the active signing keys.
3. Pre-rotation commitments (quantum and compromise defense)
Pre-rotation is KERI’s signature cryptographic innovation. During every key generation, two key pairs are minted:
- Current signing key (
K0): Used to sign requests and assertions. - Next key pair (
K1): Kept completely offline in secure storage. Only its cryptographic hash,H(K1), is published in thenxtfield of the current event.
sequenceDiagram
autonumber
participant Active as Active Signing Key (K0)
participant Cold as Cold Offline Key (K1)
participant Ledger as Public KEL Stream
Note over Active,Cold: Inception: Controller publishes K0 and H(K1)
Active->>Ledger: Event 0: icp (keys: K0, nxt: H(K1))
Note over Active: Attacker compromises K0
Note over Active: Attacker attempts to rotate keys...
Active--xLedger: Attacker cannot sign Event 1 because they do not have K1
Note over Cold: Honest controller detects compromise and rotates:
Cold->>Ledger: Event 1: rot (keys: K1, nxt: H(K2), signed by K1)
Note over Ledger: Event 1 is cryptographically valid.<br/>Attacker is permanently locked outEven if an attacker gains root access to the active appliance and steals K0, they cannot hijack the AID because they cannot create a valid rotation event without K1.
Composable Event Streaming Representation (CESR)
Companion Memory uses CESR for binary-text dual representation. CESR allows cryptographic data (public keys, signatures, and digests) to be streamed over standard JSON or binary protocols with zero ambiguity:
| Selector prefix | Meaning | Byte size | Formatted length | Example |
|---|---|---|---|---|
B | Ed25519 public key | 32 bytes | 44 characters | B4Xz... |
D | Basic Ed25519 AID prefix | 32 bytes | 44 characters | did:keri:D4Xz... |
E | SHA-256 digest / SAID | 32 bytes | 44 characters | EP8k... |
0A | Ed25519 signature | 64 bytes | 88 characters | 0ACd... |
Because CESR specifies the exact cryptographic primitive in its prefix code, verifiers know which algorithm to apply without out-of-band metadata negotiation.
Self-Addressing Identifiers (SAID) for audit non-repudiation
Companion Memory uses SAIDs (RFC 8785 canonical JSON with embedded Blake3 or SHA-256 digests) to make consent grants and audit records tamper-evident:
flowchart TD
Obj["1. Raw audit record<br/>askId, asker, responder, outcome, disclosedCount"] --> Place["2. Inject 44-character placeholder<br/>d: '############################################'"]
Place --> Canon["3. Deterministic canonical stringification<br/>(RFC 8785: alphabetical key sorting)"]
Canon --> Hash["4. SHA-256 hash calculation"]
Hash --> Embed["5. Embed CESR digest into field d<br/>d: 'EXz9...44chars'"]
Embed --> FinalDoc["6. Verifiable Self-Addressing Document"]The verification property
When either party needs to verify the authenticity of an audit record:
- Replace field
dwithSAID_PLACEHOLDER_44(#repeated 44 times). - Serialize canonically.
- Compute the SHA-256 digest.
- Verify that
computedDigest === originalValue(d).
If a single byte of the query, response count, or timestamp was tampered with, the digest fails to match, providing cryptographic proof of tampering.
Out-of-Band Introductions (OOBI)
Companions establish bilateral peer relationships using OOBI URLs:
https://hub.example.com/.well-known/keri/oobi/did:keri:D4Xz9a8b...When two users pair their Companions:
sequenceDiagram
autonumber
actor Alice as Alice
participant AppA as Alice's Hub
participant AppB as Bob's Hub
actor Bob as Bob
Bob->>AppB: Generate pairing QR code / OOBI
Bob->>Alice: Share OOBI link via secure channel (Signal, QR)
Alice->>AppA: Enter Bob's OOBI URL
AppA->>AppB: GET /.well-known/keri/oobi/:bobAid
AppB-->>AppA: Return Bob's KEL & active endpoint
AppA->>AppA: Verify Bob's KEL inception event & key state
AppA->>AppA: Create Peer Link (status: active, peerIssuer: 'did:keri', peerSubject: bobAid)
AppA-->>Alice: Bob verified and linkedNeither party needs to contact Companion Portal or any centralized server during this exchange. The link is established directly between the two appliances. (If CI_PEER_DIRECTORY_URL is configured, users can optionally publish and resolve handles via the Companion Portal peer directory at /api/peers/resolve/:handle as a convenience discovery step before verifying the peer’s KEL directly.)
Solving the three federation failure modes
The KERI integration in Companion Memory directly resolves three critical architectural vulnerabilities:
1. Eliminating the centralized token dependency (Gap G3)
- Previous behavior:
/agent/v1/askrequired a Companion Portal OIDC bearer token addressed to the responder’s configuredpeers.audience. If Companion Portal went offline, or if two users were running off-grid without internet access, federated asks failed completely. - KERI solution: If a request carries an RFC 9421 HTTP Message Signature signed by a verified KERI AID (
keyid="did:keri:..."), Companion Memory authenticates the peer directly as{ issuer: 'did:keri', subject: keyid }. Asks work offline over local LAN or private mesh networks.
2. Ending username and directory drift
- Previous behavior: Hub forward-auth identified users by email address or ephemeral directory UUIDs. If a user changed their email, or if a Hub was restored onto a fresh database with a new directory UUID, the user was placed into an empty account, losing their memory graph.
- KERI solution: Companion Hub derives a permanent sovereign AID (
did:keri:<user-aid>) from the user’s immutable public ID. Companion Memory indexes(issuer: 'did:keri', subject: userAid)inci.federated_identities. Renaming an address or reinstalling Hub never detaches the user from their memory database.
3. Cryptographic grant revocation without policy leakage
- Previous behavior: Revoking a permission required notifying external peers or synchronizing a shared policy file, which could leak when and why a relationship cooled.
- KERI solution: Grants are represented as Authentic Chained Data Containers (ACDC) governed by Transaction Event Logs (TEL). Revoking a grant writes a
revevent to the local TEL. When an incoming ask arrives, the responder’s engine verifies the local TEL and denies the ask with standarddeliveredstatus, without revealing revocation reasons to the asker.
Related
- Asking and sharing architecture — the ToIP 4-layer dual stack, six-rung disclosure ladder, and five ADR invariants
- Asking other Companions — screen-by-screen guide to
/asksand how request signing appears in the UI - System architecture — forward-auth headers (
X-CI-Hub-User-AID,X-CI-Hub-AID) and storage architecture - Use cases and workflows — concrete RFC 9421 signed ask and SAID audit examples