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