@sovereignclaw/memory
v0.1.0
Published
Sovereign memory primitives for SovereignClaw - encrypted, revocable, 0G-backed.
Downloads
128
Maintainers
Readme
@sovereignclaw/memory
Sovereign, encrypted, revocable memory primitives for SovereignClaw agents.
Storage backends are pluggable (InMemory for tests, OG_Log for 0G Storage)
and any backend can be wrapped with encrypted(...) to get authenticated
client-side encryption (AES-256-GCM, KEK derived from an EOA signer).
Install
pnpm add @sovereignclaw/memory ethers10-line quickstart
import { JsonRpcProvider, Wallet } from 'ethers';
import { OG_Log, encrypted, deriveKekFromSigner } from '@sovereignclaw/memory';
const signer = new Wallet(process.env.PRIVATE_KEY!, new JsonRpcProvider(process.env.RPC_URL!));
const kek = await deriveKekFromSigner(signer, 'my-agent');
const memory = encrypted(
OG_Log({
namespace: 'my-agent',
rpcUrl: process.env.RPC_URL!,
indexerUrl: process.env.INDEXER_URL!,
signer,
}),
{ kek },
);
await memory.set('greeting', new TextEncoder().encode('hello from sovereignclaw'));
const value = await memory.get('greeting'); // plaintext Uint8Array; ciphertext on the logAPI
| Export | Kind | Purpose |
| ----------------------------- | --------- | ------------------------------------------------------------------- |
| MemoryProvider | interface | get / set / delete / list / flush / close over keyed byte values. |
| InMemory(opts) | adapter | Process-local backend. Namespaced. Used by tests and coordination. |
| OG_Log(opts) | adapter | 0G Storage Log backend. Writes envelopes; keeps a pointer tree. |
| encrypted(provider, opts) | wrapper | AES-256-GCM around any provider. KEK in, keys/ciphertext out. |
| deriveKekFromSigner | fn | EIP-191 sign a namespaced message, keccak256 → 32-byte KEK. |
| encryptValue / decryptValue | fn | Lower-level GCM helpers with AAD binding. |
| buildAad | fn | Builds the canonical AAD for a (namespace, key, version) tuple. |
| TOMBSTONE / isTombstone | const/fn | Delete marker sentinel for append-only stores. |
| readEnvelopeByRoot | fn | Low-level: read a single envelope by its 0G root hash. |
Errors
All typed; all extend MemoryError:
| Error | When |
| -------------------------- | ---------------------------------------------------------------- |
| DecryptionError | Envelope failed to decrypt (wrong KEK, wrong AAD, corrupt data). |
| TamperingDetectedError | GCM tag mismatch — the envelope was tampered with in transit. |
| MalformedCiphertextError | Envelope header didn’t match the expected v1 layout. |
| StorageError | Backend rejected a read/write for a non-SDK reason. |
| StorageSdkError | 0G SDK threw or the indexer returned a transient fee/node error. |
| InvalidKeyError | KEK is not 32 bytes / AAD is malformed. |
| KeyDerivationError | deriveKekFromSigner failed (usually the signer refused). |
| ProviderClosedError | Operation after provider.close(). |
What’s sovereign about this
- Plaintext never leaves the wallet.
encrypted()encrypts before any network call. Anyone with only the indexer can read ciphertext. - The KEK is reproducible. Derived from an EOA signature over a namespaced message, so the same wallet + namespace always gets the same KEK — no key storage service.
- Append-only with tombstones.
delete(key)writes a tombstone, not a physical erase. Combined withAgentNFT.revoke()and the oracle’s revocation registry, this is how iNFT memory becomes unreadable.
Further reading
docs/architecture.md— layered diagram + trust model.docs/benchmarks.md— measured numbers and methodology.docs/dev-log.md— phase-by-phase design decisions.
License
MIT — see the repo root.
