@agirails/sdk 4.4.8 → 4.5.2

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.
Files changed (99) hide show
  1. package/dist/builders/DeliveryProofBuilder.d.ts +224 -13
  2. package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -1
  3. package/dist/builders/DeliveryProofBuilder.js +247 -13
  4. package/dist/builders/DeliveryProofBuilder.js.map +1 -1
  5. package/dist/cli/agirails.d.ts +85 -1
  6. package/dist/cli/agirails.d.ts.map +1 -1
  7. package/dist/cli/agirails.js +429 -154
  8. package/dist/cli/agirails.js.map +1 -1
  9. package/dist/cli/commands/init.d.ts +54 -0
  10. package/dist/cli/commands/init.d.ts.map +1 -1
  11. package/dist/cli/commands/init.js +193 -1
  12. package/dist/cli/commands/init.js.map +1 -1
  13. package/dist/cli/commands/receipt.d.ts +70 -2
  14. package/dist/cli/commands/receipt.d.ts.map +1 -1
  15. package/dist/cli/commands/receipt.js +218 -3
  16. package/dist/cli/commands/receipt.js.map +1 -1
  17. package/dist/cli/commands/test.d.ts +77 -1
  18. package/dist/cli/commands/test.d.ts.map +1 -1
  19. package/dist/cli/commands/test.js +264 -2
  20. package/dist/cli/commands/test.js.map +1 -1
  21. package/dist/cli/lib/runRequest.d.ts +90 -0
  22. package/dist/cli/lib/runRequest.d.ts.map +1 -1
  23. package/dist/cli/lib/runRequest.js +300 -9
  24. package/dist/cli/lib/runRequest.js.map +1 -1
  25. package/dist/cli/lib/sentinelReflections.d.ts +111 -0
  26. package/dist/cli/lib/sentinelReflections.d.ts.map +1 -0
  27. package/dist/cli/lib/sentinelReflections.js +193 -0
  28. package/dist/cli/lib/sentinelReflections.js.map +1 -0
  29. package/dist/delivery/MockDeliveryChannel.d.ts +208 -0
  30. package/dist/delivery/MockDeliveryChannel.d.ts.map +1 -0
  31. package/dist/delivery/MockDeliveryChannel.js +445 -0
  32. package/dist/delivery/MockDeliveryChannel.js.map +1 -0
  33. package/dist/delivery/RelayDeliveryChannel.d.ts +176 -0
  34. package/dist/delivery/RelayDeliveryChannel.d.ts.map +1 -0
  35. package/dist/delivery/RelayDeliveryChannel.js +377 -0
  36. package/dist/delivery/RelayDeliveryChannel.js.map +1 -0
  37. package/dist/delivery/channel.d.ts +282 -0
  38. package/dist/delivery/channel.d.ts.map +1 -0
  39. package/dist/delivery/channel.js +76 -0
  40. package/dist/delivery/channel.js.map +1 -0
  41. package/dist/delivery/channelLog.d.ts +115 -0
  42. package/dist/delivery/channelLog.d.ts.map +1 -0
  43. package/dist/delivery/channelLog.js +94 -0
  44. package/dist/delivery/channelLog.js.map +1 -0
  45. package/dist/delivery/crypto.d.ts +312 -0
  46. package/dist/delivery/crypto.d.ts.map +1 -0
  47. package/dist/delivery/crypto.js +495 -0
  48. package/dist/delivery/crypto.js.map +1 -0
  49. package/dist/delivery/eip712.d.ts +248 -0
  50. package/dist/delivery/eip712.d.ts.map +1 -0
  51. package/dist/delivery/eip712.js +397 -0
  52. package/dist/delivery/eip712.js.map +1 -0
  53. package/dist/delivery/envelopeBuilder.d.ts +531 -0
  54. package/dist/delivery/envelopeBuilder.d.ts.map +1 -0
  55. package/dist/delivery/envelopeBuilder.js +832 -0
  56. package/dist/delivery/envelopeBuilder.js.map +1 -0
  57. package/dist/delivery/index.d.ts +53 -0
  58. package/dist/delivery/index.d.ts.map +1 -0
  59. package/dist/delivery/index.js +143 -0
  60. package/dist/delivery/index.js.map +1 -0
  61. package/dist/delivery/keys.d.ts +344 -0
  62. package/dist/delivery/keys.d.ts.map +1 -0
  63. package/dist/delivery/keys.js +513 -0
  64. package/dist/delivery/keys.js.map +1 -0
  65. package/dist/delivery/nonce-keys.d.ts +93 -0
  66. package/dist/delivery/nonce-keys.d.ts.map +1 -0
  67. package/dist/delivery/nonce-keys.js +88 -0
  68. package/dist/delivery/nonce-keys.js.map +1 -0
  69. package/dist/delivery/setupBuilder.d.ts +403 -0
  70. package/dist/delivery/setupBuilder.d.ts.map +1 -0
  71. package/dist/delivery/setupBuilder.js +554 -0
  72. package/dist/delivery/setupBuilder.js.map +1 -0
  73. package/dist/delivery/types.d.ts +722 -0
  74. package/dist/delivery/types.d.ts.map +1 -0
  75. package/dist/delivery/types.js +150 -0
  76. package/dist/delivery/types.js.map +1 -0
  77. package/dist/delivery/validate.d.ts +288 -0
  78. package/dist/delivery/validate.d.ts.map +1 -0
  79. package/dist/delivery/validate.js +648 -0
  80. package/dist/delivery/validate.js.map +1 -0
  81. package/dist/level1/Agent.d.ts +130 -0
  82. package/dist/level1/Agent.d.ts.map +1 -1
  83. package/dist/level1/Agent.js +248 -0
  84. package/dist/level1/Agent.js.map +1 -1
  85. package/dist/level1/types/Options.d.ts +62 -0
  86. package/dist/level1/types/Options.d.ts.map +1 -1
  87. package/dist/level1/types/Options.js +22 -0
  88. package/dist/level1/types/Options.js.map +1 -1
  89. package/dist/runtime/MockRuntime.d.ts +32 -0
  90. package/dist/runtime/MockRuntime.d.ts.map +1 -1
  91. package/dist/runtime/MockRuntime.js +44 -0
  92. package/dist/runtime/MockRuntime.js.map +1 -1
  93. package/dist/wallet/aa/BundlerClient.d.ts.map +1 -1
  94. package/dist/wallet/aa/BundlerClient.js +18 -3
  95. package/dist/wallet/aa/BundlerClient.js.map +1 -1
  96. package/dist/wallet/aa/PaymasterClient.d.ts.map +1 -1
  97. package/dist/wallet/aa/PaymasterClient.js +4 -1
  98. package/dist/wallet/aa/PaymasterClient.js.map +1 -1
  99. package/package.json +6 -1
@@ -0,0 +1,513 @@
1
+ "use strict";
2
+ /**
3
+ * AIP-16 Delivery Surface — X25519 Keys, ECDH, HKDF (Phase 2a Foundation)
4
+ * ========================================================================
5
+ *
6
+ * Cryptographic primitives for the encrypted delivery scheme
7
+ * (`x25519-aes256gcm-v1`) of AIP-16 Rev 5.
8
+ *
9
+ * This module is intentionally *primitive-level* — it deals only in
10
+ * raw key material (Uint8Array), 0x-prefixed hex serialization, and
11
+ * the three numbered steps of the ECDH+HKDF derivation:
12
+ *
13
+ * 1. Generate an ephemeral X25519 keypair.
14
+ * 2. Combine the local secret with the peer's public key (ECDH on
15
+ * Curve25519, per RFC 7748) to produce a 32-byte shared secret.
16
+ * 3. Stretch the shared secret to a 32-byte AES-256-GCM key via
17
+ * HKDF-SHA256 (RFC 5869), using the on-chain `txId` as the salt
18
+ * and `"agirails-delivery-v1"` as the info string.
19
+ *
20
+ * AEAD encryption itself, body framing, and EIP-712 signing live in
21
+ * later phases (`crypto.ts`, `envelopeBuilder.ts`); this file is
22
+ * deliberately small so it can be audited end-to-end.
23
+ *
24
+ * ## Library choice
25
+ *
26
+ * X25519 is implemented via `@noble/curves/ed25519` (audited, no
27
+ * native deps, constant-time on supported runtimes). HKDF-SHA256 is
28
+ * provided by Node's built-in `crypto.hkdfSync` — chosen over
29
+ * `@noble/hashes` to minimize the new-dependency surface. Both choices
30
+ * are deterministic and have no global state.
31
+ *
32
+ * ## Memory hygiene
33
+ *
34
+ * Private key material returned by `generateEphemeralKeyPair` is held
35
+ * in plain `Uint8Array`s. The intent of "ephemeral" in AIP-16 is that
36
+ * the caller derives the session key and then drops the reference to
37
+ * the private key. Forward secrecy against compromise of long-term
38
+ * provider/requester keys is provided by *fresh keypair per delivery*;
39
+ * there is no key-rotation mechanism within a single delivery exchange.
40
+ *
41
+ * Callers SHOULD avoid logging `EphemeralKeyPair.privateKey` or any
42
+ * value derived from it.
43
+ *
44
+ * ## What is NOT here
45
+ *
46
+ * - AES-256-GCM seal/open (later: `crypto.ts`).
47
+ * - keccak256 hashing of body bytes (uses ethers in builders).
48
+ * - EIP-712 signing (already in `eip712.ts`).
49
+ * - Smart-wallet equality checks (later: verifier modules).
50
+ *
51
+ * @module delivery/keys
52
+ * @see {@link https://www.rfc-editor.org/rfc/rfc7748 RFC 7748 — Elliptic Curves for Security (X25519)}
53
+ * @see {@link https://www.rfc-editor.org/rfc/rfc5869 RFC 5869 — HKDF}
54
+ * @see ./types — `DeliveryErrorCode` (crypto_* codes referenced here)
55
+ * @see ./eip712 — EIP-712 domain & recovery (the *other* foundation module)
56
+ */
57
+ Object.defineProperty(exports, "__esModule", { value: true });
58
+ exports.pubkeyFromHex = exports.pubkeyToHex = exports.deriveSessionKey = exports.deriveSharedSecret = exports.generateEphemeralKeyPair = exports.DeliveryCryptoError = exports.DELIVERY_HKDF_INFO_V1 = exports.TX_ID_BYTES = exports.DELIVERY_SESSION_KEY_LENGTH = exports.X25519_SHARED_SECRET_LENGTH = exports.X25519_PRIVATE_KEY_LENGTH = exports.X25519_PUBLIC_KEY_LENGTH = void 0;
59
+ const node_crypto_1 = require("node:crypto");
60
+ const ed25519_1 = require("@noble/curves/ed25519");
61
+ // ============================================================================
62
+ // Constants
63
+ // ============================================================================
64
+ /**
65
+ * Length (in bytes) of an X25519 public key. RFC 7748 §5.
66
+ *
67
+ * Both the buyer's `buyerEphemeralPubkey` field and the provider's
68
+ * `providerEphemeralPubkey` field in the signed EIP-712 payloads carry
69
+ * exactly this many bytes (encoded as `bytes32` in the typed-data
70
+ * schema; X25519 keys happen to also be 32 bytes, which is why a
71
+ * single `bytes32` slot fits).
72
+ */
73
+ exports.X25519_PUBLIC_KEY_LENGTH = 32;
74
+ /**
75
+ * Length (in bytes) of an X25519 private key (clamped scalar). RFC 7748 §5.
76
+ *
77
+ * Equal to {@link X25519_PUBLIC_KEY_LENGTH}, which is coincidence — the
78
+ * scalar field of Curve25519 is 252 bits but is encoded into a 32-byte
79
+ * little-endian field with the canonical clamping applied by
80
+ * `@noble/curves`.
81
+ */
82
+ exports.X25519_PRIVATE_KEY_LENGTH = 32;
83
+ /**
84
+ * Length (in bytes) of the X25519 shared secret produced by ECDH.
85
+ *
86
+ * Per RFC 7748 the shared secret is the 32-byte little-endian encoding
87
+ * of the resulting u-coordinate.
88
+ */
89
+ exports.X25519_SHARED_SECRET_LENGTH = 32;
90
+ /**
91
+ * Length (in bytes) of the session key derived from HKDF. Sized for
92
+ * AES-256-GCM (the only AEAD scheme defined for `x25519-aes256gcm-v1`).
93
+ */
94
+ exports.DELIVERY_SESSION_KEY_LENGTH = 32;
95
+ /**
96
+ * Length (in bytes) of an on-chain `txId` (`bytes32`).
97
+ *
98
+ * The txId is used directly as the HKDF salt: it is high-entropy
99
+ * (keccak256 of requester/provider/amount/serviceHash/nonce) and
100
+ * unique per transaction, satisfying RFC 5869's salt recommendation
101
+ * ("a non-secret random value, ideally hash-output length").
102
+ */
103
+ exports.TX_ID_BYTES = 32;
104
+ /**
105
+ * HKDF `info` string for v1 delivery session-key derivation.
106
+ *
107
+ * Per RFC 5869 the `info` parameter provides context binding so that
108
+ * the same `(ikm, salt)` pair produces distinct keys for distinct
109
+ * application contexts. Locking this string at v1 prevents accidental
110
+ * key reuse with any future delivery scheme that lands in v2.
111
+ *
112
+ * Encoded as UTF-8 bytes when passed to `hkdfSync`.
113
+ */
114
+ exports.DELIVERY_HKDF_INFO_V1 = 'agirails-delivery-v1';
115
+ // ============================================================================
116
+ // Error Class
117
+ // ============================================================================
118
+ /**
119
+ * Error thrown by the delivery key primitives when key material or
120
+ * ECDH/HKDF inputs are malformed, or when the derivation produces a
121
+ * degenerate result (e.g. all-zero shared secret indicating a
122
+ * low-order peer pubkey).
123
+ *
124
+ * Mirrors the `DeliveryEip712Error` pattern from `./eip712.ts` — a
125
+ * plain `Error` subclass with a stable `code` field. The codes here
126
+ * are drawn from the `crypto_*` subset of {@link DeliveryErrorCode}.
127
+ *
128
+ * The higher-level `ACTPError`-based delivery class is introduced
129
+ * alongside the builders/verifiers in a later phase; for the
130
+ * pre-builder foundation we keep the dependency surface minimal (no
131
+ * `ACTPError` import, no `State` import).
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * try {
136
+ * const shared = deriveSharedSecret(myPriv, peerPub);
137
+ * } catch (err) {
138
+ * if (err instanceof DeliveryCryptoError) {
139
+ * console.error(err.code, err.message, err.details);
140
+ * }
141
+ * throw err;
142
+ * }
143
+ * ```
144
+ */
145
+ class DeliveryCryptoError extends Error {
146
+ constructor(code, message, details) {
147
+ super(message);
148
+ this.name = 'DeliveryCryptoError';
149
+ this.code = code;
150
+ this.details = details;
151
+ // Restore prototype chain for `instanceof` after transpilation to ES5.
152
+ Object.setPrototypeOf(this, DeliveryCryptoError.prototype);
153
+ }
154
+ }
155
+ exports.DeliveryCryptoError = DeliveryCryptoError;
156
+ // ============================================================================
157
+ // Internal Helpers
158
+ // ============================================================================
159
+ /** Hex alphabet for fast lowercase encoding without `.toLowerCase()` overhead. */
160
+ const HEX_CHARS = '0123456789abcdef';
161
+ /**
162
+ * Encode raw bytes to a lowercase 0x-prefixed hex string.
163
+ *
164
+ * Hand-rolled rather than `Buffer.from(...).toString('hex')` to avoid
165
+ * any subtle Buffer-vs-Uint8Array confusion (Buffer is a Node-only
166
+ * subclass that overrides several typed-array methods). The output is
167
+ * pure ASCII so there is no encoding ambiguity.
168
+ *
169
+ * @internal
170
+ */
171
+ function bytesToHexLower(bytes) {
172
+ let out = '0x';
173
+ for (let i = 0; i < bytes.length; i++) {
174
+ const b = bytes[i]; // bounded by loop
175
+ out += HEX_CHARS[(b >>> 4) & 0x0f];
176
+ out += HEX_CHARS[b & 0x0f];
177
+ }
178
+ return out;
179
+ }
180
+ /**
181
+ * Decode a 0x-prefixed hex string to raw bytes. Strict on shape: the
182
+ * string MUST start with `0x` (or `0X`), MUST contain only hex digits
183
+ * after the prefix, and MUST have an even number of hex digits.
184
+ *
185
+ * Throws {@link DeliveryCryptoError} with code `crypto_keygen_failed`
186
+ * (the most-applicable existing code) for malformed input. The
187
+ * specific failure reason is in the error `message` and `details`.
188
+ *
189
+ * @internal
190
+ */
191
+ function hexToBytes(hex, ctx) {
192
+ if (typeof hex !== 'string') {
193
+ throw new DeliveryCryptoError('crypto_keygen_failed', `${ctx.field} must be a string, got ${typeof hex}`, { field: ctx.field, type: typeof hex });
194
+ }
195
+ if (hex.length < 2 || (hex[0] !== '0' || (hex[1] !== 'x' && hex[1] !== 'X'))) {
196
+ throw new DeliveryCryptoError('crypto_keygen_failed', `${ctx.field} must start with 0x prefix`, { field: ctx.field, prefix: hex.slice(0, 4) });
197
+ }
198
+ const body = hex.slice(2);
199
+ if (body.length !== ctx.expectedLength * 2) {
200
+ throw new DeliveryCryptoError('crypto_keygen_failed', `${ctx.field} must be ${ctx.expectedLength * 2} hex chars after 0x (got ${body.length})`, { field: ctx.field, expectedHexChars: ctx.expectedLength * 2, actualHexChars: body.length });
201
+ }
202
+ if (!/^[0-9a-fA-F]*$/.test(body)) {
203
+ throw new DeliveryCryptoError('crypto_keygen_failed', `${ctx.field} contains non-hex characters`, { field: ctx.field });
204
+ }
205
+ const out = new Uint8Array(ctx.expectedLength);
206
+ for (let i = 0; i < ctx.expectedLength; i++) {
207
+ const hi = parseInt(body[i * 2], 16);
208
+ const lo = parseInt(body[i * 2 + 1], 16);
209
+ out[i] = (hi << 4) | lo;
210
+ }
211
+ return out;
212
+ }
213
+ /**
214
+ * Branded assertion that `value` is exactly `length` bytes long.
215
+ * Throws {@link DeliveryCryptoError} with the supplied code on
216
+ * mismatch. Used to guard the public ECDH/HKDF entry points.
217
+ *
218
+ * @internal
219
+ */
220
+ function assertByteLength(value, length, code, field) {
221
+ if (!(value instanceof Uint8Array)) {
222
+ throw new DeliveryCryptoError(code, `${field} must be a Uint8Array, got ${typeof value}`, { field, type: typeof value });
223
+ }
224
+ if (value.length !== length) {
225
+ throw new DeliveryCryptoError(code, `${field} must be exactly ${length} bytes (got ${value.length})`, { field, expectedLength: length, actualLength: value.length });
226
+ }
227
+ }
228
+ /**
229
+ * Check whether a buffer is *entirely* zero. Used to detect degenerate
230
+ * ECDH outputs (peer pubkey was a low-order Curve25519 point — all
231
+ * such points map to the zero shared secret, allowing a malicious peer
232
+ * to force a known key).
233
+ *
234
+ * Implemented as an OR-fold rather than `bytes.every(b => b === 0)` so
235
+ * the JIT can hoist the loop; the constant-time properties of this
236
+ * particular check are not security-critical (the secret would have
237
+ * leaked regardless).
238
+ *
239
+ * @internal
240
+ */
241
+ function isAllZero(bytes) {
242
+ let acc = 0;
243
+ for (let i = 0; i < bytes.length; i++) {
244
+ acc |= bytes[i];
245
+ }
246
+ return acc === 0;
247
+ }
248
+ // ============================================================================
249
+ // Public API: Key Generation
250
+ // ============================================================================
251
+ /**
252
+ * Generate a fresh X25519 ephemeral keypair using the system CSPRNG
253
+ * (via `@noble/curves`, which delegates to `crypto.getRandomValues` /
254
+ * `node:crypto.randomBytes`).
255
+ *
256
+ * The returned pair is intended to live for a *single* delivery
257
+ * exchange:
258
+ * - Buyer side: generated when constructing the `DeliverySetup`,
259
+ * public key embedded into `buyerEphemeralPubkey`, private key
260
+ * held in memory until the envelope arrives and is decrypted.
261
+ * - Provider side: generated when sealing the envelope, public key
262
+ * embedded into `providerEphemeralPubkey`, private key used to
263
+ * derive the shared secret and then dropped (forward secrecy w.r.t.
264
+ * long-term provider keys).
265
+ *
266
+ * @returns A new {@link EphemeralKeyPair}.
267
+ * @throws {DeliveryCryptoError} `crypto_keygen_failed` if the
268
+ * underlying library returns key material of unexpected length
269
+ * (defensive — should never happen with `@noble/curves` on a
270
+ * conformant runtime).
271
+ *
272
+ * @example
273
+ * ```typescript
274
+ * const kp = generateEphemeralKeyPair();
275
+ * // kp.publicKeyHex → "0x" + 64-hex-char ephemeral pubkey
276
+ * // pass kp.publicKey to deriveSharedSecret(myPriv, theirPub) on the peer
277
+ * ```
278
+ */
279
+ function generateEphemeralKeyPair() {
280
+ let secretKey;
281
+ let publicKey;
282
+ try {
283
+ const generated = ed25519_1.x25519.keygen();
284
+ secretKey = generated.secretKey;
285
+ publicKey = generated.publicKey;
286
+ }
287
+ catch (err) {
288
+ throw new DeliveryCryptoError('crypto_keygen_failed', `Underlying X25519 keygen failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err.message : String(err) });
289
+ }
290
+ // Defensive length checks: @noble/curves SHOULD return 32-byte values,
291
+ // but we guard so a regression in the library doesn't silently feed
292
+ // malformed key material into ECDH downstream.
293
+ if (!(publicKey instanceof Uint8Array) || publicKey.length !== exports.X25519_PUBLIC_KEY_LENGTH) {
294
+ throw new DeliveryCryptoError('crypto_keygen_failed', `X25519 keygen returned public key of unexpected length: ${publicKey?.length}`, { actualLength: publicKey?.length, expectedLength: exports.X25519_PUBLIC_KEY_LENGTH });
295
+ }
296
+ if (!(secretKey instanceof Uint8Array) || secretKey.length !== exports.X25519_PRIVATE_KEY_LENGTH) {
297
+ throw new DeliveryCryptoError('crypto_keygen_failed', `X25519 keygen returned private key of unexpected length: ${secretKey?.length}`, { actualLength: secretKey?.length, expectedLength: exports.X25519_PRIVATE_KEY_LENGTH });
298
+ }
299
+ return {
300
+ publicKey,
301
+ privateKey: secretKey,
302
+ publicKeyHex: bytesToHexLower(publicKey),
303
+ };
304
+ }
305
+ exports.generateEphemeralKeyPair = generateEphemeralKeyPair;
306
+ // ============================================================================
307
+ // Public API: ECDH
308
+ // ============================================================================
309
+ /**
310
+ * Compute the X25519 ECDH shared secret between a local private key
311
+ * and a peer's public key.
312
+ *
313
+ * Per RFC 7748, the shared secret is `X25519(privateKey, peerPubkey)`
314
+ * — the 32-byte little-endian encoding of the u-coordinate of the
315
+ * scalar multiplication. Both inputs MUST be exactly 32 bytes;
316
+ * X25519 itself accepts any 32-byte scalar (the canonical clamping
317
+ * is applied internally by `@noble/curves`), but malformed lengths
318
+ * indicate caller bugs.
319
+ *
320
+ * ## Low-order point check
321
+ *
322
+ * Curve25519 has a small set of "low-order" public keys for which
323
+ * the ECDH output is the all-zero secret regardless of the local
324
+ * private key. A peer that supplies a low-order pubkey can therefore
325
+ * force a known shared secret. We detect this by rejecting all-zero
326
+ * outputs with `crypto_shared_secret_failed`; the caller MUST treat
327
+ * this as a peer-protocol violation, not a transient error.
328
+ *
329
+ * (See RFC 7748 §6.1, which notes that implementations "MAY" reject
330
+ * such inputs; for AGIRAILS we MUST.)
331
+ *
332
+ * @param privateKey - Local X25519 private scalar, exactly 32 bytes.
333
+ * @param peerPubkey - Peer's X25519 public key, exactly 32 bytes.
334
+ * @returns The 32-byte shared secret (NOT the session key — see
335
+ * {@link deriveSessionKey} for the HKDF stretch).
336
+ * @throws {DeliveryCryptoError} `crypto_shared_secret_failed` if
337
+ * either input is the wrong length, if `@noble/curves` raises, or
338
+ * if the resulting shared secret is all-zero (degenerate peer).
339
+ *
340
+ * @example
341
+ * ```typescript
342
+ * const shared = deriveSharedSecret(buyerPriv, providerPub);
343
+ * const key = deriveSessionKey(shared, txId);
344
+ * // → 32-byte AES-256-GCM key
345
+ * ```
346
+ */
347
+ function deriveSharedSecret(privateKey, peerPubkey) {
348
+ assertByteLength(privateKey, exports.X25519_PRIVATE_KEY_LENGTH, 'crypto_shared_secret_failed', 'privateKey');
349
+ assertByteLength(peerPubkey, exports.X25519_PUBLIC_KEY_LENGTH, 'crypto_shared_secret_failed', 'peerPubkey');
350
+ let shared;
351
+ try {
352
+ shared = ed25519_1.x25519.getSharedSecret(privateKey, peerPubkey);
353
+ }
354
+ catch (err) {
355
+ throw new DeliveryCryptoError('crypto_shared_secret_failed', `X25519 ECDH failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err.message : String(err) });
356
+ }
357
+ if (!(shared instanceof Uint8Array) || shared.length !== exports.X25519_SHARED_SECRET_LENGTH) {
358
+ throw new DeliveryCryptoError('crypto_shared_secret_failed', `X25519 ECDH returned unexpected length: ${shared?.length}`, { actualLength: shared?.length, expectedLength: exports.X25519_SHARED_SECRET_LENGTH });
359
+ }
360
+ if (isAllZero(shared)) {
361
+ throw new DeliveryCryptoError('crypto_shared_secret_failed', 'X25519 ECDH produced an all-zero shared secret (peer pubkey is a ' +
362
+ 'low-order Curve25519 point). Treat the peer as malicious.', { peerPubkeyHex: bytesToHexLower(peerPubkey) });
363
+ }
364
+ return shared;
365
+ }
366
+ exports.deriveSharedSecret = deriveSharedSecret;
367
+ // ============================================================================
368
+ // Public API: HKDF
369
+ // ============================================================================
370
+ /**
371
+ * Stretch an X25519 shared secret into a 32-byte AES-256-GCM session
372
+ * key via HKDF-SHA256 (RFC 5869).
373
+ *
374
+ * The derivation parameters are locked for AIP-16 v1:
375
+ * - `ikm` = `sharedSecret` (32 bytes, output of {@link deriveSharedSecret})
376
+ * - `salt` = `txId` (32 bytes, decoded from the 0x-prefixed hex form)
377
+ * - `info` = `"agirails-delivery-v1"` UTF-8 by default (overridable
378
+ * for *testing only* via the optional `info` argument —
379
+ * production callers MUST use the default)
380
+ * - `digest` = SHA-256
381
+ * - `keylen` = 32 bytes
382
+ *
383
+ * Salting with the on-chain `txId` binds the session key to a
384
+ * specific ACTP transaction. Even if two parties exchange the same
385
+ * ephemeral keypairs across two different transactions (which would
386
+ * itself be a protocol violation), the resulting session keys would
387
+ * differ — limiting blast radius.
388
+ *
389
+ * ## Implementation choice: node:crypto
390
+ *
391
+ * We use Node's built-in `crypto.hkdfSync` rather than `@noble/hashes`
392
+ * to keep the dependency surface minimal. The behavior is identical:
393
+ * both implementations follow RFC 5869 step-for-step.
394
+ *
395
+ * Note that `hkdfSync` returns an `ArrayBuffer`; we wrap it in a
396
+ * `Uint8Array` view for ergonomic interop with `@noble/curves` and
397
+ * the rest of the SDK.
398
+ *
399
+ * @param sharedSecret - The 32-byte ECDH output from {@link deriveSharedSecret}.
400
+ * @param txId - The on-chain transaction id (`bytes32`) as a 0x-prefixed
401
+ * lowercase hex string (66 chars total).
402
+ * @param info - Optional info string override. Defaults to
403
+ * {@link DELIVERY_HKDF_INFO_V1}. Production callers MUST omit this
404
+ * argument; it exists solely so tests can assert that distinct
405
+ * info strings produce distinct keys (negative test).
406
+ * @returns A 32-byte session key suitable for AES-256-GCM.
407
+ * @throws {DeliveryCryptoError} `crypto_hkdf_failed` on length mismatch,
408
+ * malformed `txId`, or underlying `hkdfSync` failure.
409
+ *
410
+ * @example
411
+ * ```typescript
412
+ * const key = deriveSessionKey(shared, '0xabc…32bytes…');
413
+ * // → 32-byte Uint8Array, ready for createCipheriv('aes-256-gcm', key, nonce)
414
+ * ```
415
+ */
416
+ function deriveSessionKey(sharedSecret, txId, info = exports.DELIVERY_HKDF_INFO_V1) {
417
+ assertByteLength(sharedSecret, exports.X25519_SHARED_SECRET_LENGTH, 'crypto_hkdf_failed', 'sharedSecret');
418
+ // Decode txId to bytes for use as HKDF salt. Reusing hexToBytes
419
+ // (with crypto_keygen_failed code) is unfortunate; we re-throw with
420
+ // the correct crypto_hkdf_failed code so the caller can branch on
421
+ // the *operation* that failed, not the helper that detected it.
422
+ let salt;
423
+ try {
424
+ salt = hexToBytes(txId, { expectedLength: exports.TX_ID_BYTES, field: 'txId' });
425
+ }
426
+ catch (err) {
427
+ throw new DeliveryCryptoError('crypto_hkdf_failed', `txId is malformed: ${err instanceof Error ? err.message : String(err)}`, {
428
+ txIdPreview: typeof txId === 'string' ? txId.slice(0, 12) : typeof txId,
429
+ cause: err instanceof Error ? err.message : String(err),
430
+ });
431
+ }
432
+ if (typeof info !== 'string') {
433
+ throw new DeliveryCryptoError('crypto_hkdf_failed', `info must be a string, got ${typeof info}`, { type: typeof info });
434
+ }
435
+ let derived;
436
+ try {
437
+ // hkdfSync(digest, ikm, salt, info, keylen)
438
+ derived = (0, node_crypto_1.hkdfSync)('sha256', sharedSecret, salt, Buffer.from(info, 'utf8'), exports.DELIVERY_SESSION_KEY_LENGTH);
439
+ }
440
+ catch (err) {
441
+ throw new DeliveryCryptoError('crypto_hkdf_failed', `HKDF-SHA256 failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err.message : String(err) });
442
+ }
443
+ const sessionKey = new Uint8Array(derived);
444
+ if (sessionKey.length !== exports.DELIVERY_SESSION_KEY_LENGTH) {
445
+ throw new DeliveryCryptoError('crypto_hkdf_failed', `HKDF returned unexpected length: ${sessionKey.length}`, {
446
+ actualLength: sessionKey.length,
447
+ expectedLength: exports.DELIVERY_SESSION_KEY_LENGTH,
448
+ });
449
+ }
450
+ return sessionKey;
451
+ }
452
+ exports.deriveSessionKey = deriveSessionKey;
453
+ // ============================================================================
454
+ // Public API: Hex Format Helpers
455
+ // ============================================================================
456
+ /**
457
+ * Serialize a 32-byte X25519 public key to its canonical 0x-prefixed
458
+ * lowercase hex form.
459
+ *
460
+ * This is exactly the form embedded into the `bytes32` slots of the
461
+ * signed EIP-712 payloads (`buyerEphemeralPubkey`,
462
+ * `providerEphemeralPubkey`). The lowercase normalization ensures
463
+ * that two SDKs producing the same key produce byte-identical hex
464
+ * strings; the JSON serialization of the wire envelope then has
465
+ * exactly one valid encoding, which is required for any downstream
466
+ * `JSON.stringify` + hash anchoring.
467
+ *
468
+ * @param pubkey - X25519 public key, exactly 32 bytes.
469
+ * @returns The 0x-prefixed lowercase hex form (66 chars).
470
+ * @throws {DeliveryCryptoError} `crypto_keygen_failed` if `pubkey` is
471
+ * not a `Uint8Array` of length 32.
472
+ *
473
+ * @example
474
+ * ```typescript
475
+ * pubkeyToHex(new Uint8Array(32)); // "0x00...00" (32 zero bytes)
476
+ * ```
477
+ */
478
+ function pubkeyToHex(pubkey) {
479
+ assertByteLength(pubkey, exports.X25519_PUBLIC_KEY_LENGTH, 'crypto_keygen_failed', 'pubkey');
480
+ return bytesToHexLower(pubkey);
481
+ }
482
+ exports.pubkeyToHex = pubkeyToHex;
483
+ /**
484
+ * Deserialize a 0x-prefixed hex string into a 32-byte X25519 public
485
+ * key.
486
+ *
487
+ * Accepts both uppercase and lowercase hex digits in the input (for
488
+ * resilience with legacy systems and Ethereum's mixed-case checksum
489
+ * convention — though X25519 keys are NOT checksummed). The output is
490
+ * always raw bytes; if you need the canonical hex form, call
491
+ * `pubkeyToHex` on the result, which will be lowercase.
492
+ *
493
+ * @param hex - 0x-prefixed hex string, exactly 66 characters (`0x` +
494
+ * 64 hex chars).
495
+ * @returns The 32-byte X25519 public key.
496
+ * @throws {DeliveryCryptoError} `crypto_keygen_failed` if `hex` is
497
+ * missing the `0x` prefix, the wrong length, or contains non-hex
498
+ * characters.
499
+ *
500
+ * @example
501
+ * ```typescript
502
+ * const bytes = pubkeyFromHex('0x' + 'ab'.repeat(32));
503
+ * // → Uint8Array(32) [0xab, 0xab, …]
504
+ * ```
505
+ */
506
+ function pubkeyFromHex(hex) {
507
+ return hexToBytes(hex, {
508
+ expectedLength: exports.X25519_PUBLIC_KEY_LENGTH,
509
+ field: 'pubkey hex',
510
+ });
511
+ }
512
+ exports.pubkeyFromHex = pubkeyFromHex;
513
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/delivery/keys.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * AIP-16 Delivery — Per-Builder Nonce Key Constants
3
+ * ===================================================
4
+ *
5
+ * The AGIRAILS delivery surface (AIP-16 Rev 5) uses two SEPARATE nonce
6
+ * spaces, one for the buyer-signed *setup* message and one for the
7
+ * provider-signed *envelope* message. These are deliberately distinct
8
+ * from the AIP-4 delivery-proof nonce key (`agirails.delivery.v1`) and
9
+ * from each other, so that:
10
+ *
11
+ * 1. A nonce burned for a setup message cannot be replayed as an
12
+ * envelope message (per-builder replay separation).
13
+ * 2. A nonce burned for an AIP-4 delivery proof cannot collide with
14
+ * the AIP-16 setup/envelope nonce spaces (cross-feature isolation).
15
+ * 3. The on-disk persistence file (`.actp/nonces.json`) keeps a
16
+ * clean, auditable per-key monotonic counter.
17
+ *
18
+ * Why per-builder separation matters (audit context):
19
+ * ----------------------------------------------------
20
+ * The existing `NonceManager` (`src/utils/NonceManager.ts`) keys nonces
21
+ * by *message-type string*. There is no central registry of known keys
22
+ * — any string is accepted. This file therefore acts as the canonical,
23
+ * type-safe constant source for AIP-16's two delivery nonce keys, so
24
+ * call sites (setup builder, envelope builder, future replay-cache
25
+ * server) all reach for the SAME literal and the TypeScript `as const`
26
+ * narrowing prevents silent drift.
27
+ *
28
+ * Reuse, NOT replace:
29
+ * -------------------
30
+ * These constants are intended to be passed straight into the existing
31
+ * `NonceManager` API (`getNextNonce`, `getAndIncrementNonce`,
32
+ * `recordNonce`, etc.) — they introduce no new manager, no new storage
33
+ * layer, and no behavioural change. They simply give the delivery layer
34
+ * a single authoritative spelling of its two nonce-key strings.
35
+ *
36
+ * @example Use with the existing nonce manager
37
+ * ```typescript
38
+ * import { createNonceManager } from '../utils/NonceManager';
39
+ * import {
40
+ * DELIVERY_NONCE_KEY_SETUP,
41
+ * DELIVERY_NONCE_KEY_ENVELOPE,
42
+ * } from './nonce-keys';
43
+ *
44
+ * const nonces = createNonceManager({ stateDirectory: process.cwd() });
45
+ *
46
+ * // Buyer setup signing path:
47
+ * const setupNonce = await (nonces as any).getAndIncrementNonce(
48
+ * DELIVERY_NONCE_KEY_SETUP,
49
+ * );
50
+ *
51
+ * // Provider envelope signing path (independent counter):
52
+ * const envelopeNonce = await (nonces as any).getAndIncrementNonce(
53
+ * DELIVERY_NONCE_KEY_ENVELOPE,
54
+ * );
55
+ * ```
56
+ *
57
+ * Reference: AIP-16 Rev 5 §replay-protection, §nonce-spaces
58
+ *
59
+ * @module delivery/nonce-keys
60
+ */
61
+ /**
62
+ * Nonce key for buyer-signed AIP-16 delivery *setup* messages.
63
+ *
64
+ * Distinct from {@link DELIVERY_NONCE_KEY_ENVELOPE} (per-builder
65
+ * separation) and from the AIP-4 delivery-proof key
66
+ * `agirails.delivery.v1` (cross-feature separation).
67
+ *
68
+ * The `.v1` suffix matches the EIP-712 domain version for the v1
69
+ * delivery surface; a future v2 would introduce a new key string
70
+ * rather than incrementing in place.
71
+ */
72
+ export declare const DELIVERY_NONCE_KEY_SETUP: "agirails.delivery.setup.v1";
73
+ /**
74
+ * Nonce key for provider-signed AIP-16 delivery *envelope* messages.
75
+ *
76
+ * Distinct from {@link DELIVERY_NONCE_KEY_SETUP} (per-builder
77
+ * separation) and from the AIP-4 delivery-proof key
78
+ * `agirails.delivery.v1` (cross-feature separation).
79
+ *
80
+ * The `.v1` suffix matches the EIP-712 domain version for the v1
81
+ * delivery surface; a future v2 would introduce a new key string
82
+ * rather than incrementing in place.
83
+ */
84
+ export declare const DELIVERY_NONCE_KEY_ENVELOPE: "agirails.delivery.envelope.v1";
85
+ /**
86
+ * Compile-time-narrowed union of all AIP-16 delivery nonce keys.
87
+ *
88
+ * Useful for typed wrappers that want to accept *only* a known
89
+ * delivery key (and reject e.g. `'agirails.delivery.v1'` which belongs
90
+ * to AIP-4).
91
+ */
92
+ export type DeliveryNonceKey = typeof DELIVERY_NONCE_KEY_SETUP | typeof DELIVERY_NONCE_KEY_ENVELOPE;
93
+ //# sourceMappingURL=nonce-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nonce-keys.d.ts","sourceRoot":"","sources":["../../src/delivery/nonce-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,8BAAwC,CAAC;AAE9E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,iCAA2C,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACxB,OAAO,wBAAwB,GAC/B,OAAO,2BAA2B,CAAC"}