/** * Persistence — encrypt a heart's state to disk and rehydrate it later. * * A heart is valuable: it holds the signing key that IS the agent's identity, * the credentials that let it compute, the heartbeat chain that records its * history. When the process dies, all of that vanishes. Persistence lets an * operator save the heart at shutdown and reload it on boot — same DID, same * credentials, continuous heartbeat chain. * * State is protected with a password-derived key and the crypto provider's * symmetric encryption (default: XSalsa20-Poly1305). * * Default KDF is **scrypt** (memory-hard, OWASP-recommended parameters). * PBKDF2-SHA256 is kept for decrypting legacy blobs written before the * migration — new writes always use scrypt. This closes audit limit #5 * where PBKDF2 alone was vulnerable to GPU/ASIC brute force. * * Format (JSON, scrypt): * { * v: 1, * kdf: "scrypt", * N: 131072, r: 8, p: 1, * saltB64: "...", * nonceB64: "...", * ciphertextB64: "...", * alg: "xsalsa20-poly1305" * } * * Sessions are NOT persisted — they are ephemeral by design. Rehydrating a * heart does not resume its conversations; those must be reestablished. */ import { type CryptoProvider, type SignKeyPair } from '../core/crypto-provider.js'; import type { GenomeCommitment } from '../core/genome.js'; import type { Heartbeat } from './heartbeat.js'; import type { RevocationEvent } from './revocation.js'; import type { LineageCertificate } from './lineage.js'; /** Encrypted credential as stored in the vault. */ export interface SerializedCredential { name: string; nonceB64: string; ciphertextB64: string; } /** The subset of heart state that survives serialization. */ export interface HeartState { /** Format version for forward compatibility. */ version: 1; /** Genome commitment (public). */ genome: GenomeCommitment; /** Signing key pair — base64-encoded for JSON. */ signingKey: { publicKeyB64: string; secretKeyB64: string; }; /** Model config. */ modelId: string; modelBaseUrl: string; /** Data source configs (headers with auth keys are in credentials). */ dataSources: Array<{ name: string; url: string; headers?: Record; }>; /** Credential vault contents (already encrypted with key derived from signingKey). */ credentials: SerializedCredential[]; /** Global heartbeat chain contents. */ heartbeats: Heartbeat[]; /** Revocations this heart is aware of. */ revocations: RevocationEvent[]; /** Lineage chain this heart carries, if any. */ lineageChain?: LineageCertificate[]; /** Root DID of the lineage, if any. */ lineageRootDid?: string; /** When this state was captured. */ savedAt: number; } /** Legacy PBKDF2 blob — can still be decrypted but new writes use scrypt. */ export interface Pbkdf2Blob { v: 1; kdf: 'pbkdf2-sha256'; iterations: number; saltB64: string; nonceB64: string; ciphertextB64: string; alg: string; } /** scrypt blob — default format for all new writes (memory-hard, OWASP-recommended). */ export interface ScryptBlob { v: 1; kdf: 'scrypt'; N: number; r: number; p: number; saltB64: string; nonceB64: string; ciphertextB64: string; alg: string; } /** Encrypted blob format — what gets written to disk. */ export type EncryptedBlob = Pbkdf2Blob | ScryptBlob; /** scrypt tuning parameters for new writes. */ export interface ScryptParams { N?: number; r?: number; p?: number; } /** * Encrypt a HeartState with a password. * Returns a JSON string safe to write to disk. * * New writes always use scrypt (memory-hard). To override parameters, * pass `scrypt: { N, r, p }`. Defaults match OWASP 2023 recommendations. */ export declare function serializeHeart(state: HeartState, password: string, opts?: { scrypt?: ScryptParams; provider?: CryptoProvider; }): string; /** * Decrypt a serialized heart blob and return the HeartState. * Throws on wrong password or tampered blob. * * Supports both scrypt (current) and PBKDF2-SHA256 (legacy) blobs. */ export declare function loadHeartState(blob: string, password: string, opts?: { provider?: CryptoProvider; }): HeartState; export declare function signKeyPairToJson(kp: SignKeyPair, provider?: CryptoProvider): { publicKeyB64: string; secretKeyB64: string; }; export declare function signKeyPairFromJson(json: { publicKeyB64: string; secretKeyB64: string; }, provider?: CryptoProvider): SignKeyPair; //# sourceMappingURL=persistence.d.ts.map