@cardanowall/sdk-ts 0.2.0 → 0.4.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.
Files changed (49) hide show
  1. package/dist/client/index.cjs +2566 -1706
  2. package/dist/client/index.cjs.map +1 -1
  3. package/dist/client/index.d.cts +42 -5
  4. package/dist/client/index.d.ts +42 -5
  5. package/dist/client/index.js +2564 -1708
  6. package/dist/client/index.js.map +1 -1
  7. package/dist/conformance/cli.cjs +5978 -3438
  8. package/dist/conformance/cli.cjs.map +1 -1
  9. package/dist/conformance/cli.js +5978 -3438
  10. package/dist/conformance/cli.js.map +1 -1
  11. package/dist/fetch/index.cjs +33 -14
  12. package/dist/fetch/index.cjs.map +1 -1
  13. package/dist/fetch/index.d.cts +2 -2
  14. package/dist/fetch/index.d.ts +2 -2
  15. package/dist/fetch/index.js +32 -15
  16. package/dist/fetch/index.js.map +1 -1
  17. package/dist/{fetch-outbound-BT5-NiYN.d.cts → fetch-outbound-dOK3ZxYa.d.cts} +7 -3
  18. package/dist/{fetch-outbound-BT5-NiYN.d.ts → fetch-outbound-dOK3ZxYa.d.ts} +7 -3
  19. package/dist/hash/index.cjs +1 -1
  20. package/dist/hash/index.cjs.map +1 -1
  21. package/dist/hash/index.js +1 -1
  22. package/dist/hash/index.js.map +1 -1
  23. package/dist/identity/index.cjs +460 -219
  24. package/dist/identity/index.cjs.map +1 -1
  25. package/dist/identity/index.d.cts +3 -2
  26. package/dist/identity/index.d.ts +3 -2
  27. package/dist/identity/index.js +460 -219
  28. package/dist/identity/index.js.map +1 -1
  29. package/dist/index.cjs +6912 -3678
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +7 -7
  32. package/dist/index.d.ts +7 -7
  33. package/dist/index.js +6890 -3672
  34. package/dist/index.js.map +1 -1
  35. package/dist/merkle/index.cjs +1 -1
  36. package/dist/merkle/index.js +1 -1
  37. package/dist/types-Cexm4VH9.d.cts +119 -0
  38. package/dist/types-CgoBub9J.d.ts +119 -0
  39. package/dist/{types-DGsZTMuZ.d.cts → types-Dp4wUSFI.d.cts} +220 -1
  40. package/dist/{types-DGsZTMuZ.d.ts → types-Dp4wUSFI.d.ts} +220 -1
  41. package/dist/verifier/index.cjs +5738 -3205
  42. package/dist/verifier/index.cjs.map +1 -1
  43. package/dist/verifier/index.d.cts +159 -111
  44. package/dist/verifier/index.d.ts +159 -111
  45. package/dist/verifier/index.js +5726 -3201
  46. package/dist/verifier/index.js.map +1 -1
  47. package/package.json +3 -3
  48. package/dist/types-B8Q3gW54.d.ts +0 -123
  49. package/dist/types-CLXdbjqr.d.cts +0 -123
@@ -3,21 +3,21 @@ import { sortCoreDeterministic } from 'cbor2/sorts';
3
3
  import { blake2b } from '@noble/hashes/blake2.js';
4
4
  import * as ed from '@noble/ed25519';
5
5
  import { sha512, sha256 as sha256$1 } from '@noble/hashes/sha2.js';
6
- import 'hash-wasm';
6
+ import { createSHA256 } from 'hash-wasm';
7
7
  import { z } from 'zod';
8
8
  import { randomBytes as randomBytes$1 } from '@noble/ciphers/utils.js';
9
- import { hmac } from '@noble/hashes/hmac.js';
10
- import { xchacha20poly1305, chacha20poly1305 } from '@noble/ciphers/chacha.js';
11
- import { hkdf } from '@noble/hashes/hkdf.js';
9
+ import { chacha20poly1305 } from '@noble/ciphers/chacha.js';
12
10
  import '@noble/curves/abstract/edwards.js';
13
11
  import '@noble/curves/abstract/montgomery.js';
14
12
  import '@noble/curves/abstract/weierstrass.js';
15
13
  import { x25519 } from '@noble/curves/ed25519.js';
16
14
  import '@noble/curves/nist.js';
17
15
  import { concatBytes, asciiToBytes, bytesToNumberLE, bytesToNumberBE } from '@noble/curves/utils.js';
16
+ import { hkdf } from '@noble/hashes/hkdf.js';
18
17
  import { sha3_256, shake256, sha3_512, shake128 } from '@noble/hashes/sha3.js';
19
18
  import { anumber, abytes, randomBytes as randomBytes$2, u32, swap32IfBE } from '@noble/hashes/utils.js';
20
19
  import { FFTCore, reverseBits } from '@noble/curves/abstract/fft.js';
20
+ import { hmac } from '@noble/hashes/hmac.js';
21
21
 
22
22
  // ../crypto-core/dist/cbor.js
23
23
  function encodeCanonicalCbor(value) {
@@ -81,6 +81,14 @@ function encodeCoseSign1(args) {
81
81
  function sha256(input) {
82
82
  return sha256$1(input);
83
83
  }
84
+ async function sha256Stream(source) {
85
+ const hasher = await createSHA256();
86
+ hasher.init();
87
+ for await (const chunk of source) {
88
+ hasher.update(chunk);
89
+ }
90
+ return hasher.digest("binary");
91
+ }
84
92
  function blake2b256(input) {
85
93
  return blake2b(input, { dkLen: 32 });
86
94
  }
@@ -136,1538 +144,2082 @@ function mthRecursive(leaves, start, end) {
136
144
  const right = mthRecursive(leaves, start + k, end);
137
145
  return hashNode(left, right);
138
146
  }
139
- var ChunkedBytesArraySchema = z.array(
140
- z.instanceof(Uint8Array).refine((b) => b.length >= 1 && b.length <= 64, {
141
- params: { code: "CHUNK_TOO_LARGE" }
142
- })
143
- ).min(1);
144
- var UTF8_ENCODER = new TextEncoder();
145
- var UriChunkArraySchema = z.array(
146
- z.string().refine(
147
- (s) => {
148
- const n = UTF8_ENCODER.encode(s).length;
149
- return n >= 1 && n <= 64;
150
- },
151
- { params: { code: "CHUNK_TOO_LARGE" } }
152
- )
153
- ).min(1);
147
+ function textKeyedMap(inner) {
148
+ return z.custom((value) => !(value instanceof Uint8Array), {
149
+ message: "CBOR byte string present where a text-keyed map is required"
150
+ }).pipe(inner);
151
+ }
154
152
  var HashDigestSchema = z.instanceof(Uint8Array);
155
153
  var HashesMapSchema = z.record(z.string(), HashDigestSchema);
156
- var MerkleCommitSchema = z.object({
157
- alg: z.string(),
158
- root: z.instanceof(Uint8Array),
159
- leaf_count: z.number().int().min(1),
160
- uris: z.array(UriChunkArraySchema).min(1).optional()
161
- }).strict();
162
- var SlotSchema = z.object({
163
- epk: z.instanceof(Uint8Array).optional(),
164
- kem_ct: ChunkedBytesArraySchema.optional(),
165
- wrap: z.instanceof(Uint8Array).optional()
166
- });
167
- z.object({
168
- m: z.number().int(),
169
- t: z.number().int(),
170
- p: z.number().int()
171
- }).strict();
172
- var PassphraseBlockSchema = z.object({
173
- alg: z.string(),
174
- salt: z.instanceof(Uint8Array).superRefine((bytes, ctx) => {
175
- if (bytes.length < 16) {
176
- ctx.addIssue({
177
- code: "custom",
178
- path: [],
179
- message: `passphrase.salt length ${bytes.length} < 16`,
180
- params: { code: "ENC_PASSPHRASE_SALT_TOO_SHORT" }
181
- });
182
- } else if (bytes.length > 64) {
183
- ctx.addIssue({
184
- code: "custom",
185
- path: [],
186
- message: `passphrase.salt length ${bytes.length} > 64`,
187
- params: { code: "ENC_PASSPHRASE_SALT_TOO_LONG" }
188
- });
189
- }
190
- }),
191
- params: z.record(z.string(), z.unknown())
192
- }).strict();
193
- z.object({
194
- scheme: z.unknown(),
195
- aead: z.string(),
196
- kem: z.string().optional(),
197
- nonce: z.instanceof(Uint8Array),
198
- slots: z.array(SlotSchema).optional(),
199
- slots_mac: z.instanceof(Uint8Array).refine((b) => b.length === 32, {
200
- params: { code: "ENC_SLOTS_MAC_INVALID_LENGTH" }
201
- }).optional(),
202
- passphrase: PassphraseBlockSchema.optional()
203
- }).strict();
204
- var ItemEntrySchema = z.object({
205
- hashes: HashesMapSchema,
206
- uris: z.array(UriChunkArraySchema).min(1).optional(),
207
- // Captured as `unknown` so the validator can run the
208
- // `ENC_REQUIRES_CONTENT_HASH` pre-check ahead of any inner-shape errors
209
- // and surface the most informative code first.
210
- enc: z.unknown().optional()
211
- }).strict();
212
- var SigEntrySchema = z.object({
213
- cose_key: ChunkedBytesArraySchema.optional(),
214
- cose_sign1: ChunkedBytesArraySchema
215
- }).strict();
154
+ var UriSchema = z.string();
155
+ var MerkleCommitSchema = textKeyedMap(
156
+ z.object({
157
+ alg: z.string(),
158
+ root: z.instanceof(Uint8Array),
159
+ leaf_count: z.union([z.number().int(), z.bigint()]),
160
+ uris: z.array(UriSchema).optional()
161
+ }).strict()
162
+ );
163
+ var SlotSchema = textKeyedMap(
164
+ z.object({
165
+ epk: z.instanceof(Uint8Array).optional(),
166
+ kem_ct: z.instanceof(Uint8Array).optional(),
167
+ wrap: z.instanceof(Uint8Array).optional()
168
+ })
169
+ );
170
+ textKeyedMap(
171
+ z.object({
172
+ m: z.union([z.number().int(), z.bigint()]),
173
+ t: z.union([z.number().int(), z.bigint()]),
174
+ p: z.union([z.number().int(), z.bigint()])
175
+ }).strict()
176
+ );
177
+ var PassphraseBlockSchema = textKeyedMap(
178
+ z.object({
179
+ alg: z.string(),
180
+ salt: z.instanceof(Uint8Array).superRefine((bytes, ctx) => {
181
+ if (bytes.length < 16) {
182
+ ctx.addIssue({
183
+ code: "custom",
184
+ path: [],
185
+ message: `passphrase.salt length ${bytes.length} < 16`,
186
+ params: { code: "ENC_PASSPHRASE_SALT_TOO_SHORT" }
187
+ });
188
+ } else if (bytes.length > 64) {
189
+ ctx.addIssue({
190
+ code: "custom",
191
+ path: [],
192
+ message: `passphrase.salt length ${bytes.length} > 64`,
193
+ params: { code: "ENC_PASSPHRASE_SALT_TOO_LONG" }
194
+ });
195
+ }
196
+ }),
197
+ params: z.record(z.string(), z.unknown())
198
+ }).strict()
199
+ );
200
+ var EncScheme1Schema = textKeyedMap(
201
+ z.object({
202
+ scheme: z.literal(1),
203
+ aead: z.string(),
204
+ kem: z.string().optional(),
205
+ nonce: z.instanceof(Uint8Array),
206
+ slots: z.array(SlotSchema).optional(),
207
+ slots_mac: z.instanceof(Uint8Array).refine((b) => b.length === 32, {
208
+ params: { code: "ENC_SLOTS_MAC_INVALID_LENGTH" }
209
+ }).optional(),
210
+ passphrase: PassphraseBlockSchema.optional()
211
+ }).strict()
212
+ );
213
+ var EncOpaqueSchema = textKeyedMap(
214
+ z.looseObject({
215
+ scheme: z.union([z.number().int().nonnegative(), z.bigint().nonnegative()])
216
+ })
217
+ );
218
+ z.union([EncScheme1Schema, EncOpaqueSchema]);
219
+ var ItemEntrySchema = textKeyedMap(
220
+ z.object({
221
+ hashes: HashesMapSchema,
222
+ uris: z.array(UriSchema).optional(),
223
+ // Captured as `unknown`: the envelope is a union whose disposition
224
+ // (typed scheme-1 vs opaque) depends on identifier support, so the
225
+ // validator's domain pass — not this schema — narrows it.
226
+ enc: z.unknown().optional()
227
+ }).strict()
228
+ );
229
+ var SigEntrySchema = textKeyedMap(
230
+ z.object({
231
+ cose_key: z.instanceof(Uint8Array).optional(),
232
+ cose_sign1: z.instanceof(Uint8Array)
233
+ }).strict()
234
+ );
216
235
  var SupersedesSchema = z.instanceof(Uint8Array).refine((b) => b.length === 32, {
217
236
  params: { code: "SUPERSEDES_TX_INVALID_LENGTH" }
218
237
  });
219
238
  var VersionLiteralSchema = z.literal(1);
220
- z.looseObject({
221
- v: VersionLiteralSchema,
222
- items: z.array(ItemEntrySchema).optional(),
223
- merkle: z.array(MerkleCommitSchema).optional(),
224
- supersedes: SupersedesSchema.optional(),
225
- sigs: z.array(SigEntrySchema).optional(),
226
- crit: z.array(z.string()).optional()
227
- });
239
+ textKeyedMap(
240
+ z.looseObject({
241
+ v: VersionLiteralSchema,
242
+ items: z.array(ItemEntrySchema).optional(),
243
+ merkle: z.array(MerkleCommitSchema).optional(),
244
+ supersedes: SupersedesSchema.optional(),
245
+ sigs: z.array(SigEntrySchema).optional(),
246
+ crit: z.array(z.string()).optional()
247
+ })
248
+ );
228
249
 
229
250
  // ../poe-standard/src/encoder.ts
230
251
  function encodePoeRecord(record) {
231
- return encodeCanonicalCbor(recordToCbor(record));
232
- }
233
- function encodeRecordBodyForSigning(record) {
234
- const body = recordToCborInternal(
252
+ return encodeCanonicalCbor(toCborValue(
235
253
  record,
236
254
  /* includeSigs */
237
- false
238
- );
239
- return encodeCanonicalCbor(body);
255
+ true
256
+ ));
240
257
  }
241
- function recordToCbor(record) {
242
- return recordToCborInternal(
258
+ function encodeRecordBodyForSigning(record) {
259
+ return encodeCanonicalCbor(toCborValue(
243
260
  record,
244
261
  /* includeSigs */
245
- true
246
- );
262
+ false
263
+ ));
247
264
  }
248
- function recordToCborInternal(record, includeSigs) {
249
- const out = { v: record.v };
250
- if (record.items !== void 0) out["items"] = record.items.map(itemToCbor);
251
- if (record.merkle !== void 0) out["merkle"] = record.merkle.map(merkleToCbor);
252
- if (record.supersedes !== void 0) out["supersedes"] = record.supersedes;
253
- if (includeSigs && record.sigs !== void 0) out["sigs"] = record.sigs.map(sigEntryToCbor);
254
- if (record.crit !== void 0) out["crit"] = record.crit.slice();
255
- for (const [k, v] of Object.entries(record)) {
256
- if (k === "v" || k === "items" || k === "merkle" || k === "supersedes" || k === "sigs" || k === "crit") {
257
- continue;
258
- }
259
- out[k] = v;
265
+ function toCborValue(record, includeSigs) {
266
+ const out = {};
267
+ for (const [key, value] of Object.entries(record)) {
268
+ if (value === void 0) continue;
269
+ if (!includeSigs && key === "sigs") continue;
270
+ out[key] = stripUndefined(value);
260
271
  }
261
272
  return out;
262
273
  }
263
- function itemToCbor(item) {
264
- const out = { hashes: hashesToCbor(item.hashes) };
265
- if (item.uris !== void 0) {
266
- out["uris"] = item.uris.map((chunks) => chunks.slice());
274
+ function stripUndefined(value) {
275
+ if (value === null || typeof value !== "object" || value instanceof Uint8Array) {
276
+ return value;
267
277
  }
268
- if (item.enc !== void 0) {
269
- out["enc"] = envelopeToCbor(item.enc);
278
+ if (Array.isArray(value)) {
279
+ return value.map((element) => stripUndefined(element));
280
+ }
281
+ if (value instanceof Map) {
282
+ const out2 = /* @__PURE__ */ new Map();
283
+ for (const [k, v] of value) {
284
+ if (v === void 0) continue;
285
+ out2.set(k, stripUndefined(v));
286
+ }
287
+ return out2;
270
288
  }
271
- return out;
272
- }
273
- function hashesToCbor(hashes2) {
274
289
  const out = {};
275
- for (const [alg, digest] of Object.entries(hashes2)) {
276
- out[alg] = digest;
290
+ for (const [k, v] of Object.entries(value)) {
291
+ if (v === void 0) continue;
292
+ out[k] = stripUndefined(v);
277
293
  }
278
294
  return out;
279
295
  }
280
- function merkleToCbor(commit) {
281
- const out = {
282
- alg: commit.alg,
283
- root: commit.root,
284
- leaf_count: commit.leaf_count
285
- };
286
- if (commit.uris !== void 0) {
287
- out["uris"] = commit.uris.map((chunks) => chunks.slice());
288
- }
289
- return out;
296
+
297
+ // ../poe-standard/src/error-codes.ts
298
+ var ERROR_CODES = [
299
+ "MALFORMED_CBOR",
300
+ "SCHEMA_TYPE_MISMATCH",
301
+ "SCHEMA_MISSING_REQUIRED",
302
+ "SCHEMA_UNKNOWN_FIELD",
303
+ "SCHEMA_INVALID_LITERAL",
304
+ "SCHEMA_EMPTY_RECORD",
305
+ "HASH_DIGEST_LENGTH_MISMATCH",
306
+ "UNSUPPORTED_HASH_ALG",
307
+ "UNSUPPORTED_MERKLE_COMMIT_ALG",
308
+ "SCHEMA_MERKLE_LEAF_COUNT_INVALID",
309
+ "INVALID_URI",
310
+ "CHUNK_TOO_LARGE",
311
+ "UNAUTHENTICATED_CIPHER_FORBIDDEN",
312
+ "UNSUPPORTED_AEAD_ALG",
313
+ "NONCE_LENGTH_MISMATCH",
314
+ "UNSUPPORTED_ENVELOPE_SCHEME",
315
+ "ENC_UNSUPPORTED",
316
+ "ENC_SLOTS_EMPTY",
317
+ "ENC_SLOT_INVALID_SHAPE",
318
+ "UNSUPPORTED_KEM_ALG",
319
+ "ENC_KEM_REQUIRED",
320
+ "KEM_EPK_LENGTH_MISMATCH",
321
+ "KEM_CT_LENGTH_MISMATCH",
322
+ "WRAP_LENGTH_MISMATCH",
323
+ "ENC_SLOTS_MAC_INVALID_LENGTH",
324
+ "ENC_SLOTS_MAC_REQUIRED",
325
+ "ENC_SLOTS_REQUIRED",
326
+ "ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
327
+ "ENC_SLOTS_TOO_MANY",
328
+ "ENC_ENVELOPE_TOO_LARGE",
329
+ "ENC_EXCLUSIVITY_VIOLATION",
330
+ "ENC_NO_KEY_PATH",
331
+ "ENC_REQUIRES_CONTENT_HASH",
332
+ "ENC_PASSPHRASE_ALG_UNSUPPORTED",
333
+ "ENC_PASSPHRASE_SALT_TOO_SHORT",
334
+ "ENC_PASSPHRASE_SALT_TOO_LONG",
335
+ "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
336
+ "ENC_PASSPHRASE_PARAMS_EXCEED_POLICY",
337
+ "MALFORMED_SIG_COSE_SIGN1",
338
+ "SIGNATURE_UNSUPPORTED",
339
+ "SIG_ENTRY_INVALID_SHAPE",
340
+ "SIG_ENTRY_KID_COSE_KEY_CONFLICT",
341
+ "SIG_PRIVATE_KEY_LEAKED",
342
+ "SUPERSEDES_TX_INVALID_LENGTH",
343
+ "EXTENSION_UNSUPPORTED_CRITICAL",
344
+ "CRIT_SHAPE_INVALID",
345
+ "TX_NOT_FOUND",
346
+ "PROVIDER_UNAVAILABLE",
347
+ "TX_INTEGRITY_MISMATCH",
348
+ "METADATA_NOT_FOUND",
349
+ "INSUFFICIENT_CONFIRMATIONS",
350
+ "SIGNATURE_INVALID",
351
+ "SIGNER_KEY_UNRESOLVED",
352
+ "WALLET_ADDRESS_MISMATCH",
353
+ "URI_TARGET_FORBIDDEN",
354
+ "URI_INTEGRITY_MISMATCH",
355
+ "URI_PROVIDER_INTEGRITY_MISMATCH",
356
+ "URI_FETCH_FAILED",
357
+ "CONTENT_UNAVAILABLE",
358
+ "CONTENT_FETCH_LIMIT_EXCEEDED",
359
+ "CIPHERTEXT_UNAVAILABLE",
360
+ "SERVICE_INDEPENDENCE_VIOLATION",
361
+ "WRONG_DECRYPTION_INPUT_SHAPE",
362
+ "WRONG_RECIPIENT_KEY",
363
+ "TAMPERED_HEADER",
364
+ "TAMPERED_CIPHERTEXT",
365
+ "KDF_DERIVATION_FAILED",
366
+ "ENC_PASSPHRASE_UNNORMALIZABLE",
367
+ "ENC_PASSPHRASE_EMPTY",
368
+ "SCHEMA_MERKLE_LEAF_COUNT_MISMATCH",
369
+ "SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED",
370
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
371
+ "MERKLE_ROOT_MISMATCH",
372
+ "MERKLE_LEAVES_UNAVAILABLE",
373
+ "MERKLE_UNSUPPORTED",
374
+ "OUT_OF_PROFILE_SKIPPED"
375
+ ];
376
+ var ERROR_CODE_PART = Object.freeze({
377
+ MALFORMED_CBOR: "A",
378
+ SCHEMA_TYPE_MISMATCH: "A",
379
+ SCHEMA_MISSING_REQUIRED: "A",
380
+ SCHEMA_UNKNOWN_FIELD: "A",
381
+ SCHEMA_INVALID_LITERAL: "A",
382
+ SCHEMA_EMPTY_RECORD: "A",
383
+ HASH_DIGEST_LENGTH_MISMATCH: "A",
384
+ UNSUPPORTED_HASH_ALG: "A",
385
+ UNSUPPORTED_MERKLE_COMMIT_ALG: "A",
386
+ SCHEMA_MERKLE_LEAF_COUNT_INVALID: "A",
387
+ INVALID_URI: "A",
388
+ CHUNK_TOO_LARGE: "carriage",
389
+ UNAUTHENTICATED_CIPHER_FORBIDDEN: "A",
390
+ UNSUPPORTED_AEAD_ALG: "A",
391
+ NONCE_LENGTH_MISMATCH: "A",
392
+ UNSUPPORTED_ENVELOPE_SCHEME: "A",
393
+ ENC_UNSUPPORTED: "A",
394
+ ENC_SLOTS_EMPTY: "A",
395
+ ENC_SLOT_INVALID_SHAPE: "A",
396
+ UNSUPPORTED_KEM_ALG: "A",
397
+ ENC_KEM_REQUIRED: "A",
398
+ KEM_EPK_LENGTH_MISMATCH: "A",
399
+ KEM_CT_LENGTH_MISMATCH: "A",
400
+ WRAP_LENGTH_MISMATCH: "A",
401
+ ENC_SLOTS_MAC_INVALID_LENGTH: "A",
402
+ ENC_SLOTS_MAC_REQUIRED: "A",
403
+ ENC_SLOTS_REQUIRED: "A",
404
+ ENC_SLOTS_DUPLICATE_KEM_MATERIAL: "A",
405
+ ENC_SLOTS_TOO_MANY: "A",
406
+ ENC_ENVELOPE_TOO_LARGE: "A",
407
+ ENC_EXCLUSIVITY_VIOLATION: "A",
408
+ ENC_NO_KEY_PATH: "A",
409
+ ENC_REQUIRES_CONTENT_HASH: "A",
410
+ ENC_PASSPHRASE_ALG_UNSUPPORTED: "A",
411
+ ENC_PASSPHRASE_SALT_TOO_SHORT: "A",
412
+ ENC_PASSPHRASE_SALT_TOO_LONG: "A",
413
+ ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW: "A",
414
+ ENC_PASSPHRASE_PARAMS_EXCEED_POLICY: "A",
415
+ MALFORMED_SIG_COSE_SIGN1: "A",
416
+ SIGNATURE_UNSUPPORTED: "A",
417
+ SIG_ENTRY_INVALID_SHAPE: "A",
418
+ SIG_ENTRY_KID_COSE_KEY_CONFLICT: "A",
419
+ SIG_PRIVATE_KEY_LEAKED: "A",
420
+ SUPERSEDES_TX_INVALID_LENGTH: "A",
421
+ EXTENSION_UNSUPPORTED_CRITICAL: "A",
422
+ CRIT_SHAPE_INVALID: "A",
423
+ TX_NOT_FOUND: "B",
424
+ PROVIDER_UNAVAILABLE: "B",
425
+ TX_INTEGRITY_MISMATCH: "B",
426
+ METADATA_NOT_FOUND: "B",
427
+ INSUFFICIENT_CONFIRMATIONS: "B",
428
+ SIGNATURE_INVALID: "B",
429
+ SIGNER_KEY_UNRESOLVED: "B",
430
+ WALLET_ADDRESS_MISMATCH: "B",
431
+ URI_TARGET_FORBIDDEN: "B",
432
+ URI_INTEGRITY_MISMATCH: "B",
433
+ URI_PROVIDER_INTEGRITY_MISMATCH: "B",
434
+ URI_FETCH_FAILED: "B",
435
+ CONTENT_UNAVAILABLE: "B",
436
+ CONTENT_FETCH_LIMIT_EXCEEDED: "B",
437
+ CIPHERTEXT_UNAVAILABLE: "B",
438
+ SERVICE_INDEPENDENCE_VIOLATION: "B",
439
+ WRONG_DECRYPTION_INPUT_SHAPE: "B",
440
+ WRONG_RECIPIENT_KEY: "B",
441
+ TAMPERED_HEADER: "B",
442
+ TAMPERED_CIPHERTEXT: "B",
443
+ KDF_DERIVATION_FAILED: "B",
444
+ ENC_PASSPHRASE_UNNORMALIZABLE: "B",
445
+ ENC_PASSPHRASE_EMPTY: "B",
446
+ SCHEMA_MERKLE_LEAF_COUNT_MISMATCH: "B",
447
+ SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED: "B",
448
+ SCHEMA_MERKLE_LEAVES_MALFORMED: "B",
449
+ MERKLE_ROOT_MISMATCH: "B",
450
+ MERKLE_LEAVES_UNAVAILABLE: "B",
451
+ MERKLE_UNSUPPORTED: "B",
452
+ OUT_OF_PROFILE_SKIPPED: "B"
453
+ });
454
+ Object.freeze(
455
+ ERROR_CODES.filter((code) => ERROR_CODE_PART[code] === "A")
456
+ );
457
+ Object.freeze(
458
+ ERROR_CODES.filter((code) => ERROR_CODE_PART[code] === "carriage")
459
+ );
460
+ Object.freeze(
461
+ ERROR_CODES.filter((code) => ERROR_CODE_PART[code] === "B")
462
+ );
463
+ new Map(
464
+ ERROR_CODES.map((code, index) => [code, index])
465
+ );
466
+ var abytesDoc = abytes;
467
+ var randomBytes = randomBytes$2;
468
+ function equalBytes(a, b) {
469
+ if (a.length !== b.length)
470
+ return false;
471
+ let diff = 0;
472
+ for (let i = 0; i < a.length; i++)
473
+ diff |= a[i] ^ b[i];
474
+ return diff === 0;
290
475
  }
291
- function envelopeToCbor(enc) {
292
- const out = {
293
- scheme: enc.scheme,
294
- aead: enc.aead,
295
- nonce: enc.nonce
296
- };
297
- if (enc.kem !== void 0) out["kem"] = enc.kem;
298
- if (enc.slots !== void 0) out["slots"] = enc.slots.map(slotToCbor);
299
- if (enc.slots_mac !== void 0) out["slots_mac"] = enc.slots_mac;
300
- if (enc.passphrase !== void 0) out["passphrase"] = passphraseToCbor(enc.passphrase);
301
- return out;
476
+ function copyBytes(bytes) {
477
+ return Uint8Array.from(abytes(bytes));
302
478
  }
303
- function slotToCbor(slot) {
304
- if (slot.kem_ct !== void 0) {
305
- return { kem_ct: slot.kem_ct.map((c) => c), wrap: slot.wrap };
306
- }
307
- return { epk: slot.epk, wrap: slot.wrap };
479
+ function splitCoder(label, ...lengths) {
480
+ const getLength = (c) => typeof c === "number" ? c : c.bytesLen;
481
+ const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0);
482
+ return {
483
+ bytesLen,
484
+ encode: (bufs) => {
485
+ const res = new Uint8Array(bytesLen);
486
+ for (let i = 0, pos = 0; i < lengths.length; i++) {
487
+ const c = lengths[i];
488
+ const l = getLength(c);
489
+ const b = typeof c === "number" ? bufs[i] : c.encode(bufs[i]);
490
+ abytes(b, l, label);
491
+ res.set(b, pos);
492
+ if (typeof c !== "number")
493
+ b.fill(0);
494
+ pos += l;
495
+ }
496
+ return res;
497
+ },
498
+ decode: (buf) => {
499
+ abytes(buf, bytesLen, label);
500
+ const res = [];
501
+ for (const c of lengths) {
502
+ const l = getLength(c);
503
+ const b = buf.subarray(0, l);
504
+ res.push(typeof c === "number" ? b : c.decode(b));
505
+ buf = buf.subarray(l);
506
+ }
507
+ return res;
508
+ }
509
+ };
308
510
  }
309
- function passphraseToCbor(pp) {
511
+ function vecCoder(c, vecLen) {
512
+ const coder = c;
513
+ const bytesLen = vecLen * coder.bytesLen;
310
514
  return {
311
- alg: pp.alg,
312
- salt: pp.salt,
313
- params: pp.params
515
+ bytesLen,
516
+ encode: (u) => {
517
+ if (u.length !== vecLen)
518
+ throw new RangeError(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`);
519
+ const res = new Uint8Array(bytesLen);
520
+ for (let i = 0, pos = 0; i < u.length; i++) {
521
+ const b = coder.encode(u[i]);
522
+ res.set(b, pos);
523
+ b.fill(0);
524
+ pos += b.length;
525
+ }
526
+ return res;
527
+ },
528
+ decode: (a) => {
529
+ abytes(a, bytesLen);
530
+ const r = [];
531
+ for (let i = 0; i < a.length; i += coder.bytesLen)
532
+ r.push(coder.decode(a.subarray(i, i + coder.bytesLen)));
533
+ return r;
534
+ }
314
535
  };
315
536
  }
316
- function sigEntryToCbor(entry) {
317
- const out = { cose_sign1: entry.cose_sign1.map((b) => b) };
318
- if (entry.cose_key !== void 0) {
319
- out["cose_key"] = entry.cose_key.map((b) => b);
537
+ function cleanBytes(...list) {
538
+ for (const t of list) {
539
+ if (Array.isArray(t))
540
+ for (const b of t)
541
+ b.fill(0);
542
+ else
543
+ t.fill(0);
320
544
  }
321
- return out;
322
545
  }
323
-
324
- // ../poe-standard/src/chunked.ts
325
- var CHUNK_MAX_BYTES = 64;
326
- var UTF8_ENCODER2 = new TextEncoder();
327
- function chunkBytes(value) {
328
- if (value.length === 0) return [new Uint8Array(0)];
329
- const chunks = [];
330
- for (let i = 0; i < value.length; i += CHUNK_MAX_BYTES) {
331
- chunks.push(value.subarray(i, Math.min(i + CHUNK_MAX_BYTES, value.length)));
332
- }
333
- return chunks;
334
- }
335
- function chunkUri(uri) {
336
- const bytes = UTF8_ENCODER2.encode(uri);
337
- if (bytes.length === 0) return [""];
338
- if (bytes.length <= CHUNK_MAX_BYTES) return [uri];
339
- const decoder = new TextDecoder("utf-8", { fatal: true });
340
- const chunks = [];
341
- let cursor = 0;
342
- while (cursor < bytes.length) {
343
- let end = Math.min(cursor + CHUNK_MAX_BYTES, bytes.length);
344
- while (end < bytes.length && (bytes[end] & 192) === 128) end--;
345
- chunks.push(decoder.decode(bytes.subarray(cursor, end)));
346
- cursor = end;
347
- }
348
- return chunks;
546
+ function getMask(bits) {
547
+ if (!Number.isSafeInteger(bits) || bits < 0 || bits > 32)
548
+ throw new RangeError(`expected bits in [0..32], got ${bits}`);
549
+ return bits === 32 ? 4294967295 : ~(-1 << bits) >>> 0;
349
550
  }
350
551
 
351
- // src/client/off-host-sign.ts
352
- var EMPTY_BYTES2 = new Uint8Array(0);
353
- var ED25519_PUBLIC_KEY_LENGTH = 32;
354
- var ED25519_SIGNATURE_LENGTH = 64;
355
- var OffHostSignError = class extends Error {
356
- code;
357
- constructor(code, message) {
358
- super(message);
359
- this.name = "OffHostSignError";
360
- this.code = code;
552
+ // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/_crystals.js
553
+ var genCrystals = (opts2) => {
554
+ const { newPoly, N: N2, Q: Q2, F: F2, ROOT_OF_UNITY: ROOT_OF_UNITY2, brvBits} = opts2;
555
+ const mod = (a, modulo = Q2) => {
556
+ const result = a % modulo | 0;
557
+ return (result >= 0 ? result | 0 : modulo + result | 0) | 0;
558
+ };
559
+ const smod = (a, modulo = Q2) => {
560
+ const r = mod(a, modulo) | 0;
561
+ return (r > modulo >> 1 ? r - modulo | 0 : r) | 0;
562
+ };
563
+ function getZettas() {
564
+ const out = newPoly(N2);
565
+ for (let i = 0; i < N2; i++) {
566
+ const b = reverseBits(i, brvBits);
567
+ const p = BigInt(ROOT_OF_UNITY2) ** BigInt(b) % BigInt(Q2);
568
+ out[i] = Number(p) | 0;
569
+ }
570
+ return out;
361
571
  }
572
+ const nttZetas = getZettas();
573
+ const field = {
574
+ add: (a, b) => mod((a | 0) + (b | 0)) | 0,
575
+ sub: (a, b) => mod((a | 0) - (b | 0)) | 0,
576
+ mul: (a, b) => mod((a | 0) * (b | 0)) | 0,
577
+ inv: (_a) => {
578
+ throw new Error("not implemented");
579
+ }
580
+ };
581
+ const nttOpts = {
582
+ N: N2,
583
+ roots: nttZetas,
584
+ invertButterflies: true,
585
+ skipStages: 1 ,
586
+ brp: false
587
+ };
588
+ const dif = FFTCore(field, { dit: false, ...nttOpts });
589
+ const dit = FFTCore(field, { dit: true, ...nttOpts });
590
+ const NTT = {
591
+ encode: (r) => {
592
+ return dif(r);
593
+ },
594
+ decode: (r) => {
595
+ dit(r);
596
+ for (let i = 0; i < r.length; i++)
597
+ r[i] = mod(F2 * r[i]);
598
+ return r;
599
+ }
600
+ };
601
+ const bitsCoder = (d, c) => {
602
+ const mask = getMask(d);
603
+ const bytesLen = d * (N2 / 8);
604
+ return {
605
+ bytesLen,
606
+ encode: (poly_) => {
607
+ const poly = poly_;
608
+ const r = new Uint8Array(bytesLen);
609
+ for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) {
610
+ buf |= (c.encode(poly[i]) & mask) << bufLen;
611
+ bufLen += d;
612
+ for (; bufLen >= 8; bufLen -= 8, buf >>= 8)
613
+ r[pos++] = buf & getMask(bufLen);
614
+ }
615
+ return r;
616
+ },
617
+ decode: (bytes) => {
618
+ const r = newPoly(N2);
619
+ for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) {
620
+ buf |= bytes[i] << bufLen;
621
+ bufLen += 8;
622
+ for (; bufLen >= d; bufLen -= d, buf >>= d)
623
+ r[pos++] = c.decode(buf & mask);
624
+ }
625
+ return r;
626
+ }
627
+ };
628
+ };
629
+ return {
630
+ mod,
631
+ smod,
632
+ nttZetas,
633
+ NTT: {
634
+ encode: (r) => NTT.encode(r),
635
+ decode: (r) => NTT.decode(r)
636
+ },
637
+ bitsCoder
638
+ };
362
639
  };
363
- function buildToSign(record) {
364
- const body = encodeRecordBodyForSigning(record);
365
- const out = new Uint8Array(CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES.length + body.length);
366
- out.set(CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES, 0);
367
- out.set(body, CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES.length);
368
- return out;
369
- }
370
- function encodePath1ProtectedHeader(signerPubkey) {
371
- const protectedHeader = /* @__PURE__ */ new Map([
372
- [1, -8],
373
- [4, signerPubkey]
374
- ]);
375
- const protectedHeaderBytes = encodeCanonicalCbor(protectedHeader);
376
- return { protectedHeader, protectedHeaderBytes };
377
- }
378
- function prepareSigStructure(args) {
379
- if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
380
- throw new OffHostSignError(
381
- "INVALID_PUBKEY_LENGTH",
382
- `signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
383
- );
384
- }
385
- const { protectedHeaderBytes } = encodePath1ProtectedHeader(args.signerPubkey);
386
- const recordBodyCbor = encodeRecordBodyForSigning(args.record);
387
- const sigStructureBytes = buildLabel309SigStructure({
388
- bodyProtectedBytes: protectedHeaderBytes,
389
- recordBodyCbor
390
- });
391
- return { sigStructureBytes, protectedHeaderBytes };
640
+ var createXofShake = (shake) => (seed, blockLen) => {
641
+ if (!blockLen)
642
+ blockLen = shake.blockLen;
643
+ const _seed = new Uint8Array(seed.length + 2);
644
+ _seed.set(seed);
645
+ const seedLen = seed.length;
646
+ const buf = new Uint8Array(blockLen);
647
+ let h = shake.create({});
648
+ let calls = 0;
649
+ let xofs = 0;
650
+ return {
651
+ stats: () => ({ calls, xofs }),
652
+ get: (x, y) => {
653
+ _seed[seedLen + 0] = x;
654
+ _seed[seedLen + 1] = y;
655
+ h.destroy();
656
+ h = shake.create({}).update(_seed);
657
+ calls++;
658
+ return () => {
659
+ xofs++;
660
+ return h.xofInto(buf);
661
+ };
662
+ },
663
+ clean: () => {
664
+ h.destroy();
665
+ cleanBytes(buf, _seed);
666
+ }
667
+ };
668
+ };
669
+ var XOF128 = /* @__PURE__ */ createXofShake(shake128);
670
+
671
+ // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/ml-kem.js
672
+ var N = 256;
673
+ var Q = 3329;
674
+ var F = 3303;
675
+ var ROOT_OF_UNITY = 17;
676
+ var crystals = /* @__PURE__ */ genCrystals({
677
+ N,
678
+ Q,
679
+ F,
680
+ ROOT_OF_UNITY,
681
+ newPoly: (n) => new Uint16Array(n),
682
+ brvBits: 7});
683
+ var PARAMS = /* @__PURE__ */ (() => Object.freeze({
684
+ 512: Object.freeze({ N, Q, K: 2, ETA1: 3, ETA2: 2, du: 10, dv: 4, RBGstrength: 128 }),
685
+ 768: Object.freeze({ N, Q, K: 3, ETA1: 2, ETA2: 2, du: 10, dv: 4, RBGstrength: 192 }),
686
+ 1024: Object.freeze({ N, Q, K: 4, ETA1: 2, ETA2: 2, du: 11, dv: 5, RBGstrength: 256 })
687
+ }))();
688
+ var compress = (d) => {
689
+ if (d >= 12)
690
+ return { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i };
691
+ const a = 2 ** (d - 1);
692
+ return {
693
+ // This only matches standalone Compress_d after bitsCoder masks the result into Z_(2^d).
694
+ encode: (i) => ((i << d) + Q / 2) / Q,
695
+ // const decompress = (i: number) => round((Q / 2 ** d) * i);
696
+ decode: (i) => i * Q + a >>> d
697
+ };
698
+ };
699
+ var byteCoder = (d) => crystals.bitsCoder(d, { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i } );
700
+ var polyCoder = (d) => d === 12 ? byteCoder(12) : crystals.bitsCoder(d, compress(d));
701
+ function polyAdd(a_, b_) {
702
+ const a = a_;
703
+ const b = b_;
704
+ for (let i = 0; i < N; i++)
705
+ a[i] = crystals.mod(a[i] + b[i]);
392
706
  }
393
- function assembleCoseSign1(args) {
394
- if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
395
- throw new OffHostSignError(
396
- "INVALID_PUBKEY_LENGTH",
397
- `signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
398
- );
399
- }
400
- if (args.signature.length !== ED25519_SIGNATURE_LENGTH) {
401
- throw new OffHostSignError(
402
- "INVALID_SIGNATURE_LENGTH",
403
- `signature must be 64 bytes (Ed25519 raw signature), got ${args.signature.length}`
404
- );
405
- }
406
- const { protectedHeader } = encodePath1ProtectedHeader(args.signerPubkey);
407
- const coseSign1Bytes = encodeCoseSign1({
408
- protectedHeader,
409
- unprotectedHeader: /* @__PURE__ */ new Map(),
410
- payload: null,
411
- signature: args.signature
412
- });
413
- const chunks = chunkBytes(coseSign1Bytes);
414
- const sigEntry = { cose_sign1: chunks };
415
- return { coseSign1Bytes, sigEntry };
707
+ function polySub(a_, b_) {
708
+ const a = a_;
709
+ const b = b_;
710
+ for (let i = 0; i < N; i++)
711
+ a[i] = crystals.mod(a[i] - b[i]);
416
712
  }
417
- function prepareSigStructureHashed(args) {
418
- if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
419
- throw new OffHostSignError(
420
- "INVALID_PUBKEY_LENGTH",
421
- `signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
422
- );
423
- }
424
- const { protectedHeaderBytes } = encodePath1ProtectedHeader(args.signerPubkey);
425
- const toSign = buildToSign(args.record);
426
- const toSignHashBytes = blake2b224(toSign);
427
- const sigStructureBytes = buildSigStructure({
428
- context: "Signature1",
429
- bodyProtectedBytes: protectedHeaderBytes,
430
- externalAad: EMPTY_BYTES2,
431
- payload: toSignHashBytes
432
- });
433
- return { sigStructureBytes, protectedHeaderBytes, toSignHashBytes };
713
+ function BaseCaseMultiply(a0, a1, b0, b1, zeta) {
714
+ const c0 = crystals.mod(a1 * b1 * zeta + a0 * b0);
715
+ const c1 = crystals.mod(a0 * b1 + a1 * b0);
716
+ return { c0, c1 };
434
717
  }
435
- function assembleCoseSign1Hashed(args) {
436
- if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
437
- throw new OffHostSignError(
438
- "INVALID_PUBKEY_LENGTH",
439
- `signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
440
- );
441
- }
442
- if (args.signature.length !== ED25519_SIGNATURE_LENGTH) {
443
- throw new OffHostSignError(
444
- "INVALID_SIGNATURE_LENGTH",
445
- `signature must be 64 bytes (Ed25519 raw signature), got ${args.signature.length}`
446
- );
718
+ function MultiplyNTTs(f_, g_) {
719
+ const f = f_;
720
+ const g = g_;
721
+ for (let i = 0; i < N / 2; i++) {
722
+ let z3 = crystals.nttZetas[64 + (i >> 1)];
723
+ if (i & 1)
724
+ z3 = -z3;
725
+ const { c0, c1 } = BaseCaseMultiply(f[2 * i + 0], f[2 * i + 1], g[2 * i + 0], g[2 * i + 1], z3);
726
+ f[2 * i + 0] = c0;
727
+ f[2 * i + 1] = c1;
447
728
  }
448
- const { protectedHeader } = encodePath1ProtectedHeader(args.signerPubkey);
449
- const unprotectedHeader = /* @__PURE__ */ new Map([["hashed", true]]);
450
- const coseSign1Bytes = encodeCoseSign1({
451
- protectedHeader,
452
- unprotectedHeader,
453
- payload: null,
454
- signature: args.signature
455
- });
456
- const chunks = chunkBytes(coseSign1Bytes);
457
- const sigEntry = { cose_sign1: chunks };
458
- return { coseSign1Bytes, sigEntry };
729
+ return f;
459
730
  }
460
-
461
- // src/client/http-error.ts
462
- var CANONICAL_PROBLEM_KEYS = /* @__PURE__ */ new Set([
463
- "type",
464
- "title",
465
- "status",
466
- "detail",
467
- "code",
468
- "trace_id",
469
- "errors",
470
- "instance"
471
- ]);
472
- function extractProblemExtensions(problem) {
473
- const out = {};
474
- for (const [key, value] of Object.entries(problem)) {
475
- if (!CANONICAL_PROBLEM_KEYS.has(key)) {
476
- out[key] = value;
731
+ function SampleNTT(xof_) {
732
+ const xof = xof_;
733
+ const r = new Uint16Array(N);
734
+ for (let j = 0; j < N; ) {
735
+ const b = xof();
736
+ if (b.length % 3)
737
+ throw new Error("SampleNTT: unaligned block");
738
+ for (let i = 0; j < N && i + 3 <= b.length; i += 3) {
739
+ const d1 = (b[i + 0] >> 0 | b[i + 1] << 8) & 4095;
740
+ const d2 = (b[i + 1] >> 4 | b[i + 2] << 4) & 4095;
741
+ if (d1 < Q)
742
+ r[j++] = d1;
743
+ if (j < N && d2 < Q)
744
+ r[j++] = d2;
477
745
  }
478
746
  }
479
- return out;
747
+ return r;
480
748
  }
481
- var Label309HttpError = class extends Error {
482
- problem;
483
- code;
484
- httpStatus;
485
- title;
486
- detail;
487
- type;
488
- traceId;
489
- instance;
490
- errors;
491
- extensions;
492
- requestId;
493
- retryAfterSeconds;
494
- constructor(init) {
495
- super(init.problem.detail || `${init.problem.title} (HTTP ${init.problem.status})`);
496
- this.name = "Label309HttpError";
497
- this.problem = init.problem;
498
- this.code = init.problem.code;
499
- this.httpStatus = init.problem.status;
500
- this.title = init.problem.title;
501
- this.detail = init.problem.detail;
502
- this.type = init.problem.type;
503
- this.traceId = init.problem.trace_id;
504
- this.instance = init.problem.instance;
505
- this.errors = init.problem.errors;
506
- this.extensions = init.extensions ?? extractProblemExtensions(init.problem);
507
- this.requestId = init.requestId ?? init.problem.trace_id;
508
- this.retryAfterSeconds = init.retryAfterSeconds;
509
- }
510
- };
511
-
512
- // src/client/batch-empty-error.ts
513
- var BatchEmptyError = class extends Label309HttpError {
514
- constructor(init) {
515
- super(init);
516
- this.name = "BatchEmptyError";
749
+ var sampleCBDBytes = (buf, eta) => {
750
+ const r = new Uint16Array(N);
751
+ const b32 = u32(buf);
752
+ swap32IfBE(b32);
753
+ let len = 0;
754
+ for (let i = 0, p = 0, bb = 0, t0 = 0; i < b32.length; i++) {
755
+ let b = b32[i];
756
+ for (let j = 0; j < 32; j++) {
757
+ bb += b & 1;
758
+ b >>= 1;
759
+ len += 1;
760
+ if (len === eta) {
761
+ t0 = bb;
762
+ bb = 0;
763
+ } else if (len === 2 * eta) {
764
+ r[p++] = crystals.mod(t0 - bb);
765
+ bb = 0;
766
+ len = 0;
767
+ }
768
+ }
517
769
  }
770
+ swap32IfBE(b32);
771
+ if (len)
772
+ throw new Error(`sampleCBD: leftover bits: ${len}`);
773
+ return r;
518
774
  };
519
-
520
- // src/client/batch-too-large-error.ts
521
- function readInt(value) {
522
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
775
+ function sampleCBD(PRF_, seed, nonce, eta) {
776
+ const PRF = PRF_;
777
+ return sampleCBDBytes(PRF(eta * N / 4, seed, nonce), eta);
523
778
  }
524
- var BatchTooLargeError = class extends Label309HttpError {
525
- max;
526
- got;
527
- constructor(init) {
528
- super(init);
529
- this.name = "BatchTooLargeError";
530
- this.max = readInt(this.extensions["max"]);
531
- this.got = readInt(this.extensions["got"]);
532
- }
533
- };
534
-
535
- // src/client/forbidden-error.ts
536
- var ForbiddenError = class extends Label309HttpError {
537
- constructor(init) {
538
- super(init);
539
- this.name = "ForbiddenError";
540
- }
779
+ var genKPKE = (opts_) => {
780
+ const opts2 = opts_;
781
+ const { K, PRF, XOF, HASH512, ETA1, ETA2, du, dv } = opts2;
782
+ const poly1 = polyCoder(1);
783
+ const polyV = polyCoder(dv);
784
+ const polyU = polyCoder(du);
785
+ const publicCoder = splitCoder("publicKey", vecCoder(polyCoder(12), K), 32);
786
+ const secretCoder = vecCoder(polyCoder(12), K);
787
+ const cipherCoder = splitCoder("ciphertext", vecCoder(polyU, K), polyV);
788
+ const seedCoder = splitCoder("seed", 32, 32);
789
+ return {
790
+ secretCoder,
791
+ lengths: {
792
+ secretKey: secretCoder.bytesLen,
793
+ publicKey: publicCoder.bytesLen,
794
+ cipherText: cipherCoder.bytesLen
795
+ },
796
+ keygen: (seed) => {
797
+ abytesDoc(seed, 32, "seed");
798
+ const seedDst = new Uint8Array(33);
799
+ seedDst.set(seed);
800
+ seedDst[32] = K;
801
+ const seedHash = HASH512(seedDst);
802
+ const [rho, sigma] = seedCoder.decode(seedHash);
803
+ const sHat = [];
804
+ const tHat = [];
805
+ for (let i = 0; i < K; i++)
806
+ sHat.push(crystals.NTT.encode(sampleCBD(PRF, sigma, i, ETA1)));
807
+ const x = XOF(rho);
808
+ for (let i = 0; i < K; i++) {
809
+ const e = crystals.NTT.encode(sampleCBD(PRF, sigma, K + i, ETA1));
810
+ for (let j = 0; j < K; j++) {
811
+ const aji = SampleNTT(x.get(j, i));
812
+ polyAdd(e, MultiplyNTTs(aji, sHat[j]));
813
+ }
814
+ tHat.push(e);
815
+ }
816
+ x.clean();
817
+ const res = {
818
+ publicKey: publicCoder.encode([tHat, rho]),
819
+ secretKey: secretCoder.encode(sHat)
820
+ };
821
+ cleanBytes(rho, sigma, sHat, tHat, seedDst, seedHash);
822
+ return res;
823
+ },
824
+ encrypt: (publicKey, msg, seed) => {
825
+ const [tHat, rho] = publicCoder.decode(publicKey);
826
+ const rHat = [];
827
+ for (let i = 0; i < K; i++)
828
+ rHat.push(crystals.NTT.encode(sampleCBD(PRF, seed, i, ETA1)));
829
+ const x = XOF(rho);
830
+ const tmp2 = new Uint16Array(N);
831
+ const u = [];
832
+ for (let i = 0; i < K; i++) {
833
+ const e1 = sampleCBD(PRF, seed, K + i, ETA2);
834
+ const tmp = new Uint16Array(N);
835
+ for (let j = 0; j < K; j++) {
836
+ const aij = SampleNTT(x.get(i, j));
837
+ polyAdd(tmp, MultiplyNTTs(aij, rHat[j]));
838
+ }
839
+ polyAdd(e1, crystals.NTT.decode(tmp));
840
+ u.push(e1);
841
+ polyAdd(tmp2, MultiplyNTTs(tHat[i], rHat[i]));
842
+ cleanBytes(tmp);
843
+ }
844
+ x.clean();
845
+ const e2 = sampleCBD(PRF, seed, 2 * K, ETA2);
846
+ polyAdd(e2, crystals.NTT.decode(tmp2));
847
+ const v = poly1.decode(msg);
848
+ polyAdd(v, e2);
849
+ cleanBytes(tHat, rHat, tmp2, e2);
850
+ return cipherCoder.encode([u, v]);
851
+ },
852
+ decrypt: (cipherText, privateKey) => {
853
+ const [u, v] = cipherCoder.decode(cipherText);
854
+ const sk = secretCoder.decode(privateKey);
855
+ const tmp = new Uint16Array(N);
856
+ for (let i = 0; i < K; i++)
857
+ polyAdd(tmp, MultiplyNTTs(sk[i], crystals.NTT.encode(u[i])));
858
+ polySub(v, crystals.NTT.decode(tmp));
859
+ cleanBytes(tmp, sk, u);
860
+ return poly1.encode(v);
861
+ }
862
+ };
541
863
  };
864
+ function createKyber(opts2) {
865
+ const rawOpts = opts2;
866
+ const KPKE = genKPKE(rawOpts);
867
+ const { HASH256, HASH512, KDF } = rawOpts;
868
+ const { secretCoder: KPKESecretCoder, lengths } = KPKE;
869
+ const secretCoder = splitCoder("secretKey", lengths.secretKey, lengths.publicKey, 32, 32);
870
+ const msgLen = 32;
871
+ const seedLen = 64;
872
+ const kemLengths = Object.freeze({
873
+ ...lengths,
874
+ seed: 64,
875
+ msg: msgLen,
876
+ msgRand: msgLen,
877
+ secretKey: secretCoder.bytesLen
878
+ });
879
+ return Object.freeze({
880
+ info: Object.freeze({ type: "ml-kem" }),
881
+ lengths: kemLengths,
882
+ keygen: (seed = randomBytes(seedLen)) => {
883
+ abytesDoc(seed, seedLen, "seed");
884
+ const { publicKey, secretKey: sk } = KPKE.keygen(seed.subarray(0, 32));
885
+ const publicKeyHash = HASH256(publicKey);
886
+ const secretKey = secretCoder.encode([sk, publicKey, publicKeyHash, seed.subarray(32)]);
887
+ cleanBytes(sk, publicKeyHash);
888
+ return {
889
+ publicKey,
890
+ secretKey
891
+ };
892
+ },
893
+ getPublicKey: (secretKey) => {
894
+ const [_sk, publicKey, _publicKeyHash, _z] = secretCoder.decode(secretKey);
895
+ return Uint8Array.from(publicKey);
896
+ },
897
+ encapsulate: (publicKey, msg = randomBytes(msgLen)) => {
898
+ abytesDoc(publicKey, lengths.publicKey, "publicKey");
899
+ abytesDoc(msg, msgLen, "message");
900
+ const eke = publicKey.subarray(0, 384 * opts2.K);
901
+ const ek = KPKESecretCoder.encode(KPKESecretCoder.decode(copyBytes(eke)));
902
+ if (!equalBytes(ek, eke)) {
903
+ cleanBytes(ek);
904
+ throw new Error("ML-KEM.encapsulate: wrong publicKey modulus");
905
+ }
906
+ cleanBytes(ek);
907
+ const kr = HASH512.create().update(msg).update(HASH256(publicKey)).digest();
908
+ const cipherText = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
909
+ cleanBytes(kr.subarray(32));
910
+ return {
911
+ cipherText,
912
+ sharedSecret: kr.subarray(0, 32)
913
+ };
914
+ },
915
+ decapsulate: (cipherText, secretKey) => {
916
+ abytesDoc(secretKey, secretCoder.bytesLen, "secretKey");
917
+ abytesDoc(cipherText, lengths.cipherText, "cipherText");
918
+ const k768 = secretCoder.bytesLen - 96;
919
+ const start = k768 + 32;
920
+ const test = HASH256(secretKey.subarray(k768 / 2, start));
921
+ if (!equalBytes(test, secretKey.subarray(start, start + 32)))
922
+ throw new Error("invalid secretKey: hash check failed");
923
+ const [sk, publicKey, publicKeyHash, z3] = secretCoder.decode(secretKey);
924
+ const msg = KPKE.decrypt(cipherText, sk);
925
+ const kr = HASH512.create().update(msg).update(publicKeyHash).digest();
926
+ const Khat = kr.subarray(0, 32);
927
+ const cipherText2 = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
928
+ const isValid = equalBytes(cipherText, cipherText2);
929
+ const Kbar = KDF.create({ dkLen: 32 }).update(z3).update(cipherText).digest();
930
+ cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar);
931
+ return isValid ? Khat : Kbar;
932
+ }
933
+ });
934
+ }
935
+ function shakePRF(dkLen, key, nonce) {
936
+ return shake256.create({ dkLen }).update(key).update(new Uint8Array([nonce])).digest();
937
+ }
938
+ var opts = /* @__PURE__ */ (() => ({
939
+ HASH256: sha3_256,
940
+ HASH512: sha3_512,
941
+ KDF: shake256,
942
+ XOF: XOF128,
943
+ PRF: shakePRF
944
+ }))();
945
+ var mk = (params) => createKyber({
946
+ ...opts,
947
+ ...params
948
+ });
949
+ var ml_kem768 = /* @__PURE__ */ (() => mk(PARAMS[768]))();
542
950
 
543
- // src/client/idempotency-conflict-error.ts
544
- var IdempotencyConflictError = class extends Label309HttpError {
545
- constructor(init) {
546
- super(init);
547
- this.name = "IdempotencyConflictError";
951
+ // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/hybrid.js
952
+ function ecKeygen(curve, allowZeroKey = false) {
953
+ const lengths = curve.lengths;
954
+ let keygen = curve.keygen;
955
+ if (allowZeroKey) {
956
+ if (!("getSharedSecret" in curve && "sign" in curve && "verify" in curve))
957
+ throw new Error("allowZeroKey requires a Weierstrass curve");
958
+ const wCurve = curve;
959
+ const Fn = wCurve.Point.Fn;
960
+ keygen = (seed = randomBytes(lengths.seed)) => {
961
+ abytes(seed, lengths.seed, "seed");
962
+ const seedScalar = Fn.isLE ? bytesToNumberLE(seed) : bytesToNumberBE(seed);
963
+ const secretKey = Fn.toBytes(Fn.create(seedScalar));
964
+ return {
965
+ secretKey,
966
+ publicKey: curve.getPublicKey(secretKey)
967
+ };
968
+ };
548
969
  }
549
- };
550
-
551
- // src/client/insufficient-funds-error.ts
552
- function readBigIntString(value) {
553
- if (typeof value !== "string") return void 0;
554
- if (!/^-?[0-9]+$/.test(value)) return void 0;
555
- try {
556
- return BigInt(value);
557
- } catch {
558
- return void 0;
970
+ return {
971
+ lengths: { secretKey: lengths.secretKey, publicKey: lengths.publicKey, seed: lengths.seed },
972
+ keygen: (seed) => keygen(seed),
973
+ getPublicKey: (secretKey) => curve.getPublicKey(secretKey)
974
+ };
975
+ }
976
+ function ecdhKem(curve, allowZeroKey = false) {
977
+ const kg = ecKeygen(curve, allowZeroKey);
978
+ if (!curve.getSharedSecret)
979
+ throw new Error("wrong curve");
980
+ return {
981
+ lengths: { ...kg.lengths, msg: kg.lengths.seed, cipherText: kg.lengths.publicKey },
982
+ keygen: kg.keygen,
983
+ getPublicKey: kg.getPublicKey,
984
+ encapsulate(publicKey, rand = randomBytes(curve.lengths.seed)) {
985
+ const seed = copyBytes(rand);
986
+ let ek = void 0;
987
+ try {
988
+ ek = this.keygen(seed).secretKey;
989
+ const sharedSecret = this.decapsulate(publicKey, ek);
990
+ const cipherText = curve.getPublicKey(ek);
991
+ return { sharedSecret, cipherText };
992
+ } finally {
993
+ cleanBytes(seed);
994
+ if (ek)
995
+ cleanBytes(ek);
996
+ }
997
+ },
998
+ decapsulate(cipherText, secretKey) {
999
+ const res = curve.getSharedSecret(secretKey, cipherText);
1000
+ return curve.lengths.publicKeyHasPrefix ? res.subarray(1) : res;
1001
+ }
1002
+ };
1003
+ }
1004
+ function splitLengths(lst, name) {
1005
+ return splitCoder(name, ...lst.map((i) => {
1006
+ if (typeof i.lengths[name] !== "number")
1007
+ throw new Error("wrong length: " + name);
1008
+ return i.lengths[name];
1009
+ }));
1010
+ }
1011
+ function expandSeedXof(xof) {
1012
+ return ((seed, seedLen) => xof(seed, { dkLen: seedLen }));
1013
+ }
1014
+ function combineKeys(realSeedLen, expandSeed_, ...ck_) {
1015
+ const expandSeed = expandSeed_;
1016
+ const ck = ck_;
1017
+ const seedCoder = splitLengths(ck, "seed");
1018
+ const pkCoder = splitLengths(ck, "publicKey");
1019
+ anumber(realSeedLen);
1020
+ function expandDecapsulationKey(seed) {
1021
+ abytes(seed, realSeedLen);
1022
+ const expandedRaw = expandSeed(seed, seedCoder.bytesLen);
1023
+ const expandedSeed = expandedRaw.buffer === seed.buffer ? copyBytes(expandedRaw) : expandedRaw;
1024
+ const expanded = [];
1025
+ const keySecret = [];
1026
+ const secretKey = [];
1027
+ const publicKey = [];
1028
+ let ok = false;
1029
+ try {
1030
+ for (const part of seedCoder.decode(expandedSeed))
1031
+ expanded.push(copyBytes(part));
1032
+ for (let i = 0; i < ck.length; i++) {
1033
+ const keys = ck[i].keygen(expanded[i]);
1034
+ keySecret.push(keys.secretKey);
1035
+ secretKey.push(copyBytes(keys.secretKey));
1036
+ publicKey.push(keys.publicKey);
1037
+ }
1038
+ ok = true;
1039
+ return { secretKey, publicKey };
1040
+ } finally {
1041
+ cleanBytes(expandedSeed, expanded, keySecret);
1042
+ if (!ok)
1043
+ cleanBytes(secretKey);
1044
+ }
559
1045
  }
1046
+ return {
1047
+ info: { lengths: { seed: realSeedLen, publicKey: pkCoder.bytesLen, secretKey: realSeedLen } },
1048
+ getPublicKey(secretKey) {
1049
+ return this.keygen(secretKey).publicKey;
1050
+ },
1051
+ keygen(seed = randomBytes(realSeedLen)) {
1052
+ const { publicKey: pk, secretKey } = expandDecapsulationKey(seed);
1053
+ try {
1054
+ const publicKey = pkCoder.encode(pk);
1055
+ return { secretKey: seed, publicKey };
1056
+ } finally {
1057
+ cleanBytes(pk);
1058
+ cleanBytes(secretKey);
1059
+ }
1060
+ },
1061
+ expandDecapsulationKey,
1062
+ realSeedLen
1063
+ };
560
1064
  }
561
- function readString(value) {
562
- return typeof value === "string" ? value : void 0;
1065
+ function combineKEMS(realSeedLen, realMsgLen, expandSeed, combiner, ...kems) {
1066
+ const rawCombiner = combiner;
1067
+ const rawKems = kems;
1068
+ const keys = combineKeys(realSeedLen, expandSeed, ...rawKems);
1069
+ const ctCoder = splitLengths(rawKems, "cipherText");
1070
+ const pkCoder = splitLengths(rawKems, "publicKey");
1071
+ const msgCoder = splitLengths(rawKems, "msg");
1072
+ anumber(realMsgLen);
1073
+ const lengths = Object.freeze({
1074
+ ...keys.info.lengths,
1075
+ msg: realMsgLen,
1076
+ msgRand: msgCoder.bytesLen,
1077
+ cipherText: ctCoder.bytesLen
1078
+ });
1079
+ return Object.freeze({
1080
+ lengths,
1081
+ getPublicKey: keys.getPublicKey,
1082
+ keygen: keys.keygen,
1083
+ encapsulate(pk, randomness = randomBytes(msgCoder.bytesLen)) {
1084
+ const pks = pkCoder.decode(pk);
1085
+ const rand = msgCoder.decode(randomness);
1086
+ const sharedSecret = [];
1087
+ const cipherText = [];
1088
+ try {
1089
+ for (let i = 0; i < rawKems.length; i++) {
1090
+ const enc = rawKems[i].encapsulate(pks[i], rand[i]);
1091
+ sharedSecret.push(enc.sharedSecret);
1092
+ cipherText.push(enc.cipherText);
1093
+ }
1094
+ return {
1095
+ // Detach the combiner result before cleanup: a caller-provided combiner may alias one of
1096
+ // the child sharedSecret buffers, and those child buffers are zeroized immediately below.
1097
+ sharedSecret: copyBytes(rawCombiner(pks, cipherText, sharedSecret)),
1098
+ cipherText: ctCoder.encode(cipherText)
1099
+ };
1100
+ } finally {
1101
+ cleanBytes(sharedSecret, cipherText);
1102
+ }
1103
+ },
1104
+ decapsulate(ct, seed) {
1105
+ const cts = ctCoder.decode(ct);
1106
+ const { publicKey, secretKey } = keys.expandDecapsulationKey(seed);
1107
+ const sharedSecret = rawKems.map((i, j) => i.decapsulate(cts[j], secretKey[j]));
1108
+ try {
1109
+ return copyBytes(rawCombiner(publicKey, cts, sharedSecret));
1110
+ } finally {
1111
+ cleanBytes(secretKey, sharedSecret);
1112
+ }
1113
+ }
1114
+ });
563
1115
  }
564
- var InsufficientFundsError = class extends Label309HttpError {
565
- balanceUsdMicros;
566
- requiredUsdMicros;
567
- topUpUrl;
568
- constructor(init) {
569
- super(init);
570
- this.name = "InsufficientFundsError";
571
- this.balanceUsdMicros = readBigIntString(this.extensions["balance_usd_micros"]);
572
- this.requiredUsdMicros = readBigIntString(this.extensions["required_usd_micros"]);
573
- this.topUpUrl = readString(this.extensions["top_up_url"]);
574
- }
575
- };
576
-
577
- // src/client/insufficient-scope-error.ts
578
- function readScopeArray(value) {
579
- if (!Array.isArray(value)) return [];
580
- return value.filter((entry) => typeof entry === "string");
1116
+ var x25519kem = /* @__PURE__ */ ecdhKem(x25519);
1117
+ var ml_kem768_x25519 = /* @__PURE__ */ (() => combineKEMS(
1118
+ 32,
1119
+ 32,
1120
+ expandSeedXof(shake256),
1121
+ // Awesome label, so much escaping hell in a single line.
1122
+ (pk, ct, ss) => sha3_256(concatBytes(ss[0], ss[1], ct[1], pk[1], asciiToBytes("\\.//^\\"))),
1123
+ ml_kem768,
1124
+ x25519kem
1125
+ ))();
1126
+ var XWing = /* @__PURE__ */ (() => ml_kem768_x25519)();
1127
+ function chacha20Poly1305Encrypt(opts2) {
1128
+ return chacha20poly1305(opts2.key, opts2.nonce, opts2.aad).encrypt(opts2.plaintext);
581
1129
  }
582
- var InsufficientScopeError = class extends Label309HttpError {
583
- requiredScopes;
584
- grantedScopes;
585
- constructor(init) {
586
- super(init);
587
- this.name = "InsufficientScopeError";
588
- this.requiredScopes = readScopeArray(this.extensions["required"]);
589
- this.grantedScopes = readScopeArray(this.extensions["granted"]);
590
- }
591
- /** Convenience for the single-scope case; first entry of `requiredScopes`. */
592
- get requiredScope() {
593
- return this.requiredScopes[0];
594
- }
595
- };
596
-
597
- // src/client/internal-server-error.ts
598
- var InternalServerError = class extends Label309HttpError {
599
- constructor(init) {
600
- super(init);
601
- this.name = "InternalServerError";
602
- }
603
- };
604
-
605
- // src/client/invalid-body-error.ts
606
- var InvalidBodyError = class extends Label309HttpError {
607
- constructor(init) {
608
- super(init);
609
- this.name = "InvalidBodyError";
610
- }
611
- };
612
-
613
- // src/client/malformed-cbor-error.ts
614
- var MalformedCborError = class extends Label309HttpError {
615
- constructor(init) {
616
- super(init);
617
- this.name = "MalformedCborError";
1130
+ var MLKEM768X25519_PUBLIC_KEY_LENGTH = 1216;
1131
+ var MLKEM768X25519_ENC_LENGTH = 1120;
1132
+ var MLKEM768X25519_ESEED_LENGTH = 64;
1133
+ function mlkem768x25519Encapsulate(opts2) {
1134
+ if (opts2.publicKey.length !== MLKEM768X25519_PUBLIC_KEY_LENGTH) {
1135
+ throw new Error(
1136
+ `mlkem768x25519 public key must be ${MLKEM768X25519_PUBLIC_KEY_LENGTH} bytes, got ${opts2.publicKey.length}`
1137
+ );
618
1138
  }
619
- };
620
-
621
- // src/client/not-found-error.ts
622
- var NotFoundError = class extends Label309HttpError {
623
- constructor(init) {
624
- super(init);
625
- this.name = "NotFoundError";
1139
+ if (opts2.eseed !== void 0 && opts2.eseed.length !== MLKEM768X25519_ESEED_LENGTH) {
1140
+ throw new Error(
1141
+ `mlkem768x25519 eseed must be ${MLKEM768X25519_ESEED_LENGTH} bytes, got ${opts2.eseed.length}`
1142
+ );
626
1143
  }
627
- };
628
-
629
- // src/client/quote-already-consumed-error.ts
630
- function readString2(value) {
631
- return typeof value === "string" ? value : void 0;
1144
+ const { cipherText, sharedSecret } = XWing.encapsulate(opts2.publicKey, opts2.eseed);
1145
+ return { enc: cipherText, ss: sharedSecret };
632
1146
  }
633
- var QuoteAlreadyConsumedError = class extends Label309HttpError {
634
- quoteId;
635
- constructor(init) {
636
- super(init);
637
- this.name = "QuoteAlreadyConsumedError";
638
- this.quoteId = readString2(this.extensions["quote_id"]);
1147
+ var X25519LowOrderPointError = class extends Error {
1148
+ code = "X25519_LOW_ORDER_POINT";
1149
+ constructor(options) {
1150
+ super("x25519 ECDH rejected: peer public key is a small-order point", options);
1151
+ this.name = "X25519LowOrderPointError";
639
1152
  }
640
1153
  };
641
-
642
- // src/client/quote-expired-error.ts
643
- function readString3(value) {
644
- return typeof value === "string" ? value : void 0;
1154
+ var NOBLE_LOW_ORDER_MESSAGE = "invalid private or public key received";
1155
+ function x25519PublicKey(opts2) {
1156
+ return x25519.getPublicKey(opts2.secretKey);
645
1157
  }
646
- var QuoteExpiredError = class extends Label309HttpError {
647
- quoteId;
648
- constructor(init) {
649
- super(init);
650
- this.name = "QuoteExpiredError";
651
- this.quoteId = readString3(this.extensions["quote_id"]);
1158
+ function x25519Ecdh(opts2) {
1159
+ try {
1160
+ return x25519.getSharedSecret(opts2.secretKey, opts2.theirPublicKey);
1161
+ } catch (e) {
1162
+ if (e instanceof Error && e.message === NOBLE_LOW_ORDER_MESSAGE) {
1163
+ throw new X25519LowOrderPointError({ cause: e });
1164
+ }
1165
+ throw e;
652
1166
  }
653
- };
654
-
655
- // src/client/quote-not-found-error.ts
656
- function readString4(value) {
657
- return typeof value === "string" ? value : void 0;
658
1167
  }
659
- var QuoteNotFoundError = class extends Label309HttpError {
660
- quoteId;
661
- constructor(init) {
662
- super(init);
663
- this.name = "QuoteNotFoundError";
664
- this.quoteId = readString4(this.extensions["quote_id"]);
665
- }
666
- };
667
-
668
- // src/client/rate-limited-error.ts
669
- var RateLimitedError = class extends Label309HttpError {
670
- constructor(init) {
671
- super(init);
672
- this.name = "RateLimitedError";
1168
+ function hkdfSha256(opts2) {
1169
+ return hkdf(sha256$1, opts2.ikm, opts2.salt, opts2.info, opts2.length);
1170
+ }
1171
+ var EciesSealedPoeError = class extends Error {
1172
+ code;
1173
+ constructor(code, message, options) {
1174
+ super(message, options);
1175
+ this.name = "EciesSealedPoeError";
1176
+ this.code = code;
673
1177
  }
674
1178
  };
675
-
676
- // src/client/record-not-found-error.ts
677
- var RecordNotFoundError = class extends Label309HttpError {
678
- constructor(init) {
679
- super(init);
680
- this.name = "RecordNotFoundError";
1179
+ var CHUNK_SIZE = 65536;
1180
+ var TAG_SIZE = 16;
1181
+ var NONCE_LENGTH = 12;
1182
+ var COUNTER_LENGTH = 11;
1183
+ var PAYLOAD_KEY_LENGTH = 32;
1184
+ var EMPTY_AAD = new Uint8Array(0);
1185
+ var ChunkNonce = class {
1186
+ nonce = new Uint8Array(NONCE_LENGTH);
1187
+ finished = false;
1188
+ next(final) {
1189
+ if (this.finished) {
1190
+ throw new Error("STREAM: no chunks may follow the final chunk");
1191
+ }
1192
+ if (final) {
1193
+ this.finished = true;
1194
+ this.nonce[COUNTER_LENGTH] = 1;
1195
+ }
1196
+ const out = this.nonce.slice();
1197
+ this.increment();
1198
+ return out;
681
1199
  }
682
- };
683
-
684
- // src/client/service-unavailable-error.ts
685
- var ServiceUnavailableError = class extends Label309HttpError {
686
- constructor(init) {
687
- super(init);
688
- this.name = "ServiceUnavailableError";
1200
+ get done() {
1201
+ return this.finished;
689
1202
  }
690
- };
691
-
692
- // src/client/unauthorized-error.ts
693
- var UnauthorizedError = class extends Label309HttpError {
694
- constructor(init) {
695
- super(init);
696
- this.name = "UnauthorizedError";
1203
+ increment() {
1204
+ for (let i = COUNTER_LENGTH - 1; i >= 0; i--) {
1205
+ const v = this.nonce[i] + 1 & 255;
1206
+ this.nonce[i] = v;
1207
+ if (v !== 0) return;
1208
+ }
1209
+ throw new Error("STREAM: chunk counter overflow");
697
1210
  }
698
1211
  };
699
-
700
- // src/client/validation-failed-error.ts
701
- var ValidationFailedError = class extends Label309HttpError {
702
- constructor(init) {
703
- super(init);
704
- this.name = "ValidationFailedError";
1212
+ function assertPayloadKey(payloadKey) {
1213
+ if (payloadKey.length !== PAYLOAD_KEY_LENGTH) {
1214
+ throw new Error(
1215
+ `STREAM: payloadKey MUST be exactly ${PAYLOAD_KEY_LENGTH} bytes, got ${payloadKey.length}`
1216
+ );
705
1217
  }
706
- };
707
-
708
- // src/client/parse-http-error.ts
709
- function asString(value) {
710
- return typeof value === "string" ? value : void 0;
711
- }
712
- function asNumber(value) {
713
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
714
1218
  }
715
- function asProblemErrorEntries(value) {
716
- if (!Array.isArray(value)) return void 0;
717
- const out = [];
718
- for (const entry of value) {
719
- if (entry === null || typeof entry !== "object") continue;
720
- const e = entry;
721
- out.push({
722
- field: typeof e["field"] === "string" ? e["field"] : "",
723
- code: typeof e["code"] === "string" ? e["code"] : "",
724
- detail: typeof e["detail"] === "string" ? e["detail"] : ""
1219
+ var StreamSealer = class {
1220
+ payloadKey;
1221
+ nonce = new ChunkNonce();
1222
+ chunkIndex = 0;
1223
+ constructor(payloadKey) {
1224
+ assertPayloadKey(payloadKey);
1225
+ this.payloadKey = payloadKey;
1226
+ }
1227
+ sealChunk(plaintext, final) {
1228
+ if (!final && plaintext.length !== CHUNK_SIZE) {
1229
+ throw new Error(
1230
+ `STREAM: non-final chunk MUST carry exactly ${CHUNK_SIZE} plaintext bytes, got ${plaintext.length}`
1231
+ );
1232
+ }
1233
+ if (final && plaintext.length > CHUNK_SIZE) {
1234
+ throw new Error(
1235
+ `STREAM: final chunk MUST carry at most ${CHUNK_SIZE} plaintext bytes, got ${plaintext.length}`
1236
+ );
1237
+ }
1238
+ if (final && plaintext.length === 0 && this.chunkIndex > 0) {
1239
+ throw new Error(
1240
+ "STREAM: a zero-length final chunk is admissible only for an empty plaintext"
1241
+ );
1242
+ }
1243
+ const sealed = chacha20Poly1305Encrypt({
1244
+ key: this.payloadKey,
1245
+ nonce: this.nonce.next(final),
1246
+ aad: EMPTY_AAD,
1247
+ plaintext
725
1248
  });
1249
+ this.chunkIndex += 1;
1250
+ return sealed;
1251
+ }
1252
+ };
1253
+ function streamSeal(args) {
1254
+ const { plaintext } = args;
1255
+ const sealer = new StreamSealer(args.payloadKey);
1256
+ const chunkCount = Math.max(1, Math.ceil(plaintext.length / CHUNK_SIZE));
1257
+ const out = new Uint8Array(plaintext.length + chunkCount * TAG_SIZE);
1258
+ let offset = 0;
1259
+ for (let i = 0; i < chunkCount; i++) {
1260
+ const final = i === chunkCount - 1;
1261
+ const chunk = plaintext.subarray(
1262
+ i * CHUNK_SIZE,
1263
+ Math.min((i + 1) * CHUNK_SIZE, plaintext.length)
1264
+ );
1265
+ const sealed = sealer.sealChunk(chunk, final);
1266
+ out.set(sealed, offset);
1267
+ offset += sealed.length;
726
1268
  }
727
1269
  return out;
728
1270
  }
729
- function synthesiseProblem(httpStatus, requestId) {
730
- const code = `http-${httpStatus}`;
731
- return {
732
- type: `about:blank`,
733
- title: `HTTP ${httpStatus}`,
734
- status: httpStatus,
735
- detail: `Server returned HTTP ${httpStatus} without a problem+json body.`,
736
- code,
737
- trace_id: requestId ?? ""
738
- };
1271
+ function encodeCanonicalCbor3(value) {
1272
+ return encode(value, {
1273
+ cde: true,
1274
+ collapseBigInts: true,
1275
+ rejectDuplicateKeys: true,
1276
+ sortKeys: sortCoreDeterministic
1277
+ });
739
1278
  }
740
- function toProblemDetails(httpStatus, body, requestId) {
741
- if (body === null || typeof body !== "object") {
742
- return synthesiseProblem(httpStatus, requestId);
743
- }
744
- const b = body;
745
- const code = asString(b["code"]);
746
- const status = asNumber(b["status"]) ?? httpStatus;
747
- const title = asString(b["title"]);
748
- if (code === void 0 && title === void 0) {
749
- return synthesiseProblem(httpStatus, requestId);
750
- }
751
- const errors = asProblemErrorEntries(b["errors"]);
752
- const base = {
753
- ...b,
754
- // RFC 7807 §4.2: `about:blank` is the default when no type URI is supplied.
755
- // The client is gateway-agnostic, so it must not invent a vendor-specific
756
- // problem-type namespace; the machine-readable discriminator is `code`.
757
- type: asString(b["type"]) ?? "about:blank",
758
- title: title ?? `HTTP ${status}`,
759
- status,
760
- detail: asString(b["detail"]) ?? "",
761
- code: code ?? `http-${status}`,
762
- trace_id: asString(b["trace_id"]) ?? requestId ?? ""
763
- };
764
- if (errors !== void 0) base["errors"] = errors;
765
- return base;
1279
+ var CARDANO_POE_ITEM_HASHES_PREFIX = new TextEncoder().encode(
1280
+ "cardano-poe-item-hashes-v1"
1281
+ );
1282
+ var CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX = new TextEncoder().encode(
1283
+ "cardano-poe-slots-transcript-v1"
1284
+ );
1285
+ var CARDANO_POE_PASSPHRASE_TRANSCRIPT_PREFIX = new TextEncoder().encode(
1286
+ "cardano-poe-passphrase-transcript-v1"
1287
+ );
1288
+ var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
1289
+ "cardano-poe-slots-mac-v1"
1290
+ );
1291
+ var CARDANO_POE_HKDF_INFO_PASSPHRASE_MAC = new TextEncoder().encode(
1292
+ "cardano-poe-passphrase-mac-v1"
1293
+ );
1294
+ var CARDANO_POE_HKDF_INFO_PAYLOAD = new TextEncoder().encode(
1295
+ "cardano-poe-payload-v1"
1296
+ );
1297
+ var CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE = new TextEncoder().encode(
1298
+ "cardano-poe-payload-passphrase-v1"
1299
+ );
1300
+ var CARDANO_POE_X25519_KEK_SALT_PREFIX = new TextEncoder().encode(
1301
+ "cardano-poe-x25519-kek-salt-v1"
1302
+ );
1303
+ var CARDANO_POE_XWING_KEK_SALT_PREFIX = new TextEncoder().encode(
1304
+ "cardano-poe-xwing-kek-salt-v1"
1305
+ );
1306
+ if (CARDANO_POE_ITEM_HASHES_PREFIX.length !== 26) {
1307
+ throw new Error("CARDANO_POE_ITEM_HASHES_PREFIX byte-length invariant violated (expected 26)");
766
1308
  }
767
- function parseHttpError(args) {
768
- const problem = toProblemDetails(args.httpStatus, args.body, args.requestId);
769
- const extensions = extractProblemExtensions(problem);
770
- const init = {
771
- problem,
772
- extensions,
773
- requestId: args.requestId,
774
- retryAfterSeconds: args.retryAfterSeconds
775
- };
776
- switch (problem.code) {
777
- case "unauthorized":
778
- return new UnauthorizedError(init);
779
- case "forbidden":
780
- case "csrf-invalid":
781
- return new ForbiddenError(init);
782
- case "insufficient-scope":
783
- return new InsufficientScopeError(init);
784
- case "insufficient-funds":
785
- return new InsufficientFundsError(init);
786
- case "quote-expired":
787
- return new QuoteExpiredError(init);
788
- case "quote-not-found":
789
- return new QuoteNotFoundError(init);
790
- case "quote-already-consumed":
791
- return new QuoteAlreadyConsumedError(init);
792
- case "not-found":
793
- return new NotFoundError(init);
794
- case "record-not-found":
795
- return new RecordNotFoundError(init);
796
- case "idempotency-key-conflict":
797
- return new IdempotencyConflictError(init);
798
- case "rate-limited":
799
- return new RateLimitedError(init);
800
- case "validation-failed":
801
- return new ValidationFailedError(init);
802
- case "invalid-body":
803
- return new InvalidBodyError(init);
804
- case "malformed-cbor":
805
- return new MalformedCborError(init);
806
- case "batch-too-large":
807
- return new BatchTooLargeError(init);
808
- case "batch-empty":
809
- return new BatchEmptyError(init);
810
- case "internal-error":
811
- return new InternalServerError(init);
812
- // A gateway that prices on a live FX oracle may surface a transient
813
- // `fx-stale` pricing outage; to a vendor-neutral client that is just a
814
- // temporary inability to serve, i.e. a service-unavailable condition.
815
- case "service-unavailable":
816
- case "fx-stale":
817
- return new ServiceUnavailableError(init);
818
- default:
819
- return new Label309HttpError(init);
820
- }
1309
+ if (CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length !== 31) {
1310
+ throw new Error(
1311
+ "CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX byte-length invariant violated (expected 31)"
1312
+ );
821
1313
  }
822
-
823
- // src/client/http-helpers.ts
824
- async function readJson(response) {
825
- const text = await response.text();
826
- if (text.length === 0) return null;
827
- try {
828
- return JSON.parse(text);
829
- } catch {
830
- return null;
1314
+ if (CARDANO_POE_PASSPHRASE_TRANSCRIPT_PREFIX.length !== 36) {
1315
+ throw new Error(
1316
+ "CARDANO_POE_PASSPHRASE_TRANSCRIPT_PREFIX byte-length invariant violated (expected 36)"
1317
+ );
1318
+ }
1319
+ if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
1320
+ throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
1321
+ }
1322
+ if (CARDANO_POE_HKDF_INFO_PASSPHRASE_MAC.length !== 29) {
1323
+ throw new Error(
1324
+ "CARDANO_POE_HKDF_INFO_PASSPHRASE_MAC byte-length invariant violated (expected 29)"
1325
+ );
1326
+ }
1327
+ if (CARDANO_POE_HKDF_INFO_PAYLOAD.length !== 22) {
1328
+ throw new Error("CARDANO_POE_HKDF_INFO_PAYLOAD byte-length invariant violated (expected 22)");
1329
+ }
1330
+ if (CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE.length !== 33) {
1331
+ throw new Error(
1332
+ "CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE byte-length invariant violated (expected 33)"
1333
+ );
1334
+ }
1335
+ if (CARDANO_POE_X25519_KEK_SALT_PREFIX.length !== 30) {
1336
+ throw new Error(
1337
+ "CARDANO_POE_X25519_KEK_SALT_PREFIX byte-length invariant violated (expected 30)"
1338
+ );
1339
+ }
1340
+ if (CARDANO_POE_XWING_KEK_SALT_PREFIX.length !== 29) {
1341
+ throw new Error("CARDANO_POE_XWING_KEK_SALT_PREFIX byte-length invariant violated (expected 29)");
1342
+ }
1343
+ var EMPTY_SALT = new Uint8Array(0);
1344
+ function labelledSha256(prefix, ...parts) {
1345
+ let total = prefix.length;
1346
+ for (const p of parts) total += p.length;
1347
+ const message = new Uint8Array(total);
1348
+ message.set(prefix, 0);
1349
+ let offset = prefix.length;
1350
+ for (const p of parts) {
1351
+ message.set(p, offset);
1352
+ offset += p.length;
1353
+ }
1354
+ return sha256$1(message);
1355
+ }
1356
+ function itemHashesHash(hashes2) {
1357
+ if (Object.keys(hashes2).length === 0) {
1358
+ throw new EciesSealedPoeError(
1359
+ "ENC_REQUIRES_CONTENT_HASH",
1360
+ "hashes MUST carry at least one content-hash entry"
1361
+ );
831
1362
  }
1363
+ return labelledSha256(CARDANO_POE_ITEM_HASHES_PREFIX, encodeCanonicalCbor3(hashes2));
832
1364
  }
833
- function parseRetryAfter(header) {
834
- if (header === null) return void 0;
835
- const parsed = Number(header);
836
- return Number.isFinite(parsed) ? parsed : void 0;
1365
+ function computeSlotsHash(args) {
1366
+ const slots = args.kem === "x25519" ? args.slots.map((s) => ({ epk: s.epk, wrap: s.wrap })) : args.slots.map((s) => ({
1367
+ kem_ct: s.kem_ct,
1368
+ wrap: s.wrap
1369
+ }));
1370
+ const transcript = {
1371
+ scheme: 1,
1372
+ path: "slots",
1373
+ aead: args.aead,
1374
+ kem: args.kem,
1375
+ nonce: args.nonce,
1376
+ slots,
1377
+ hashes_hash: args.hashesHash
1378
+ };
1379
+ return labelledSha256(CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX, encodeCanonicalCbor3(transcript));
837
1380
  }
838
- async function throwIfNotOk(response) {
839
- if (response.ok) return;
840
- const body = await readJson(response);
841
- const requestId = response.headers.get("x-request-id") ?? void 0;
842
- const retryAfterSeconds = parseRetryAfter(response.headers.get("retry-after"));
843
- throw parseHttpError({ httpStatus: response.status, body, requestId, retryAfterSeconds });
1381
+ function computeSlotsMac(args) {
1382
+ const macKey = hkdfSha256({
1383
+ ikm: args.cek,
1384
+ salt: EMPTY_SALT,
1385
+ info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
1386
+ length: 32
1387
+ });
1388
+ return hmac(sha256$1, macKey, args.slotsHash);
844
1389
  }
845
-
846
- // src/client/account.ts
847
- function buildHeaders(apiKey) {
848
- const headers = new Headers({
849
- "content-type": "application/json",
850
- accept: "application/json"
1390
+ function slotsPayloadKey(args) {
1391
+ return hkdfSha256({
1392
+ ikm: args.cek,
1393
+ salt: args.nonce,
1394
+ info: CARDANO_POE_HKDF_INFO_PAYLOAD,
1395
+ length: 32
851
1396
  });
852
- if (apiKey !== void 0) headers.set("authorization", `Bearer ${apiKey}`);
853
- return headers;
854
1397
  }
855
- var AccountNamespace = class {
856
- config;
857
- constructor(config) {
858
- this.config = config;
859
- }
860
- /**
861
- * Fetch the caller's current prepaid USD balance.
862
- *
863
- * Returns `{ balanceUsdMicros }`, the gateway's `balance_usd_micros` field
864
- * (USD micro-cents as a decimal string). The string is preserved verbatim —
865
- * never parsed into a number — so no precision is lost. An account with no
866
- * ledger activity yet reads `"0"`.
867
- *
868
- * Requires authentication: 401 (UnauthorizedError) when anonymous, 403
869
- * (InsufficientScopeError) when the Bearer key lacks the `account:read`
870
- * scope.
871
- */
872
- async balance() {
873
- const response = await this.config.fetch(`${this.config.baseUrl}/api/v1/account/balance`, {
874
- method: "GET",
875
- headers: buildHeaders(this.config.apiKey)
876
- });
877
- await throwIfNotOk(response);
878
- const body = await readJson(response);
879
- return { balanceUsdMicros: body.balance_usd_micros };
880
- }
881
- };
882
-
883
- // src/client/invalid-client-config-error.ts
884
- var InvalidClientConfigError = class extends Error {
885
- code = "INVALID_CLIENT_CONFIG";
886
- constructor(message) {
887
- super(message);
888
- this.name = "InvalidClientConfigError";
1398
+ function x25519KekSalt(args) {
1399
+ return labelledSha256(CARDANO_POE_X25519_KEK_SALT_PREFIX, args.nonce, args.epk, args.pubR);
1400
+ }
1401
+ function xwingKekSalt(args) {
1402
+ return labelledSha256(CARDANO_POE_XWING_KEK_SALT_PREFIX, args.nonce, args.kemCt, args.pubR);
1403
+ }
1404
+ var SEALED_POE_AEAD = "chacha20-poly1305-stream64k";
1405
+ var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
1406
+ var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
1407
+ "cardano-poe-kek-mlkem768x25519-v1"
1408
+ );
1409
+ var ZERO_NONCE_12 = new Uint8Array(12);
1410
+ var X25519_PUBLIC_KEY_LENGTH = 32;
1411
+ var X25519_SECRET_KEY_LENGTH = 32;
1412
+ var CEK_LENGTH = 32;
1413
+ var NONCE_LENGTH2 = 24;
1414
+ var WRAP_LENGTH = 48;
1415
+ var SLOTS_MAC_LENGTH = 32;
1416
+ if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
1417
+ throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
1418
+ }
1419
+ if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
1420
+ throw new Error(
1421
+ "CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
1422
+ );
1423
+ }
1424
+ if (ZERO_NONCE_12.length !== 12) {
1425
+ throw new Error("ZERO_NONCE_12 byte-length invariant violated (expected 12)");
1426
+ }
1427
+ function uniformIndexBelow(m) {
1428
+ const limit = 4294967296 - 4294967296 % m;
1429
+ const buf = new Uint32Array(1);
1430
+ let x;
1431
+ do {
1432
+ crypto.getRandomValues(buf);
1433
+ x = buf[0];
1434
+ } while (x >= limit);
1435
+ return x % m;
1436
+ }
1437
+ function csprngShuffle(arr) {
1438
+ for (let i = arr.length - 1; i > 0; i--) {
1439
+ const j = uniformIndexBelow(i + 1);
1440
+ const tmp = arr[i];
1441
+ arr[i] = arr[j];
1442
+ arr[j] = tmp;
889
1443
  }
890
- };
891
-
892
- // src/hex.ts
893
- function bytesToHex(bytes) {
894
- return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
895
1444
  }
896
- function encodeCanonicalCbor3(value) {
897
- return encode(value, {
898
- cde: true,
899
- collapseBigInts: true,
900
- rejectDuplicateKeys: true,
901
- sortKeys: sortCoreDeterministic
1445
+ function wrapSlotX25519(args) {
1446
+ const privEph = args.privEph ?? randomBytes$1(X25519_SECRET_KEY_LENGTH);
1447
+ if (privEph.length !== X25519_SECRET_KEY_LENGTH) {
1448
+ throw new EciesSealedPoeError(
1449
+ "INVALID_EPHEMERAL_SECRET_LENGTH",
1450
+ `ephemeralSecrets[${args.slotIdx}] MUST be exactly ${X25519_SECRET_KEY_LENGTH} bytes, got ${privEph.length}`
1451
+ );
1452
+ }
1453
+ const epk = x25519PublicKey({ secretKey: privEph });
1454
+ const shared = x25519Ecdh({ secretKey: privEph, theirPublicKey: args.pubR });
1455
+ const kek = hkdfSha256({
1456
+ ikm: shared,
1457
+ salt: x25519KekSalt({ nonce: args.nonce, epk, pubR: args.pubR }),
1458
+ info: CARDANO_POE_HKDF_INFO_KEK,
1459
+ length: 32
1460
+ });
1461
+ const wrap = chacha20Poly1305Encrypt({
1462
+ key: kek,
1463
+ nonce: ZERO_NONCE_12,
1464
+ aad: CARDANO_POE_HKDF_INFO_KEK,
1465
+ plaintext: args.cek
902
1466
  });
1467
+ if (wrap.length !== WRAP_LENGTH) {
1468
+ throw new Error(`internal: wrap.length=${wrap.length}, expected ${WRAP_LENGTH}`);
1469
+ }
1470
+ return { epk, wrap };
903
1471
  }
904
- var LEAVES_LIST_FORMAT_V1 = "cardano-poe-merkle-leaves-v1";
905
- var TREE_ALG_RFC9162 = "rfc9162-sha256";
906
- var DIGEST_LENGTH2 = 32;
907
- var MerkleLeavesListError = class extends Error {
908
- code;
909
- constructor(code, message) {
910
- super(message ? `${code}: ${message}` : code);
911
- this.code = code;
912
- this.name = "MerkleLeavesListError";
1472
+ function wrapSlotMlkem768X25519(args) {
1473
+ const { enc, ss } = mlkem768x25519Encapsulate({
1474
+ publicKey: args.pubR,
1475
+ ...args.eseed !== void 0 ? { eseed: args.eseed } : {}
1476
+ });
1477
+ if (enc.length !== MLKEM768X25519_ENC_LENGTH) {
1478
+ throw new Error(`internal: enc.length=${enc.length}, expected ${MLKEM768X25519_ENC_LENGTH}`);
913
1479
  }
914
- };
915
- function encodeLeavesList(args) {
916
- if (!(args.root instanceof Uint8Array) || args.root.length !== DIGEST_LENGTH2) {
917
- throw new MerkleLeavesListError(
918
- "SCHEMA_MERKLE_LEAVES_MALFORMED",
919
- `root must be a Uint8Array(${DIGEST_LENGTH2})`
920
- );
1480
+ const kek = hkdfSha256({
1481
+ ikm: ss,
1482
+ salt: xwingKekSalt({ nonce: args.nonce, kemCt: enc, pubR: args.pubR }),
1483
+ info: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
1484
+ length: 32
1485
+ });
1486
+ const wrap = chacha20Poly1305Encrypt({
1487
+ key: kek,
1488
+ nonce: ZERO_NONCE_12,
1489
+ aad: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
1490
+ plaintext: args.cek
1491
+ });
1492
+ if (wrap.length !== WRAP_LENGTH) {
1493
+ throw new Error(`internal: wrap.length=${wrap.length}, expected ${WRAP_LENGTH}`);
921
1494
  }
922
- if (args.leaves.length < 1) {
923
- throw new MerkleLeavesListError(
924
- "SCHEMA_MERKLE_LEAVES_MALFORMED",
925
- "leaves array must be non-empty"
1495
+ return { kem_ct: enc, wrap };
1496
+ }
1497
+ function eciesSealedPoeWrap(args) {
1498
+ const { plaintext, recipientPublicKeys } = args;
1499
+ const kem = args.kem ?? "x25519";
1500
+ const n = recipientPublicKeys.length;
1501
+ const hashesHash = itemHashesHash(args.hashes);
1502
+ if (n < 1) {
1503
+ throw new EciesSealedPoeError(
1504
+ "ENC_SLOTS_EMPTY",
1505
+ `recipientPublicKeys.length=${n} must be >= 1`
926
1506
  );
927
1507
  }
928
- const leavesCopy = [];
929
- for (let i = 0; i < args.leaves.length; i++) {
930
- const leaf = args.leaves[i];
931
- if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH2) {
932
- throw new MerkleLeavesListError(
933
- "SCHEMA_MERKLE_LEAVES_MALFORMED",
934
- `leaves[${i}] must be a Uint8Array(${DIGEST_LENGTH2})`
1508
+ const expectedPubLen = kem === "x25519" ? X25519_PUBLIC_KEY_LENGTH : MLKEM768X25519_PUBLIC_KEY_LENGTH;
1509
+ for (let i = 0; i < n; i++) {
1510
+ const pub = recipientPublicKeys[i];
1511
+ if (pub === void 0 || pub.length !== expectedPubLen) {
1512
+ throw new EciesSealedPoeError(
1513
+ "KEM_EPK_LENGTH_MISMATCH",
1514
+ `recipientPublicKeys[${i}] MUST be exactly ${expectedPubLen} bytes for kem='${kem}'`
935
1515
  );
936
1516
  }
937
- leavesCopy.push(leaf);
938
1517
  }
939
- if (args.leafAlg !== void 0 && typeof args.leafAlg !== "string") {
940
- throw new MerkleLeavesListError(
941
- "SCHEMA_MERKLE_LEAVES_MALFORMED",
942
- "leaf_alg must be a string when present"
1518
+ if (kem === "x25519") {
1519
+ if (args.eseeds !== void 0) {
1520
+ throw new EciesSealedPoeError(
1521
+ "EPHEMERAL_SECRETS_COUNT_MISMATCH",
1522
+ "eseeds is an X-Wing (mlkem768x25519) override and MUST NOT be supplied for kem='x25519'"
1523
+ );
1524
+ }
1525
+ if (args.ephemeralSecrets !== void 0 && args.ephemeralSecrets.length !== n) {
1526
+ throw new EciesSealedPoeError(
1527
+ "EPHEMERAL_SECRETS_COUNT_MISMATCH",
1528
+ `ephemeralSecrets.length=${args.ephemeralSecrets.length} must match recipientPublicKeys.length=${n}`
1529
+ );
1530
+ }
1531
+ } else {
1532
+ if (args.ephemeralSecrets !== void 0) {
1533
+ throw new EciesSealedPoeError(
1534
+ "EPHEMERAL_SECRETS_COUNT_MISMATCH",
1535
+ "ephemeralSecrets is an X25519 override and MUST NOT be supplied for kem='mlkem768x25519'"
1536
+ );
1537
+ }
1538
+ if (args.eseeds !== void 0) {
1539
+ if (args.eseeds.length !== n) {
1540
+ throw new EciesSealedPoeError(
1541
+ "EPHEMERAL_SECRETS_COUNT_MISMATCH",
1542
+ `eseeds.length=${args.eseeds.length} must match recipientPublicKeys.length=${n}`
1543
+ );
1544
+ }
1545
+ for (let i = 0; i < n; i++) {
1546
+ const eseed = args.eseeds[i];
1547
+ if (eseed.length !== MLKEM768X25519_ESEED_LENGTH) {
1548
+ throw new EciesSealedPoeError(
1549
+ "INVALID_EPHEMERAL_SECRET_LENGTH",
1550
+ `eseeds[${i}] MUST be exactly ${MLKEM768X25519_ESEED_LENGTH} bytes, got ${eseed.length}`
1551
+ );
1552
+ }
1553
+ }
1554
+ }
1555
+ }
1556
+ const cek = args.cek ?? randomBytes$1(CEK_LENGTH);
1557
+ const nonce = args.nonce ?? randomBytes$1(NONCE_LENGTH2);
1558
+ if (cek.length !== CEK_LENGTH) {
1559
+ throw new EciesSealedPoeError(
1560
+ "INVALID_CEK_LENGTH",
1561
+ `cek MUST be exactly ${CEK_LENGTH} bytes, got ${cek.length}`
943
1562
  );
944
1563
  }
945
- const map = {
946
- format: LEAVES_LIST_FORMAT_V1,
947
- tree_alg: TREE_ALG_RFC9162,
948
- root: args.root,
949
- leaves: leavesCopy,
950
- leaf_count: leavesCopy.length
951
- };
952
- if (args.leafAlg !== void 0) {
953
- map["leaf_alg"] = args.leafAlg;
1564
+ if (nonce.length !== NONCE_LENGTH2) {
1565
+ throw new EciesSealedPoeError(
1566
+ "NONCE_LENGTH_MISMATCH",
1567
+ `nonce MUST be exactly ${NONCE_LENGTH2} bytes, got ${nonce.length}`
1568
+ );
954
1569
  }
955
- return encodeCanonicalCbor3(map);
956
- }
957
- var abytesDoc = abytes;
958
- var randomBytes = randomBytes$2;
959
- function equalBytes(a, b) {
960
- if (a.length !== b.length)
961
- return false;
962
- let diff = 0;
963
- for (let i = 0; i < a.length; i++)
964
- diff |= a[i] ^ b[i];
965
- return diff === 0;
966
- }
967
- function copyBytes(bytes) {
968
- return Uint8Array.from(abytes(bytes));
969
- }
970
- function splitCoder(label, ...lengths) {
971
- const getLength = (c) => typeof c === "number" ? c : c.bytesLen;
972
- const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0);
973
- return {
974
- bytesLen,
975
- encode: (bufs) => {
976
- const res = new Uint8Array(bytesLen);
977
- for (let i = 0, pos = 0; i < lengths.length; i++) {
978
- const c = lengths[i];
979
- const l = getLength(c);
980
- const b = typeof c === "number" ? bufs[i] : c.encode(bufs[i]);
981
- abytes(b, l, label);
982
- res.set(b, pos);
983
- if (typeof c !== "number")
984
- b.fill(0);
985
- pos += l;
986
- }
987
- return res;
988
- },
989
- decode: (buf) => {
990
- abytes(buf, bytesLen, label);
991
- const res = [];
992
- for (const c of lengths) {
993
- const l = getLength(c);
994
- const b = buf.subarray(0, l);
995
- res.push(typeof c === "number" ? b : c.decode(b));
996
- buf = buf.subarray(l);
997
- }
998
- return res;
1570
+ let envelope;
1571
+ if (kem === "x25519") {
1572
+ const slots = [];
1573
+ for (let i = 0; i < n; i++) {
1574
+ slots.push(
1575
+ wrapSlotX25519({
1576
+ pubR: recipientPublicKeys[i],
1577
+ privEph: args.ephemeralSecrets ? args.ephemeralSecrets[i] : void 0,
1578
+ cek,
1579
+ nonce,
1580
+ slotIdx: i
1581
+ })
1582
+ );
999
1583
  }
1000
- };
1001
- }
1002
- function vecCoder(c, vecLen) {
1003
- const coder = c;
1004
- const bytesLen = vecLen * coder.bytesLen;
1005
- return {
1006
- bytesLen,
1007
- encode: (u) => {
1008
- if (u.length !== vecLen)
1009
- throw new RangeError(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`);
1010
- const res = new Uint8Array(bytesLen);
1011
- for (let i = 0, pos = 0; i < u.length; i++) {
1012
- const b = coder.encode(u[i]);
1013
- res.set(b, pos);
1014
- b.fill(0);
1015
- pos += b.length;
1016
- }
1017
- return res;
1018
- },
1019
- decode: (a) => {
1020
- abytes(a, bytesLen);
1021
- const r = [];
1022
- for (let i = 0; i < a.length; i += coder.bytesLen)
1023
- r.push(coder.decode(a.subarray(i, i + coder.bytesLen)));
1024
- return r;
1584
+ if (args.skipShuffle !== true) {
1585
+ csprngShuffle(slots);
1586
+ }
1587
+ const slotsHash = computeSlotsHash({
1588
+ aead: SEALED_POE_AEAD,
1589
+ kem: "x25519",
1590
+ nonce,
1591
+ slots,
1592
+ hashesHash
1593
+ });
1594
+ envelope = {
1595
+ scheme: 1,
1596
+ aead: SEALED_POE_AEAD,
1597
+ kem: "x25519",
1598
+ nonce,
1599
+ slots,
1600
+ slots_mac: sizedSlotsMac(cek, slotsHash)
1601
+ };
1602
+ } else {
1603
+ const slots = [];
1604
+ for (let i = 0; i < n; i++) {
1605
+ slots.push(
1606
+ wrapSlotMlkem768X25519({
1607
+ pubR: recipientPublicKeys[i],
1608
+ eseed: args.eseeds ? args.eseeds[i] : void 0,
1609
+ cek,
1610
+ nonce
1611
+ })
1612
+ );
1025
1613
  }
1026
- };
1027
- }
1028
- function cleanBytes(...list) {
1029
- for (const t of list) {
1030
- if (Array.isArray(t))
1031
- for (const b of t)
1032
- b.fill(0);
1033
- else
1034
- t.fill(0);
1614
+ if (args.skipShuffle !== true) {
1615
+ csprngShuffle(slots);
1616
+ }
1617
+ const slotsHash = computeSlotsHash({
1618
+ aead: SEALED_POE_AEAD,
1619
+ kem: "mlkem768x25519",
1620
+ nonce,
1621
+ slots,
1622
+ hashesHash
1623
+ });
1624
+ envelope = {
1625
+ scheme: 1,
1626
+ aead: SEALED_POE_AEAD,
1627
+ kem: "mlkem768x25519",
1628
+ nonce,
1629
+ slots,
1630
+ slots_mac: sizedSlotsMac(cek, slotsHash)
1631
+ };
1035
1632
  }
1633
+ const ciphertext = streamSeal({
1634
+ payloadKey: slotsPayloadKey({ cek, nonce }),
1635
+ plaintext
1636
+ });
1637
+ return { envelope, ciphertext };
1036
1638
  }
1037
- function getMask(bits) {
1038
- if (!Number.isSafeInteger(bits) || bits < 0 || bits > 32)
1039
- throw new RangeError(`expected bits in [0..32], got ${bits}`);
1040
- return bits === 32 ? 4294967295 : ~(-1 << bits) >>> 0;
1639
+ function sizedSlotsMac(cek, slotsHash) {
1640
+ const slotsMac = computeSlotsMac({ cek, slotsHash });
1641
+ if (slotsMac.length !== SLOTS_MAC_LENGTH) {
1642
+ throw new Error(`internal: slots_mac.length=${slotsMac.length}, expected ${SLOTS_MAC_LENGTH}`);
1643
+ }
1644
+ return slotsMac;
1041
1645
  }
1646
+ new TextEncoder();
1647
+ new TextEncoder();
1042
1648
 
1043
- // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/_crystals.js
1044
- var genCrystals = (opts2) => {
1045
- const { newPoly, N: N2, Q: Q2, F: F2, ROOT_OF_UNITY: ROOT_OF_UNITY2, brvBits} = opts2;
1046
- const mod = (a, modulo = Q2) => {
1047
- const result = a % modulo | 0;
1048
- return (result >= 0 ? result | 0 : modulo + result | 0) | 0;
1049
- };
1050
- const smod = (a, modulo = Q2) => {
1051
- const r = mod(a, modulo) | 0;
1052
- return (r > modulo >> 1 ? r - modulo | 0 : r) | 0;
1053
- };
1054
- function getZettas() {
1055
- const out = newPoly(N2);
1056
- for (let i = 0; i < N2; i++) {
1057
- const b = reverseBits(i, brvBits);
1058
- const p = BigInt(ROOT_OF_UNITY2) ** BigInt(b) % BigInt(Q2);
1059
- out[i] = Number(p) | 0;
1060
- }
1061
- return out;
1649
+ // src/client/off-host-sign.ts
1650
+ var EMPTY_BYTES2 = new Uint8Array(0);
1651
+ var ED25519_PUBLIC_KEY_LENGTH = 32;
1652
+ var ED25519_SIGNATURE_LENGTH = 64;
1653
+ function cloneToOwnedBuffer(src) {
1654
+ const out = new Uint8Array(new ArrayBuffer(src.length));
1655
+ out.set(src);
1656
+ return out;
1657
+ }
1658
+ var OffHostSignError = class extends Error {
1659
+ code;
1660
+ constructor(code, message) {
1661
+ super(message);
1662
+ this.name = "OffHostSignError";
1663
+ this.code = code;
1062
1664
  }
1063
- const nttZetas = getZettas();
1064
- const field = {
1065
- add: (a, b) => mod((a | 0) + (b | 0)) | 0,
1066
- sub: (a, b) => mod((a | 0) - (b | 0)) | 0,
1067
- mul: (a, b) => mod((a | 0) * (b | 0)) | 0,
1068
- inv: (_a) => {
1069
- throw new Error("not implemented");
1070
- }
1071
- };
1072
- const nttOpts = {
1073
- N: N2,
1074
- roots: nttZetas,
1075
- invertButterflies: true,
1076
- skipStages: 1 ,
1077
- brp: false
1078
- };
1079
- const dif = FFTCore(field, { dit: false, ...nttOpts });
1080
- const dit = FFTCore(field, { dit: true, ...nttOpts });
1081
- const NTT = {
1082
- encode: (r) => {
1083
- return dif(r);
1084
- },
1085
- decode: (r) => {
1086
- dit(r);
1087
- for (let i = 0; i < r.length; i++)
1088
- r[i] = mod(F2 * r[i]);
1089
- return r;
1090
- }
1091
- };
1092
- const bitsCoder = (d, c) => {
1093
- const mask = getMask(d);
1094
- const bytesLen = d * (N2 / 8);
1095
- return {
1096
- bytesLen,
1097
- encode: (poly_) => {
1098
- const poly = poly_;
1099
- const r = new Uint8Array(bytesLen);
1100
- for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) {
1101
- buf |= (c.encode(poly[i]) & mask) << bufLen;
1102
- bufLen += d;
1103
- for (; bufLen >= 8; bufLen -= 8, buf >>= 8)
1104
- r[pos++] = buf & getMask(bufLen);
1105
- }
1106
- return r;
1107
- },
1108
- decode: (bytes) => {
1109
- const r = newPoly(N2);
1110
- for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) {
1111
- buf |= bytes[i] << bufLen;
1112
- bufLen += 8;
1113
- for (; bufLen >= d; bufLen -= d, buf >>= d)
1114
- r[pos++] = c.decode(buf & mask);
1115
- }
1116
- return r;
1117
- }
1118
- };
1119
- };
1120
- return {
1121
- mod,
1122
- smod,
1123
- nttZetas,
1124
- NTT: {
1125
- encode: (r) => NTT.encode(r),
1126
- decode: (r) => NTT.decode(r)
1127
- },
1128
- bitsCoder
1129
- };
1130
1665
  };
1131
- var createXofShake = (shake) => (seed, blockLen) => {
1132
- if (!blockLen)
1133
- blockLen = shake.blockLen;
1134
- const _seed = new Uint8Array(seed.length + 2);
1135
- _seed.set(seed);
1136
- const seedLen = seed.length;
1137
- const buf = new Uint8Array(blockLen);
1138
- let h = shake.create({});
1139
- let calls = 0;
1140
- let xofs = 0;
1141
- return {
1142
- stats: () => ({ calls, xofs }),
1143
- get: (x, y) => {
1144
- _seed[seedLen + 0] = x;
1145
- _seed[seedLen + 1] = y;
1146
- h.destroy();
1147
- h = shake.create({}).update(_seed);
1148
- calls++;
1149
- return () => {
1150
- xofs++;
1151
- return h.xofInto(buf);
1152
- };
1153
- },
1154
- clean: () => {
1155
- h.destroy();
1156
- cleanBytes(buf, _seed);
1666
+ function buildToSign(record) {
1667
+ const body = encodeRecordBodyForSigning(record);
1668
+ const out = new Uint8Array(CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES.length + body.length);
1669
+ out.set(CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES, 0);
1670
+ out.set(body, CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES.length);
1671
+ return out;
1672
+ }
1673
+ function encodePath1ProtectedHeader(signerPubkey) {
1674
+ const protectedHeader = /* @__PURE__ */ new Map([
1675
+ [1, -8],
1676
+ [4, signerPubkey]
1677
+ ]);
1678
+ const protectedHeaderBytes = encodeCanonicalCbor(protectedHeader);
1679
+ return { protectedHeader, protectedHeaderBytes };
1680
+ }
1681
+ function prepareSigStructure(args) {
1682
+ if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
1683
+ throw new OffHostSignError(
1684
+ "INVALID_PUBKEY_LENGTH",
1685
+ `signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
1686
+ );
1687
+ }
1688
+ const { protectedHeaderBytes } = encodePath1ProtectedHeader(args.signerPubkey);
1689
+ const recordBodyCbor = encodeRecordBodyForSigning(args.record);
1690
+ const sigStructureBytes = buildLabel309SigStructure({
1691
+ bodyProtectedBytes: protectedHeaderBytes,
1692
+ recordBodyCbor
1693
+ });
1694
+ return { sigStructureBytes, protectedHeaderBytes };
1695
+ }
1696
+ function assembleCoseSign1(args) {
1697
+ if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
1698
+ throw new OffHostSignError(
1699
+ "INVALID_PUBKEY_LENGTH",
1700
+ `signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
1701
+ );
1702
+ }
1703
+ if (args.signature.length !== ED25519_SIGNATURE_LENGTH) {
1704
+ throw new OffHostSignError(
1705
+ "INVALID_SIGNATURE_LENGTH",
1706
+ `signature must be 64 bytes (Ed25519 raw signature), got ${args.signature.length}`
1707
+ );
1708
+ }
1709
+ const { protectedHeader } = encodePath1ProtectedHeader(args.signerPubkey);
1710
+ const coseSign1Bytes = encodeCoseSign1({
1711
+ protectedHeader,
1712
+ unprotectedHeader: /* @__PURE__ */ new Map(),
1713
+ payload: null,
1714
+ signature: args.signature
1715
+ });
1716
+ const sigEntry = { cose_sign1: cloneToOwnedBuffer(coseSign1Bytes) };
1717
+ return { coseSign1Bytes, sigEntry };
1718
+ }
1719
+ function prepareSigStructureHashed(args) {
1720
+ if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
1721
+ throw new OffHostSignError(
1722
+ "INVALID_PUBKEY_LENGTH",
1723
+ `signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
1724
+ );
1725
+ }
1726
+ const { protectedHeaderBytes } = encodePath1ProtectedHeader(args.signerPubkey);
1727
+ const toSign = buildToSign(args.record);
1728
+ const toSignHashBytes = blake2b224(toSign);
1729
+ const sigStructureBytes = buildSigStructure({
1730
+ context: "Signature1",
1731
+ bodyProtectedBytes: protectedHeaderBytes,
1732
+ externalAad: EMPTY_BYTES2,
1733
+ payload: toSignHashBytes
1734
+ });
1735
+ return { sigStructureBytes, protectedHeaderBytes, toSignHashBytes };
1736
+ }
1737
+ function assembleCoseSign1Hashed(args) {
1738
+ if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
1739
+ throw new OffHostSignError(
1740
+ "INVALID_PUBKEY_LENGTH",
1741
+ `signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
1742
+ );
1743
+ }
1744
+ if (args.signature.length !== ED25519_SIGNATURE_LENGTH) {
1745
+ throw new OffHostSignError(
1746
+ "INVALID_SIGNATURE_LENGTH",
1747
+ `signature must be 64 bytes (Ed25519 raw signature), got ${args.signature.length}`
1748
+ );
1749
+ }
1750
+ const { protectedHeader } = encodePath1ProtectedHeader(args.signerPubkey);
1751
+ const unprotectedHeader = /* @__PURE__ */ new Map([["hashed", true]]);
1752
+ const coseSign1Bytes = encodeCoseSign1({
1753
+ protectedHeader,
1754
+ unprotectedHeader,
1755
+ payload: null,
1756
+ signature: args.signature
1757
+ });
1758
+ const sigEntry = { cose_sign1: cloneToOwnedBuffer(coseSign1Bytes) };
1759
+ return { coseSign1Bytes, sigEntry };
1760
+ }
1761
+
1762
+ // src/client/http-error.ts
1763
+ var CANONICAL_PROBLEM_KEYS = /* @__PURE__ */ new Set([
1764
+ "type",
1765
+ "title",
1766
+ "status",
1767
+ "detail",
1768
+ "code",
1769
+ "trace_id",
1770
+ "errors",
1771
+ "instance"
1772
+ ]);
1773
+ function extractProblemExtensions(problem) {
1774
+ const out = {};
1775
+ for (const [key, value] of Object.entries(problem)) {
1776
+ if (!CANONICAL_PROBLEM_KEYS.has(key)) {
1777
+ out[key] = value;
1157
1778
  }
1158
- };
1779
+ }
1780
+ return out;
1781
+ }
1782
+ var Label309HttpError = class extends Error {
1783
+ problem;
1784
+ code;
1785
+ httpStatus;
1786
+ title;
1787
+ detail;
1788
+ type;
1789
+ traceId;
1790
+ instance;
1791
+ errors;
1792
+ extensions;
1793
+ requestId;
1794
+ retryAfterSeconds;
1795
+ constructor(init) {
1796
+ super(init.problem.detail || `${init.problem.title} (HTTP ${init.problem.status})`);
1797
+ this.name = "Label309HttpError";
1798
+ this.problem = init.problem;
1799
+ this.code = init.problem.code;
1800
+ this.httpStatus = init.problem.status;
1801
+ this.title = init.problem.title;
1802
+ this.detail = init.problem.detail;
1803
+ this.type = init.problem.type;
1804
+ this.traceId = init.problem.trace_id;
1805
+ this.instance = init.problem.instance;
1806
+ this.errors = init.problem.errors;
1807
+ this.extensions = init.extensions ?? extractProblemExtensions(init.problem);
1808
+ this.requestId = init.requestId ?? init.problem.trace_id;
1809
+ this.retryAfterSeconds = init.retryAfterSeconds;
1810
+ }
1159
1811
  };
1160
- var XOF128 = /* @__PURE__ */ createXofShake(shake128);
1161
1812
 
1162
- // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/ml-kem.js
1163
- var N = 256;
1164
- var Q = 3329;
1165
- var F = 3303;
1166
- var ROOT_OF_UNITY = 17;
1167
- var crystals = /* @__PURE__ */ genCrystals({
1168
- N,
1169
- Q,
1170
- F,
1171
- ROOT_OF_UNITY,
1172
- newPoly: (n) => new Uint16Array(n),
1173
- brvBits: 7});
1174
- var PARAMS = /* @__PURE__ */ (() => Object.freeze({
1175
- 512: Object.freeze({ N, Q, K: 2, ETA1: 3, ETA2: 2, du: 10, dv: 4, RBGstrength: 128 }),
1176
- 768: Object.freeze({ N, Q, K: 3, ETA1: 2, ETA2: 2, du: 10, dv: 4, RBGstrength: 192 }),
1177
- 1024: Object.freeze({ N, Q, K: 4, ETA1: 2, ETA2: 2, du: 11, dv: 5, RBGstrength: 256 })
1178
- }))();
1179
- var compress = (d) => {
1180
- if (d >= 12)
1181
- return { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i };
1182
- const a = 2 ** (d - 1);
1183
- return {
1184
- // This only matches standalone Compress_d after bitsCoder masks the result into Z_(2^d).
1185
- encode: (i) => ((i << d) + Q / 2) / Q,
1186
- // const decompress = (i: number) => round((Q / 2 ** d) * i);
1187
- decode: (i) => i * Q + a >>> d
1188
- };
1813
+ // src/client/batch-empty-error.ts
1814
+ var BatchEmptyError = class extends Label309HttpError {
1815
+ constructor(init) {
1816
+ super(init);
1817
+ this.name = "BatchEmptyError";
1818
+ }
1189
1819
  };
1190
- var byteCoder = (d) => crystals.bitsCoder(d, { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i } );
1191
- var polyCoder = (d) => d === 12 ? byteCoder(12) : crystals.bitsCoder(d, compress(d));
1192
- function polyAdd(a_, b_) {
1193
- const a = a_;
1194
- const b = b_;
1195
- for (let i = 0; i < N; i++)
1196
- a[i] = crystals.mod(a[i] + b[i]);
1820
+
1821
+ // src/client/batch-too-large-error.ts
1822
+ function readInt(value) {
1823
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1197
1824
  }
1198
- function polySub(a_, b_) {
1199
- const a = a_;
1200
- const b = b_;
1201
- for (let i = 0; i < N; i++)
1202
- a[i] = crystals.mod(a[i] - b[i]);
1825
+ var BatchTooLargeError = class extends Label309HttpError {
1826
+ max;
1827
+ got;
1828
+ constructor(init) {
1829
+ super(init);
1830
+ this.name = "BatchTooLargeError";
1831
+ this.max = readInt(this.extensions["max"]);
1832
+ this.got = readInt(this.extensions["got"]);
1833
+ }
1834
+ };
1835
+
1836
+ // src/client/forbidden-error.ts
1837
+ var ForbiddenError = class extends Label309HttpError {
1838
+ constructor(init) {
1839
+ super(init);
1840
+ this.name = "ForbiddenError";
1841
+ }
1842
+ };
1843
+
1844
+ // src/client/idempotency-conflict-error.ts
1845
+ var IdempotencyConflictError = class extends Label309HttpError {
1846
+ constructor(init) {
1847
+ super(init);
1848
+ this.name = "IdempotencyConflictError";
1849
+ }
1850
+ };
1851
+
1852
+ // src/client/insufficient-funds-error.ts
1853
+ function readBigIntString(value) {
1854
+ if (typeof value !== "string") return void 0;
1855
+ if (!/^-?[0-9]+$/.test(value)) return void 0;
1856
+ try {
1857
+ return BigInt(value);
1858
+ } catch {
1859
+ return void 0;
1860
+ }
1203
1861
  }
1204
- function BaseCaseMultiply(a0, a1, b0, b1, zeta) {
1205
- const c0 = crystals.mod(a1 * b1 * zeta + a0 * b0);
1206
- const c1 = crystals.mod(a0 * b1 + a1 * b0);
1207
- return { c0, c1 };
1862
+ function readString(value) {
1863
+ return typeof value === "string" ? value : void 0;
1208
1864
  }
1209
- function MultiplyNTTs(f_, g_) {
1210
- const f = f_;
1211
- const g = g_;
1212
- for (let i = 0; i < N / 2; i++) {
1213
- let z3 = crystals.nttZetas[64 + (i >> 1)];
1214
- if (i & 1)
1215
- z3 = -z3;
1216
- const { c0, c1 } = BaseCaseMultiply(f[2 * i + 0], f[2 * i + 1], g[2 * i + 0], g[2 * i + 1], z3);
1217
- f[2 * i + 0] = c0;
1218
- f[2 * i + 1] = c1;
1865
+ var InsufficientFundsError = class extends Label309HttpError {
1866
+ balanceUsdMicros;
1867
+ requiredUsdMicros;
1868
+ topUpUrl;
1869
+ constructor(init) {
1870
+ super(init);
1871
+ this.name = "InsufficientFundsError";
1872
+ this.balanceUsdMicros = readBigIntString(this.extensions["balance_usd_micros"]);
1873
+ this.requiredUsdMicros = readBigIntString(this.extensions["required_usd_micros"]);
1874
+ this.topUpUrl = readString(this.extensions["top_up_url"]);
1219
1875
  }
1220
- return f;
1876
+ };
1877
+
1878
+ // src/client/insufficient-scope-error.ts
1879
+ function readScopeArray(value) {
1880
+ if (!Array.isArray(value)) return [];
1881
+ return value.filter((entry) => typeof entry === "string");
1221
1882
  }
1222
- function SampleNTT(xof_) {
1223
- const xof = xof_;
1224
- const r = new Uint16Array(N);
1225
- for (let j = 0; j < N; ) {
1226
- const b = xof();
1227
- if (b.length % 3)
1228
- throw new Error("SampleNTT: unaligned block");
1229
- for (let i = 0; j < N && i + 3 <= b.length; i += 3) {
1230
- const d1 = (b[i + 0] >> 0 | b[i + 1] << 8) & 4095;
1231
- const d2 = (b[i + 1] >> 4 | b[i + 2] << 4) & 4095;
1232
- if (d1 < Q)
1233
- r[j++] = d1;
1234
- if (j < N && d2 < Q)
1235
- r[j++] = d2;
1236
- }
1883
+ var InsufficientScopeError = class extends Label309HttpError {
1884
+ requiredScopes;
1885
+ grantedScopes;
1886
+ constructor(init) {
1887
+ super(init);
1888
+ this.name = "InsufficientScopeError";
1889
+ this.requiredScopes = readScopeArray(this.extensions["required"]);
1890
+ this.grantedScopes = readScopeArray(this.extensions["granted"]);
1237
1891
  }
1238
- return r;
1892
+ /** Convenience for the single-scope case; first entry of `requiredScopes`. */
1893
+ get requiredScope() {
1894
+ return this.requiredScopes[0];
1895
+ }
1896
+ };
1897
+
1898
+ // src/client/internal-server-error.ts
1899
+ var InternalServerError = class extends Label309HttpError {
1900
+ constructor(init) {
1901
+ super(init);
1902
+ this.name = "InternalServerError";
1903
+ }
1904
+ };
1905
+
1906
+ // src/client/invalid-body-error.ts
1907
+ var InvalidBodyError = class extends Label309HttpError {
1908
+ constructor(init) {
1909
+ super(init);
1910
+ this.name = "InvalidBodyError";
1911
+ }
1912
+ };
1913
+
1914
+ // src/client/malformed-cbor-error.ts
1915
+ var MalformedCborError = class extends Label309HttpError {
1916
+ constructor(init) {
1917
+ super(init);
1918
+ this.name = "MalformedCborError";
1919
+ }
1920
+ };
1921
+
1922
+ // src/client/not-found-error.ts
1923
+ var NotFoundError = class extends Label309HttpError {
1924
+ constructor(init) {
1925
+ super(init);
1926
+ this.name = "NotFoundError";
1927
+ }
1928
+ };
1929
+
1930
+ // src/client/quote-already-consumed-error.ts
1931
+ function readString2(value) {
1932
+ return typeof value === "string" ? value : void 0;
1239
1933
  }
1240
- var sampleCBDBytes = (buf, eta) => {
1241
- const r = new Uint16Array(N);
1242
- const b32 = u32(buf);
1243
- swap32IfBE(b32);
1244
- let len = 0;
1245
- for (let i = 0, p = 0, bb = 0, t0 = 0; i < b32.length; i++) {
1246
- let b = b32[i];
1247
- for (let j = 0; j < 32; j++) {
1248
- bb += b & 1;
1249
- b >>= 1;
1250
- len += 1;
1251
- if (len === eta) {
1252
- t0 = bb;
1253
- bb = 0;
1254
- } else if (len === 2 * eta) {
1255
- r[p++] = crystals.mod(t0 - bb);
1256
- bb = 0;
1257
- len = 0;
1258
- }
1259
- }
1934
+ var QuoteAlreadyConsumedError = class extends Label309HttpError {
1935
+ quoteId;
1936
+ constructor(init) {
1937
+ super(init);
1938
+ this.name = "QuoteAlreadyConsumedError";
1939
+ this.quoteId = readString2(this.extensions["quote_id"]);
1260
1940
  }
1261
- swap32IfBE(b32);
1262
- if (len)
1263
- throw new Error(`sampleCBD: leftover bits: ${len}`);
1264
- return r;
1265
1941
  };
1266
- function sampleCBD(PRF_, seed, nonce, eta) {
1267
- const PRF = PRF_;
1268
- return sampleCBDBytes(PRF(eta * N / 4, seed, nonce), eta);
1942
+
1943
+ // src/client/quote-expired-error.ts
1944
+ function readString3(value) {
1945
+ return typeof value === "string" ? value : void 0;
1269
1946
  }
1270
- var genKPKE = (opts_) => {
1271
- const opts2 = opts_;
1272
- const { K, PRF, XOF, HASH512, ETA1, ETA2, du, dv } = opts2;
1273
- const poly1 = polyCoder(1);
1274
- const polyV = polyCoder(dv);
1275
- const polyU = polyCoder(du);
1276
- const publicCoder = splitCoder("publicKey", vecCoder(polyCoder(12), K), 32);
1277
- const secretCoder = vecCoder(polyCoder(12), K);
1278
- const cipherCoder = splitCoder("ciphertext", vecCoder(polyU, K), polyV);
1279
- const seedCoder = splitCoder("seed", 32, 32);
1280
- return {
1281
- secretCoder,
1282
- lengths: {
1283
- secretKey: secretCoder.bytesLen,
1284
- publicKey: publicCoder.bytesLen,
1285
- cipherText: cipherCoder.bytesLen
1286
- },
1287
- keygen: (seed) => {
1288
- abytesDoc(seed, 32, "seed");
1289
- const seedDst = new Uint8Array(33);
1290
- seedDst.set(seed);
1291
- seedDst[32] = K;
1292
- const seedHash = HASH512(seedDst);
1293
- const [rho, sigma] = seedCoder.decode(seedHash);
1294
- const sHat = [];
1295
- const tHat = [];
1296
- for (let i = 0; i < K; i++)
1297
- sHat.push(crystals.NTT.encode(sampleCBD(PRF, sigma, i, ETA1)));
1298
- const x = XOF(rho);
1299
- for (let i = 0; i < K; i++) {
1300
- const e = crystals.NTT.encode(sampleCBD(PRF, sigma, K + i, ETA1));
1301
- for (let j = 0; j < K; j++) {
1302
- const aji = SampleNTT(x.get(j, i));
1303
- polyAdd(e, MultiplyNTTs(aji, sHat[j]));
1304
- }
1305
- tHat.push(e);
1306
- }
1307
- x.clean();
1308
- const res = {
1309
- publicKey: publicCoder.encode([tHat, rho]),
1310
- secretKey: secretCoder.encode(sHat)
1311
- };
1312
- cleanBytes(rho, sigma, sHat, tHat, seedDst, seedHash);
1313
- return res;
1314
- },
1315
- encrypt: (publicKey, msg, seed) => {
1316
- const [tHat, rho] = publicCoder.decode(publicKey);
1317
- const rHat = [];
1318
- for (let i = 0; i < K; i++)
1319
- rHat.push(crystals.NTT.encode(sampleCBD(PRF, seed, i, ETA1)));
1320
- const x = XOF(rho);
1321
- const tmp2 = new Uint16Array(N);
1322
- const u = [];
1323
- for (let i = 0; i < K; i++) {
1324
- const e1 = sampleCBD(PRF, seed, K + i, ETA2);
1325
- const tmp = new Uint16Array(N);
1326
- for (let j = 0; j < K; j++) {
1327
- const aij = SampleNTT(x.get(i, j));
1328
- polyAdd(tmp, MultiplyNTTs(aij, rHat[j]));
1329
- }
1330
- polyAdd(e1, crystals.NTT.decode(tmp));
1331
- u.push(e1);
1332
- polyAdd(tmp2, MultiplyNTTs(tHat[i], rHat[i]));
1333
- cleanBytes(tmp);
1334
- }
1335
- x.clean();
1336
- const e2 = sampleCBD(PRF, seed, 2 * K, ETA2);
1337
- polyAdd(e2, crystals.NTT.decode(tmp2));
1338
- const v = poly1.decode(msg);
1339
- polyAdd(v, e2);
1340
- cleanBytes(tHat, rHat, tmp2, e2);
1341
- return cipherCoder.encode([u, v]);
1342
- },
1343
- decrypt: (cipherText, privateKey) => {
1344
- const [u, v] = cipherCoder.decode(cipherText);
1345
- const sk = secretCoder.decode(privateKey);
1346
- const tmp = new Uint16Array(N);
1347
- for (let i = 0; i < K; i++)
1348
- polyAdd(tmp, MultiplyNTTs(sk[i], crystals.NTT.encode(u[i])));
1349
- polySub(v, crystals.NTT.decode(tmp));
1350
- cleanBytes(tmp, sk, u);
1351
- return poly1.encode(v);
1352
- }
1353
- };
1947
+ var QuoteExpiredError = class extends Label309HttpError {
1948
+ quoteId;
1949
+ constructor(init) {
1950
+ super(init);
1951
+ this.name = "QuoteExpiredError";
1952
+ this.quoteId = readString3(this.extensions["quote_id"]);
1953
+ }
1354
1954
  };
1355
- function createKyber(opts2) {
1356
- const rawOpts = opts2;
1357
- const KPKE = genKPKE(rawOpts);
1358
- const { HASH256, HASH512, KDF } = rawOpts;
1359
- const { secretCoder: KPKESecretCoder, lengths } = KPKE;
1360
- const secretCoder = splitCoder("secretKey", lengths.secretKey, lengths.publicKey, 32, 32);
1361
- const msgLen = 32;
1362
- const seedLen = 64;
1363
- const kemLengths = Object.freeze({
1364
- ...lengths,
1365
- seed: 64,
1366
- msg: msgLen,
1367
- msgRand: msgLen,
1368
- secretKey: secretCoder.bytesLen
1369
- });
1370
- return Object.freeze({
1371
- info: Object.freeze({ type: "ml-kem" }),
1372
- lengths: kemLengths,
1373
- keygen: (seed = randomBytes(seedLen)) => {
1374
- abytesDoc(seed, seedLen, "seed");
1375
- const { publicKey, secretKey: sk } = KPKE.keygen(seed.subarray(0, 32));
1376
- const publicKeyHash = HASH256(publicKey);
1377
- const secretKey = secretCoder.encode([sk, publicKey, publicKeyHash, seed.subarray(32)]);
1378
- cleanBytes(sk, publicKeyHash);
1379
- return {
1380
- publicKey,
1381
- secretKey
1382
- };
1383
- },
1384
- getPublicKey: (secretKey) => {
1385
- const [_sk, publicKey, _publicKeyHash, _z] = secretCoder.decode(secretKey);
1386
- return Uint8Array.from(publicKey);
1387
- },
1388
- encapsulate: (publicKey, msg = randomBytes(msgLen)) => {
1389
- abytesDoc(publicKey, lengths.publicKey, "publicKey");
1390
- abytesDoc(msg, msgLen, "message");
1391
- const eke = publicKey.subarray(0, 384 * opts2.K);
1392
- const ek = KPKESecretCoder.encode(KPKESecretCoder.decode(copyBytes(eke)));
1393
- if (!equalBytes(ek, eke)) {
1394
- cleanBytes(ek);
1395
- throw new Error("ML-KEM.encapsulate: wrong publicKey modulus");
1396
- }
1397
- cleanBytes(ek);
1398
- const kr = HASH512.create().update(msg).update(HASH256(publicKey)).digest();
1399
- const cipherText = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
1400
- cleanBytes(kr.subarray(32));
1401
- return {
1402
- cipherText,
1403
- sharedSecret: kr.subarray(0, 32)
1404
- };
1405
- },
1406
- decapsulate: (cipherText, secretKey) => {
1407
- abytesDoc(secretKey, secretCoder.bytesLen, "secretKey");
1408
- abytesDoc(cipherText, lengths.cipherText, "cipherText");
1409
- const k768 = secretCoder.bytesLen - 96;
1410
- const start = k768 + 32;
1411
- const test = HASH256(secretKey.subarray(k768 / 2, start));
1412
- if (!equalBytes(test, secretKey.subarray(start, start + 32)))
1413
- throw new Error("invalid secretKey: hash check failed");
1414
- const [sk, publicKey, publicKeyHash, z3] = secretCoder.decode(secretKey);
1415
- const msg = KPKE.decrypt(cipherText, sk);
1416
- const kr = HASH512.create().update(msg).update(publicKeyHash).digest();
1417
- const Khat = kr.subarray(0, 32);
1418
- const cipherText2 = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
1419
- const isValid = equalBytes(cipherText, cipherText2);
1420
- const Kbar = KDF.create({ dkLen: 32 }).update(z3).update(cipherText).digest();
1421
- cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar);
1422
- return isValid ? Khat : Kbar;
1423
- }
1424
- });
1425
- }
1426
- function shakePRF(dkLen, key, nonce) {
1427
- return shake256.create({ dkLen }).update(key).update(new Uint8Array([nonce])).digest();
1955
+
1956
+ // src/client/quote-not-found-error.ts
1957
+ function readString4(value) {
1958
+ return typeof value === "string" ? value : void 0;
1428
1959
  }
1429
- var opts = /* @__PURE__ */ (() => ({
1430
- HASH256: sha3_256,
1431
- HASH512: sha3_512,
1432
- KDF: shake256,
1433
- XOF: XOF128,
1434
- PRF: shakePRF
1435
- }))();
1436
- var mk = (params) => createKyber({
1437
- ...opts,
1438
- ...params
1439
- });
1440
- var ml_kem768 = /* @__PURE__ */ (() => mk(PARAMS[768]))();
1960
+ var QuoteNotFoundError = class extends Label309HttpError {
1961
+ quoteId;
1962
+ constructor(init) {
1963
+ super(init);
1964
+ this.name = "QuoteNotFoundError";
1965
+ this.quoteId = readString4(this.extensions["quote_id"]);
1966
+ }
1967
+ };
1441
1968
 
1442
- // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/hybrid.js
1443
- function ecKeygen(curve, allowZeroKey = false) {
1444
- const lengths = curve.lengths;
1445
- let keygen = curve.keygen;
1446
- if (allowZeroKey) {
1447
- if (!("getSharedSecret" in curve && "sign" in curve && "verify" in curve))
1448
- throw new Error("allowZeroKey requires a Weierstrass curve");
1449
- const wCurve = curve;
1450
- const Fn = wCurve.Point.Fn;
1451
- keygen = (seed = randomBytes(lengths.seed)) => {
1452
- abytes(seed, lengths.seed, "seed");
1453
- const seedScalar = Fn.isLE ? bytesToNumberLE(seed) : bytesToNumberBE(seed);
1454
- const secretKey = Fn.toBytes(Fn.create(seedScalar));
1455
- return {
1456
- secretKey,
1457
- publicKey: curve.getPublicKey(secretKey)
1458
- };
1459
- };
1969
+ // src/client/rate-limited-error.ts
1970
+ var RateLimitedError = class extends Label309HttpError {
1971
+ constructor(init) {
1972
+ super(init);
1973
+ this.name = "RateLimitedError";
1974
+ }
1975
+ };
1976
+
1977
+ // src/client/record-not-found-error.ts
1978
+ var RecordNotFoundError = class extends Label309HttpError {
1979
+ constructor(init) {
1980
+ super(init);
1981
+ this.name = "RecordNotFoundError";
1982
+ }
1983
+ };
1984
+
1985
+ // src/client/service-unavailable-error.ts
1986
+ var ServiceUnavailableError = class extends Label309HttpError {
1987
+ constructor(init) {
1988
+ super(init);
1989
+ this.name = "ServiceUnavailableError";
1990
+ }
1991
+ };
1992
+
1993
+ // src/client/unauthorized-error.ts
1994
+ var UnauthorizedError = class extends Label309HttpError {
1995
+ constructor(init) {
1996
+ super(init);
1997
+ this.name = "UnauthorizedError";
1998
+ }
1999
+ };
2000
+
2001
+ // src/client/validation-failed-error.ts
2002
+ var ValidationFailedError = class extends Label309HttpError {
2003
+ constructor(init) {
2004
+ super(init);
2005
+ this.name = "ValidationFailedError";
2006
+ }
2007
+ };
2008
+
2009
+ // src/client/parse-http-error.ts
2010
+ function asString(value) {
2011
+ return typeof value === "string" ? value : void 0;
2012
+ }
2013
+ function asNumber(value) {
2014
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
2015
+ }
2016
+ function asProblemErrorEntries(value) {
2017
+ if (!Array.isArray(value)) return void 0;
2018
+ const out = [];
2019
+ for (const entry of value) {
2020
+ if (entry === null || typeof entry !== "object") continue;
2021
+ const e = entry;
2022
+ out.push({
2023
+ field: typeof e["field"] === "string" ? e["field"] : "",
2024
+ code: typeof e["code"] === "string" ? e["code"] : "",
2025
+ detail: typeof e["detail"] === "string" ? e["detail"] : ""
2026
+ });
1460
2027
  }
1461
- return {
1462
- lengths: { secretKey: lengths.secretKey, publicKey: lengths.publicKey, seed: lengths.seed },
1463
- keygen: (seed) => keygen(seed),
1464
- getPublicKey: (secretKey) => curve.getPublicKey(secretKey)
1465
- };
2028
+ return out;
1466
2029
  }
1467
- function ecdhKem(curve, allowZeroKey = false) {
1468
- const kg = ecKeygen(curve, allowZeroKey);
1469
- if (!curve.getSharedSecret)
1470
- throw new Error("wrong curve");
2030
+ function synthesiseProblem(httpStatus, requestId) {
2031
+ const code = `http-${httpStatus}`;
1471
2032
  return {
1472
- lengths: { ...kg.lengths, msg: kg.lengths.seed, cipherText: kg.lengths.publicKey },
1473
- keygen: kg.keygen,
1474
- getPublicKey: kg.getPublicKey,
1475
- encapsulate(publicKey, rand = randomBytes(curve.lengths.seed)) {
1476
- const seed = copyBytes(rand);
1477
- let ek = void 0;
1478
- try {
1479
- ek = this.keygen(seed).secretKey;
1480
- const sharedSecret = this.decapsulate(publicKey, ek);
1481
- const cipherText = curve.getPublicKey(ek);
1482
- return { sharedSecret, cipherText };
1483
- } finally {
1484
- cleanBytes(seed);
1485
- if (ek)
1486
- cleanBytes(ek);
1487
- }
1488
- },
1489
- decapsulate(cipherText, secretKey) {
1490
- const res = curve.getSharedSecret(secretKey, cipherText);
1491
- return curve.lengths.publicKeyHasPrefix ? res.subarray(1) : res;
1492
- }
2033
+ type: `about:blank`,
2034
+ title: `HTTP ${httpStatus}`,
2035
+ status: httpStatus,
2036
+ detail: `Server returned HTTP ${httpStatus} without a problem+json body.`,
2037
+ code,
2038
+ trace_id: requestId ?? ""
1493
2039
  };
1494
2040
  }
1495
- function splitLengths(lst, name) {
1496
- return splitCoder(name, ...lst.map((i) => {
1497
- if (typeof i.lengths[name] !== "number")
1498
- throw new Error("wrong length: " + name);
1499
- return i.lengths[name];
1500
- }));
1501
- }
1502
- function expandSeedXof(xof) {
1503
- return ((seed, seedLen) => xof(seed, { dkLen: seedLen }));
1504
- }
1505
- function combineKeys(realSeedLen, expandSeed_, ...ck_) {
1506
- const expandSeed = expandSeed_;
1507
- const ck = ck_;
1508
- const seedCoder = splitLengths(ck, "seed");
1509
- const pkCoder = splitLengths(ck, "publicKey");
1510
- anumber(realSeedLen);
1511
- function expandDecapsulationKey(seed) {
1512
- abytes(seed, realSeedLen);
1513
- const expandedRaw = expandSeed(seed, seedCoder.bytesLen);
1514
- const expandedSeed = expandedRaw.buffer === seed.buffer ? copyBytes(expandedRaw) : expandedRaw;
1515
- const expanded = [];
1516
- const keySecret = [];
1517
- const secretKey = [];
1518
- const publicKey = [];
1519
- let ok = false;
1520
- try {
1521
- for (const part of seedCoder.decode(expandedSeed))
1522
- expanded.push(copyBytes(part));
1523
- for (let i = 0; i < ck.length; i++) {
1524
- const keys = ck[i].keygen(expanded[i]);
1525
- keySecret.push(keys.secretKey);
1526
- secretKey.push(copyBytes(keys.secretKey));
1527
- publicKey.push(keys.publicKey);
1528
- }
1529
- ok = true;
1530
- return { secretKey, publicKey };
1531
- } finally {
1532
- cleanBytes(expandedSeed, expanded, keySecret);
1533
- if (!ok)
1534
- cleanBytes(secretKey);
1535
- }
2041
+ function toProblemDetails(httpStatus, body, requestId) {
2042
+ if (body === null || typeof body !== "object") {
2043
+ return synthesiseProblem(httpStatus, requestId);
1536
2044
  }
1537
- return {
1538
- info: { lengths: { seed: realSeedLen, publicKey: pkCoder.bytesLen, secretKey: realSeedLen } },
1539
- getPublicKey(secretKey) {
1540
- return this.keygen(secretKey).publicKey;
1541
- },
1542
- keygen(seed = randomBytes(realSeedLen)) {
1543
- const { publicKey: pk, secretKey } = expandDecapsulationKey(seed);
1544
- try {
1545
- const publicKey = pkCoder.encode(pk);
1546
- return { secretKey: seed, publicKey };
1547
- } finally {
1548
- cleanBytes(pk);
1549
- cleanBytes(secretKey);
1550
- }
1551
- },
1552
- expandDecapsulationKey,
1553
- realSeedLen
2045
+ const b = body;
2046
+ const code = asString(b["code"]);
2047
+ const status = asNumber(b["status"]) ?? httpStatus;
2048
+ const title = asString(b["title"]);
2049
+ if (code === void 0 && title === void 0) {
2050
+ return synthesiseProblem(httpStatus, requestId);
2051
+ }
2052
+ const errors = asProblemErrorEntries(b["errors"]);
2053
+ const base = {
2054
+ ...b,
2055
+ // RFC 7807 §4.2: `about:blank` is the default when no type URI is supplied.
2056
+ // The client is gateway-agnostic, so it must not invent a vendor-specific
2057
+ // problem-type namespace; the machine-readable discriminator is `code`.
2058
+ type: asString(b["type"]) ?? "about:blank",
2059
+ title: title ?? `HTTP ${status}`,
2060
+ status,
2061
+ detail: asString(b["detail"]) ?? "",
2062
+ code: code ?? `http-${status}`,
2063
+ trace_id: asString(b["trace_id"]) ?? requestId ?? ""
1554
2064
  };
2065
+ if (errors !== void 0) base["errors"] = errors;
2066
+ return base;
1555
2067
  }
1556
- function combineKEMS(realSeedLen, realMsgLen, expandSeed, combiner, ...kems) {
1557
- const rawCombiner = combiner;
1558
- const rawKems = kems;
1559
- const keys = combineKeys(realSeedLen, expandSeed, ...rawKems);
1560
- const ctCoder = splitLengths(rawKems, "cipherText");
1561
- const pkCoder = splitLengths(rawKems, "publicKey");
1562
- const msgCoder = splitLengths(rawKems, "msg");
1563
- anumber(realMsgLen);
1564
- const lengths = Object.freeze({
1565
- ...keys.info.lengths,
1566
- msg: realMsgLen,
1567
- msgRand: msgCoder.bytesLen,
1568
- cipherText: ctCoder.bytesLen
1569
- });
1570
- return Object.freeze({
1571
- lengths,
1572
- getPublicKey: keys.getPublicKey,
1573
- keygen: keys.keygen,
1574
- encapsulate(pk, randomness = randomBytes(msgCoder.bytesLen)) {
1575
- const pks = pkCoder.decode(pk);
1576
- const rand = msgCoder.decode(randomness);
1577
- const sharedSecret = [];
1578
- const cipherText = [];
1579
- try {
1580
- for (let i = 0; i < rawKems.length; i++) {
1581
- const enc = rawKems[i].encapsulate(pks[i], rand[i]);
1582
- sharedSecret.push(enc.sharedSecret);
1583
- cipherText.push(enc.cipherText);
1584
- }
1585
- return {
1586
- // Detach the combiner result before cleanup: a caller-provided combiner may alias one of
1587
- // the child sharedSecret buffers, and those child buffers are zeroized immediately below.
1588
- sharedSecret: copyBytes(rawCombiner(pks, cipherText, sharedSecret)),
1589
- cipherText: ctCoder.encode(cipherText)
1590
- };
1591
- } finally {
1592
- cleanBytes(sharedSecret, cipherText);
1593
- }
1594
- },
1595
- decapsulate(ct, seed) {
1596
- const cts = ctCoder.decode(ct);
1597
- const { publicKey, secretKey } = keys.expandDecapsulationKey(seed);
1598
- const sharedSecret = rawKems.map((i, j) => i.decapsulate(cts[j], secretKey[j]));
1599
- try {
1600
- return copyBytes(rawCombiner(publicKey, cts, sharedSecret));
1601
- } finally {
1602
- cleanBytes(secretKey, sharedSecret);
1603
- }
1604
- }
1605
- });
2068
+ function parseHttpError(args) {
2069
+ const problem = toProblemDetails(args.httpStatus, args.body, args.requestId);
2070
+ const extensions = extractProblemExtensions(problem);
2071
+ const init = {
2072
+ problem,
2073
+ extensions,
2074
+ requestId: args.requestId,
2075
+ retryAfterSeconds: args.retryAfterSeconds
2076
+ };
2077
+ switch (problem.code) {
2078
+ case "unauthorized":
2079
+ return new UnauthorizedError(init);
2080
+ case "forbidden":
2081
+ case "csrf-invalid":
2082
+ return new ForbiddenError(init);
2083
+ case "insufficient-scope":
2084
+ return new InsufficientScopeError(init);
2085
+ // The three 402 funding/affordability failures are one condition to a
2086
+ // caller: the account cannot fund the operation. `insufficient-funds` is the
2087
+ // balance shortfall; `insufficient-storage-credit` is the storage funding
2088
+ // source being out of credit; `no-funding-grant` is the absence of any
2089
+ // funding source entitling the account beyond the free window. All three
2090
+ // surface as the same funding error so a caller routes the user to top up
2091
+ // without branching on the code.
2092
+ case "insufficient-funds":
2093
+ case "insufficient-storage-credit":
2094
+ case "no-funding-grant":
2095
+ return new InsufficientFundsError(init);
2096
+ case "quote-expired":
2097
+ return new QuoteExpiredError(init);
2098
+ case "quote-not-found":
2099
+ return new QuoteNotFoundError(init);
2100
+ case "quote-already-consumed":
2101
+ return new QuoteAlreadyConsumedError(init);
2102
+ case "not-found":
2103
+ return new NotFoundError(init);
2104
+ case "record-not-found":
2105
+ return new RecordNotFoundError(init);
2106
+ case "idempotency-key-conflict":
2107
+ return new IdempotencyConflictError(init);
2108
+ case "rate-limited":
2109
+ return new RateLimitedError(init);
2110
+ case "validation-failed":
2111
+ return new ValidationFailedError(init);
2112
+ case "invalid-body":
2113
+ return new InvalidBodyError(init);
2114
+ case "malformed-cbor":
2115
+ return new MalformedCborError(init);
2116
+ case "batch-too-large":
2117
+ return new BatchTooLargeError(init);
2118
+ case "batch-empty":
2119
+ return new BatchEmptyError(init);
2120
+ case "internal-error":
2121
+ return new InternalServerError(init);
2122
+ // A gateway that prices on a live FX oracle may surface a transient
2123
+ // `fx-stale` pricing outage; to a vendor-neutral client that is just a
2124
+ // temporary inability to serve, i.e. a service-unavailable condition.
2125
+ case "service-unavailable":
2126
+ case "fx-stale":
2127
+ return new ServiceUnavailableError(init);
2128
+ default:
2129
+ return new Label309HttpError(init);
2130
+ }
2131
+ }
2132
+
2133
+ // src/client/http-helpers.ts
2134
+ async function readJson(response) {
2135
+ const text = await response.text();
2136
+ if (text.length === 0) return null;
2137
+ try {
2138
+ return JSON.parse(text);
2139
+ } catch {
2140
+ return null;
2141
+ }
1606
2142
  }
1607
- var x25519kem = /* @__PURE__ */ ecdhKem(x25519);
1608
- var ml_kem768_x25519 = /* @__PURE__ */ (() => combineKEMS(
1609
- 32,
1610
- 32,
1611
- expandSeedXof(shake256),
1612
- // Awesome label, so much escaping hell in a single line.
1613
- (pk, ct, ss) => sha3_256(concatBytes(ss[0], ss[1], ct[1], pk[1], asciiToBytes("\\.//^\\"))),
1614
- ml_kem768,
1615
- x25519kem
1616
- ))();
1617
- var XWing = /* @__PURE__ */ (() => ml_kem768_x25519)();
1618
- function chacha20Poly1305Encrypt(opts2) {
1619
- return chacha20poly1305(opts2.key, opts2.nonce, opts2.aad).encrypt(opts2.plaintext);
2143
+ function parseRetryAfter(header) {
2144
+ if (header === null) return void 0;
2145
+ const parsed = Number(header);
2146
+ return Number.isFinite(parsed) ? parsed : void 0;
1620
2147
  }
1621
- function xchacha20Poly1305Encrypt(opts2) {
1622
- return xchacha20poly1305(opts2.key, opts2.nonce, opts2.aad).encrypt(opts2.plaintext);
2148
+ async function throwIfNotOk(response) {
2149
+ if (response.ok) return;
2150
+ const body = await readJson(response);
2151
+ const requestId = response.headers.get("x-request-id") ?? void 0;
2152
+ const retryAfterSeconds = parseRetryAfter(response.headers.get("retry-after"));
2153
+ throw parseHttpError({ httpStatus: response.status, body, requestId, retryAfterSeconds });
1623
2154
  }
1624
- function hkdfSha256(opts2) {
1625
- return hkdf(sha256$1, opts2.ikm, opts2.salt, opts2.info, opts2.length);
2155
+
2156
+ // src/client/account.ts
2157
+ function buildHeaders(apiKey) {
2158
+ const headers = new Headers({
2159
+ "content-type": "application/json",
2160
+ accept: "application/json"
2161
+ });
2162
+ if (apiKey !== void 0) headers.set("authorization", `Bearer ${apiKey}`);
2163
+ return headers;
1626
2164
  }
1627
- var MLKEM768X25519_PUBLIC_KEY_LENGTH = 1216;
1628
- var MLKEM768X25519_ENC_LENGTH = 1120;
1629
- var MLKEM768X25519_ESEED_LENGTH = 64;
1630
- function mlkem768x25519Encapsulate(opts2) {
1631
- if (opts2.publicKey.length !== MLKEM768X25519_PUBLIC_KEY_LENGTH) {
1632
- throw new Error(
1633
- `mlkem768x25519 public key must be ${MLKEM768X25519_PUBLIC_KEY_LENGTH} bytes, got ${opts2.publicKey.length}`
1634
- );
2165
+ var AccountNamespace = class {
2166
+ config;
2167
+ constructor(config) {
2168
+ this.config = config;
1635
2169
  }
1636
- if (opts2.eseed !== void 0 && opts2.eseed.length !== MLKEM768X25519_ESEED_LENGTH) {
1637
- throw new Error(
1638
- `mlkem768x25519 eseed must be ${MLKEM768X25519_ESEED_LENGTH} bytes, got ${opts2.eseed.length}`
1639
- );
2170
+ /**
2171
+ * Fetch the caller's current prepaid USD balance.
2172
+ *
2173
+ * Returns `{ balanceUsdMicros }`, the gateway's `balance_usd_micros` field
2174
+ * (USD micro-cents as a decimal string). The string is preserved verbatim —
2175
+ * never parsed into a number — so no precision is lost. An account with no
2176
+ * ledger activity yet reads `"0"`.
2177
+ *
2178
+ * Requires authentication: 401 (UnauthorizedError) when anonymous, 403
2179
+ * (InsufficientScopeError) when the Bearer key lacks the `account:read`
2180
+ * scope.
2181
+ */
2182
+ async balance() {
2183
+ const response = await this.config.fetch(`${this.config.baseUrl}/api/v1/account/balance`, {
2184
+ method: "GET",
2185
+ headers: buildHeaders(this.config.apiKey)
2186
+ });
2187
+ await throwIfNotOk(response);
2188
+ const body = await readJson(response);
2189
+ return { balanceUsdMicros: body.balance_usd_micros };
1640
2190
  }
1641
- const { cipherText, sharedSecret } = XWing.encapsulate(opts2.publicKey, opts2.eseed);
1642
- return { enc: cipherText, ss: sharedSecret };
1643
- }
1644
- var X25519LowOrderPointError = class extends Error {
1645
- code = "X25519_LOW_ORDER_POINT";
1646
- constructor(options) {
1647
- super("x25519 ECDH rejected: peer public key is a small-order point", options);
1648
- this.name = "X25519LowOrderPointError";
2191
+ };
2192
+
2193
+ // src/client/invalid-client-config-error.ts
2194
+ var InvalidClientConfigError = class extends Error {
2195
+ code = "INVALID_CLIENT_CONFIG";
2196
+ constructor(message) {
2197
+ super(message);
2198
+ this.name = "InvalidClientConfigError";
1649
2199
  }
1650
2200
  };
1651
- var NOBLE_LOW_ORDER_MESSAGE = "invalid private or public key received";
1652
- function x25519PublicKey(opts2) {
1653
- return x25519.getPublicKey(opts2.secretKey);
2201
+
2202
+ // src/hex.ts
2203
+ function bytesToHex(bytes) {
2204
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
1654
2205
  }
1655
- function x25519Ecdh(opts2) {
1656
- try {
1657
- return x25519.getSharedSecret(opts2.secretKey, opts2.theirPublicKey);
1658
- } catch (e) {
1659
- if (e instanceof Error && e.message === NOBLE_LOW_ORDER_MESSAGE) {
1660
- throw new X25519LowOrderPointError({ cause: e });
1661
- }
1662
- throw e;
2206
+
2207
+ // src/client/partial-upload-error.ts
2208
+ var PartialUploadError = class extends Error {
2209
+ response;
2210
+ failed;
2211
+ constructor(response) {
2212
+ const failed = response.uploads.filter((u) => u.ok === false);
2213
+ super(
2214
+ `${failed.length} of ${response.uploads.length} upload(s) failed: ${failed.map((f) => `[${f.idx}] ${f.error.code} \u2014 ${f.error.detail}`).join("; ")}`
2215
+ );
2216
+ this.name = "PartialUploadError";
2217
+ this.response = response;
2218
+ this.failed = failed;
1663
2219
  }
1664
- }
1665
- var EciesSealedPoeError = class extends Error {
1666
- code;
1667
- constructor(code, message, options) {
1668
- super(message, options);
1669
- this.name = "EciesSealedPoeError";
1670
- this.code = code;
2220
+ /** Convenience: the `idx` of every failed entry, in input order. */
2221
+ get failedIndices() {
2222
+ return this.failed.map((f) => f.idx);
1671
2223
  }
1672
2224
  };
1673
2225
  function encodeCanonicalCbor4(value) {
@@ -1678,318 +2230,547 @@ function encodeCanonicalCbor4(value) {
1678
2230
  sortKeys: sortCoreDeterministic
1679
2231
  });
1680
2232
  }
1681
- var CHUNK_MAX_BYTES2 = 64;
1682
- function chunkKemCt(value) {
1683
- if (value.length === 0) {
1684
- throw new Error("chunkKemCt: refusing to chunk an empty byte string");
2233
+ var LEAVES_LIST_FORMAT_V1 = "cardano-poe-merkle-leaves-v1";
2234
+ var TREE_ALG_RFC9162 = "rfc9162-sha256";
2235
+ var DIGEST_LENGTH2 = 32;
2236
+ var MerkleLeavesListError = class extends Error {
2237
+ code;
2238
+ constructor(code, message) {
2239
+ super(message ? `${code}: ${message}` : code);
2240
+ this.code = code;
2241
+ this.name = "MerkleLeavesListError";
2242
+ }
2243
+ };
2244
+ function encodeLeavesList(args) {
2245
+ if (!(args.root instanceof Uint8Array) || args.root.length !== DIGEST_LENGTH2) {
2246
+ throw new MerkleLeavesListError(
2247
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
2248
+ `root must be a Uint8Array(${DIGEST_LENGTH2})`
2249
+ );
2250
+ }
2251
+ if (args.leaves.length < 1) {
2252
+ throw new MerkleLeavesListError(
2253
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
2254
+ "leaves array must be non-empty"
2255
+ );
2256
+ }
2257
+ const leavesCopy = [];
2258
+ for (let i = 0; i < args.leaves.length; i++) {
2259
+ const leaf = args.leaves[i];
2260
+ if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH2) {
2261
+ throw new MerkleLeavesListError(
2262
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
2263
+ `leaves[${i}] must be a Uint8Array(${DIGEST_LENGTH2})`
2264
+ );
2265
+ }
2266
+ leavesCopy.push(leaf);
2267
+ }
2268
+ if (args.leafAlg !== void 0 && typeof args.leafAlg !== "string") {
2269
+ throw new MerkleLeavesListError(
2270
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
2271
+ "leaf_alg must be a string when present"
2272
+ );
1685
2273
  }
1686
- const chunks = [];
1687
- for (let i = 0; i < value.length; i += CHUNK_MAX_BYTES2) {
1688
- chunks.push(value.subarray(i, Math.min(i + CHUNK_MAX_BYTES2, value.length)));
2274
+ const map = {
2275
+ format: LEAVES_LIST_FORMAT_V1,
2276
+ tree_alg: TREE_ALG_RFC9162,
2277
+ root: args.root,
2278
+ leaves: leavesCopy,
2279
+ leaf_count: leavesCopy.length
2280
+ };
2281
+ if (args.leafAlg !== void 0) {
2282
+ map["leaf_alg"] = args.leafAlg;
1689
2283
  }
1690
- return chunks;
2284
+ return encodeCanonicalCbor4(map);
1691
2285
  }
1692
- function joinKemCt(chunks) {
1693
- let total = 0;
1694
- for (const c of chunks) total += c.length;
1695
- const out = new Uint8Array(total);
1696
- let offset = 0;
1697
- for (const c of chunks) {
1698
- out.set(c, offset);
1699
- offset += c.length;
2286
+
2287
+ // src/client/resumable-source.ts
2288
+ var openHandlePromise;
2289
+ async function loadOpen() {
2290
+ if (openHandlePromise === void 0) {
2291
+ openHandlePromise = import('fs/promises').then((fs) => fs.open);
1700
2292
  }
1701
- return out;
2293
+ return openHandlePromise;
1702
2294
  }
1703
- function slotsToMacCbor(slots, kem) {
1704
- let value;
1705
- if (kem === "x25519") {
1706
- value = slots.map((s) => ({ epk: s.epk, wrap: s.wrap }));
1707
- } else {
1708
- value = slots.map((s) => ({
1709
- // Canonicalize the chunk boundaries before the MAC commits to them:
1710
- // reassemble the logical ciphertext and re-split into canonical ≤ 64-byte
1711
- // chunks. The on-wire `kem_ct` array is a transport detail (the Cardano
1712
- // ledger's 64-byte metadatum cap), and a hostile or non-canonical chunking
1713
- // ([1, 63, …] instead of [64, …]) reassembles to the SAME bytes — so the
1714
- // MAC must be invariant to it. Committing to the verbatim wire chunks would
1715
- // let an attacker re-chunk an honest envelope and break the slots_mac match
1716
- // for an honest recipient. Honest (already-64B-chunked) records are
1717
- // unchanged; a real byte flip still changes the reassembled bytes and is
1718
- // still rejected.
1719
- kem_ct: chunkKemCt(joinKemCt(s.kem_ct)),
1720
- wrap: s.wrap
1721
- }));
1722
- }
1723
- return encodeCanonicalCbor4(value);
2295
+ var HASH_STREAM_CHUNK_BYTES = 1024 * 1024;
2296
+ function isResumableSource(value) {
2297
+ return typeof value === "object" && value !== null && typeof value.size === "number" && typeof value.slice === "function" && typeof value.stream === "function" && // A Blob/File shares all three members but exposes `.arrayBuffer`; exclude it
2298
+ // here so the adapter contract is unambiguous regardless of check order. A
2299
+ // Blob is handled by its own branch, which adapts `.slice`/`.stream` to bytes.
2300
+ typeof value.arrayBuffer !== "function";
1724
2301
  }
1725
- var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
1726
- var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
1727
- "cardano-poe-kek-mlkem768x25519-v1"
1728
- );
1729
- var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
1730
- "cardano-poe-slots-mac-v1"
1731
- );
1732
- var ZERO_NONCE_12 = new Uint8Array(12);
1733
- var EMPTY_SALT = new Uint8Array(0);
1734
- var X25519_PUBLIC_KEY_LENGTH = 32;
1735
- var X25519_SECRET_KEY_LENGTH = 32;
1736
- var CEK_LENGTH = 32;
1737
- var NONCE_LENGTH = 24;
1738
- var WRAP_LENGTH = 48;
1739
- var SLOTS_MAC_LENGTH = 32;
1740
- if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
1741
- throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
2302
+ function isBlobLike(value) {
2303
+ return typeof value === "object" && value !== null && typeof value.size === "number" && typeof value.slice === "function" && typeof value.arrayBuffer === "function";
1742
2304
  }
1743
- if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
1744
- throw new Error(
1745
- "CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
2305
+ async function blobSlice(blob, start, end) {
2306
+ return new Uint8Array(await blob.slice(start, end).arrayBuffer());
2307
+ }
2308
+ async function* blobStream(blob) {
2309
+ const reader = blob.stream().getReader();
2310
+ try {
2311
+ for (; ; ) {
2312
+ const { done, value } = await reader.read();
2313
+ if (done) break;
2314
+ if (value) yield value;
2315
+ }
2316
+ } finally {
2317
+ reader.releaseLock();
2318
+ }
2319
+ }
2320
+ function fromBlob(blob) {
2321
+ return {
2322
+ size: blob.size,
2323
+ slice: (start, end) => blobSlice(blob, start, end),
2324
+ stream: () => blobStream(blob)
2325
+ };
2326
+ }
2327
+ function fromBytes(bytes) {
2328
+ return {
2329
+ size: bytes.byteLength,
2330
+ slice: (start, end) => bytes.subarray(start, end),
2331
+ stream: async function* () {
2332
+ for (let offset = 0; offset < bytes.byteLength; offset += HASH_STREAM_CHUNK_BYTES) {
2333
+ yield bytes.subarray(offset, Math.min(offset + HASH_STREAM_CHUNK_BYTES, bytes.byteLength));
2334
+ }
2335
+ }
2336
+ };
2337
+ }
2338
+ async function fromPath(path) {
2339
+ const open = await loadOpen();
2340
+ const sliceAt = async (start, end) => {
2341
+ const length = end - start;
2342
+ if (length <= 0) return new Uint8Array(0);
2343
+ const handle = await open(path, "r");
2344
+ try {
2345
+ const buffer = new Uint8Array(length);
2346
+ let filled = 0;
2347
+ while (filled < length) {
2348
+ const { bytesRead } = await handle.read(buffer, filled, length - filled, start + filled);
2349
+ if (bytesRead === 0) break;
2350
+ filled += bytesRead;
2351
+ }
2352
+ return filled === length ? buffer : buffer.subarray(0, filled);
2353
+ } finally {
2354
+ await handle.close();
2355
+ }
2356
+ };
2357
+ const streamFile = async function* () {
2358
+ const handle = await open(path, "r");
2359
+ try {
2360
+ const buffer = new Uint8Array(HASH_STREAM_CHUNK_BYTES);
2361
+ let position = 0;
2362
+ for (; ; ) {
2363
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);
2364
+ if (bytesRead === 0) break;
2365
+ position += bytesRead;
2366
+ yield buffer.slice(0, bytesRead);
2367
+ }
2368
+ } finally {
2369
+ await handle.close();
2370
+ }
2371
+ };
2372
+ const { size } = await statSize(path);
2373
+ return { size, slice: sliceAt, stream: streamFile };
2374
+ }
2375
+ async function statSize(path) {
2376
+ const open = await loadOpen();
2377
+ const handle = await open(path, "r");
2378
+ try {
2379
+ const stats = await handle.stat();
2380
+ return { size: stats.size };
2381
+ } finally {
2382
+ await handle.close();
2383
+ }
2384
+ }
2385
+ async function toResumableSource(input) {
2386
+ if (typeof input === "string") return fromPath(input);
2387
+ if (input instanceof Uint8Array) return fromBytes(input);
2388
+ if (isBlobLike(input)) return fromBlob(input);
2389
+ if (isResumableSource(input)) return input;
2390
+ throw new TypeError(
2391
+ "uploadResumable: unsupported source. Pass a Blob/File, a Uint8Array, a filesystem path string, or a ResumableSource."
1746
2392
  );
1747
2393
  }
1748
- if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
1749
- throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
2394
+
2395
+ // src/client/resumable-upload.ts
2396
+ var DEFAULT_RESUMABLE_THRESHOLD_BYTES = 50331648;
2397
+ var DEFAULT_RESUMABLE_CHUNK_BYTES = 50331648;
2398
+ var DEFAULT_PARALLELISM = 4;
2399
+ var DEFAULT_MAX_CHUNK_RETRIES = 4;
2400
+ var DEFAULT_CONTENT_TYPE = "application/octet-stream";
2401
+ var DEFAULT_TARGET = "arweave";
2402
+ var ATTEMPT_POLL_INTERVAL_MS = 1e3;
2403
+ var ATTEMPT_POLL_MAX_ATTEMPTS = 600;
2404
+ function bytesToHex2(bytes) {
2405
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
1750
2406
  }
1751
- if (ZERO_NONCE_12.length !== 12) {
1752
- throw new Error("ZERO_NONCE_12 byte-length invariant violated (expected 12)");
2407
+ var B64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2408
+ function bytesToBase64(bytes) {
2409
+ let out = "";
2410
+ let i = 0;
2411
+ for (; i + 2 < bytes.length; i += 3) {
2412
+ const n = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
2413
+ out += B64_ALPHABET[n >> 18 & 63] + B64_ALPHABET[n >> 12 & 63] + B64_ALPHABET[n >> 6 & 63] + B64_ALPHABET[n & 63];
2414
+ }
2415
+ const rem = bytes.length - i;
2416
+ if (rem === 1) {
2417
+ const n = bytes[i] << 16;
2418
+ out += B64_ALPHABET[n >> 18 & 63] + B64_ALPHABET[n >> 12 & 63] + "==";
2419
+ } else if (rem === 2) {
2420
+ const n = bytes[i] << 16 | bytes[i + 1] << 8;
2421
+ out += B64_ALPHABET[n >> 18 & 63] + B64_ALPHABET[n >> 12 & 63] + B64_ALPHABET[n >> 6 & 63] + "=";
2422
+ }
2423
+ return out;
2424
+ }
2425
+ function jsonHeaders(config, idempotencyKey) {
2426
+ const headers = new Headers({ "content-type": "application/json", accept: "application/json" });
2427
+ if (config.apiKey !== void 0) headers.set("authorization", `Bearer ${config.apiKey}`);
2428
+ if (idempotencyKey !== void 0) headers.set("idempotency-key", idempotencyKey);
2429
+ return headers;
2430
+ }
2431
+ function octetHeaders(config, length, digestBase64) {
2432
+ const headers = new Headers({
2433
+ "content-type": "application/octet-stream",
2434
+ accept: "application/json",
2435
+ "content-length": String(length),
2436
+ digest: `sha-256=${digestBase64}`
2437
+ });
2438
+ if (config.apiKey !== void 0) headers.set("authorization", `Bearer ${config.apiKey}`);
2439
+ return headers;
2440
+ }
2441
+ var SESSIONS_PATH = "/api/v1/poe/uploads/sessions";
2442
+ function chunkRange(index, chunkBytes, totalBytes) {
2443
+ const start = index * chunkBytes;
2444
+ return [start, Math.min(start + chunkBytes, totalBytes)];
1753
2445
  }
1754
- function concat(a, b) {
1755
- const out = new Uint8Array(a.length + b.length);
1756
- out.set(a, 0);
1757
- out.set(b, a.length);
2446
+ function missingIndices(received, chunkCount) {
2447
+ const have = new Set(received);
2448
+ const out = [];
2449
+ for (let i = 0; i < chunkCount; i++) if (!have.has(i)) out.push(i);
1758
2450
  return out;
1759
2451
  }
1760
- function uniformIndexBelow(m) {
1761
- const limit = 4294967296 - 4294967296 % m;
1762
- const buf = new Uint32Array(1);
1763
- let x;
1764
- do {
1765
- crypto.getRandomValues(buf);
1766
- x = buf[0];
1767
- } while (x >= limit);
1768
- return x % m;
2452
+ function serverMissing(status) {
2453
+ if (Array.isArray(status.missing)) return status.missing;
2454
+ return missingIndices(status.received, status.chunk_count);
2455
+ }
2456
+ async function hashWholeFile(source) {
2457
+ return bytesToHex2(await sha256Stream(source.stream()));
2458
+ }
2459
+ async function createSession(config, body, signal) {
2460
+ const response = await config.fetch(`${config.baseUrl}${SESSIONS_PATH}`, {
2461
+ method: "POST",
2462
+ headers: jsonHeaders(config),
2463
+ body: JSON.stringify(body),
2464
+ ...signal ? { signal } : {}
2465
+ });
2466
+ await throwIfNotOk(response);
2467
+ return await readJson(response);
2468
+ }
2469
+ async function getSessionStatus(config, sessionId, signal) {
2470
+ const response = await config.fetch(
2471
+ `${config.baseUrl}${SESSIONS_PATH}/${encodeURIComponent(sessionId)}`,
2472
+ {
2473
+ method: "GET",
2474
+ headers: jsonHeaders(config),
2475
+ ...signal ? { signal } : {}
2476
+ }
2477
+ );
2478
+ await throwIfNotOk(response);
2479
+ return await readJson(response);
2480
+ }
2481
+ async function putChunk(config, sessionId, index, bytes, signal) {
2482
+ const digest = bytesToBase64(sha256(bytes));
2483
+ const response = await config.fetch(
2484
+ `${config.baseUrl}${SESSIONS_PATH}/${encodeURIComponent(sessionId)}/chunks/${index}`,
2485
+ {
2486
+ method: "PUT",
2487
+ headers: octetHeaders(config, bytes.byteLength, digest),
2488
+ // A Blob body streams without copying; a matching-digest re-PUT is an
2489
+ // idempotent 200 server-side, so a retried chunk is always safe.
2490
+ body: new Blob([bytes], { type: "application/octet-stream" }),
2491
+ ...signal ? { signal } : {}
2492
+ }
2493
+ );
2494
+ await throwIfNotOk(response);
2495
+ return await readJson(response);
1769
2496
  }
1770
- function csprngShuffle(arr) {
1771
- for (let i = arr.length - 1; i > 0; i--) {
1772
- const j = uniformIndexBelow(i + 1);
1773
- const tmp = arr[i];
1774
- arr[i] = arr[j];
1775
- arr[j] = tmp;
1776
- }
2497
+ async function completeSession(config, sessionId, idempotencyKey, signal) {
2498
+ const response = await config.fetch(
2499
+ `${config.baseUrl}${SESSIONS_PATH}/${encodeURIComponent(sessionId)}/complete`,
2500
+ {
2501
+ method: "POST",
2502
+ headers: jsonHeaders(config, idempotencyKey),
2503
+ ...signal ? { signal } : {}
2504
+ }
2505
+ );
2506
+ await throwIfNotOk(response);
2507
+ return await readJson(response);
1777
2508
  }
1778
- function wrapSlotX25519(args) {
1779
- const privEph = args.privEph ?? randomBytes$1(X25519_SECRET_KEY_LENGTH);
1780
- if (privEph.length !== X25519_SECRET_KEY_LENGTH) {
1781
- throw new EciesSealedPoeError(
1782
- "INVALID_EPHEMERAL_SECRET_LENGTH",
1783
- `ephemeralSecrets[${args.slotIdx}] MUST be exactly ${X25519_SECRET_KEY_LENGTH} bytes, got ${privEph.length}`
2509
+ async function pollAttempt(config, attemptId, signal) {
2510
+ for (let attempt = 0; attempt < ATTEMPT_POLL_MAX_ATTEMPTS; attempt++) {
2511
+ const response = await config.fetch(
2512
+ `${config.baseUrl}/api/v1/poe/uploads/attempts/${encodeURIComponent(attemptId)}`,
2513
+ {
2514
+ method: "GET",
2515
+ headers: jsonHeaders(config),
2516
+ ...signal ? { signal } : {}
2517
+ }
1784
2518
  );
2519
+ await throwIfNotOk(response);
2520
+ const status = await readJson(response);
2521
+ if (status.state !== "reserved") return status;
2522
+ await delay(ATTEMPT_POLL_INTERVAL_MS, signal);
1785
2523
  }
1786
- const epk = x25519PublicKey({ secretKey: privEph });
1787
- const shared = x25519Ecdh({ secretKey: privEph, theirPublicKey: args.pubR });
1788
- const kek = hkdfSha256({
1789
- ikm: shared,
1790
- salt: concat(epk, args.pubR),
1791
- info: CARDANO_POE_HKDF_INFO_KEK,
1792
- length: 32
1793
- });
1794
- const wrap = chacha20Poly1305Encrypt({
1795
- key: kek,
1796
- nonce: ZERO_NONCE_12,
1797
- aad: CARDANO_POE_HKDF_INFO_KEK,
1798
- plaintext: args.cek
1799
- });
1800
- if (wrap.length !== WRAP_LENGTH) {
1801
- throw new Error(`internal: wrap.length=${wrap.length}, expected ${WRAP_LENGTH}`);
1802
- }
1803
- return { epk, wrap };
2524
+ throw new ResumableUploadError(
2525
+ "ATTEMPT_POLL_TIMEOUT",
2526
+ `upload attempt ${attemptId} did not reach a terminal state in time`
2527
+ );
1804
2528
  }
1805
- function wrapSlotMlkem768X25519(args) {
1806
- const { enc, ss } = mlkem768x25519Encapsulate({
1807
- publicKey: args.pubR,
1808
- ...args.eseed !== void 0 ? { eseed: args.eseed } : {}
1809
- });
1810
- if (enc.length !== MLKEM768X25519_ENC_LENGTH) {
1811
- throw new Error(`internal: enc.length=${enc.length}, expected ${MLKEM768X25519_ENC_LENGTH}`);
1812
- }
1813
- const kek = hkdfSha256({
1814
- ikm: ss,
1815
- salt: EMPTY_SALT,
1816
- info: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
1817
- length: 32
1818
- });
1819
- const wrap = chacha20Poly1305Encrypt({
1820
- key: kek,
1821
- nonce: ZERO_NONCE_12,
1822
- aad: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
1823
- plaintext: args.cek
2529
+ function delay(ms, signal) {
2530
+ return new Promise((resolve, reject) => {
2531
+ if (signal?.aborted) {
2532
+ reject(signalReason(signal));
2533
+ return;
2534
+ }
2535
+ const timer = setTimeout(() => {
2536
+ signal?.removeEventListener("abort", onAbort);
2537
+ resolve();
2538
+ }, ms);
2539
+ const onAbort = () => {
2540
+ clearTimeout(timer);
2541
+ reject(signalReason(signal));
2542
+ };
2543
+ signal?.addEventListener("abort", onAbort, { once: true });
1824
2544
  });
1825
- if (wrap.length !== WRAP_LENGTH) {
1826
- throw new Error(`internal: wrap.length=${wrap.length}, expected ${WRAP_LENGTH}`);
1827
- }
1828
- return { kem_ct: chunkKemCt(enc), wrap };
1829
2545
  }
1830
- function eciesSealedPoeWrap(args) {
1831
- const { plaintext, recipientPublicKeys } = args;
1832
- const kem = args.kem ?? "x25519";
1833
- const n = recipientPublicKeys.length;
1834
- if (n < 1) {
1835
- throw new EciesSealedPoeError(
1836
- "ENC_SLOTS_EMPTY",
1837
- `recipientPublicKeys.length=${n} must be >= 1`
2546
+ function signalReason(signal) {
2547
+ const reason = signal?.reason;
2548
+ return reason instanceof Error ? reason : new ResumableUploadError("ABORTED", "upload aborted");
2549
+ }
2550
+ var ResumableUploadError = class extends Error {
2551
+ code;
2552
+ constructor(code, message) {
2553
+ super(message);
2554
+ this.name = "ResumableUploadError";
2555
+ this.code = code;
2556
+ }
2557
+ };
2558
+ async function uploadChunks(config, sessionId, source, chunkBytes, totalBytes, missing, parallelism, maxRetries, signal) {
2559
+ let cursor = 0;
2560
+ const workers = [];
2561
+ const lanes = Math.max(1, Math.min(parallelism, missing.length || 1));
2562
+ for (let lane = 0; lane < lanes; lane++) {
2563
+ workers.push(
2564
+ (async () => {
2565
+ for (; ; ) {
2566
+ if (signal?.aborted) throw signalReason(signal);
2567
+ const next = cursor++;
2568
+ if (next >= missing.length) return;
2569
+ const index = missing[next];
2570
+ const [start, end] = chunkRange(index, chunkBytes, totalBytes);
2571
+ const bytes = await source.slice(start, end);
2572
+ await putChunkWithRetry(config, sessionId, index, bytes, maxRetries, signal);
2573
+ }
2574
+ })()
1838
2575
  );
1839
2576
  }
1840
- const expectedPubLen = kem === "x25519" ? X25519_PUBLIC_KEY_LENGTH : MLKEM768X25519_PUBLIC_KEY_LENGTH;
1841
- for (let i = 0; i < n; i++) {
1842
- const pub = recipientPublicKeys[i];
1843
- if (pub === void 0 || pub.length !== expectedPubLen) {
1844
- throw new EciesSealedPoeError(
1845
- "KEM_EPK_LENGTH_MISMATCH",
1846
- `recipientPublicKeys[${i}] MUST be exactly ${expectedPubLen} bytes for kem='${kem}'`
1847
- );
2577
+ await Promise.all(workers);
2578
+ }
2579
+ async function putChunkWithRetry(config, sessionId, index, bytes, maxRetries, signal) {
2580
+ let lastError;
2581
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
2582
+ if (signal?.aborted) throw signalReason(signal);
2583
+ try {
2584
+ await putChunk(config, sessionId, index, bytes, signal);
2585
+ return;
2586
+ } catch (err) {
2587
+ if (signal?.aborted) throw signalReason(signal);
2588
+ if (isTerminalChunkError(err)) throw err;
2589
+ lastError = err;
2590
+ if (attempt < maxRetries) {
2591
+ await delay(Math.min(250 * 2 ** attempt, 8e3), signal);
2592
+ }
1848
2593
  }
1849
2594
  }
1850
- if (kem === "x25519") {
1851
- if (args.eseeds !== void 0) {
1852
- throw new EciesSealedPoeError(
1853
- "EPHEMERAL_SECRETS_COUNT_MISMATCH",
1854
- "eseeds is an X-Wing (mlkem768x25519) override and MUST NOT be supplied for kem='x25519'"
1855
- );
2595
+ throw new ResumableUploadError(
2596
+ "CHUNK_UPLOAD_FAILED",
2597
+ `chunk ${index} failed after ${maxRetries + 1} attempt(s): ${lastError instanceof Error ? lastError.message : String(lastError)}`
2598
+ );
2599
+ }
2600
+ async function uploadResumable(config, singleShot, input) {
2601
+ const source = await toResumableSource(input.source);
2602
+ const target = input.target ?? DEFAULT_TARGET;
2603
+ const threshold = input.threshold ?? DEFAULT_RESUMABLE_THRESHOLD_BYTES;
2604
+ const totalBytes = source.size;
2605
+ if (totalBytes <= threshold && input.sessionId === void 0) {
2606
+ const bytes = await source.slice(0, totalBytes);
2607
+ const result = await singleShot({
2608
+ target,
2609
+ bytes,
2610
+ ...input.idempotencyKey !== void 0 ? { idempotencyKey: input.idempotencyKey } : {},
2611
+ ...input.signal ? { signal: input.signal } : {}
2612
+ });
2613
+ return {
2614
+ uri: result.uri,
2615
+ sha256: result.sha256,
2616
+ bytes: result.bytes,
2617
+ deduplicated: false,
2618
+ mode: "single-shot"
2619
+ };
2620
+ }
2621
+ return runSession(config, source, target, totalBytes, input);
2622
+ }
2623
+ async function runSession(config, source, target, totalBytes, input) {
2624
+ const signal = input.signal;
2625
+ let sessionId;
2626
+ let chunkBytes;
2627
+ let missing;
2628
+ let declaredSha256;
2629
+ let gridTotalBytes;
2630
+ if (input.sessionId !== void 0) {
2631
+ const status = await getSessionStatus(config, input.sessionId, signal);
2632
+ if (status.state === "completed" && status.uri !== null) {
2633
+ return {
2634
+ uri: status.uri,
2635
+ sha256: status.sha256,
2636
+ bytes: status.total_bytes,
2637
+ deduplicated: false,
2638
+ mode: "chunked"
2639
+ };
1856
2640
  }
1857
- if (args.ephemeralSecrets !== void 0 && args.ephemeralSecrets.length !== n) {
1858
- throw new EciesSealedPoeError(
1859
- "EPHEMERAL_SECRETS_COUNT_MISMATCH",
1860
- `ephemeralSecrets.length=${args.ephemeralSecrets.length} must match recipientPublicKeys.length=${n}`
2641
+ if (status.state === "failed" || status.state === "expired") {
2642
+ throw new ResumableUploadError(
2643
+ "SESSION_FAILED",
2644
+ `cannot resume session ${input.sessionId} in state '${status.state}'`
1861
2645
  );
1862
2646
  }
2647
+ sessionId = status.session_id;
2648
+ declaredSha256 = status.sha256;
2649
+ chunkBytes = status.chunk_bytes;
2650
+ gridTotalBytes = status.total_bytes;
2651
+ missing = serverMissing(status);
1863
2652
  } else {
1864
- if (args.ephemeralSecrets !== void 0) {
1865
- throw new EciesSealedPoeError(
1866
- "EPHEMERAL_SECRETS_COUNT_MISMATCH",
1867
- "ephemeralSecrets is an X25519 override and MUST NOT be supplied for kem='mlkem768x25519'"
1868
- );
2653
+ declaredSha256 = await hashWholeFile(source);
2654
+ const requestedChunkBytes = input.chunkBytes ?? DEFAULT_RESUMABLE_CHUNK_BYTES;
2655
+ const created = await createSession(
2656
+ config,
2657
+ {
2658
+ target,
2659
+ sha256: declaredSha256,
2660
+ total_bytes: totalBytes,
2661
+ chunk_bytes: requestedChunkBytes,
2662
+ content_type: input.contentType ?? DEFAULT_CONTENT_TYPE
2663
+ },
2664
+ signal
2665
+ );
2666
+ if ("deduplicated" in created) {
2667
+ return {
2668
+ uri: created.uri,
2669
+ sha256: created.sha256,
2670
+ bytes: created.bytes,
2671
+ deduplicated: true,
2672
+ mode: "chunked"
2673
+ };
1869
2674
  }
1870
- if (args.eseeds !== void 0) {
1871
- if (args.eseeds.length !== n) {
1872
- throw new EciesSealedPoeError(
1873
- "EPHEMERAL_SECRETS_COUNT_MISMATCH",
1874
- `eseeds.length=${args.eseeds.length} must match recipientPublicKeys.length=${n}`
1875
- );
2675
+ sessionId = created.session_id;
2676
+ chunkBytes = created.chunk_bytes;
2677
+ gridTotalBytes = totalBytes;
2678
+ missing = missingIndices(created.received, created.chunk_count);
2679
+ }
2680
+ if (missing.length > 0) {
2681
+ await uploadChunks(
2682
+ config,
2683
+ sessionId,
2684
+ source,
2685
+ chunkBytes,
2686
+ gridTotalBytes,
2687
+ missing,
2688
+ input.parallelism ?? DEFAULT_PARALLELISM,
2689
+ input.maxChunkRetries ?? DEFAULT_MAX_CHUNK_RETRIES,
2690
+ signal
2691
+ );
2692
+ }
2693
+ return finishSession(config, sessionId, declaredSha256, input);
2694
+ }
2695
+ async function finishSession(config, sessionId, declaredSha256, input) {
2696
+ const signal = input.signal;
2697
+ const idempotencyKey = input.idempotencyKey ?? `resumable-${declaredSha256}`;
2698
+ const COMPLETE_RETRIES = 2;
2699
+ for (let attempt = 0; attempt <= COMPLETE_RETRIES; attempt++) {
2700
+ try {
2701
+ const completion = await completeSession(config, sessionId, idempotencyKey, signal);
2702
+ if ("ok" in completion) {
2703
+ return {
2704
+ uri: completion.uri,
2705
+ sha256: completion.sha256,
2706
+ bytes: completion.bytes,
2707
+ // The server sends the number 0 for a dedup-on-commit (the bytes were
2708
+ // already stored, so nothing was charged); compare numerically.
2709
+ deduplicated: completion.charged_usd_micros === 0,
2710
+ mode: "chunked"
2711
+ };
1876
2712
  }
1877
- for (let i = 0; i < n; i++) {
1878
- const eseed = args.eseeds[i];
1879
- if (eseed.length !== MLKEM768X25519_ESEED_LENGTH) {
1880
- throw new EciesSealedPoeError(
1881
- "INVALID_EPHEMERAL_SECRET_LENGTH",
1882
- `eseeds[${i}] MUST be exactly ${MLKEM768X25519_ESEED_LENGTH} bytes, got ${eseed.length}`
1883
- );
1884
- }
2713
+ return resolveAccepted(config, completion.attempt_id, signal);
2714
+ } catch (err) {
2715
+ if (attempt < COMPLETE_RETRIES && isIncompleteUpload(err)) {
2716
+ const status = await getSessionStatus(config, sessionId, signal);
2717
+ const stillMissing = serverMissing(status);
2718
+ if (stillMissing.length === 0) continue;
2719
+ await uploadChunks(
2720
+ config,
2721
+ sessionId,
2722
+ await toResumableSource(input.source),
2723
+ status.chunk_bytes,
2724
+ // Re-bound the resend grid against the server's declared total too, so a
2725
+ // source that grew during the upload cannot over-read the final chunk.
2726
+ status.total_bytes,
2727
+ stillMissing,
2728
+ input.parallelism ?? DEFAULT_PARALLELISM,
2729
+ input.maxChunkRetries ?? DEFAULT_MAX_CHUNK_RETRIES,
2730
+ signal
2731
+ );
2732
+ continue;
1885
2733
  }
2734
+ throw err;
1886
2735
  }
1887
2736
  }
1888
- const cek = args.cek ?? randomBytes$1(CEK_LENGTH);
1889
- const nonce = args.nonce ?? randomBytes$1(NONCE_LENGTH);
1890
- if (cek.length !== CEK_LENGTH) {
1891
- throw new EciesSealedPoeError(
1892
- "INVALID_CEK_LENGTH",
1893
- `cek MUST be exactly ${CEK_LENGTH} bytes, got ${cek.length}`
2737
+ throw new ResumableUploadError(
2738
+ "SESSION_FAILED",
2739
+ `session ${sessionId} could not be completed after resending missing chunks`
2740
+ );
2741
+ }
2742
+ async function resolveAccepted(config, attemptId, signal) {
2743
+ const status = await pollAttempt(config, attemptId, signal);
2744
+ if (status.state === "released") {
2745
+ throw new ResumableUploadError(
2746
+ "ATTEMPT_FAILED",
2747
+ `upload attempt ${attemptId} was released: ${status.reason}`
1894
2748
  );
1895
2749
  }
1896
- if (nonce.length !== NONCE_LENGTH) {
1897
- throw new EciesSealedPoeError(
1898
- "NONCE_LENGTH_MISMATCH",
1899
- `nonce MUST be exactly ${NONCE_LENGTH} bytes, got ${nonce.length}`
2750
+ if (status.uri.length === 0) {
2751
+ throw new ResumableUploadError(
2752
+ "ATTEMPT_FAILED",
2753
+ `upload attempt ${attemptId} committed without a uri`
1900
2754
  );
1901
2755
  }
1902
- let envelope;
1903
- if (kem === "x25519") {
1904
- const slots = [];
1905
- for (let i = 0; i < n; i++) {
1906
- slots.push(
1907
- wrapSlotX25519({
1908
- pubR: recipientPublicKeys[i],
1909
- privEph: args.ephemeralSecrets ? args.ephemeralSecrets[i] : void 0,
1910
- cek,
1911
- slotIdx: i
1912
- })
1913
- );
1914
- }
1915
- if (args.skipShuffle !== true) {
1916
- csprngShuffle(slots);
1917
- }
1918
- const slotsMac = computeSlotsMac(cek, slots, "x25519");
1919
- envelope = {
1920
- scheme: 1,
1921
- aead: "xchacha20-poly1305",
1922
- kem: "x25519",
1923
- nonce,
1924
- slots,
1925
- slots_mac: slotsMac
1926
- };
1927
- } else {
1928
- const slots = [];
1929
- for (let i = 0; i < n; i++) {
1930
- slots.push(
1931
- wrapSlotMlkem768X25519({
1932
- pubR: recipientPublicKeys[i],
1933
- eseed: args.eseeds ? args.eseeds[i] : void 0,
1934
- cek
1935
- })
1936
- );
1937
- }
1938
- if (args.skipShuffle !== true) {
1939
- csprngShuffle(slots);
1940
- }
1941
- const slotsMac = computeSlotsMac(cek, slots, "mlkem768x25519");
1942
- envelope = {
1943
- scheme: 1,
1944
- aead: "xchacha20-poly1305",
1945
- kem: "mlkem768x25519",
1946
- nonce,
1947
- slots,
1948
- slots_mac: slotsMac
1949
- };
1950
- }
1951
- const adContent = concat(nonce, envelope.slots_mac);
1952
- const ciphertext = xchacha20Poly1305Encrypt({
1953
- key: cek,
1954
- nonce,
1955
- aad: adContent,
1956
- plaintext
1957
- });
1958
- return { envelope, ciphertext };
2756
+ return {
2757
+ uri: status.uri,
2758
+ sha256: status.sha256,
2759
+ bytes: status.bytes,
2760
+ // A committed attempt that charged nothing deduped against bytes already
2761
+ // stored for this account on this backend.
2762
+ deduplicated: status.charged_usd_micros === 0,
2763
+ mode: "chunked"
2764
+ };
1959
2765
  }
1960
- function computeSlotsMac(cek, slots, kem) {
1961
- const hmacKey = hkdfSha256({
1962
- ikm: cek,
1963
- salt: EMPTY_SALT,
1964
- info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
1965
- length: 32
1966
- });
1967
- const slotsCbor = slotsToMacCbor(slots, kem);
1968
- const slotsMac = hmac(sha256$1, hmacKey, slotsCbor);
1969
- if (slotsMac.length !== SLOTS_MAC_LENGTH) {
1970
- throw new Error(`internal: slots_mac.length=${slotsMac.length}, expected ${SLOTS_MAC_LENGTH}`);
1971
- }
1972
- return slotsMac;
2766
+ function isTerminalChunkError(err) {
2767
+ if (!(err instanceof Label309HttpError)) return false;
2768
+ const status = err.httpStatus;
2769
+ return status >= 400 && status < 500 && status !== 408 && status !== 429;
2770
+ }
2771
+ function isIncompleteUpload(err) {
2772
+ return typeof err === "object" && err !== null && "code" in err && err.code === "incomplete-upload";
1973
2773
  }
1974
-
1975
- // src/client/partial-upload-error.ts
1976
- var PartialUploadError = class extends Error {
1977
- response;
1978
- failed;
1979
- constructor(response) {
1980
- const failed = response.uploads.filter((u) => u.ok === false);
1981
- super(
1982
- `${failed.length} of ${response.uploads.length} upload(s) failed: ${failed.map((f) => `[${f.idx}] ${f.error.code} \u2014 ${f.error.detail}`).join("; ")}`
1983
- );
1984
- this.name = "PartialUploadError";
1985
- this.response = response;
1986
- this.failed = failed;
1987
- }
1988
- /** Convenience: the `idx` of every failed entry, in input order. */
1989
- get failedIndices() {
1990
- return this.failed.map((f) => f.idx);
1991
- }
1992
- };
1993
2774
 
1994
2775
  // src/client/publish.ts
1995
2776
  var ED25519_PUBLIC_KEY_LENGTH2 = 32;
@@ -2006,7 +2787,7 @@ var PublishError = class extends Error {
2006
2787
  this.code = code;
2007
2788
  }
2008
2789
  };
2009
- function bytesToHex2(bytes) {
2790
+ function bytesToHex3(bytes) {
2010
2791
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
2011
2792
  }
2012
2793
  function hexToBytes(hex) {
@@ -2027,14 +2808,14 @@ function toBytes(content) {
2027
2808
  if (typeof content === "string") return new TextEncoder().encode(content);
2028
2809
  return content;
2029
2810
  }
2030
- function cloneToOwnedBuffer(src) {
2811
+ function cloneToOwnedBuffer2(src) {
2031
2812
  const out = new Uint8Array(new ArrayBuffer(src.length));
2032
2813
  out.set(src);
2033
2814
  return out;
2034
2815
  }
2035
2816
  function hashContent(bytes, alg) {
2036
- if (alg === "sha2-256") return cloneToOwnedBuffer(sha256(bytes));
2037
- if (alg === "blake2b-256") return cloneToOwnedBuffer(blake2b256(bytes));
2817
+ if (alg === "sha2-256") return cloneToOwnedBuffer2(sha256(bytes));
2818
+ if (alg === "blake2b-256") return cloneToOwnedBuffer2(blake2b256(bytes));
2038
2819
  throw new PublishError(
2039
2820
  "UNSUPPORTED_HASH_ALG",
2040
2821
  `hashAlg must be 'sha2-256' or 'blake2b-256', got '${alg}'`
@@ -2118,29 +2899,45 @@ async function postPublish(config, recordBytesHex, quoteId, idempotencyKey) {
2118
2899
  const parsed = await readJson2(response);
2119
2900
  return { ...parsed, dedup_hit: response.status === 200 };
2120
2901
  }
2121
- async function postUploads(config, blobs, idempotencyKey) {
2902
+ var singleShotUpload = (config) => async ({ target, bytes, idempotencyKey, signal }) => {
2122
2903
  const form = new FormData();
2123
- form.append("target", STORAGE_TARGET_ARWEAVE);
2124
- for (let idx = 0; idx < blobs.length; idx++) {
2125
- const bytes = blobs[idx];
2126
- form.append(
2127
- `file_${idx}`,
2128
- new Blob([bytes], { type: "application/octet-stream" }),
2129
- `file_${idx}.bin`
2130
- );
2131
- }
2904
+ form.append("target", target);
2905
+ form.append(
2906
+ "file_0",
2907
+ new Blob([bytes], { type: "application/octet-stream" }),
2908
+ "file_0.bin"
2909
+ );
2132
2910
  const response = await config.fetch(`${config.baseUrl}/api/v1/poe/uploads`, {
2133
2911
  method: "POST",
2134
2912
  headers: buildMultipartHeaders(config.apiKey, idempotencyKey),
2135
- body: form
2913
+ body: form,
2914
+ ...signal ? { signal } : {}
2136
2915
  });
2137
2916
  await throwIfNotOk2(response);
2138
2917
  const result = await readJson2(response);
2139
- const anyFailed = result.uploads.some((u) => u.ok === false);
2140
- if (anyFailed) {
2918
+ const entry = result.uploads[0];
2919
+ if (entry === void 0 || entry.ok === false) {
2141
2920
  throw new PartialUploadError(result);
2142
2921
  }
2143
- return result;
2922
+ const ok = entry;
2923
+ return { uri: ok.uri, sha256: ok.sha256, bytes: ok.bytes };
2924
+ };
2925
+ async function uploadBlob(config, bytes, idempotencyKey) {
2926
+ const target = STORAGE_TARGET_ARWEAVE;
2927
+ if (bytes.byteLength <= DEFAULT_RESUMABLE_THRESHOLD_BYTES) {
2928
+ const single = await singleShotUpload(config)({
2929
+ target,
2930
+ bytes,
2931
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {}
2932
+ });
2933
+ return single.uri;
2934
+ }
2935
+ const result = await uploadResumable(config, singleShotUpload(config), {
2936
+ target,
2937
+ source: bytes,
2938
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {}
2939
+ });
2940
+ return result.uri;
2144
2941
  }
2145
2942
  async function publishContent(config, input) {
2146
2943
  if (input.signer !== void 0) assertSigner(input.signer);
@@ -2152,7 +2949,7 @@ async function publishContent(config, input) {
2152
2949
  items: [{ hashes: { [hashAlg]: digest } }]
2153
2950
  };
2154
2951
  const recordBytes = await encodeRecord(record, input.signer);
2155
- return postPublish(config, bytesToHex2(recordBytes), input.quoteId, input.idempotencyKey);
2952
+ return postPublish(config, bytesToHex3(recordBytes), input.quoteId, input.idempotencyKey);
2156
2953
  }
2157
2954
  var DIGEST_BYTE_LENGTH = {
2158
2955
  "sha2-256": 32,
@@ -2184,14 +2981,14 @@ async function publishPrehashed(config, input) {
2184
2981
  `hashes[${alg}] must be a ${expected}-byte digest (got ${bytes.length} bytes)`
2185
2982
  );
2186
2983
  }
2187
- decoded[alg] = cloneToOwnedBuffer(bytes);
2984
+ decoded[alg] = cloneToOwnedBuffer2(bytes);
2188
2985
  }
2189
2986
  const record = {
2190
2987
  v: 1,
2191
2988
  items: [{ hashes: decoded }]
2192
2989
  };
2193
2990
  const recordBytes = await encodeRecord(record, input.signer);
2194
- return postPublish(config, bytesToHex2(recordBytes), input.quoteId, input.idempotencyKey);
2991
+ return postPublish(config, bytesToHex3(recordBytes), input.quoteId, input.idempotencyKey);
2195
2992
  }
2196
2993
  async function publishSealed(config, input) {
2197
2994
  if (input.signer !== void 0) assertSigner(input.signer);
@@ -2215,41 +3012,42 @@ async function publishSealed(config, input) {
2215
3012
  const hashAlg = input.hashAlg ?? "sha2-256";
2216
3013
  const plaintext = toBytes(input.content);
2217
3014
  const plaintextDigest = hashContent(plaintext, hashAlg);
3015
+ const hashes2 = { [hashAlg]: plaintextDigest };
2218
3016
  const sealed = eciesSealedPoeWrap({
2219
3017
  plaintext,
3018
+ hashes: hashes2,
2220
3019
  recipientPublicKeys: input.recipients.map((r) => r),
2221
3020
  kem
2222
3021
  });
2223
- const uploadsResp = await postUploads(config, [sealed.ciphertext], input.idempotencyKey);
2224
- const uri = uploadsResp.uploads[0].uri;
3022
+ const uri = await uploadBlob(config, sealed.ciphertext, input.idempotencyKey);
2225
3023
  const env = sealed.envelope;
2226
3024
  const slots = env.kem === "mlkem768x25519" ? env.slots.map((s) => ({
2227
- kem_ct: s.kem_ct.map((c) => cloneToOwnedBuffer(c)),
2228
- wrap: cloneToOwnedBuffer(s.wrap)
3025
+ kem_ct: cloneToOwnedBuffer2(s.kem_ct),
3026
+ wrap: cloneToOwnedBuffer2(s.wrap)
2229
3027
  })) : env.slots.map((s) => ({
2230
- epk: cloneToOwnedBuffer(s.epk),
2231
- wrap: cloneToOwnedBuffer(s.wrap)
3028
+ epk: cloneToOwnedBuffer2(s.epk),
3029
+ wrap: cloneToOwnedBuffer2(s.wrap)
2232
3030
  }));
2233
3031
  const envelope = {
2234
3032
  scheme: 1,
2235
3033
  aead: env.aead,
2236
3034
  kem: env.kem,
2237
- nonce: cloneToOwnedBuffer(env.nonce),
3035
+ nonce: cloneToOwnedBuffer2(env.nonce),
2238
3036
  slots,
2239
- slots_mac: cloneToOwnedBuffer(env.slots_mac)
3037
+ slots_mac: cloneToOwnedBuffer2(env.slots_mac)
2240
3038
  };
2241
3039
  const record = {
2242
3040
  v: 1,
2243
3041
  items: [
2244
3042
  {
2245
- hashes: { [hashAlg]: plaintextDigest },
2246
- uris: [chunkUri(uri)],
3043
+ hashes: hashes2,
3044
+ uris: [uri],
2247
3045
  enc: envelope
2248
3046
  }
2249
3047
  ]
2250
3048
  };
2251
3049
  const recordBytes = await encodeRecord(record, input.signer);
2252
- return postPublish(config, bytesToHex2(recordBytes), input.quoteId, input.idempotencyKey);
3050
+ return postPublish(config, bytesToHex3(recordBytes), input.quoteId, input.idempotencyKey);
2253
3051
  }
2254
3052
  async function publishMerkle(config, input) {
2255
3053
  if (input.signer !== void 0) assertSigner(input.signer);
@@ -2272,21 +3070,20 @@ async function publishMerkle(config, input) {
2272
3070
  }
2273
3071
  return bytes;
2274
3072
  });
2275
- const root = cloneToOwnedBuffer(merkleSha2256Root(leaves));
3073
+ const root = cloneToOwnedBuffer2(merkleSha2256Root(leaves));
2276
3074
  const leavesListCbor = encodeLeavesList({ leaves, root });
2277
- const uploadsResp = await postUploads(config, [leavesListCbor], input.idempotencyKey);
2278
- const uri = uploadsResp.uploads[0].uri;
3075
+ const uri = await uploadBlob(config, leavesListCbor, input.idempotencyKey);
2279
3076
  const merkleEntry = {
2280
3077
  alg: MERKLE_ALG_ID,
2281
3078
  root,
2282
3079
  leaf_count: leaves.length,
2283
- uris: [chunkUri(uri)]
3080
+ uris: [uri]
2284
3081
  };
2285
3082
  const record = { v: 1, merkle: [merkleEntry] };
2286
3083
  const recordBytes = await encodeRecord(record, input.signer);
2287
3084
  const published = await postPublish(
2288
3085
  config,
2289
- bytesToHex2(recordBytes),
3086
+ bytesToHex3(recordBytes),
2290
3087
  input.quoteId,
2291
3088
  input.idempotencyKey
2292
3089
  );
@@ -2294,7 +3091,7 @@ async function publishMerkle(config, input) {
2294
3091
  id: published.id,
2295
3092
  tx_hash: published.tx_hash,
2296
3093
  status: published.status,
2297
- root: bytesToHex2(root),
3094
+ root: bytesToHex3(root),
2298
3095
  leaf_count: leaves.length,
2299
3096
  ar_uri: uri,
2300
3097
  balance_after_usd_micros: published.balance_after_usd_micros
@@ -2389,6 +3186,65 @@ var PoeNamespace = class {
2389
3186
  await throwIfNotOk(response);
2390
3187
  return await readJson(response);
2391
3188
  }
3189
+ /**
3190
+ * Upload a single file of any size, choosing the ingress path by size.
3191
+ *
3192
+ * A file at or below `threshold` (default ~48 MiB) is sent with the unchanged
3193
+ * single-shot `uploads()` multipart call. A larger file is uploaded as a
3194
+ * resumable, content-addressed session: the helper streams the whole-file
3195
+ * SHA-256 once (never buffering a multi-GB file), creates a session, PUTs each
3196
+ * chunk (several in parallel, retrying a failed chunk), then completes —
3197
+ * polling the shared attempt endpoint when completion is accepted
3198
+ * asynchronously. Both paths converge on one `ar://` URI.
3199
+ *
3200
+ * The chunk size is the server's authoritative `chunk_bytes` from the create
3201
+ * response, clamped to its `max_chunk_bytes` ceiling; the client's `chunkBytes`
3202
+ * is only a request. A create-time dedup hit returns the existing URI without
3203
+ * uploading; a `402` funding error is surfaced as a typed error.
3204
+ *
3205
+ * The `source` works in both runtimes: a `Blob`/`File` in the browser, a
3206
+ * `Uint8Array`, a filesystem path string, or a pre-adapted `ResumableSource`
3207
+ * on the server. To resume an interrupted upload, pass the prior `sessionId`;
3208
+ * the helper GETs its status and uploads only the missing chunks.
3209
+ */
3210
+ async uploadResumable(input) {
3211
+ return uploadResumable(this.config, this.singleShotUpload, input);
3212
+ }
3213
+ /**
3214
+ * Upload exactly one blob via the single-shot multipart route and resolve its
3215
+ * `ar://` URI. Backs the small-file branch of `uploadResumable`; it shares the
3216
+ * `uploads()` wire shape but takes one blob and an optional abort signal, and
3217
+ * surfaces a per-file failure as a `PartialUploadError` (the resumable helper
3218
+ * promises a single resolved URI, unlike the raw `uploads()` passthrough).
3219
+ */
3220
+ singleShotUpload = async ({
3221
+ target,
3222
+ bytes,
3223
+ idempotencyKey,
3224
+ signal
3225
+ }) => {
3226
+ const form = new FormData();
3227
+ form.append("target", target);
3228
+ form.append(
3229
+ "file_0",
3230
+ new Blob([bytes], { type: "application/octet-stream" }),
3231
+ "file_0.bin"
3232
+ );
3233
+ const response = await this.config.fetch(`${this.config.baseUrl}/api/v1/poe/uploads`, {
3234
+ method: "POST",
3235
+ headers: buildMultipartHeaders2({ apiKey: this.config.apiKey, idempotencyKey }),
3236
+ body: form,
3237
+ ...signal ? { signal } : {}
3238
+ });
3239
+ await throwIfNotOk(response);
3240
+ const result = await readJson(response);
3241
+ const entry = result.uploads[0];
3242
+ if (entry === void 0 || entry.ok === false) {
3243
+ throw new PartialUploadError(result);
3244
+ }
3245
+ const ok = entry;
3246
+ return { uri: ok.uri, sha256: ok.sha256, bytes: ok.bytes };
3247
+ };
2392
3248
  /**
2393
3249
  * Submit a single finalised canonical-CBOR record to Cardano. Caller is
2394
3250
  * responsible for constructing the record bytes (use `publishContent` /
@@ -2636,6 +3492,6 @@ var Label309Client = class {
2636
3492
  (*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) *)
2637
3493
  */
2638
3494
 
2639
- export { AccountNamespace, BatchEmptyError, BatchTooLargeError, ForbiddenError, IdempotencyConflictError, InsufficientFundsError, InsufficientScopeError, InternalServerError, InvalidBodyError, InvalidClientConfigError, Label309Client, Label309HttpError, MalformedCborError, NotFoundError, OffHostSignError, PartialUploadError, PoeNamespace, PublishError, QuoteAlreadyConsumedError, QuoteExpiredError, QuoteNotFoundError, RateLimitedError, RecordNotFoundError, RecordsNamespace, ServiceUnavailableError, UnauthorizedError, ValidationFailedError, assembleCoseSign1, assembleCoseSign1Hashed, buildToSign, parseHttpError, prepareSigStructure, prepareSigStructureHashed };
3495
+ export { AccountNamespace, BatchEmptyError, BatchTooLargeError, DEFAULT_RESUMABLE_CHUNK_BYTES, DEFAULT_RESUMABLE_THRESHOLD_BYTES, ForbiddenError, IdempotencyConflictError, InsufficientFundsError, InsufficientScopeError, InternalServerError, InvalidBodyError, InvalidClientConfigError, Label309Client, Label309HttpError, MalformedCborError, NotFoundError, OffHostSignError, PartialUploadError, PoeNamespace, PublishError, QuoteAlreadyConsumedError, QuoteExpiredError, QuoteNotFoundError, RateLimitedError, RecordNotFoundError, RecordsNamespace, ResumableUploadError, ServiceUnavailableError, UnauthorizedError, ValidationFailedError, assembleCoseSign1, assembleCoseSign1Hashed, buildToSign, parseHttpError, prepareSigStructure, prepareSigStructureHashed, toResumableSource };
2640
3496
  //# sourceMappingURL=index.js.map
2641
3497
  //# sourceMappingURL=index.js.map