@atbash/sdk 0.7.2-dev.0 → 0.9.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -281,6 +281,16 @@ interface AtbashOptions {
281
281
  * per-call `verifyPubKey` still overrides it.
282
282
  */
283
283
  verifyPubKey?: string;
284
+ /**
285
+ * Org's encryption public key (33-byte compressed secp256k1, hex). When set,
286
+ * tool calls are sealed to it and signed as `log_encrypted_tool_call` instead
287
+ * of `log_tool_call`, so the action never reaches the block in clear.
288
+ *
289
+ * Required for any org that has registered a key — the contract refuses
290
+ * plaintext for those. Omitted, behaviour is unchanged. A per-call
291
+ * `orgEncryptionPubKey` overrides this, same as `verifyPubKey`.
292
+ */
293
+ orgEncryptionPubKey?: string;
284
294
  /** When true (default), `auditToolCall` denies on any error. */
285
295
  failClosed?: boolean;
286
296
  logger?: AtbashLogger;
@@ -332,6 +342,8 @@ interface JudgeOptions {
332
342
  provider?: string;
333
343
  model?: string;
334
344
  verifyPubKey?: string;
345
+ /** Per-call override of {@link AtbashOptions.orgEncryptionPubKey}. */
346
+ orgEncryptionPubKey?: string;
335
347
  /**
336
348
  * Org name — when set, the SDK resolves which chain the agent lives
337
349
  * on via the off-chain `org_networks` map (authoritative) before
@@ -360,6 +372,8 @@ interface LogToolCallOptions {
360
372
  toolArgsJson?: string;
361
373
  /** Per-call chain override — same semantics as `JudgeOptions.chainOpts`. */
362
374
  chainOpts?: ChainOpts;
375
+ /** Per-call override of {@link AtbashOptions.orgEncryptionPubKey}. */
376
+ orgEncryptionPubKey?: string;
363
377
  }
364
378
 
365
379
  interface ChainConfig {
@@ -377,6 +391,8 @@ declare class Atbash {
377
391
  readonly orgName?: string;
378
392
  /** Default judge response-signing pubkey, if configured (see fromConfig). */
379
393
  readonly verifyPubKey?: string;
394
+ /** Default org encryption key — see {@link AtbashOptions.orgEncryptionPubKey}. */
395
+ readonly orgEncryptionPubKey?: string;
380
396
  /** When true (default), `auditToolCall` denies on any error. */
381
397
  readonly failClosed: boolean;
382
398
  private readonly logger;
@@ -1051,11 +1067,163 @@ declare function flushTelemetry(): Promise<void>;
1051
1067
  */
1052
1068
  declare function shutdownTelemetry(): Promise<void>;
1053
1069
 
1070
+ /**
1071
+ * Signs `log_encrypted_tool_call` — the ciphertext-only counterpart of
1072
+ * `log_tool_call`.
1073
+ *
1074
+ * Why this is not in the Rust core like the other signing helpers: the operation
1075
+ * takes a `byte_array` argument, and the only consumer today is the dashboard,
1076
+ * which loads the browser bundle where Rust is unreachable by construction. This
1077
+ * module is plain TypeScript so the node and browser builds share one
1078
+ * implementation and cannot drift. The Rust core gets the same operation when the
1079
+ * native/Python/Go callers need it — the wire format is pinned by `crypto/ecies.ts`.
1080
+ *
1081
+ * The contract refuses plaintext once an org registers an encryption key
1082
+ * (`log_tool_call` → "Organization requires encrypted payloads"), so for those
1083
+ * orgs this is the only way to log a tool call at all.
1084
+ */
1085
+ /**
1086
+ * Commitment to the plaintext claims a caller sends alongside the ciphertext.
1087
+ *
1088
+ * The judge server reads tool_name / action / context / tool_args_json from the
1089
+ * request body and feeds them to policy evaluation, but it holds no org key, so
1090
+ * it cannot check them against content_cipher. This hash is a signed operation
1091
+ * argument, which makes it the one thing it can check them against.
1092
+ *
1093
+ * An array, not an object: key order is not part of a JSON array, so the two
1094
+ * implementations cannot drift on serialization. Must stay identical to
1095
+ * `claimHashHex` in the dashboard (`src/lib/api/judge/action-hash.ts`).
1096
+ */
1097
+ declare function claimHashHex(toolName: string, action: string, context: string, toolArgsJson: string): string;
1098
+ /** Plaintext fields of a tool call, sealed into a single ECIES payload. */
1099
+ interface ToolCallPlaintext {
1100
+ tool_name: string;
1101
+ action: string;
1102
+ context: string;
1103
+ tool_args_json: string;
1104
+ }
1105
+ /**
1106
+ * Canonical form of an action for the retry-cache hash.
1107
+ *
1108
+ * Must stay identical to `normalizeActionForHash` in the dashboard
1109
+ * (`src/lib/api/judge/on-chain.ts`): both write the same
1110
+ * `tool_call_log.normalized_action_hash` column, and `get_resolved_hold_by_action_hash`
1111
+ * matches a YELLOW hold retry against it. Diverging here silently breaks
1112
+ * hold resolution rather than failing loudly.
1113
+ */
1114
+ declare function normalizeActionForHash(action: string): string;
1115
+ /**
1116
+ * Sign a `log_encrypted_tool_call` operation.
1117
+ *
1118
+ * Everything the agent did — action, context, tool name and args — goes into a
1119
+ * single ECIES payload readable only with the org's private key. Nothing
1120
+ * identifying the action is left in the operation arguments, which are permanent
1121
+ * block data.
1122
+ *
1123
+ * `actionHash` is the one exception, and it is deliberate: it is a SHA-256 over
1124
+ * the normalized action, so the chain can match a held action against its retry
1125
+ * without being able to read it.
1126
+ *
1127
+ * @returns hex-encoded signed transaction, ready to POST as `signed_log_tool_call`.
1128
+ */
1129
+ declare function signEncryptedToolCall(toolCallId: string, action: string, context: string, toolName: string, toolArgsJson: string, orgEncryptionPubKey: string, privkeyHex: string, blockchainRidHex: string): string;
1130
+
1131
+ /**
1132
+ * ECIES over secp256k1 — encrypts on-chain payloads to an organization's public key.
1133
+ *
1134
+ * Only the holder of the org's private key can decrypt. Everyone else — including
1135
+ * anyone querying the Chromia node directly, and Atbash itself — sees ciphertext.
1136
+ * The recipient key is a dedicated encryption keypair the org generates in the
1137
+ * dashboard and registers via `org_set_encryption_key`; it is read back with the
1138
+ * `get_org_encryption_pubkey` query.
1139
+ *
1140
+ * ─── WIRE FORMAT (normative) ────────────────────────────────────────────────
1141
+ * This exact layout is mirrored in the Atbash dashboard
1142
+ * (`src/lib/chromia/ecies.ts`) and must stay byte-for-byte identical: the SDK
1143
+ * encrypts tool calls, the dashboard decrypts them.
1144
+ *
1145
+ * version 1 byte = 0x01
1146
+ * ephemeral_pubkey 33 bytes compressed secp256k1 point
1147
+ * nonce 12 bytes random, per message
1148
+ * ciphertext+tag N bytes AES-256-GCM output (16-byte tag appended)
1149
+ *
1150
+ * Version 0x01 is FROZEN, not provisional. Records encrypted under it already
1151
+ * exist on the deployed chains, and the ledger is immutable — redefining 0x01
1152
+ * would make them permanently unreadable, not merely stale. Evolving the format
1153
+ * means emitting a NEW version byte and keeping a 0x01 decrypt path, in both
1154
+ * repos, forever.
1155
+ *
1156
+ * Raw bytes, not base64: the on-chain columns are `byte_array`, so encoding to
1157
+ * text would add ~33% to what are the largest columns in the schema.
1158
+ *
1159
+ * Key agreement, per message:
1160
+ * shared_x = ECDH(ephemeral_privkey, org_pubkey).x // 32 bytes
1161
+ * key = HKDF-SHA256(ikm=shared_x, salt=ephemeral_pubkey, info=domain, len=32)
1162
+ * aad = "<domain>|<record_id>"
1163
+ *
1164
+ * A fresh ephemeral keypair is generated for every message and its private half is
1165
+ * discarded immediately. This is what makes the scheme forward-secret with respect
1166
+ * to the *sender*: leaking an agent's long-term signing key later does not expose
1167
+ * anything it encrypted in the past. (Deriving the shared secret from the agent's
1168
+ * static key instead would let anyone recompute every past shared secret, since the
1169
+ * org's public key is public by definition.)
1170
+ *
1171
+ * Three separate bindings, each closing a different substitution:
1172
+ * salt = ephemeral pubkey — ties the key to this exact handshake
1173
+ * info = domain — a verdict payload cannot be read as a tool call
1174
+ * aad = domain|record_id — a payload cannot be lifted onto another row
1175
+ */
1176
+ /**
1177
+ * Cryptographic domain per payload kind. Fed to HKDF `info`, so each kind derives
1178
+ * a different key from the same handshake — a verdict payload handed to the
1179
+ * tool-call reader fails authentication rather than decoding to an empty struct.
1180
+ *
1181
+ * Must match `EciesDomain` in the dashboard's src/lib/chromia/ecies.ts exactly:
1182
+ * the string is an input to key derivation, so any difference makes the two sides
1183
+ * mutually unreadable.
1184
+ */
1185
+ declare const EciesDomain: {
1186
+ readonly toolCall: "atbash:chain-encryption:v1:toolcall";
1187
+ readonly verdict: "atbash:chain-encryption:v1:verdict";
1188
+ readonly note: "atbash:chain-encryption:v1:note";
1189
+ readonly policy: "atbash:chain-encryption:v1:policy";
1190
+ readonly raw: "atbash:chain-encryption:v1:raw";
1191
+ };
1192
+ type EciesDomain = (typeof EciesDomain)[keyof typeof EciesDomain];
1193
+ /**
1194
+ * Encrypt `plaintext` so that only the holder of `orgPubKeyHex` can read it.
1195
+ *
1196
+ * @param plaintext UTF-8 text to protect.
1197
+ * @param orgPubKeyHex Org's compressed secp256k1 public key (33 bytes hex).
1198
+ * @param aad Context bound to the ciphertext — pass the record's id.
1199
+ * @returns raw payload for a Rell `byte_array` column.
1200
+ */
1201
+ declare function encryptForOrg(plaintext: string, orgPubKeyHex: string, aad: string, domain?: EciesDomain): Uint8Array;
1202
+ /**
1203
+ * Decrypt a payload produced by {@link encryptForOrg}.
1204
+ *
1205
+ * Throws if the key is wrong, the `aad` does not match the one used at encrypt
1206
+ * time, or the ciphertext was tampered with — GCM authentication makes all three
1207
+ * indistinguishable by design.
1208
+ *
1209
+ * @param payload Value read from the on-chain `byte_array` column.
1210
+ * @param orgPrivKeyHex Org's secp256k1 private key (32 bytes hex).
1211
+ * @param aad Must equal the `aad` used when encrypting.
1212
+ */
1213
+ declare function decryptForOrg(payload: Uint8Array, orgPrivKeyHex: string, aad: string, domain?: EciesDomain): string;
1214
+ /**
1215
+ * Size in bytes of the encrypted payload for a given plaintext length. Lets
1216
+ * callers check against the on-chain column cap (MAX_CONTENT_CIPHER_SIZE)
1217
+ * before submitting a transaction the contract would reject.
1218
+ */
1219
+ declare function encryptedLength(plaintextByteLength: number): number;
1220
+
1054
1221
  declare function isValidPrivateKey(hex: string): boolean;
1055
1222
  declare function derivePublicKey(privkey: string): string;
1056
1223
  declare function generateKeypair(): KeyPair;
1057
1224
  declare function loadAgent(privkey: string): AgentAuth;
1058
1225
  declare function signLogToolCall(toolCallId: string, action: string, context: string, toolName: string, toolArgsJson: string, privkey: string, blockchainRid: string): string;
1226
+
1059
1227
  declare function signJudgeAction(judgmentId: string, action: string, context: string, extra: string, privkey: string, blockchainRid: string): string;
1060
1228
  declare function verifySignature(body: Buffer, signatureHex: string, pubkeyHex: string): boolean;
1061
1229
  declare function normalizeForMatching(text: string): string;
@@ -1065,4 +1233,4 @@ declare function containsSecret(text: string): boolean;
1065
1233
  declare function createMemorySnapshot(entries: MemoryEntry[], takenAt: number): MemorySnapshot;
1066
1234
  declare function diffMemorySnapshots(before: MemorySnapshot, after: MemorySnapshot): MemoryDiffResult;
1067
1235
 
1068
- export { type ActionType, type AgentAuth, type AgentMemoryEntry, type AgentPolicy, type AnomalySeverity, type AnomalyType, Atbash, AtbashAPIError, type AtbashLogger, type AtbashOptions, type AtbashUserConfig, type ChainOpts, type ClassifierToolContext, type ClassifierToolEvent, type ClassifyMemoryReadOptions, type ClassifyMemoryWriteOptions, type ClientSource, type CommitMemoryOptions, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, DEFAULT_MEMORY_PATH_PATTERNS, DEFAULT_MEMORY_READ_TOOL_NAMES, DEFAULT_MEMORY_WRITE_TOOL_NAMES, type Decision, type DecisionVerdict, type EncryptedMemory, type FromConfigOptions, type GuardLogger, type GuardMemoryDecision, type GuardMemoryWriteInput, type GuardMemoryWriteResult, type HeldAction, type HeldActionReview, type HookDecision, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentState, type JudgmentStatus, type KeyPair, type LogToolCallOptions, type LogToolCallResult, type MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, MemoryGuardManager, type MemoryGuardManagerOptions, MemoryIntegrityError, type MemoryPointer, type MemoryRollbackEvent, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type ModifiedEntry, type Network, type OrgSubscription, PointerStore, type Provider, type PubkeyValue, type RedactResult, type RollbackMemoryOptions, type SecretKind, type SecretMatch, SignatureVerificationError, type Subscription, type SyncMemoryOptions, type SyncMemoryResult, type TelemetryConfig, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, type WrappedLogger, classifyMemoryRead, classifyMemoryWrite, commitMemoryVersion, containsEvasionCharacters, containsSecret, createFileLogger, createMemoryGuardManager, createMemorySnapshot, decryptMemoryContent, defaultPluginLogPath, defaultPointerPath, deriveMemoryKey, derivePublicKey, diffMemorySnapshots, encryptMemoryContent, flushTelemetry, generateKeypair, getActiveMemory, getActiveMemoryId, getAllAgentMemory, getConfigDir, getConfigPath, getMemoryById, getMemoryHistory, getRollbackHistory, guardMemoryWrite, isValidPrivateKey, loadAgent, loadAgentFromFile, loadUserConfig, normalizeForMatching, normalizeStatus, normalizeVerdict, pubkeyToHex, recordCall, recordDuration, redactJsonStrings, redactSecrets, resolve, resolveKeyPath, rollbackMemory, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, signJudgeAction, signLogToolCall, syncLocalMemory, validateJudgeEndpoint, verifyJudgeResponseSignature, verifySignature };
1236
+ export { type ActionType, type AgentAuth, type AgentMemoryEntry, type AgentPolicy, type AnomalySeverity, type AnomalyType, Atbash, AtbashAPIError, type AtbashLogger, type AtbashOptions, type AtbashUserConfig, type ChainOpts, type ClassifierToolContext, type ClassifierToolEvent, type ClassifyMemoryReadOptions, type ClassifyMemoryWriteOptions, type ClientSource, type CommitMemoryOptions, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, DEFAULT_MEMORY_PATH_PATTERNS, DEFAULT_MEMORY_READ_TOOL_NAMES, DEFAULT_MEMORY_WRITE_TOOL_NAMES, type Decision, type DecisionVerdict, EciesDomain, type EncryptedMemory, type FromConfigOptions, type GuardLogger, type GuardMemoryDecision, type GuardMemoryWriteInput, type GuardMemoryWriteResult, type HeldAction, type HeldActionReview, type HookDecision, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentState, type JudgmentStatus, type KeyPair, type LogToolCallOptions, type LogToolCallResult, type MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, MemoryGuardManager, type MemoryGuardManagerOptions, MemoryIntegrityError, type MemoryPointer, type MemoryRollbackEvent, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type ModifiedEntry, type Network, type OrgSubscription, PointerStore, type Provider, type PubkeyValue, type RedactResult, type RollbackMemoryOptions, type SecretKind, type SecretMatch, SignatureVerificationError, type Subscription, type SyncMemoryOptions, type SyncMemoryResult, type TelemetryConfig, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallPlaintext, type ToolCallRecord, type ValidatedEndpoint, type Verdict, type WrappedLogger, claimHashHex, classifyMemoryRead, classifyMemoryWrite, commitMemoryVersion, containsEvasionCharacters, containsSecret, createFileLogger, createMemoryGuardManager, createMemorySnapshot, decryptForOrg, decryptMemoryContent, defaultPluginLogPath, defaultPointerPath, deriveMemoryKey, derivePublicKey, diffMemorySnapshots, encryptForOrg, encryptMemoryContent, encryptedLength, flushTelemetry, generateKeypair, getActiveMemory, getActiveMemoryId, getAllAgentMemory, getConfigDir, getConfigPath, getMemoryById, getMemoryHistory, getRollbackHistory, guardMemoryWrite, isValidPrivateKey, loadAgent, loadAgentFromFile, loadUserConfig, normalizeActionForHash, normalizeForMatching, normalizeStatus, normalizeVerdict, pubkeyToHex, recordCall, recordDuration, redactJsonStrings, redactSecrets, resolve, resolveKeyPath, rollbackMemory, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, signEncryptedToolCall, signJudgeAction, signLogToolCall, syncLocalMemory, validateJudgeEndpoint, verifyJudgeResponseSignature, verifySignature };