@cardanowall/sdk-ts 0.2.0 → 0.3.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 +1608 -1525
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.js +1608 -1525
- package/dist/client/index.js.map +1 -1
- package/dist/conformance/cli.cjs +2334 -2073
- package/dist/conformance/cli.cjs.map +1 -1
- package/dist/conformance/cli.js +2334 -2073
- package/dist/conformance/cli.js.map +1 -1
- package/dist/identity/index.cjs +219 -104
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.js +219 -104
- package/dist/identity/index.js.map +1 -1
- package/dist/index.cjs +2762 -2484
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2762 -2484
- package/dist/index.js.map +1 -1
- package/dist/verifier/index.cjs +2335 -2074
- package/dist/verifier/index.cjs.map +1 -1
- package/dist/verifier/index.js +2336 -2075
- package/dist/verifier/index.js.map +1 -1
- package/package.json +3 -3
package/dist/client/index.js
CHANGED
|
@@ -320,1656 +320,1739 @@ function sigEntryToCbor(entry) {
|
|
|
320
320
|
}
|
|
321
321
|
return out;
|
|
322
322
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
return chunks;
|
|
334
|
-
}
|
|
335
|
-
function chunkUri(uri) {
|
|
336
|
-
const bytes = UTF8_ENCODER2.encode(uri);
|
|
337
|
-
if (bytes.length === 0) return [""];
|
|
338
|
-
if (bytes.length <= CHUNK_MAX_BYTES) return [uri];
|
|
339
|
-
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
340
|
-
const chunks = [];
|
|
341
|
-
let cursor = 0;
|
|
342
|
-
while (cursor < bytes.length) {
|
|
343
|
-
let end = Math.min(cursor + CHUNK_MAX_BYTES, bytes.length);
|
|
344
|
-
while (end < bytes.length && (bytes[end] & 192) === 128) end--;
|
|
345
|
-
chunks.push(decoder.decode(bytes.subarray(cursor, end)));
|
|
346
|
-
cursor = end;
|
|
347
|
-
}
|
|
348
|
-
return chunks;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// src/client/off-host-sign.ts
|
|
352
|
-
var EMPTY_BYTES2 = new Uint8Array(0);
|
|
353
|
-
var ED25519_PUBLIC_KEY_LENGTH = 32;
|
|
354
|
-
var ED25519_SIGNATURE_LENGTH = 64;
|
|
355
|
-
var OffHostSignError = class extends Error {
|
|
356
|
-
code;
|
|
357
|
-
constructor(code, message) {
|
|
358
|
-
super(message);
|
|
359
|
-
this.name = "OffHostSignError";
|
|
360
|
-
this.code = code;
|
|
361
|
-
}
|
|
362
|
-
};
|
|
363
|
-
function buildToSign(record) {
|
|
364
|
-
const body = encodeRecordBodyForSigning(record);
|
|
365
|
-
const out = new Uint8Array(CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES.length + body.length);
|
|
366
|
-
out.set(CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES, 0);
|
|
367
|
-
out.set(body, CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES.length);
|
|
368
|
-
return out;
|
|
323
|
+
var abytesDoc = abytes;
|
|
324
|
+
var randomBytes = randomBytes$2;
|
|
325
|
+
function equalBytes(a, b) {
|
|
326
|
+
if (a.length !== b.length)
|
|
327
|
+
return false;
|
|
328
|
+
let diff = 0;
|
|
329
|
+
for (let i = 0; i < a.length; i++)
|
|
330
|
+
diff |= a[i] ^ b[i];
|
|
331
|
+
return diff === 0;
|
|
369
332
|
}
|
|
370
|
-
function
|
|
371
|
-
|
|
372
|
-
[1, -8],
|
|
373
|
-
[4, signerPubkey]
|
|
374
|
-
]);
|
|
375
|
-
const protectedHeaderBytes = encodeCanonicalCbor(protectedHeader);
|
|
376
|
-
return { protectedHeader, protectedHeaderBytes };
|
|
333
|
+
function copyBytes(bytes) {
|
|
334
|
+
return Uint8Array.from(abytes(bytes));
|
|
377
335
|
}
|
|
378
|
-
function
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
336
|
+
function splitCoder(label, ...lengths) {
|
|
337
|
+
const getLength = (c) => typeof c === "number" ? c : c.bytesLen;
|
|
338
|
+
const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0);
|
|
339
|
+
return {
|
|
340
|
+
bytesLen,
|
|
341
|
+
encode: (bufs) => {
|
|
342
|
+
const res = new Uint8Array(bytesLen);
|
|
343
|
+
for (let i = 0, pos = 0; i < lengths.length; i++) {
|
|
344
|
+
const c = lengths[i];
|
|
345
|
+
const l = getLength(c);
|
|
346
|
+
const b = typeof c === "number" ? bufs[i] : c.encode(bufs[i]);
|
|
347
|
+
abytes(b, l, label);
|
|
348
|
+
res.set(b, pos);
|
|
349
|
+
if (typeof c !== "number")
|
|
350
|
+
b.fill(0);
|
|
351
|
+
pos += l;
|
|
352
|
+
}
|
|
353
|
+
return res;
|
|
354
|
+
},
|
|
355
|
+
decode: (buf) => {
|
|
356
|
+
abytes(buf, bytesLen, label);
|
|
357
|
+
const res = [];
|
|
358
|
+
for (const c of lengths) {
|
|
359
|
+
const l = getLength(c);
|
|
360
|
+
const b = buf.subarray(0, l);
|
|
361
|
+
res.push(typeof c === "number" ? b : c.decode(b));
|
|
362
|
+
buf = buf.subarray(l);
|
|
363
|
+
}
|
|
364
|
+
return res;
|
|
365
|
+
}
|
|
366
|
+
};
|
|
392
367
|
}
|
|
393
|
-
function
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
)
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
368
|
+
function vecCoder(c, vecLen) {
|
|
369
|
+
const coder = c;
|
|
370
|
+
const bytesLen = vecLen * coder.bytesLen;
|
|
371
|
+
return {
|
|
372
|
+
bytesLen,
|
|
373
|
+
encode: (u) => {
|
|
374
|
+
if (u.length !== vecLen)
|
|
375
|
+
throw new RangeError(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`);
|
|
376
|
+
const res = new Uint8Array(bytesLen);
|
|
377
|
+
for (let i = 0, pos = 0; i < u.length; i++) {
|
|
378
|
+
const b = coder.encode(u[i]);
|
|
379
|
+
res.set(b, pos);
|
|
380
|
+
b.fill(0);
|
|
381
|
+
pos += b.length;
|
|
382
|
+
}
|
|
383
|
+
return res;
|
|
384
|
+
},
|
|
385
|
+
decode: (a) => {
|
|
386
|
+
abytes(a, bytesLen);
|
|
387
|
+
const r = [];
|
|
388
|
+
for (let i = 0; i < a.length; i += coder.bytesLen)
|
|
389
|
+
r.push(coder.decode(a.subarray(i, i + coder.bytesLen)));
|
|
390
|
+
return r;
|
|
391
|
+
}
|
|
392
|
+
};
|
|
416
393
|
}
|
|
417
|
-
function
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
394
|
+
function cleanBytes(...list) {
|
|
395
|
+
for (const t of list) {
|
|
396
|
+
if (Array.isArray(t))
|
|
397
|
+
for (const b of t)
|
|
398
|
+
b.fill(0);
|
|
399
|
+
else
|
|
400
|
+
t.fill(0);
|
|
423
401
|
}
|
|
424
|
-
const { protectedHeaderBytes } = encodePath1ProtectedHeader(args.signerPubkey);
|
|
425
|
-
const toSign = buildToSign(args.record);
|
|
426
|
-
const toSignHashBytes = blake2b224(toSign);
|
|
427
|
-
const sigStructureBytes = buildSigStructure({
|
|
428
|
-
context: "Signature1",
|
|
429
|
-
bodyProtectedBytes: protectedHeaderBytes,
|
|
430
|
-
externalAad: EMPTY_BYTES2,
|
|
431
|
-
payload: toSignHashBytes
|
|
432
|
-
});
|
|
433
|
-
return { sigStructureBytes, protectedHeaderBytes, toSignHashBytes };
|
|
434
402
|
}
|
|
435
|
-
function
|
|
436
|
-
if (
|
|
437
|
-
throw new
|
|
438
|
-
|
|
439
|
-
`signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
|
|
440
|
-
);
|
|
441
|
-
}
|
|
442
|
-
if (args.signature.length !== ED25519_SIGNATURE_LENGTH) {
|
|
443
|
-
throw new OffHostSignError(
|
|
444
|
-
"INVALID_SIGNATURE_LENGTH",
|
|
445
|
-
`signature must be 64 bytes (Ed25519 raw signature), got ${args.signature.length}`
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
const { protectedHeader } = encodePath1ProtectedHeader(args.signerPubkey);
|
|
449
|
-
const unprotectedHeader = /* @__PURE__ */ new Map([["hashed", true]]);
|
|
450
|
-
const coseSign1Bytes = encodeCoseSign1({
|
|
451
|
-
protectedHeader,
|
|
452
|
-
unprotectedHeader,
|
|
453
|
-
payload: null,
|
|
454
|
-
signature: args.signature
|
|
455
|
-
});
|
|
456
|
-
const chunks = chunkBytes(coseSign1Bytes);
|
|
457
|
-
const sigEntry = { cose_sign1: chunks };
|
|
458
|
-
return { coseSign1Bytes, sigEntry };
|
|
403
|
+
function getMask(bits) {
|
|
404
|
+
if (!Number.isSafeInteger(bits) || bits < 0 || bits > 32)
|
|
405
|
+
throw new RangeError(`expected bits in [0..32], got ${bits}`);
|
|
406
|
+
return bits === 32 ? 4294967295 : ~(-1 << bits) >>> 0;
|
|
459
407
|
}
|
|
460
408
|
|
|
461
|
-
//
|
|
462
|
-
var
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
function
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
409
|
+
// ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/_crystals.js
|
|
410
|
+
var genCrystals = (opts2) => {
|
|
411
|
+
const { newPoly, N: N2, Q: Q2, F: F2, ROOT_OF_UNITY: ROOT_OF_UNITY2, brvBits} = opts2;
|
|
412
|
+
const mod = (a, modulo = Q2) => {
|
|
413
|
+
const result = a % modulo | 0;
|
|
414
|
+
return (result >= 0 ? result | 0 : modulo + result | 0) | 0;
|
|
415
|
+
};
|
|
416
|
+
const smod = (a, modulo = Q2) => {
|
|
417
|
+
const r = mod(a, modulo) | 0;
|
|
418
|
+
return (r > modulo >> 1 ? r - modulo | 0 : r) | 0;
|
|
419
|
+
};
|
|
420
|
+
function getZettas() {
|
|
421
|
+
const out = newPoly(N2);
|
|
422
|
+
for (let i = 0; i < N2; i++) {
|
|
423
|
+
const b = reverseBits(i, brvBits);
|
|
424
|
+
const p = BigInt(ROOT_OF_UNITY2) ** BigInt(b) % BigInt(Q2);
|
|
425
|
+
out[i] = Number(p) | 0;
|
|
477
426
|
}
|
|
427
|
+
return out;
|
|
478
428
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
429
|
+
const nttZetas = getZettas();
|
|
430
|
+
const field = {
|
|
431
|
+
add: (a, b) => mod((a | 0) + (b | 0)) | 0,
|
|
432
|
+
sub: (a, b) => mod((a | 0) - (b | 0)) | 0,
|
|
433
|
+
mul: (a, b) => mod((a | 0) * (b | 0)) | 0,
|
|
434
|
+
inv: (_a) => {
|
|
435
|
+
throw new Error("not implemented");
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
const nttOpts = {
|
|
439
|
+
N: N2,
|
|
440
|
+
roots: nttZetas,
|
|
441
|
+
invertButterflies: true,
|
|
442
|
+
skipStages: 1 ,
|
|
443
|
+
brp: false
|
|
444
|
+
};
|
|
445
|
+
const dif = FFTCore(field, { dit: false, ...nttOpts });
|
|
446
|
+
const dit = FFTCore(field, { dit: true, ...nttOpts });
|
|
447
|
+
const NTT = {
|
|
448
|
+
encode: (r) => {
|
|
449
|
+
return dif(r);
|
|
450
|
+
},
|
|
451
|
+
decode: (r) => {
|
|
452
|
+
dit(r);
|
|
453
|
+
for (let i = 0; i < r.length; i++)
|
|
454
|
+
r[i] = mod(F2 * r[i]);
|
|
455
|
+
return r;
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
const bitsCoder = (d, c) => {
|
|
459
|
+
const mask = getMask(d);
|
|
460
|
+
const bytesLen = d * (N2 / 8);
|
|
461
|
+
return {
|
|
462
|
+
bytesLen,
|
|
463
|
+
encode: (poly_) => {
|
|
464
|
+
const poly = poly_;
|
|
465
|
+
const r = new Uint8Array(bytesLen);
|
|
466
|
+
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) {
|
|
467
|
+
buf |= (c.encode(poly[i]) & mask) << bufLen;
|
|
468
|
+
bufLen += d;
|
|
469
|
+
for (; bufLen >= 8; bufLen -= 8, buf >>= 8)
|
|
470
|
+
r[pos++] = buf & getMask(bufLen);
|
|
471
|
+
}
|
|
472
|
+
return r;
|
|
473
|
+
},
|
|
474
|
+
decode: (bytes) => {
|
|
475
|
+
const r = newPoly(N2);
|
|
476
|
+
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) {
|
|
477
|
+
buf |= bytes[i] << bufLen;
|
|
478
|
+
bufLen += 8;
|
|
479
|
+
for (; bufLen >= d; bufLen -= d, buf >>= d)
|
|
480
|
+
r[pos++] = c.decode(buf & mask);
|
|
481
|
+
}
|
|
482
|
+
return r;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
};
|
|
486
|
+
return {
|
|
487
|
+
mod,
|
|
488
|
+
smod,
|
|
489
|
+
nttZetas,
|
|
490
|
+
NTT: {
|
|
491
|
+
encode: (r) => NTT.encode(r),
|
|
492
|
+
decode: (r) => NTT.decode(r)
|
|
493
|
+
},
|
|
494
|
+
bitsCoder
|
|
495
|
+
};
|
|
533
496
|
};
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
497
|
+
var createXofShake = (shake) => (seed, blockLen) => {
|
|
498
|
+
if (!blockLen)
|
|
499
|
+
blockLen = shake.blockLen;
|
|
500
|
+
const _seed = new Uint8Array(seed.length + 2);
|
|
501
|
+
_seed.set(seed);
|
|
502
|
+
const seedLen = seed.length;
|
|
503
|
+
const buf = new Uint8Array(blockLen);
|
|
504
|
+
let h = shake.create({});
|
|
505
|
+
let calls = 0;
|
|
506
|
+
let xofs = 0;
|
|
507
|
+
return {
|
|
508
|
+
stats: () => ({ calls, xofs }),
|
|
509
|
+
get: (x, y) => {
|
|
510
|
+
_seed[seedLen + 0] = x;
|
|
511
|
+
_seed[seedLen + 1] = y;
|
|
512
|
+
h.destroy();
|
|
513
|
+
h = shake.create({}).update(_seed);
|
|
514
|
+
calls++;
|
|
515
|
+
return () => {
|
|
516
|
+
xofs++;
|
|
517
|
+
return h.xofInto(buf);
|
|
518
|
+
};
|
|
519
|
+
},
|
|
520
|
+
clean: () => {
|
|
521
|
+
h.destroy();
|
|
522
|
+
cleanBytes(buf, _seed);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
541
525
|
};
|
|
526
|
+
var XOF128 = /* @__PURE__ */ createXofShake(shake128);
|
|
542
527
|
|
|
543
|
-
//
|
|
544
|
-
var
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
528
|
+
// ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/ml-kem.js
|
|
529
|
+
var N = 256;
|
|
530
|
+
var Q = 3329;
|
|
531
|
+
var F = 3303;
|
|
532
|
+
var ROOT_OF_UNITY = 17;
|
|
533
|
+
var crystals = /* @__PURE__ */ genCrystals({
|
|
534
|
+
N,
|
|
535
|
+
Q,
|
|
536
|
+
F,
|
|
537
|
+
ROOT_OF_UNITY,
|
|
538
|
+
newPoly: (n) => new Uint16Array(n),
|
|
539
|
+
brvBits: 7});
|
|
540
|
+
var PARAMS = /* @__PURE__ */ (() => Object.freeze({
|
|
541
|
+
512: Object.freeze({ N, Q, K: 2, ETA1: 3, ETA2: 2, du: 10, dv: 4, RBGstrength: 128 }),
|
|
542
|
+
768: Object.freeze({ N, Q, K: 3, ETA1: 2, ETA2: 2, du: 10, dv: 4, RBGstrength: 192 }),
|
|
543
|
+
1024: Object.freeze({ N, Q, K: 4, ETA1: 2, ETA2: 2, du: 11, dv: 5, RBGstrength: 256 })
|
|
544
|
+
}))();
|
|
545
|
+
var compress = (d) => {
|
|
546
|
+
if (d >= 12)
|
|
547
|
+
return { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i };
|
|
548
|
+
const a = 2 ** (d - 1);
|
|
549
|
+
return {
|
|
550
|
+
// This only matches standalone Compress_d after bitsCoder masks the result into Z_(2^d).
|
|
551
|
+
encode: (i) => ((i << d) + Q / 2) / Q,
|
|
552
|
+
// const decompress = (i: number) => round((Q / 2 ** d) * i);
|
|
553
|
+
decode: (i) => i * Q + a >>> d
|
|
554
|
+
};
|
|
549
555
|
};
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
function
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
} catch {
|
|
558
|
-
return void 0;
|
|
559
|
-
}
|
|
556
|
+
var byteCoder = (d) => crystals.bitsCoder(d, { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i } );
|
|
557
|
+
var polyCoder = (d) => d === 12 ? byteCoder(12) : crystals.bitsCoder(d, compress(d));
|
|
558
|
+
function polyAdd(a_, b_) {
|
|
559
|
+
const a = a_;
|
|
560
|
+
const b = b_;
|
|
561
|
+
for (let i = 0; i < N; i++)
|
|
562
|
+
a[i] = crystals.mod(a[i] + b[i]);
|
|
560
563
|
}
|
|
561
|
-
function
|
|
562
|
-
|
|
564
|
+
function polySub(a_, b_) {
|
|
565
|
+
const a = a_;
|
|
566
|
+
const b = b_;
|
|
567
|
+
for (let i = 0; i < N; i++)
|
|
568
|
+
a[i] = crystals.mod(a[i] - b[i]);
|
|
563
569
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
570
|
+
function BaseCaseMultiply(a0, a1, b0, b1, zeta) {
|
|
571
|
+
const c0 = crystals.mod(a1 * b1 * zeta + a0 * b0);
|
|
572
|
+
const c1 = crystals.mod(a0 * b1 + a1 * b0);
|
|
573
|
+
return { c0, c1 };
|
|
574
|
+
}
|
|
575
|
+
function MultiplyNTTs(f_, g_) {
|
|
576
|
+
const f = f_;
|
|
577
|
+
const g = g_;
|
|
578
|
+
for (let i = 0; i < N / 2; i++) {
|
|
579
|
+
let z3 = crystals.nttZetas[64 + (i >> 1)];
|
|
580
|
+
if (i & 1)
|
|
581
|
+
z3 = -z3;
|
|
582
|
+
const { c0, c1 } = BaseCaseMultiply(f[2 * i + 0], f[2 * i + 1], g[2 * i + 0], g[2 * i + 1], z3);
|
|
583
|
+
f[2 * i + 0] = c0;
|
|
584
|
+
f[2 * i + 1] = c1;
|
|
574
585
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
// src/client/insufficient-scope-error.ts
|
|
578
|
-
function readScopeArray(value) {
|
|
579
|
-
if (!Array.isArray(value)) return [];
|
|
580
|
-
return value.filter((entry) => typeof entry === "string");
|
|
586
|
+
return f;
|
|
581
587
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
588
|
+
function SampleNTT(xof_) {
|
|
589
|
+
const xof = xof_;
|
|
590
|
+
const r = new Uint16Array(N);
|
|
591
|
+
for (let j = 0; j < N; ) {
|
|
592
|
+
const b = xof();
|
|
593
|
+
if (b.length % 3)
|
|
594
|
+
throw new Error("SampleNTT: unaligned block");
|
|
595
|
+
for (let i = 0; j < N && i + 3 <= b.length; i += 3) {
|
|
596
|
+
const d1 = (b[i + 0] >> 0 | b[i + 1] << 8) & 4095;
|
|
597
|
+
const d2 = (b[i + 1] >> 4 | b[i + 2] << 4) & 4095;
|
|
598
|
+
if (d1 < Q)
|
|
599
|
+
r[j++] = d1;
|
|
600
|
+
if (j < N && d2 < Q)
|
|
601
|
+
r[j++] = d2;
|
|
602
|
+
}
|
|
590
603
|
}
|
|
591
|
-
|
|
592
|
-
get requiredScope() {
|
|
593
|
-
return this.requiredScopes[0];
|
|
594
|
-
}
|
|
595
|
-
};
|
|
596
|
-
|
|
597
|
-
// src/client/internal-server-error.ts
|
|
598
|
-
var InternalServerError = class extends Label309HttpError {
|
|
599
|
-
constructor(init) {
|
|
600
|
-
super(init);
|
|
601
|
-
this.name = "InternalServerError";
|
|
602
|
-
}
|
|
603
|
-
};
|
|
604
|
-
|
|
605
|
-
// src/client/invalid-body-error.ts
|
|
606
|
-
var InvalidBodyError = class extends Label309HttpError {
|
|
607
|
-
constructor(init) {
|
|
608
|
-
super(init);
|
|
609
|
-
this.name = "InvalidBodyError";
|
|
610
|
-
}
|
|
611
|
-
};
|
|
612
|
-
|
|
613
|
-
// src/client/malformed-cbor-error.ts
|
|
614
|
-
var MalformedCborError = class extends Label309HttpError {
|
|
615
|
-
constructor(init) {
|
|
616
|
-
super(init);
|
|
617
|
-
this.name = "MalformedCborError";
|
|
618
|
-
}
|
|
619
|
-
};
|
|
620
|
-
|
|
621
|
-
// src/client/not-found-error.ts
|
|
622
|
-
var NotFoundError = class extends Label309HttpError {
|
|
623
|
-
constructor(init) {
|
|
624
|
-
super(init);
|
|
625
|
-
this.name = "NotFoundError";
|
|
626
|
-
}
|
|
627
|
-
};
|
|
628
|
-
|
|
629
|
-
// src/client/quote-already-consumed-error.ts
|
|
630
|
-
function readString2(value) {
|
|
631
|
-
return typeof value === "string" ? value : void 0;
|
|
632
|
-
}
|
|
633
|
-
var QuoteAlreadyConsumedError = class extends Label309HttpError {
|
|
634
|
-
quoteId;
|
|
635
|
-
constructor(init) {
|
|
636
|
-
super(init);
|
|
637
|
-
this.name = "QuoteAlreadyConsumedError";
|
|
638
|
-
this.quoteId = readString2(this.extensions["quote_id"]);
|
|
639
|
-
}
|
|
640
|
-
};
|
|
641
|
-
|
|
642
|
-
// src/client/quote-expired-error.ts
|
|
643
|
-
function readString3(value) {
|
|
644
|
-
return typeof value === "string" ? value : void 0;
|
|
604
|
+
return r;
|
|
645
605
|
}
|
|
646
|
-
var
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
606
|
+
var sampleCBDBytes = (buf, eta) => {
|
|
607
|
+
const r = new Uint16Array(N);
|
|
608
|
+
const b32 = u32(buf);
|
|
609
|
+
swap32IfBE(b32);
|
|
610
|
+
let len = 0;
|
|
611
|
+
for (let i = 0, p = 0, bb = 0, t0 = 0; i < b32.length; i++) {
|
|
612
|
+
let b = b32[i];
|
|
613
|
+
for (let j = 0; j < 32; j++) {
|
|
614
|
+
bb += b & 1;
|
|
615
|
+
b >>= 1;
|
|
616
|
+
len += 1;
|
|
617
|
+
if (len === eta) {
|
|
618
|
+
t0 = bb;
|
|
619
|
+
bb = 0;
|
|
620
|
+
} else if (len === 2 * eta) {
|
|
621
|
+
r[p++] = crystals.mod(t0 - bb);
|
|
622
|
+
bb = 0;
|
|
623
|
+
len = 0;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
652
626
|
}
|
|
627
|
+
swap32IfBE(b32);
|
|
628
|
+
if (len)
|
|
629
|
+
throw new Error(`sampleCBD: leftover bits: ${len}`);
|
|
630
|
+
return r;
|
|
653
631
|
};
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
return typeof value === "string" ? value : void 0;
|
|
632
|
+
function sampleCBD(PRF_, seed, nonce, eta) {
|
|
633
|
+
const PRF = PRF_;
|
|
634
|
+
return sampleCBDBytes(PRF(eta * N / 4, seed, nonce), eta);
|
|
658
635
|
}
|
|
659
|
-
var
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
636
|
+
var genKPKE = (opts_) => {
|
|
637
|
+
const opts2 = opts_;
|
|
638
|
+
const { K, PRF, XOF, HASH512, ETA1, ETA2, du, dv } = opts2;
|
|
639
|
+
const poly1 = polyCoder(1);
|
|
640
|
+
const polyV = polyCoder(dv);
|
|
641
|
+
const polyU = polyCoder(du);
|
|
642
|
+
const publicCoder = splitCoder("publicKey", vecCoder(polyCoder(12), K), 32);
|
|
643
|
+
const secretCoder = vecCoder(polyCoder(12), K);
|
|
644
|
+
const cipherCoder = splitCoder("ciphertext", vecCoder(polyU, K), polyV);
|
|
645
|
+
const seedCoder = splitCoder("seed", 32, 32);
|
|
646
|
+
return {
|
|
647
|
+
secretCoder,
|
|
648
|
+
lengths: {
|
|
649
|
+
secretKey: secretCoder.bytesLen,
|
|
650
|
+
publicKey: publicCoder.bytesLen,
|
|
651
|
+
cipherText: cipherCoder.bytesLen
|
|
652
|
+
},
|
|
653
|
+
keygen: (seed) => {
|
|
654
|
+
abytesDoc(seed, 32, "seed");
|
|
655
|
+
const seedDst = new Uint8Array(33);
|
|
656
|
+
seedDst.set(seed);
|
|
657
|
+
seedDst[32] = K;
|
|
658
|
+
const seedHash = HASH512(seedDst);
|
|
659
|
+
const [rho, sigma] = seedCoder.decode(seedHash);
|
|
660
|
+
const sHat = [];
|
|
661
|
+
const tHat = [];
|
|
662
|
+
for (let i = 0; i < K; i++)
|
|
663
|
+
sHat.push(crystals.NTT.encode(sampleCBD(PRF, sigma, i, ETA1)));
|
|
664
|
+
const x = XOF(rho);
|
|
665
|
+
for (let i = 0; i < K; i++) {
|
|
666
|
+
const e = crystals.NTT.encode(sampleCBD(PRF, sigma, K + i, ETA1));
|
|
667
|
+
for (let j = 0; j < K; j++) {
|
|
668
|
+
const aji = SampleNTT(x.get(j, i));
|
|
669
|
+
polyAdd(e, MultiplyNTTs(aji, sHat[j]));
|
|
670
|
+
}
|
|
671
|
+
tHat.push(e);
|
|
672
|
+
}
|
|
673
|
+
x.clean();
|
|
674
|
+
const res = {
|
|
675
|
+
publicKey: publicCoder.encode([tHat, rho]),
|
|
676
|
+
secretKey: secretCoder.encode(sHat)
|
|
677
|
+
};
|
|
678
|
+
cleanBytes(rho, sigma, sHat, tHat, seedDst, seedHash);
|
|
679
|
+
return res;
|
|
680
|
+
},
|
|
681
|
+
encrypt: (publicKey, msg, seed) => {
|
|
682
|
+
const [tHat, rho] = publicCoder.decode(publicKey);
|
|
683
|
+
const rHat = [];
|
|
684
|
+
for (let i = 0; i < K; i++)
|
|
685
|
+
rHat.push(crystals.NTT.encode(sampleCBD(PRF, seed, i, ETA1)));
|
|
686
|
+
const x = XOF(rho);
|
|
687
|
+
const tmp2 = new Uint16Array(N);
|
|
688
|
+
const u = [];
|
|
689
|
+
for (let i = 0; i < K; i++) {
|
|
690
|
+
const e1 = sampleCBD(PRF, seed, K + i, ETA2);
|
|
691
|
+
const tmp = new Uint16Array(N);
|
|
692
|
+
for (let j = 0; j < K; j++) {
|
|
693
|
+
const aij = SampleNTT(x.get(i, j));
|
|
694
|
+
polyAdd(tmp, MultiplyNTTs(aij, rHat[j]));
|
|
695
|
+
}
|
|
696
|
+
polyAdd(e1, crystals.NTT.decode(tmp));
|
|
697
|
+
u.push(e1);
|
|
698
|
+
polyAdd(tmp2, MultiplyNTTs(tHat[i], rHat[i]));
|
|
699
|
+
cleanBytes(tmp);
|
|
700
|
+
}
|
|
701
|
+
x.clean();
|
|
702
|
+
const e2 = sampleCBD(PRF, seed, 2 * K, ETA2);
|
|
703
|
+
polyAdd(e2, crystals.NTT.decode(tmp2));
|
|
704
|
+
const v = poly1.decode(msg);
|
|
705
|
+
polyAdd(v, e2);
|
|
706
|
+
cleanBytes(tHat, rHat, tmp2, e2);
|
|
707
|
+
return cipherCoder.encode([u, v]);
|
|
708
|
+
},
|
|
709
|
+
decrypt: (cipherText, privateKey) => {
|
|
710
|
+
const [u, v] = cipherCoder.decode(cipherText);
|
|
711
|
+
const sk = secretCoder.decode(privateKey);
|
|
712
|
+
const tmp = new Uint16Array(N);
|
|
713
|
+
for (let i = 0; i < K; i++)
|
|
714
|
+
polyAdd(tmp, MultiplyNTTs(sk[i], crystals.NTT.encode(u[i])));
|
|
715
|
+
polySub(v, crystals.NTT.decode(tmp));
|
|
716
|
+
cleanBytes(tmp, sk, u);
|
|
717
|
+
return poly1.encode(v);
|
|
718
|
+
}
|
|
719
|
+
};
|
|
706
720
|
};
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
721
|
+
function createKyber(opts2) {
|
|
722
|
+
const rawOpts = opts2;
|
|
723
|
+
const KPKE = genKPKE(rawOpts);
|
|
724
|
+
const { HASH256, HASH512, KDF } = rawOpts;
|
|
725
|
+
const { secretCoder: KPKESecretCoder, lengths } = KPKE;
|
|
726
|
+
const secretCoder = splitCoder("secretKey", lengths.secretKey, lengths.publicKey, 32, 32);
|
|
727
|
+
const msgLen = 32;
|
|
728
|
+
const seedLen = 64;
|
|
729
|
+
const kemLengths = Object.freeze({
|
|
730
|
+
...lengths,
|
|
731
|
+
seed: 64,
|
|
732
|
+
msg: msgLen,
|
|
733
|
+
msgRand: msgLen,
|
|
734
|
+
secretKey: secretCoder.bytesLen
|
|
735
|
+
});
|
|
736
|
+
return Object.freeze({
|
|
737
|
+
info: Object.freeze({ type: "ml-kem" }),
|
|
738
|
+
lengths: kemLengths,
|
|
739
|
+
keygen: (seed = randomBytes(seedLen)) => {
|
|
740
|
+
abytesDoc(seed, seedLen, "seed");
|
|
741
|
+
const { publicKey, secretKey: sk } = KPKE.keygen(seed.subarray(0, 32));
|
|
742
|
+
const publicKeyHash = HASH256(publicKey);
|
|
743
|
+
const secretKey = secretCoder.encode([sk, publicKey, publicKeyHash, seed.subarray(32)]);
|
|
744
|
+
cleanBytes(sk, publicKeyHash);
|
|
745
|
+
return {
|
|
746
|
+
publicKey,
|
|
747
|
+
secretKey
|
|
748
|
+
};
|
|
749
|
+
},
|
|
750
|
+
getPublicKey: (secretKey) => {
|
|
751
|
+
const [_sk, publicKey, _publicKeyHash, _z] = secretCoder.decode(secretKey);
|
|
752
|
+
return Uint8Array.from(publicKey);
|
|
753
|
+
},
|
|
754
|
+
encapsulate: (publicKey, msg = randomBytes(msgLen)) => {
|
|
755
|
+
abytesDoc(publicKey, lengths.publicKey, "publicKey");
|
|
756
|
+
abytesDoc(msg, msgLen, "message");
|
|
757
|
+
const eke = publicKey.subarray(0, 384 * opts2.K);
|
|
758
|
+
const ek = KPKESecretCoder.encode(KPKESecretCoder.decode(copyBytes(eke)));
|
|
759
|
+
if (!equalBytes(ek, eke)) {
|
|
760
|
+
cleanBytes(ek);
|
|
761
|
+
throw new Error("ML-KEM.encapsulate: wrong publicKey modulus");
|
|
762
|
+
}
|
|
763
|
+
cleanBytes(ek);
|
|
764
|
+
const kr = HASH512.create().update(msg).update(HASH256(publicKey)).digest();
|
|
765
|
+
const cipherText = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
|
|
766
|
+
cleanBytes(kr.subarray(32));
|
|
767
|
+
return {
|
|
768
|
+
cipherText,
|
|
769
|
+
sharedSecret: kr.subarray(0, 32)
|
|
770
|
+
};
|
|
771
|
+
},
|
|
772
|
+
decapsulate: (cipherText, secretKey) => {
|
|
773
|
+
abytesDoc(secretKey, secretCoder.bytesLen, "secretKey");
|
|
774
|
+
abytesDoc(cipherText, lengths.cipherText, "cipherText");
|
|
775
|
+
const k768 = secretCoder.bytesLen - 96;
|
|
776
|
+
const start = k768 + 32;
|
|
777
|
+
const test = HASH256(secretKey.subarray(k768 / 2, start));
|
|
778
|
+
if (!equalBytes(test, secretKey.subarray(start, start + 32)))
|
|
779
|
+
throw new Error("invalid secretKey: hash check failed");
|
|
780
|
+
const [sk, publicKey, publicKeyHash, z3] = secretCoder.decode(secretKey);
|
|
781
|
+
const msg = KPKE.decrypt(cipherText, sk);
|
|
782
|
+
const kr = HASH512.create().update(msg).update(publicKeyHash).digest();
|
|
783
|
+
const Khat = kr.subarray(0, 32);
|
|
784
|
+
const cipherText2 = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
|
|
785
|
+
const isValid = equalBytes(cipherText, cipherText2);
|
|
786
|
+
const Kbar = KDF.create({ dkLen: 32 }).update(z3).update(cipherText).digest();
|
|
787
|
+
cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar);
|
|
788
|
+
return isValid ? Khat : Kbar;
|
|
789
|
+
}
|
|
790
|
+
});
|
|
711
791
|
}
|
|
712
|
-
function
|
|
713
|
-
return
|
|
792
|
+
function shakePRF(dkLen, key, nonce) {
|
|
793
|
+
return shake256.create({ dkLen }).update(key).update(new Uint8Array([nonce])).digest();
|
|
714
794
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
795
|
+
var opts = /* @__PURE__ */ (() => ({
|
|
796
|
+
HASH256: sha3_256,
|
|
797
|
+
HASH512: sha3_512,
|
|
798
|
+
KDF: shake256,
|
|
799
|
+
XOF: XOF128,
|
|
800
|
+
PRF: shakePRF
|
|
801
|
+
}))();
|
|
802
|
+
var mk = (params) => createKyber({
|
|
803
|
+
...opts,
|
|
804
|
+
...params
|
|
805
|
+
});
|
|
806
|
+
var ml_kem768 = /* @__PURE__ */ (() => mk(PARAMS[768]))();
|
|
807
|
+
|
|
808
|
+
// ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/hybrid.js
|
|
809
|
+
function ecKeygen(curve, allowZeroKey = false) {
|
|
810
|
+
const lengths = curve.lengths;
|
|
811
|
+
let keygen = curve.keygen;
|
|
812
|
+
if (allowZeroKey) {
|
|
813
|
+
if (!("getSharedSecret" in curve && "sign" in curve && "verify" in curve))
|
|
814
|
+
throw new Error("allowZeroKey requires a Weierstrass curve");
|
|
815
|
+
const wCurve = curve;
|
|
816
|
+
const Fn = wCurve.Point.Fn;
|
|
817
|
+
keygen = (seed = randomBytes(lengths.seed)) => {
|
|
818
|
+
abytes(seed, lengths.seed, "seed");
|
|
819
|
+
const seedScalar = Fn.isLE ? bytesToNumberLE(seed) : bytesToNumberBE(seed);
|
|
820
|
+
const secretKey = Fn.toBytes(Fn.create(seedScalar));
|
|
821
|
+
return {
|
|
822
|
+
secretKey,
|
|
823
|
+
publicKey: curve.getPublicKey(secretKey)
|
|
824
|
+
};
|
|
825
|
+
};
|
|
726
826
|
}
|
|
727
|
-
return out;
|
|
728
|
-
}
|
|
729
|
-
function synthesiseProblem(httpStatus, requestId) {
|
|
730
|
-
const code = `http-${httpStatus}`;
|
|
731
827
|
return {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
detail: `Server returned HTTP ${httpStatus} without a problem+json body.`,
|
|
736
|
-
code,
|
|
737
|
-
trace_id: requestId ?? ""
|
|
738
|
-
};
|
|
739
|
-
}
|
|
740
|
-
function toProblemDetails(httpStatus, body, requestId) {
|
|
741
|
-
if (body === null || typeof body !== "object") {
|
|
742
|
-
return synthesiseProblem(httpStatus, requestId);
|
|
743
|
-
}
|
|
744
|
-
const b = body;
|
|
745
|
-
const code = asString(b["code"]);
|
|
746
|
-
const status = asNumber(b["status"]) ?? httpStatus;
|
|
747
|
-
const title = asString(b["title"]);
|
|
748
|
-
if (code === void 0 && title === void 0) {
|
|
749
|
-
return synthesiseProblem(httpStatus, requestId);
|
|
750
|
-
}
|
|
751
|
-
const errors = asProblemErrorEntries(b["errors"]);
|
|
752
|
-
const base = {
|
|
753
|
-
...b,
|
|
754
|
-
// RFC 7807 §4.2: `about:blank` is the default when no type URI is supplied.
|
|
755
|
-
// The client is gateway-agnostic, so it must not invent a vendor-specific
|
|
756
|
-
// problem-type namespace; the machine-readable discriminator is `code`.
|
|
757
|
-
type: asString(b["type"]) ?? "about:blank",
|
|
758
|
-
title: title ?? `HTTP ${status}`,
|
|
759
|
-
status,
|
|
760
|
-
detail: asString(b["detail"]) ?? "",
|
|
761
|
-
code: code ?? `http-${status}`,
|
|
762
|
-
trace_id: asString(b["trace_id"]) ?? requestId ?? ""
|
|
828
|
+
lengths: { secretKey: lengths.secretKey, publicKey: lengths.publicKey, seed: lengths.seed },
|
|
829
|
+
keygen: (seed) => keygen(seed),
|
|
830
|
+
getPublicKey: (secretKey) => curve.getPublicKey(secretKey)
|
|
763
831
|
};
|
|
764
|
-
if (errors !== void 0) base["errors"] = errors;
|
|
765
|
-
return base;
|
|
766
832
|
}
|
|
767
|
-
function
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
return
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
case "record-not-found":
|
|
795
|
-
return new RecordNotFoundError(init);
|
|
796
|
-
case "idempotency-key-conflict":
|
|
797
|
-
return new IdempotencyConflictError(init);
|
|
798
|
-
case "rate-limited":
|
|
799
|
-
return new RateLimitedError(init);
|
|
800
|
-
case "validation-failed":
|
|
801
|
-
return new ValidationFailedError(init);
|
|
802
|
-
case "invalid-body":
|
|
803
|
-
return new InvalidBodyError(init);
|
|
804
|
-
case "malformed-cbor":
|
|
805
|
-
return new MalformedCborError(init);
|
|
806
|
-
case "batch-too-large":
|
|
807
|
-
return new BatchTooLargeError(init);
|
|
808
|
-
case "batch-empty":
|
|
809
|
-
return new BatchEmptyError(init);
|
|
810
|
-
case "internal-error":
|
|
811
|
-
return new InternalServerError(init);
|
|
812
|
-
// A gateway that prices on a live FX oracle may surface a transient
|
|
813
|
-
// `fx-stale` pricing outage; to a vendor-neutral client that is just a
|
|
814
|
-
// temporary inability to serve, i.e. a service-unavailable condition.
|
|
815
|
-
case "service-unavailable":
|
|
816
|
-
case "fx-stale":
|
|
817
|
-
return new ServiceUnavailableError(init);
|
|
818
|
-
default:
|
|
819
|
-
return new Label309HttpError(init);
|
|
820
|
-
}
|
|
833
|
+
function ecdhKem(curve, allowZeroKey = false) {
|
|
834
|
+
const kg = ecKeygen(curve, allowZeroKey);
|
|
835
|
+
if (!curve.getSharedSecret)
|
|
836
|
+
throw new Error("wrong curve");
|
|
837
|
+
return {
|
|
838
|
+
lengths: { ...kg.lengths, msg: kg.lengths.seed, cipherText: kg.lengths.publicKey },
|
|
839
|
+
keygen: kg.keygen,
|
|
840
|
+
getPublicKey: kg.getPublicKey,
|
|
841
|
+
encapsulate(publicKey, rand = randomBytes(curve.lengths.seed)) {
|
|
842
|
+
const seed = copyBytes(rand);
|
|
843
|
+
let ek = void 0;
|
|
844
|
+
try {
|
|
845
|
+
ek = this.keygen(seed).secretKey;
|
|
846
|
+
const sharedSecret = this.decapsulate(publicKey, ek);
|
|
847
|
+
const cipherText = curve.getPublicKey(ek);
|
|
848
|
+
return { sharedSecret, cipherText };
|
|
849
|
+
} finally {
|
|
850
|
+
cleanBytes(seed);
|
|
851
|
+
if (ek)
|
|
852
|
+
cleanBytes(ek);
|
|
853
|
+
}
|
|
854
|
+
},
|
|
855
|
+
decapsulate(cipherText, secretKey) {
|
|
856
|
+
const res = curve.getSharedSecret(secretKey, cipherText);
|
|
857
|
+
return curve.lengths.publicKeyHasPrefix ? res.subarray(1) : res;
|
|
858
|
+
}
|
|
859
|
+
};
|
|
821
860
|
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
return JSON.parse(text);
|
|
829
|
-
} catch {
|
|
830
|
-
return null;
|
|
831
|
-
}
|
|
861
|
+
function splitLengths(lst, name) {
|
|
862
|
+
return splitCoder(name, ...lst.map((i) => {
|
|
863
|
+
if (typeof i.lengths[name] !== "number")
|
|
864
|
+
throw new Error("wrong length: " + name);
|
|
865
|
+
return i.lengths[name];
|
|
866
|
+
}));
|
|
832
867
|
}
|
|
833
|
-
function
|
|
834
|
-
|
|
835
|
-
const parsed = Number(header);
|
|
836
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
868
|
+
function expandSeedXof(xof) {
|
|
869
|
+
return ((seed, seedLen) => xof(seed, { dkLen: seedLen }));
|
|
837
870
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
const
|
|
841
|
-
const
|
|
842
|
-
const
|
|
843
|
-
|
|
871
|
+
function combineKeys(realSeedLen, expandSeed_, ...ck_) {
|
|
872
|
+
const expandSeed = expandSeed_;
|
|
873
|
+
const ck = ck_;
|
|
874
|
+
const seedCoder = splitLengths(ck, "seed");
|
|
875
|
+
const pkCoder = splitLengths(ck, "publicKey");
|
|
876
|
+
anumber(realSeedLen);
|
|
877
|
+
function expandDecapsulationKey(seed) {
|
|
878
|
+
abytes(seed, realSeedLen);
|
|
879
|
+
const expandedRaw = expandSeed(seed, seedCoder.bytesLen);
|
|
880
|
+
const expandedSeed = expandedRaw.buffer === seed.buffer ? copyBytes(expandedRaw) : expandedRaw;
|
|
881
|
+
const expanded = [];
|
|
882
|
+
const keySecret = [];
|
|
883
|
+
const secretKey = [];
|
|
884
|
+
const publicKey = [];
|
|
885
|
+
let ok = false;
|
|
886
|
+
try {
|
|
887
|
+
for (const part of seedCoder.decode(expandedSeed))
|
|
888
|
+
expanded.push(copyBytes(part));
|
|
889
|
+
for (let i = 0; i < ck.length; i++) {
|
|
890
|
+
const keys = ck[i].keygen(expanded[i]);
|
|
891
|
+
keySecret.push(keys.secretKey);
|
|
892
|
+
secretKey.push(copyBytes(keys.secretKey));
|
|
893
|
+
publicKey.push(keys.publicKey);
|
|
894
|
+
}
|
|
895
|
+
ok = true;
|
|
896
|
+
return { secretKey, publicKey };
|
|
897
|
+
} finally {
|
|
898
|
+
cleanBytes(expandedSeed, expanded, keySecret);
|
|
899
|
+
if (!ok)
|
|
900
|
+
cleanBytes(secretKey);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return {
|
|
904
|
+
info: { lengths: { seed: realSeedLen, publicKey: pkCoder.bytesLen, secretKey: realSeedLen } },
|
|
905
|
+
getPublicKey(secretKey) {
|
|
906
|
+
return this.keygen(secretKey).publicKey;
|
|
907
|
+
},
|
|
908
|
+
keygen(seed = randomBytes(realSeedLen)) {
|
|
909
|
+
const { publicKey: pk, secretKey } = expandDecapsulationKey(seed);
|
|
910
|
+
try {
|
|
911
|
+
const publicKey = pkCoder.encode(pk);
|
|
912
|
+
return { secretKey: seed, publicKey };
|
|
913
|
+
} finally {
|
|
914
|
+
cleanBytes(pk);
|
|
915
|
+
cleanBytes(secretKey);
|
|
916
|
+
}
|
|
917
|
+
},
|
|
918
|
+
expandDecapsulationKey,
|
|
919
|
+
realSeedLen
|
|
920
|
+
};
|
|
844
921
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
const
|
|
849
|
-
|
|
850
|
-
|
|
922
|
+
function combineKEMS(realSeedLen, realMsgLen, expandSeed, combiner, ...kems) {
|
|
923
|
+
const rawCombiner = combiner;
|
|
924
|
+
const rawKems = kems;
|
|
925
|
+
const keys = combineKeys(realSeedLen, expandSeed, ...rawKems);
|
|
926
|
+
const ctCoder = splitLengths(rawKems, "cipherText");
|
|
927
|
+
const pkCoder = splitLengths(rawKems, "publicKey");
|
|
928
|
+
const msgCoder = splitLengths(rawKems, "msg");
|
|
929
|
+
anumber(realMsgLen);
|
|
930
|
+
const lengths = Object.freeze({
|
|
931
|
+
...keys.info.lengths,
|
|
932
|
+
msg: realMsgLen,
|
|
933
|
+
msgRand: msgCoder.bytesLen,
|
|
934
|
+
cipherText: ctCoder.bytesLen
|
|
935
|
+
});
|
|
936
|
+
return Object.freeze({
|
|
937
|
+
lengths,
|
|
938
|
+
getPublicKey: keys.getPublicKey,
|
|
939
|
+
keygen: keys.keygen,
|
|
940
|
+
encapsulate(pk, randomness = randomBytes(msgCoder.bytesLen)) {
|
|
941
|
+
const pks = pkCoder.decode(pk);
|
|
942
|
+
const rand = msgCoder.decode(randomness);
|
|
943
|
+
const sharedSecret = [];
|
|
944
|
+
const cipherText = [];
|
|
945
|
+
try {
|
|
946
|
+
for (let i = 0; i < rawKems.length; i++) {
|
|
947
|
+
const enc = rawKems[i].encapsulate(pks[i], rand[i]);
|
|
948
|
+
sharedSecret.push(enc.sharedSecret);
|
|
949
|
+
cipherText.push(enc.cipherText);
|
|
950
|
+
}
|
|
951
|
+
return {
|
|
952
|
+
// Detach the combiner result before cleanup: a caller-provided combiner may alias one of
|
|
953
|
+
// the child sharedSecret buffers, and those child buffers are zeroized immediately below.
|
|
954
|
+
sharedSecret: copyBytes(rawCombiner(pks, cipherText, sharedSecret)),
|
|
955
|
+
cipherText: ctCoder.encode(cipherText)
|
|
956
|
+
};
|
|
957
|
+
} finally {
|
|
958
|
+
cleanBytes(sharedSecret, cipherText);
|
|
959
|
+
}
|
|
960
|
+
},
|
|
961
|
+
decapsulate(ct, seed) {
|
|
962
|
+
const cts = ctCoder.decode(ct);
|
|
963
|
+
const { publicKey, secretKey } = keys.expandDecapsulationKey(seed);
|
|
964
|
+
const sharedSecret = rawKems.map((i, j) => i.decapsulate(cts[j], secretKey[j]));
|
|
965
|
+
try {
|
|
966
|
+
return copyBytes(rawCombiner(publicKey, cts, sharedSecret));
|
|
967
|
+
} finally {
|
|
968
|
+
cleanBytes(secretKey, sharedSecret);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
851
971
|
});
|
|
852
|
-
if (apiKey !== void 0) headers.set("authorization", `Bearer ${apiKey}`);
|
|
853
|
-
return headers;
|
|
854
972
|
}
|
|
855
|
-
var
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
973
|
+
var x25519kem = /* @__PURE__ */ ecdhKem(x25519);
|
|
974
|
+
var ml_kem768_x25519 = /* @__PURE__ */ (() => combineKEMS(
|
|
975
|
+
32,
|
|
976
|
+
32,
|
|
977
|
+
expandSeedXof(shake256),
|
|
978
|
+
// Awesome label, so much escaping hell in a single line.
|
|
979
|
+
(pk, ct, ss) => sha3_256(concatBytes(ss[0], ss[1], ct[1], pk[1], asciiToBytes("\\.//^\\"))),
|
|
980
|
+
ml_kem768,
|
|
981
|
+
x25519kem
|
|
982
|
+
))();
|
|
983
|
+
var XWing = /* @__PURE__ */ (() => ml_kem768_x25519)();
|
|
984
|
+
function chacha20Poly1305Encrypt(opts2) {
|
|
985
|
+
return chacha20poly1305(opts2.key, opts2.nonce, opts2.aad).encrypt(opts2.plaintext);
|
|
986
|
+
}
|
|
987
|
+
function xchacha20Poly1305Encrypt(opts2) {
|
|
988
|
+
return xchacha20poly1305(opts2.key, opts2.nonce, opts2.aad).encrypt(opts2.plaintext);
|
|
989
|
+
}
|
|
990
|
+
function hkdfSha256(opts2) {
|
|
991
|
+
return hkdf(sha256$1, opts2.ikm, opts2.salt, opts2.info, opts2.length);
|
|
992
|
+
}
|
|
993
|
+
var MLKEM768X25519_PUBLIC_KEY_LENGTH = 1216;
|
|
994
|
+
var MLKEM768X25519_ENC_LENGTH = 1120;
|
|
995
|
+
var MLKEM768X25519_ESEED_LENGTH = 64;
|
|
996
|
+
function mlkem768x25519Encapsulate(opts2) {
|
|
997
|
+
if (opts2.publicKey.length !== MLKEM768X25519_PUBLIC_KEY_LENGTH) {
|
|
998
|
+
throw new Error(
|
|
999
|
+
`mlkem768x25519 public key must be ${MLKEM768X25519_PUBLIC_KEY_LENGTH} bytes, got ${opts2.publicKey.length}`
|
|
1000
|
+
);
|
|
859
1001
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
* (USD micro-cents as a decimal string). The string is preserved verbatim —
|
|
865
|
-
* never parsed into a number — so no precision is lost. An account with no
|
|
866
|
-
* ledger activity yet reads `"0"`.
|
|
867
|
-
*
|
|
868
|
-
* Requires authentication: 401 (UnauthorizedError) when anonymous, 403
|
|
869
|
-
* (InsufficientScopeError) when the Bearer key lacks the `account:read`
|
|
870
|
-
* scope.
|
|
871
|
-
*/
|
|
872
|
-
async balance() {
|
|
873
|
-
const response = await this.config.fetch(`${this.config.baseUrl}/api/v1/account/balance`, {
|
|
874
|
-
method: "GET",
|
|
875
|
-
headers: buildHeaders(this.config.apiKey)
|
|
876
|
-
});
|
|
877
|
-
await throwIfNotOk(response);
|
|
878
|
-
const body = await readJson(response);
|
|
879
|
-
return { balanceUsdMicros: body.balance_usd_micros };
|
|
1002
|
+
if (opts2.eseed !== void 0 && opts2.eseed.length !== MLKEM768X25519_ESEED_LENGTH) {
|
|
1003
|
+
throw new Error(
|
|
1004
|
+
`mlkem768x25519 eseed must be ${MLKEM768X25519_ESEED_LENGTH} bytes, got ${opts2.eseed.length}`
|
|
1005
|
+
);
|
|
880
1006
|
}
|
|
881
|
-
};
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
var
|
|
885
|
-
code = "
|
|
886
|
-
constructor(
|
|
887
|
-
super(
|
|
888
|
-
this.name = "
|
|
1007
|
+
const { cipherText, sharedSecret } = XWing.encapsulate(opts2.publicKey, opts2.eseed);
|
|
1008
|
+
return { enc: cipherText, ss: sharedSecret };
|
|
1009
|
+
}
|
|
1010
|
+
var X25519LowOrderPointError = class extends Error {
|
|
1011
|
+
code = "X25519_LOW_ORDER_POINT";
|
|
1012
|
+
constructor(options) {
|
|
1013
|
+
super("x25519 ECDH rejected: peer public key is a small-order point", options);
|
|
1014
|
+
this.name = "X25519LowOrderPointError";
|
|
889
1015
|
}
|
|
890
1016
|
};
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
1017
|
+
var NOBLE_LOW_ORDER_MESSAGE = "invalid private or public key received";
|
|
1018
|
+
function x25519PublicKey(opts2) {
|
|
1019
|
+
return x25519.getPublicKey(opts2.secretKey);
|
|
895
1020
|
}
|
|
896
|
-
function
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1021
|
+
function x25519Ecdh(opts2) {
|
|
1022
|
+
try {
|
|
1023
|
+
return x25519.getSharedSecret(opts2.secretKey, opts2.theirPublicKey);
|
|
1024
|
+
} catch (e) {
|
|
1025
|
+
if (e instanceof Error && e.message === NOBLE_LOW_ORDER_MESSAGE) {
|
|
1026
|
+
throw new X25519LowOrderPointError({ cause: e });
|
|
1027
|
+
}
|
|
1028
|
+
throw e;
|
|
1029
|
+
}
|
|
903
1030
|
}
|
|
904
|
-
var
|
|
905
|
-
var TREE_ALG_RFC9162 = "rfc9162-sha256";
|
|
906
|
-
var DIGEST_LENGTH2 = 32;
|
|
907
|
-
var MerkleLeavesListError = class extends Error {
|
|
1031
|
+
var EciesSealedPoeError = class extends Error {
|
|
908
1032
|
code;
|
|
909
|
-
constructor(code, message) {
|
|
910
|
-
super(message
|
|
1033
|
+
constructor(code, message, options) {
|
|
1034
|
+
super(message, options);
|
|
1035
|
+
this.name = "EciesSealedPoeError";
|
|
911
1036
|
this.code = code;
|
|
912
|
-
this.name = "MerkleLeavesListError";
|
|
913
1037
|
}
|
|
914
1038
|
};
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
`root must be a Uint8Array(${DIGEST_LENGTH2})`
|
|
920
|
-
);
|
|
921
|
-
}
|
|
922
|
-
if (args.leaves.length < 1) {
|
|
923
|
-
throw new MerkleLeavesListError(
|
|
924
|
-
"SCHEMA_MERKLE_LEAVES_MALFORMED",
|
|
925
|
-
"leaves array must be non-empty"
|
|
926
|
-
);
|
|
1039
|
+
var CHUNK_MAX_BYTES = 64;
|
|
1040
|
+
function chunkKemCt(value) {
|
|
1041
|
+
if (value.length === 0) {
|
|
1042
|
+
throw new Error("chunkKemCt: refusing to chunk an empty byte string");
|
|
927
1043
|
}
|
|
928
|
-
const
|
|
929
|
-
for (let i = 0; i <
|
|
930
|
-
|
|
931
|
-
if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH2) {
|
|
932
|
-
throw new MerkleLeavesListError(
|
|
933
|
-
"SCHEMA_MERKLE_LEAVES_MALFORMED",
|
|
934
|
-
`leaves[${i}] must be a Uint8Array(${DIGEST_LENGTH2})`
|
|
935
|
-
);
|
|
936
|
-
}
|
|
937
|
-
leavesCopy.push(leaf);
|
|
1044
|
+
const chunks = [];
|
|
1045
|
+
for (let i = 0; i < value.length; i += CHUNK_MAX_BYTES) {
|
|
1046
|
+
chunks.push(value.subarray(i, Math.min(i + CHUNK_MAX_BYTES, value.length)));
|
|
938
1047
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1048
|
+
return chunks;
|
|
1049
|
+
}
|
|
1050
|
+
function joinKemCt(chunks) {
|
|
1051
|
+
let total = 0;
|
|
1052
|
+
for (const c of chunks) total += c.length;
|
|
1053
|
+
const out = new Uint8Array(total);
|
|
1054
|
+
let offset = 0;
|
|
1055
|
+
for (const c of chunks) {
|
|
1056
|
+
out.set(c, offset);
|
|
1057
|
+
offset += c.length;
|
|
944
1058
|
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
leaf_count: leavesCopy.length
|
|
951
|
-
};
|
|
952
|
-
if (args.leafAlg !== void 0) {
|
|
953
|
-
map["leaf_alg"] = args.leafAlg;
|
|
1059
|
+
return out;
|
|
1060
|
+
}
|
|
1061
|
+
function canonicalizeSlots(slots, kem) {
|
|
1062
|
+
if (kem === "x25519") {
|
|
1063
|
+
return slots.map((s) => ({ epk: s.epk, wrap: s.wrap }));
|
|
954
1064
|
}
|
|
955
|
-
return
|
|
1065
|
+
return slots.map((s) => ({
|
|
1066
|
+
kem_ct: chunkKemCt(joinKemCt(s.kem_ct)),
|
|
1067
|
+
wrap: s.wrap
|
|
1068
|
+
}));
|
|
956
1069
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
diff |= a[i] ^ b[i];
|
|
965
|
-
return diff === 0;
|
|
1070
|
+
function encodeCanonicalCbor3(value) {
|
|
1071
|
+
return encode(value, {
|
|
1072
|
+
cde: true,
|
|
1073
|
+
collapseBigInts: true,
|
|
1074
|
+
rejectDuplicateKeys: true,
|
|
1075
|
+
sortKeys: sortCoreDeterministic
|
|
1076
|
+
});
|
|
966
1077
|
}
|
|
967
|
-
|
|
968
|
-
|
|
1078
|
+
var CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX = new TextEncoder().encode(
|
|
1079
|
+
"cardano-poe-slots-transcript-v1"
|
|
1080
|
+
);
|
|
1081
|
+
var CARDANO_POE_HKDF_INFO_PAYLOAD = new TextEncoder().encode(
|
|
1082
|
+
"cardano-poe-payload-v1"
|
|
1083
|
+
);
|
|
1084
|
+
var CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE = new TextEncoder().encode(
|
|
1085
|
+
"cardano-poe-payload-passphrase-v1"
|
|
1086
|
+
);
|
|
1087
|
+
var CARDANO_POE_XWING_KEK_SALT_PREFIX = new TextEncoder().encode(
|
|
1088
|
+
"cardano-poe-xwing-kek-salt-v1"
|
|
1089
|
+
);
|
|
1090
|
+
if (CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length !== 31) {
|
|
1091
|
+
throw new Error(
|
|
1092
|
+
"CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX byte-length invariant violated (expected 31)"
|
|
1093
|
+
);
|
|
969
1094
|
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0);
|
|
973
|
-
return {
|
|
974
|
-
bytesLen,
|
|
975
|
-
encode: (bufs) => {
|
|
976
|
-
const res = new Uint8Array(bytesLen);
|
|
977
|
-
for (let i = 0, pos = 0; i < lengths.length; i++) {
|
|
978
|
-
const c = lengths[i];
|
|
979
|
-
const l = getLength(c);
|
|
980
|
-
const b = typeof c === "number" ? bufs[i] : c.encode(bufs[i]);
|
|
981
|
-
abytes(b, l, label);
|
|
982
|
-
res.set(b, pos);
|
|
983
|
-
if (typeof c !== "number")
|
|
984
|
-
b.fill(0);
|
|
985
|
-
pos += l;
|
|
986
|
-
}
|
|
987
|
-
return res;
|
|
988
|
-
},
|
|
989
|
-
decode: (buf) => {
|
|
990
|
-
abytes(buf, bytesLen, label);
|
|
991
|
-
const res = [];
|
|
992
|
-
for (const c of lengths) {
|
|
993
|
-
const l = getLength(c);
|
|
994
|
-
const b = buf.subarray(0, l);
|
|
995
|
-
res.push(typeof c === "number" ? b : c.decode(b));
|
|
996
|
-
buf = buf.subarray(l);
|
|
997
|
-
}
|
|
998
|
-
return res;
|
|
999
|
-
}
|
|
1000
|
-
};
|
|
1095
|
+
if (CARDANO_POE_HKDF_INFO_PAYLOAD.length !== 22) {
|
|
1096
|
+
throw new Error("CARDANO_POE_HKDF_INFO_PAYLOAD byte-length invariant violated (expected 22)");
|
|
1001
1097
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
bytesLen,
|
|
1007
|
-
encode: (u) => {
|
|
1008
|
-
if (u.length !== vecLen)
|
|
1009
|
-
throw new RangeError(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`);
|
|
1010
|
-
const res = new Uint8Array(bytesLen);
|
|
1011
|
-
for (let i = 0, pos = 0; i < u.length; i++) {
|
|
1012
|
-
const b = coder.encode(u[i]);
|
|
1013
|
-
res.set(b, pos);
|
|
1014
|
-
b.fill(0);
|
|
1015
|
-
pos += b.length;
|
|
1016
|
-
}
|
|
1017
|
-
return res;
|
|
1018
|
-
},
|
|
1019
|
-
decode: (a) => {
|
|
1020
|
-
abytes(a, bytesLen);
|
|
1021
|
-
const r = [];
|
|
1022
|
-
for (let i = 0; i < a.length; i += coder.bytesLen)
|
|
1023
|
-
r.push(coder.decode(a.subarray(i, i + coder.bytesLen)));
|
|
1024
|
-
return r;
|
|
1025
|
-
}
|
|
1026
|
-
};
|
|
1098
|
+
if (CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE.length !== 33) {
|
|
1099
|
+
throw new Error(
|
|
1100
|
+
"CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE byte-length invariant violated (expected 33)"
|
|
1101
|
+
);
|
|
1027
1102
|
}
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
if (Array.isArray(t))
|
|
1031
|
-
for (const b of t)
|
|
1032
|
-
b.fill(0);
|
|
1033
|
-
else
|
|
1034
|
-
t.fill(0);
|
|
1035
|
-
}
|
|
1103
|
+
if (CARDANO_POE_XWING_KEK_SALT_PREFIX.length !== 29) {
|
|
1104
|
+
throw new Error("CARDANO_POE_XWING_KEK_SALT_PREFIX byte-length invariant violated (expected 29)");
|
|
1036
1105
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1106
|
+
var MAX_SEALED_PLAINTEXT = 274877906880;
|
|
1107
|
+
function assertPlaintextWithinBound(plaintextLength) {
|
|
1108
|
+
if (plaintextLength >= MAX_SEALED_PLAINTEXT) {
|
|
1109
|
+
throw new SealedPayloadTooLargeError(
|
|
1110
|
+
`plaintext length ${plaintextLength} is at or above the maximum sealed payload size ${MAX_SEALED_PLAINTEXT}`
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1041
1113
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
const mod = (a, modulo = Q2) => {
|
|
1047
|
-
const result = a % modulo | 0;
|
|
1048
|
-
return (result >= 0 ? result | 0 : modulo + result | 0) | 0;
|
|
1049
|
-
};
|
|
1050
|
-
const smod = (a, modulo = Q2) => {
|
|
1051
|
-
const r = mod(a, modulo) | 0;
|
|
1052
|
-
return (r > modulo >> 1 ? r - modulo | 0 : r) | 0;
|
|
1053
|
-
};
|
|
1054
|
-
function getZettas() {
|
|
1055
|
-
const out = newPoly(N2);
|
|
1056
|
-
for (let i = 0; i < N2; i++) {
|
|
1057
|
-
const b = reverseBits(i, brvBits);
|
|
1058
|
-
const p = BigInt(ROOT_OF_UNITY2) ** BigInt(b) % BigInt(Q2);
|
|
1059
|
-
out[i] = Number(p) | 0;
|
|
1060
|
-
}
|
|
1061
|
-
return out;
|
|
1114
|
+
var SealedPayloadTooLargeError = class extends Error {
|
|
1115
|
+
constructor(message) {
|
|
1116
|
+
super(message);
|
|
1117
|
+
this.name = "SealedPayloadTooLargeError";
|
|
1062
1118
|
}
|
|
1063
|
-
const nttZetas = getZettas();
|
|
1064
|
-
const field = {
|
|
1065
|
-
add: (a, b) => mod((a | 0) + (b | 0)) | 0,
|
|
1066
|
-
sub: (a, b) => mod((a | 0) - (b | 0)) | 0,
|
|
1067
|
-
mul: (a, b) => mod((a | 0) * (b | 0)) | 0,
|
|
1068
|
-
inv: (_a) => {
|
|
1069
|
-
throw new Error("not implemented");
|
|
1070
|
-
}
|
|
1071
|
-
};
|
|
1072
|
-
const nttOpts = {
|
|
1073
|
-
N: N2,
|
|
1074
|
-
roots: nttZetas,
|
|
1075
|
-
invertButterflies: true,
|
|
1076
|
-
skipStages: 1 ,
|
|
1077
|
-
brp: false
|
|
1078
|
-
};
|
|
1079
|
-
const dif = FFTCore(field, { dit: false, ...nttOpts });
|
|
1080
|
-
const dit = FFTCore(field, { dit: true, ...nttOpts });
|
|
1081
|
-
const NTT = {
|
|
1082
|
-
encode: (r) => {
|
|
1083
|
-
return dif(r);
|
|
1084
|
-
},
|
|
1085
|
-
decode: (r) => {
|
|
1086
|
-
dit(r);
|
|
1087
|
-
for (let i = 0; i < r.length; i++)
|
|
1088
|
-
r[i] = mod(F2 * r[i]);
|
|
1089
|
-
return r;
|
|
1090
|
-
}
|
|
1091
|
-
};
|
|
1092
|
-
const bitsCoder = (d, c) => {
|
|
1093
|
-
const mask = getMask(d);
|
|
1094
|
-
const bytesLen = d * (N2 / 8);
|
|
1095
|
-
return {
|
|
1096
|
-
bytesLen,
|
|
1097
|
-
encode: (poly_) => {
|
|
1098
|
-
const poly = poly_;
|
|
1099
|
-
const r = new Uint8Array(bytesLen);
|
|
1100
|
-
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) {
|
|
1101
|
-
buf |= (c.encode(poly[i]) & mask) << bufLen;
|
|
1102
|
-
bufLen += d;
|
|
1103
|
-
for (; bufLen >= 8; bufLen -= 8, buf >>= 8)
|
|
1104
|
-
r[pos++] = buf & getMask(bufLen);
|
|
1105
|
-
}
|
|
1106
|
-
return r;
|
|
1107
|
-
},
|
|
1108
|
-
decode: (bytes) => {
|
|
1109
|
-
const r = newPoly(N2);
|
|
1110
|
-
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) {
|
|
1111
|
-
buf |= bytes[i] << bufLen;
|
|
1112
|
-
bufLen += 8;
|
|
1113
|
-
for (; bufLen >= d; bufLen -= d, buf >>= d)
|
|
1114
|
-
r[pos++] = c.decode(buf & mask);
|
|
1115
|
-
}
|
|
1116
|
-
return r;
|
|
1117
|
-
}
|
|
1118
|
-
};
|
|
1119
|
-
};
|
|
1120
|
-
return {
|
|
1121
|
-
mod,
|
|
1122
|
-
smod,
|
|
1123
|
-
nttZetas,
|
|
1124
|
-
NTT: {
|
|
1125
|
-
encode: (r) => NTT.encode(r),
|
|
1126
|
-
decode: (r) => NTT.decode(r)
|
|
1127
|
-
},
|
|
1128
|
-
bitsCoder
|
|
1129
|
-
};
|
|
1130
1119
|
};
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
let calls = 0;
|
|
1140
|
-
let xofs = 0;
|
|
1141
|
-
return {
|
|
1142
|
-
stats: () => ({ calls, xofs }),
|
|
1143
|
-
get: (x, y) => {
|
|
1144
|
-
_seed[seedLen + 0] = x;
|
|
1145
|
-
_seed[seedLen + 1] = y;
|
|
1146
|
-
h.destroy();
|
|
1147
|
-
h = shake.create({}).update(_seed);
|
|
1148
|
-
calls++;
|
|
1149
|
-
return () => {
|
|
1150
|
-
xofs++;
|
|
1151
|
-
return h.xofInto(buf);
|
|
1152
|
-
};
|
|
1153
|
-
},
|
|
1154
|
-
clean: () => {
|
|
1155
|
-
h.destroy();
|
|
1156
|
-
cleanBytes(buf, _seed);
|
|
1157
|
-
}
|
|
1120
|
+
function computeSlotsHash(args) {
|
|
1121
|
+
const transcript = {
|
|
1122
|
+
scheme: 1,
|
|
1123
|
+
path: "slots",
|
|
1124
|
+
aead: "xchacha20-poly1305",
|
|
1125
|
+
kem: args.kem,
|
|
1126
|
+
nonce: args.nonce,
|
|
1127
|
+
slots: canonicalizeSlots(args.slots, args.kem)
|
|
1158
1128
|
};
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
var PARAMS = /* @__PURE__ */ (() => Object.freeze({
|
|
1175
|
-
512: Object.freeze({ N, Q, K: 2, ETA1: 3, ETA2: 2, du: 10, dv: 4, RBGstrength: 128 }),
|
|
1176
|
-
768: Object.freeze({ N, Q, K: 3, ETA1: 2, ETA2: 2, du: 10, dv: 4, RBGstrength: 192 }),
|
|
1177
|
-
1024: Object.freeze({ N, Q, K: 4, ETA1: 2, ETA2: 2, du: 11, dv: 5, RBGstrength: 256 })
|
|
1178
|
-
}))();
|
|
1179
|
-
var compress = (d) => {
|
|
1180
|
-
if (d >= 12)
|
|
1181
|
-
return { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i };
|
|
1182
|
-
const a = 2 ** (d - 1);
|
|
1183
|
-
return {
|
|
1184
|
-
// This only matches standalone Compress_d after bitsCoder masks the result into Z_(2^d).
|
|
1185
|
-
encode: (i) => ((i << d) + Q / 2) / Q,
|
|
1186
|
-
// const decompress = (i: number) => round((Q / 2 ** d) * i);
|
|
1187
|
-
decode: (i) => i * Q + a >>> d
|
|
1129
|
+
const encoded = encodeCanonicalCbor3(transcript);
|
|
1130
|
+
const message = new Uint8Array(CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length + encoded.length);
|
|
1131
|
+
message.set(CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX, 0);
|
|
1132
|
+
message.set(encoded, CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length);
|
|
1133
|
+
return sha256$1(message);
|
|
1134
|
+
}
|
|
1135
|
+
function adContentSlots(args) {
|
|
1136
|
+
const ad = {
|
|
1137
|
+
scheme: 1,
|
|
1138
|
+
path: "slots",
|
|
1139
|
+
aead: "xchacha20-poly1305",
|
|
1140
|
+
kem: args.kem,
|
|
1141
|
+
nonce: args.nonce,
|
|
1142
|
+
slots_hash: args.slotsHash,
|
|
1143
|
+
slots_mac: args.slotsMac
|
|
1188
1144
|
};
|
|
1189
|
-
|
|
1190
|
-
var byteCoder = (d) => crystals.bitsCoder(d, { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i } );
|
|
1191
|
-
var polyCoder = (d) => d === 12 ? byteCoder(12) : crystals.bitsCoder(d, compress(d));
|
|
1192
|
-
function polyAdd(a_, b_) {
|
|
1193
|
-
const a = a_;
|
|
1194
|
-
const b = b_;
|
|
1195
|
-
for (let i = 0; i < N; i++)
|
|
1196
|
-
a[i] = crystals.mod(a[i] + b[i]);
|
|
1145
|
+
return encodeCanonicalCbor3(ad);
|
|
1197
1146
|
}
|
|
1198
|
-
function
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1147
|
+
function slotsPayloadKey(args) {
|
|
1148
|
+
return hkdfSha256({
|
|
1149
|
+
ikm: args.cek,
|
|
1150
|
+
salt: args.nonce,
|
|
1151
|
+
info: CARDANO_POE_HKDF_INFO_PAYLOAD,
|
|
1152
|
+
length: 32
|
|
1153
|
+
});
|
|
1203
1154
|
}
|
|
1204
|
-
function
|
|
1205
|
-
const
|
|
1206
|
-
|
|
1207
|
-
|
|
1155
|
+
function xwingKekSalt(args) {
|
|
1156
|
+
const message = new Uint8Array(
|
|
1157
|
+
CARDANO_POE_XWING_KEK_SALT_PREFIX.length + args.kemCt.length + args.pubR.length
|
|
1158
|
+
);
|
|
1159
|
+
let offset = 0;
|
|
1160
|
+
message.set(CARDANO_POE_XWING_KEK_SALT_PREFIX, offset);
|
|
1161
|
+
offset += CARDANO_POE_XWING_KEK_SALT_PREFIX.length;
|
|
1162
|
+
message.set(args.kemCt, offset);
|
|
1163
|
+
offset += args.kemCt.length;
|
|
1164
|
+
message.set(args.pubR, offset);
|
|
1165
|
+
return sha256$1(message);
|
|
1208
1166
|
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1167
|
+
var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
|
|
1168
|
+
var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
|
|
1169
|
+
"cardano-poe-kek-mlkem768x25519-v1"
|
|
1170
|
+
);
|
|
1171
|
+
var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
|
|
1172
|
+
"cardano-poe-slots-mac-v1"
|
|
1173
|
+
);
|
|
1174
|
+
var ZERO_NONCE_12 = new Uint8Array(12);
|
|
1175
|
+
var EMPTY_SALT = new Uint8Array(0);
|
|
1176
|
+
var X25519_PUBLIC_KEY_LENGTH = 32;
|
|
1177
|
+
var X25519_SECRET_KEY_LENGTH = 32;
|
|
1178
|
+
var CEK_LENGTH = 32;
|
|
1179
|
+
var NONCE_LENGTH = 24;
|
|
1180
|
+
var WRAP_LENGTH = 48;
|
|
1181
|
+
var SLOTS_MAC_LENGTH = 32;
|
|
1182
|
+
if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
|
|
1183
|
+
throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
|
|
1184
|
+
}
|
|
1185
|
+
if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
|
|
1186
|
+
throw new Error(
|
|
1187
|
+
"CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
|
|
1191
|
+
throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
|
|
1192
|
+
}
|
|
1193
|
+
if (ZERO_NONCE_12.length !== 12) {
|
|
1194
|
+
throw new Error("ZERO_NONCE_12 byte-length invariant violated (expected 12)");
|
|
1195
|
+
}
|
|
1196
|
+
function concat(a, b) {
|
|
1197
|
+
const out = new Uint8Array(a.length + b.length);
|
|
1198
|
+
out.set(a, 0);
|
|
1199
|
+
out.set(b, a.length);
|
|
1200
|
+
return out;
|
|
1201
|
+
}
|
|
1202
|
+
function uniformIndexBelow(m) {
|
|
1203
|
+
const limit = 4294967296 - 4294967296 % m;
|
|
1204
|
+
const buf = new Uint32Array(1);
|
|
1205
|
+
let x;
|
|
1206
|
+
do {
|
|
1207
|
+
crypto.getRandomValues(buf);
|
|
1208
|
+
x = buf[0];
|
|
1209
|
+
} while (x >= limit);
|
|
1210
|
+
return x % m;
|
|
1211
|
+
}
|
|
1212
|
+
function csprngShuffle(arr) {
|
|
1213
|
+
for (let i = arr.length - 1; i > 0; i--) {
|
|
1214
|
+
const j = uniformIndexBelow(i + 1);
|
|
1215
|
+
const tmp = arr[i];
|
|
1216
|
+
arr[i] = arr[j];
|
|
1217
|
+
arr[j] = tmp;
|
|
1219
1218
|
}
|
|
1220
|
-
return f;
|
|
1221
1219
|
}
|
|
1222
|
-
function
|
|
1223
|
-
const
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
for (let i = 0; j < N && i + 3 <= b.length; i += 3) {
|
|
1230
|
-
const d1 = (b[i + 0] >> 0 | b[i + 1] << 8) & 4095;
|
|
1231
|
-
const d2 = (b[i + 1] >> 4 | b[i + 2] << 4) & 4095;
|
|
1232
|
-
if (d1 < Q)
|
|
1233
|
-
r[j++] = d1;
|
|
1234
|
-
if (j < N && d2 < Q)
|
|
1235
|
-
r[j++] = d2;
|
|
1236
|
-
}
|
|
1220
|
+
function wrapSlotX25519(args) {
|
|
1221
|
+
const privEph = args.privEph ?? randomBytes$1(X25519_SECRET_KEY_LENGTH);
|
|
1222
|
+
if (privEph.length !== X25519_SECRET_KEY_LENGTH) {
|
|
1223
|
+
throw new EciesSealedPoeError(
|
|
1224
|
+
"INVALID_EPHEMERAL_SECRET_LENGTH",
|
|
1225
|
+
`ephemeralSecrets[${args.slotIdx}] MUST be exactly ${X25519_SECRET_KEY_LENGTH} bytes, got ${privEph.length}`
|
|
1226
|
+
);
|
|
1237
1227
|
}
|
|
1238
|
-
|
|
1228
|
+
const epk = x25519PublicKey({ secretKey: privEph });
|
|
1229
|
+
const shared = x25519Ecdh({ secretKey: privEph, theirPublicKey: args.pubR });
|
|
1230
|
+
const kek = hkdfSha256({
|
|
1231
|
+
ikm: shared,
|
|
1232
|
+
salt: concat(epk, args.pubR),
|
|
1233
|
+
info: CARDANO_POE_HKDF_INFO_KEK,
|
|
1234
|
+
length: 32
|
|
1235
|
+
});
|
|
1236
|
+
const wrap = chacha20Poly1305Encrypt({
|
|
1237
|
+
key: kek,
|
|
1238
|
+
nonce: ZERO_NONCE_12,
|
|
1239
|
+
aad: CARDANO_POE_HKDF_INFO_KEK,
|
|
1240
|
+
plaintext: args.cek
|
|
1241
|
+
});
|
|
1242
|
+
if (wrap.length !== WRAP_LENGTH) {
|
|
1243
|
+
throw new Error(`internal: wrap.length=${wrap.length}, expected ${WRAP_LENGTH}`);
|
|
1244
|
+
}
|
|
1245
|
+
return { epk, wrap };
|
|
1239
1246
|
}
|
|
1240
|
-
|
|
1241
|
-
const
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
for (let j = 0; j < 32; j++) {
|
|
1248
|
-
bb += b & 1;
|
|
1249
|
-
b >>= 1;
|
|
1250
|
-
len += 1;
|
|
1251
|
-
if (len === eta) {
|
|
1252
|
-
t0 = bb;
|
|
1253
|
-
bb = 0;
|
|
1254
|
-
} else if (len === 2 * eta) {
|
|
1255
|
-
r[p++] = crystals.mod(t0 - bb);
|
|
1256
|
-
bb = 0;
|
|
1257
|
-
len = 0;
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1247
|
+
function wrapSlotMlkem768X25519(args) {
|
|
1248
|
+
const { enc, ss } = mlkem768x25519Encapsulate({
|
|
1249
|
+
publicKey: args.pubR,
|
|
1250
|
+
...args.eseed !== void 0 ? { eseed: args.eseed } : {}
|
|
1251
|
+
});
|
|
1252
|
+
if (enc.length !== MLKEM768X25519_ENC_LENGTH) {
|
|
1253
|
+
throw new Error(`internal: enc.length=${enc.length}, expected ${MLKEM768X25519_ENC_LENGTH}`);
|
|
1260
1254
|
}
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
const
|
|
1268
|
-
|
|
1255
|
+
const kek = hkdfSha256({
|
|
1256
|
+
ikm: ss,
|
|
1257
|
+
salt: xwingKekSalt({ kemCt: enc, pubR: args.pubR }),
|
|
1258
|
+
info: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
|
|
1259
|
+
length: 32
|
|
1260
|
+
});
|
|
1261
|
+
const wrap = chacha20Poly1305Encrypt({
|
|
1262
|
+
key: kek,
|
|
1263
|
+
nonce: ZERO_NONCE_12,
|
|
1264
|
+
aad: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
|
|
1265
|
+
plaintext: args.cek
|
|
1266
|
+
});
|
|
1267
|
+
if (wrap.length !== WRAP_LENGTH) {
|
|
1268
|
+
throw new Error(`internal: wrap.length=${wrap.length}, expected ${WRAP_LENGTH}`);
|
|
1269
|
+
}
|
|
1270
|
+
return { kem_ct: chunkKemCt(enc), wrap };
|
|
1269
1271
|
}
|
|
1270
|
-
|
|
1271
|
-
const
|
|
1272
|
-
const
|
|
1273
|
-
const
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1272
|
+
function eciesSealedPoeWrap(args) {
|
|
1273
|
+
const { plaintext, recipientPublicKeys } = args;
|
|
1274
|
+
const kem = args.kem ?? "x25519";
|
|
1275
|
+
const n = recipientPublicKeys.length;
|
|
1276
|
+
assertPlaintextWithinBound(plaintext.length);
|
|
1277
|
+
if (n < 1) {
|
|
1278
|
+
throw new EciesSealedPoeError(
|
|
1279
|
+
"ENC_SLOTS_EMPTY",
|
|
1280
|
+
`recipientPublicKeys.length=${n} must be >= 1`
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
const expectedPubLen = kem === "x25519" ? X25519_PUBLIC_KEY_LENGTH : MLKEM768X25519_PUBLIC_KEY_LENGTH;
|
|
1284
|
+
for (let i = 0; i < n; i++) {
|
|
1285
|
+
const pub = recipientPublicKeys[i];
|
|
1286
|
+
if (pub === void 0 || pub.length !== expectedPubLen) {
|
|
1287
|
+
throw new EciesSealedPoeError(
|
|
1288
|
+
"KEM_EPK_LENGTH_MISMATCH",
|
|
1289
|
+
`recipientPublicKeys[${i}] MUST be exactly ${expectedPubLen} bytes for kem='${kem}'`
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
if (kem === "x25519") {
|
|
1294
|
+
if (args.eseeds !== void 0) {
|
|
1295
|
+
throw new EciesSealedPoeError(
|
|
1296
|
+
"EPHEMERAL_SECRETS_COUNT_MISMATCH",
|
|
1297
|
+
"eseeds is an X-Wing (mlkem768x25519) override and MUST NOT be supplied for kem='x25519'"
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
if (args.ephemeralSecrets !== void 0 && args.ephemeralSecrets.length !== n) {
|
|
1301
|
+
throw new EciesSealedPoeError(
|
|
1302
|
+
"EPHEMERAL_SECRETS_COUNT_MISMATCH",
|
|
1303
|
+
`ephemeralSecrets.length=${args.ephemeralSecrets.length} must match recipientPublicKeys.length=${n}`
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
} else {
|
|
1307
|
+
if (args.ephemeralSecrets !== void 0) {
|
|
1308
|
+
throw new EciesSealedPoeError(
|
|
1309
|
+
"EPHEMERAL_SECRETS_COUNT_MISMATCH",
|
|
1310
|
+
"ephemeralSecrets is an X25519 override and MUST NOT be supplied for kem='mlkem768x25519'"
|
|
1311
|
+
);
|
|
1312
|
+
}
|
|
1313
|
+
if (args.eseeds !== void 0) {
|
|
1314
|
+
if (args.eseeds.length !== n) {
|
|
1315
|
+
throw new EciesSealedPoeError(
|
|
1316
|
+
"EPHEMERAL_SECRETS_COUNT_MISMATCH",
|
|
1317
|
+
`eseeds.length=${args.eseeds.length} must match recipientPublicKeys.length=${n}`
|
|
1318
|
+
);
|
|
1306
1319
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
},
|
|
1315
|
-
encrypt: (publicKey, msg, seed) => {
|
|
1316
|
-
const [tHat, rho] = publicCoder.decode(publicKey);
|
|
1317
|
-
const rHat = [];
|
|
1318
|
-
for (let i = 0; i < K; i++)
|
|
1319
|
-
rHat.push(crystals.NTT.encode(sampleCBD(PRF, seed, i, ETA1)));
|
|
1320
|
-
const x = XOF(rho);
|
|
1321
|
-
const tmp2 = new Uint16Array(N);
|
|
1322
|
-
const u = [];
|
|
1323
|
-
for (let i = 0; i < K; i++) {
|
|
1324
|
-
const e1 = sampleCBD(PRF, seed, K + i, ETA2);
|
|
1325
|
-
const tmp = new Uint16Array(N);
|
|
1326
|
-
for (let j = 0; j < K; j++) {
|
|
1327
|
-
const aij = SampleNTT(x.get(i, j));
|
|
1328
|
-
polyAdd(tmp, MultiplyNTTs(aij, rHat[j]));
|
|
1320
|
+
for (let i = 0; i < n; i++) {
|
|
1321
|
+
const eseed = args.eseeds[i];
|
|
1322
|
+
if (eseed.length !== MLKEM768X25519_ESEED_LENGTH) {
|
|
1323
|
+
throw new EciesSealedPoeError(
|
|
1324
|
+
"INVALID_EPHEMERAL_SECRET_LENGTH",
|
|
1325
|
+
`eseeds[${i}] MUST be exactly ${MLKEM768X25519_ESEED_LENGTH} bytes, got ${eseed.length}`
|
|
1326
|
+
);
|
|
1329
1327
|
}
|
|
1330
|
-
polyAdd(e1, crystals.NTT.decode(tmp));
|
|
1331
|
-
u.push(e1);
|
|
1332
|
-
polyAdd(tmp2, MultiplyNTTs(tHat[i], rHat[i]));
|
|
1333
|
-
cleanBytes(tmp);
|
|
1334
1328
|
}
|
|
1335
|
-
x.clean();
|
|
1336
|
-
const e2 = sampleCBD(PRF, seed, 2 * K, ETA2);
|
|
1337
|
-
polyAdd(e2, crystals.NTT.decode(tmp2));
|
|
1338
|
-
const v = poly1.decode(msg);
|
|
1339
|
-
polyAdd(v, e2);
|
|
1340
|
-
cleanBytes(tHat, rHat, tmp2, e2);
|
|
1341
|
-
return cipherCoder.encode([u, v]);
|
|
1342
|
-
},
|
|
1343
|
-
decrypt: (cipherText, privateKey) => {
|
|
1344
|
-
const [u, v] = cipherCoder.decode(cipherText);
|
|
1345
|
-
const sk = secretCoder.decode(privateKey);
|
|
1346
|
-
const tmp = new Uint16Array(N);
|
|
1347
|
-
for (let i = 0; i < K; i++)
|
|
1348
|
-
polyAdd(tmp, MultiplyNTTs(sk[i], crystals.NTT.encode(u[i])));
|
|
1349
|
-
polySub(v, crystals.NTT.decode(tmp));
|
|
1350
|
-
cleanBytes(tmp, sk, u);
|
|
1351
|
-
return poly1.encode(v);
|
|
1352
1329
|
}
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
abytesDoc(secretKey, secretCoder.bytesLen, "secretKey");
|
|
1408
|
-
abytesDoc(cipherText, lengths.cipherText, "cipherText");
|
|
1409
|
-
const k768 = secretCoder.bytesLen - 96;
|
|
1410
|
-
const start = k768 + 32;
|
|
1411
|
-
const test = HASH256(secretKey.subarray(k768 / 2, start));
|
|
1412
|
-
if (!equalBytes(test, secretKey.subarray(start, start + 32)))
|
|
1413
|
-
throw new Error("invalid secretKey: hash check failed");
|
|
1414
|
-
const [sk, publicKey, publicKeyHash, z3] = secretCoder.decode(secretKey);
|
|
1415
|
-
const msg = KPKE.decrypt(cipherText, sk);
|
|
1416
|
-
const kr = HASH512.create().update(msg).update(publicKeyHash).digest();
|
|
1417
|
-
const Khat = kr.subarray(0, 32);
|
|
1418
|
-
const cipherText2 = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
|
|
1419
|
-
const isValid = equalBytes(cipherText, cipherText2);
|
|
1420
|
-
const Kbar = KDF.create({ dkLen: 32 }).update(z3).update(cipherText).digest();
|
|
1421
|
-
cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar);
|
|
1422
|
-
return isValid ? Khat : Kbar;
|
|
1330
|
+
}
|
|
1331
|
+
const cek = args.cek ?? randomBytes$1(CEK_LENGTH);
|
|
1332
|
+
const nonce = args.nonce ?? randomBytes$1(NONCE_LENGTH);
|
|
1333
|
+
if (cek.length !== CEK_LENGTH) {
|
|
1334
|
+
throw new EciesSealedPoeError(
|
|
1335
|
+
"INVALID_CEK_LENGTH",
|
|
1336
|
+
`cek MUST be exactly ${CEK_LENGTH} bytes, got ${cek.length}`
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
if (nonce.length !== NONCE_LENGTH) {
|
|
1340
|
+
throw new EciesSealedPoeError(
|
|
1341
|
+
"NONCE_LENGTH_MISMATCH",
|
|
1342
|
+
`nonce MUST be exactly ${NONCE_LENGTH} bytes, got ${nonce.length}`
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
let envelope;
|
|
1346
|
+
let slotsHash;
|
|
1347
|
+
if (kem === "x25519") {
|
|
1348
|
+
const slots = [];
|
|
1349
|
+
for (let i = 0; i < n; i++) {
|
|
1350
|
+
slots.push(
|
|
1351
|
+
wrapSlotX25519({
|
|
1352
|
+
pubR: recipientPublicKeys[i],
|
|
1353
|
+
privEph: args.ephemeralSecrets ? args.ephemeralSecrets[i] : void 0,
|
|
1354
|
+
cek,
|
|
1355
|
+
slotIdx: i
|
|
1356
|
+
})
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
if (args.skipShuffle !== true) {
|
|
1360
|
+
csprngShuffle(slots);
|
|
1361
|
+
}
|
|
1362
|
+
slotsHash = computeSlotsHash({ kem: "x25519", nonce, slots });
|
|
1363
|
+
envelope = {
|
|
1364
|
+
scheme: 1,
|
|
1365
|
+
aead: "xchacha20-poly1305",
|
|
1366
|
+
kem: "x25519",
|
|
1367
|
+
nonce,
|
|
1368
|
+
slots,
|
|
1369
|
+
slots_mac: computeSlotsMac(cek, slotsHash)
|
|
1370
|
+
};
|
|
1371
|
+
} else {
|
|
1372
|
+
const slots = [];
|
|
1373
|
+
for (let i = 0; i < n; i++) {
|
|
1374
|
+
slots.push(
|
|
1375
|
+
wrapSlotMlkem768X25519({
|
|
1376
|
+
pubR: recipientPublicKeys[i],
|
|
1377
|
+
eseed: args.eseeds ? args.eseeds[i] : void 0,
|
|
1378
|
+
cek
|
|
1379
|
+
})
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
if (args.skipShuffle !== true) {
|
|
1383
|
+
csprngShuffle(slots);
|
|
1423
1384
|
}
|
|
1385
|
+
slotsHash = computeSlotsHash({ kem: "mlkem768x25519", nonce, slots });
|
|
1386
|
+
envelope = {
|
|
1387
|
+
scheme: 1,
|
|
1388
|
+
aead: "xchacha20-poly1305",
|
|
1389
|
+
kem: "mlkem768x25519",
|
|
1390
|
+
nonce,
|
|
1391
|
+
slots,
|
|
1392
|
+
slots_mac: computeSlotsMac(cek, slotsHash)
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
const payloadKey = slotsPayloadKey({ cek, nonce });
|
|
1396
|
+
const adContent = adContentSlots({
|
|
1397
|
+
kem: envelope.kem,
|
|
1398
|
+
nonce,
|
|
1399
|
+
slotsHash,
|
|
1400
|
+
slotsMac: envelope.slots_mac
|
|
1424
1401
|
});
|
|
1402
|
+
const ciphertext = xchacha20Poly1305Encrypt({
|
|
1403
|
+
key: payloadKey,
|
|
1404
|
+
nonce,
|
|
1405
|
+
aad: adContent,
|
|
1406
|
+
plaintext
|
|
1407
|
+
});
|
|
1408
|
+
return { envelope, ciphertext };
|
|
1425
1409
|
}
|
|
1426
|
-
function
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
})
|
|
1436
|
-
var mk = (params) => createKyber({
|
|
1437
|
-
...opts,
|
|
1438
|
-
...params
|
|
1439
|
-
});
|
|
1440
|
-
var ml_kem768 = /* @__PURE__ */ (() => mk(PARAMS[768]))();
|
|
1441
|
-
|
|
1442
|
-
// ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/hybrid.js
|
|
1443
|
-
function ecKeygen(curve, allowZeroKey = false) {
|
|
1444
|
-
const lengths = curve.lengths;
|
|
1445
|
-
let keygen = curve.keygen;
|
|
1446
|
-
if (allowZeroKey) {
|
|
1447
|
-
if (!("getSharedSecret" in curve && "sign" in curve && "verify" in curve))
|
|
1448
|
-
throw new Error("allowZeroKey requires a Weierstrass curve");
|
|
1449
|
-
const wCurve = curve;
|
|
1450
|
-
const Fn = wCurve.Point.Fn;
|
|
1451
|
-
keygen = (seed = randomBytes(lengths.seed)) => {
|
|
1452
|
-
abytes(seed, lengths.seed, "seed");
|
|
1453
|
-
const seedScalar = Fn.isLE ? bytesToNumberLE(seed) : bytesToNumberBE(seed);
|
|
1454
|
-
const secretKey = Fn.toBytes(Fn.create(seedScalar));
|
|
1455
|
-
return {
|
|
1456
|
-
secretKey,
|
|
1457
|
-
publicKey: curve.getPublicKey(secretKey)
|
|
1458
|
-
};
|
|
1459
|
-
};
|
|
1410
|
+
function computeSlotsMac(cek, slotsHash) {
|
|
1411
|
+
const hmacKey = hkdfSha256({
|
|
1412
|
+
ikm: cek,
|
|
1413
|
+
salt: EMPTY_SALT,
|
|
1414
|
+
info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
|
|
1415
|
+
length: 32
|
|
1416
|
+
});
|
|
1417
|
+
const slotsMac = hmac(sha256$1, hmacKey, slotsHash);
|
|
1418
|
+
if (slotsMac.length !== SLOTS_MAC_LENGTH) {
|
|
1419
|
+
throw new Error(`internal: slots_mac.length=${slotsMac.length}, expected ${SLOTS_MAC_LENGTH}`);
|
|
1460
1420
|
}
|
|
1461
|
-
return
|
|
1462
|
-
lengths: { secretKey: lengths.secretKey, publicKey: lengths.publicKey, seed: lengths.seed },
|
|
1463
|
-
keygen: (seed) => keygen(seed),
|
|
1464
|
-
getPublicKey: (secretKey) => curve.getPublicKey(secretKey)
|
|
1465
|
-
};
|
|
1421
|
+
return slotsMac;
|
|
1466
1422
|
}
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
try {
|
|
1479
|
-
ek = this.keygen(seed).secretKey;
|
|
1480
|
-
const sharedSecret = this.decapsulate(publicKey, ek);
|
|
1481
|
-
const cipherText = curve.getPublicKey(ek);
|
|
1482
|
-
return { sharedSecret, cipherText };
|
|
1483
|
-
} finally {
|
|
1484
|
-
cleanBytes(seed);
|
|
1485
|
-
if (ek)
|
|
1486
|
-
cleanBytes(ek);
|
|
1487
|
-
}
|
|
1488
|
-
},
|
|
1489
|
-
decapsulate(cipherText, secretKey) {
|
|
1490
|
-
const res = curve.getSharedSecret(secretKey, cipherText);
|
|
1491
|
-
return curve.lengths.publicKeyHasPrefix ? res.subarray(1) : res;
|
|
1492
|
-
}
|
|
1493
|
-
};
|
|
1423
|
+
|
|
1424
|
+
// ../poe-standard/src/chunked.ts
|
|
1425
|
+
var CHUNK_MAX_BYTES2 = 64;
|
|
1426
|
+
var UTF8_ENCODER2 = new TextEncoder();
|
|
1427
|
+
function chunkBytes(value) {
|
|
1428
|
+
if (value.length === 0) return [new Uint8Array(0)];
|
|
1429
|
+
const chunks = [];
|
|
1430
|
+
for (let i = 0; i < value.length; i += CHUNK_MAX_BYTES2) {
|
|
1431
|
+
chunks.push(value.subarray(i, Math.min(i + CHUNK_MAX_BYTES2, value.length)));
|
|
1432
|
+
}
|
|
1433
|
+
return chunks;
|
|
1494
1434
|
}
|
|
1495
|
-
function
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1435
|
+
function chunkUri(uri) {
|
|
1436
|
+
const bytes = UTF8_ENCODER2.encode(uri);
|
|
1437
|
+
if (bytes.length === 0) return [""];
|
|
1438
|
+
if (bytes.length <= CHUNK_MAX_BYTES2) return [uri];
|
|
1439
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
1440
|
+
const chunks = [];
|
|
1441
|
+
let cursor = 0;
|
|
1442
|
+
while (cursor < bytes.length) {
|
|
1443
|
+
let end = Math.min(cursor + CHUNK_MAX_BYTES2, bytes.length);
|
|
1444
|
+
while (end < bytes.length && (bytes[end] & 192) === 128) end--;
|
|
1445
|
+
chunks.push(decoder.decode(bytes.subarray(cursor, end)));
|
|
1446
|
+
cursor = end;
|
|
1447
|
+
}
|
|
1448
|
+
return chunks;
|
|
1501
1449
|
}
|
|
1502
|
-
|
|
1503
|
-
|
|
1450
|
+
|
|
1451
|
+
// src/client/off-host-sign.ts
|
|
1452
|
+
var EMPTY_BYTES2 = new Uint8Array(0);
|
|
1453
|
+
var ED25519_PUBLIC_KEY_LENGTH = 32;
|
|
1454
|
+
var ED25519_SIGNATURE_LENGTH = 64;
|
|
1455
|
+
var OffHostSignError = class extends Error {
|
|
1456
|
+
code;
|
|
1457
|
+
constructor(code, message) {
|
|
1458
|
+
super(message);
|
|
1459
|
+
this.name = "OffHostSignError";
|
|
1460
|
+
this.code = code;
|
|
1461
|
+
}
|
|
1462
|
+
};
|
|
1463
|
+
function buildToSign(record) {
|
|
1464
|
+
const body = encodeRecordBodyForSigning(record);
|
|
1465
|
+
const out = new Uint8Array(CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES.length + body.length);
|
|
1466
|
+
out.set(CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES, 0);
|
|
1467
|
+
out.set(body, CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES.length);
|
|
1468
|
+
return out;
|
|
1504
1469
|
}
|
|
1505
|
-
function
|
|
1506
|
-
const
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
let ok = false;
|
|
1520
|
-
try {
|
|
1521
|
-
for (const part of seedCoder.decode(expandedSeed))
|
|
1522
|
-
expanded.push(copyBytes(part));
|
|
1523
|
-
for (let i = 0; i < ck.length; i++) {
|
|
1524
|
-
const keys = ck[i].keygen(expanded[i]);
|
|
1525
|
-
keySecret.push(keys.secretKey);
|
|
1526
|
-
secretKey.push(copyBytes(keys.secretKey));
|
|
1527
|
-
publicKey.push(keys.publicKey);
|
|
1528
|
-
}
|
|
1529
|
-
ok = true;
|
|
1530
|
-
return { secretKey, publicKey };
|
|
1531
|
-
} finally {
|
|
1532
|
-
cleanBytes(expandedSeed, expanded, keySecret);
|
|
1533
|
-
if (!ok)
|
|
1534
|
-
cleanBytes(secretKey);
|
|
1535
|
-
}
|
|
1470
|
+
function encodePath1ProtectedHeader(signerPubkey) {
|
|
1471
|
+
const protectedHeader = /* @__PURE__ */ new Map([
|
|
1472
|
+
[1, -8],
|
|
1473
|
+
[4, signerPubkey]
|
|
1474
|
+
]);
|
|
1475
|
+
const protectedHeaderBytes = encodeCanonicalCbor(protectedHeader);
|
|
1476
|
+
return { protectedHeader, protectedHeaderBytes };
|
|
1477
|
+
}
|
|
1478
|
+
function prepareSigStructure(args) {
|
|
1479
|
+
if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
|
|
1480
|
+
throw new OffHostSignError(
|
|
1481
|
+
"INVALID_PUBKEY_LENGTH",
|
|
1482
|
+
`signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
|
|
1483
|
+
);
|
|
1536
1484
|
}
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
try {
|
|
1545
|
-
const publicKey = pkCoder.encode(pk);
|
|
1546
|
-
return { secretKey: seed, publicKey };
|
|
1547
|
-
} finally {
|
|
1548
|
-
cleanBytes(pk);
|
|
1549
|
-
cleanBytes(secretKey);
|
|
1550
|
-
}
|
|
1551
|
-
},
|
|
1552
|
-
expandDecapsulationKey,
|
|
1553
|
-
realSeedLen
|
|
1554
|
-
};
|
|
1485
|
+
const { protectedHeaderBytes } = encodePath1ProtectedHeader(args.signerPubkey);
|
|
1486
|
+
const recordBodyCbor = encodeRecordBodyForSigning(args.record);
|
|
1487
|
+
const sigStructureBytes = buildLabel309SigStructure({
|
|
1488
|
+
bodyProtectedBytes: protectedHeaderBytes,
|
|
1489
|
+
recordBodyCbor
|
|
1490
|
+
});
|
|
1491
|
+
return { sigStructureBytes, protectedHeaderBytes };
|
|
1555
1492
|
}
|
|
1556
|
-
function
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1493
|
+
function assembleCoseSign1(args) {
|
|
1494
|
+
if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
|
|
1495
|
+
throw new OffHostSignError(
|
|
1496
|
+
"INVALID_PUBKEY_LENGTH",
|
|
1497
|
+
`signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
|
|
1498
|
+
);
|
|
1499
|
+
}
|
|
1500
|
+
if (args.signature.length !== ED25519_SIGNATURE_LENGTH) {
|
|
1501
|
+
throw new OffHostSignError(
|
|
1502
|
+
"INVALID_SIGNATURE_LENGTH",
|
|
1503
|
+
`signature must be 64 bytes (Ed25519 raw signature), got ${args.signature.length}`
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
const { protectedHeader } = encodePath1ProtectedHeader(args.signerPubkey);
|
|
1507
|
+
const coseSign1Bytes = encodeCoseSign1({
|
|
1508
|
+
protectedHeader,
|
|
1509
|
+
unprotectedHeader: /* @__PURE__ */ new Map(),
|
|
1510
|
+
payload: null,
|
|
1511
|
+
signature: args.signature
|
|
1569
1512
|
});
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1513
|
+
const chunks = chunkBytes(coseSign1Bytes);
|
|
1514
|
+
const sigEntry = { cose_sign1: chunks };
|
|
1515
|
+
return { coseSign1Bytes, sigEntry };
|
|
1516
|
+
}
|
|
1517
|
+
function prepareSigStructureHashed(args) {
|
|
1518
|
+
if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
|
|
1519
|
+
throw new OffHostSignError(
|
|
1520
|
+
"INVALID_PUBKEY_LENGTH",
|
|
1521
|
+
`signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
|
|
1522
|
+
);
|
|
1523
|
+
}
|
|
1524
|
+
const { protectedHeaderBytes } = encodePath1ProtectedHeader(args.signerPubkey);
|
|
1525
|
+
const toSign = buildToSign(args.record);
|
|
1526
|
+
const toSignHashBytes = blake2b224(toSign);
|
|
1527
|
+
const sigStructureBytes = buildSigStructure({
|
|
1528
|
+
context: "Signature1",
|
|
1529
|
+
bodyProtectedBytes: protectedHeaderBytes,
|
|
1530
|
+
externalAad: EMPTY_BYTES2,
|
|
1531
|
+
payload: toSignHashBytes
|
|
1532
|
+
});
|
|
1533
|
+
return { sigStructureBytes, protectedHeaderBytes, toSignHashBytes };
|
|
1534
|
+
}
|
|
1535
|
+
function assembleCoseSign1Hashed(args) {
|
|
1536
|
+
if (args.signerPubkey.length !== ED25519_PUBLIC_KEY_LENGTH) {
|
|
1537
|
+
throw new OffHostSignError(
|
|
1538
|
+
"INVALID_PUBKEY_LENGTH",
|
|
1539
|
+
`signerPubkey must be 32 bytes (Ed25519 raw public key), got ${args.signerPubkey.length}`
|
|
1540
|
+
);
|
|
1541
|
+
}
|
|
1542
|
+
if (args.signature.length !== ED25519_SIGNATURE_LENGTH) {
|
|
1543
|
+
throw new OffHostSignError(
|
|
1544
|
+
"INVALID_SIGNATURE_LENGTH",
|
|
1545
|
+
`signature must be 64 bytes (Ed25519 raw signature), got ${args.signature.length}`
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
const { protectedHeader } = encodePath1ProtectedHeader(args.signerPubkey);
|
|
1549
|
+
const unprotectedHeader = /* @__PURE__ */ new Map([["hashed", true]]);
|
|
1550
|
+
const coseSign1Bytes = encodeCoseSign1({
|
|
1551
|
+
protectedHeader,
|
|
1552
|
+
unprotectedHeader,
|
|
1553
|
+
payload: null,
|
|
1554
|
+
signature: args.signature
|
|
1605
1555
|
});
|
|
1556
|
+
const chunks = chunkBytes(coseSign1Bytes);
|
|
1557
|
+
const sigEntry = { cose_sign1: chunks };
|
|
1558
|
+
return { coseSign1Bytes, sigEntry };
|
|
1606
1559
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1560
|
+
|
|
1561
|
+
// src/client/http-error.ts
|
|
1562
|
+
var CANONICAL_PROBLEM_KEYS = /* @__PURE__ */ new Set([
|
|
1563
|
+
"type",
|
|
1564
|
+
"title",
|
|
1565
|
+
"status",
|
|
1566
|
+
"detail",
|
|
1567
|
+
"code",
|
|
1568
|
+
"trace_id",
|
|
1569
|
+
"errors",
|
|
1570
|
+
"instance"
|
|
1571
|
+
]);
|
|
1572
|
+
function extractProblemExtensions(problem) {
|
|
1573
|
+
const out = {};
|
|
1574
|
+
for (const [key, value] of Object.entries(problem)) {
|
|
1575
|
+
if (!CANONICAL_PROBLEM_KEYS.has(key)) {
|
|
1576
|
+
out[key] = value;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
return out;
|
|
1620
1580
|
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1581
|
+
var Label309HttpError = class extends Error {
|
|
1582
|
+
problem;
|
|
1583
|
+
code;
|
|
1584
|
+
httpStatus;
|
|
1585
|
+
title;
|
|
1586
|
+
detail;
|
|
1587
|
+
type;
|
|
1588
|
+
traceId;
|
|
1589
|
+
instance;
|
|
1590
|
+
errors;
|
|
1591
|
+
extensions;
|
|
1592
|
+
requestId;
|
|
1593
|
+
retryAfterSeconds;
|
|
1594
|
+
constructor(init) {
|
|
1595
|
+
super(init.problem.detail || `${init.problem.title} (HTTP ${init.problem.status})`);
|
|
1596
|
+
this.name = "Label309HttpError";
|
|
1597
|
+
this.problem = init.problem;
|
|
1598
|
+
this.code = init.problem.code;
|
|
1599
|
+
this.httpStatus = init.problem.status;
|
|
1600
|
+
this.title = init.problem.title;
|
|
1601
|
+
this.detail = init.problem.detail;
|
|
1602
|
+
this.type = init.problem.type;
|
|
1603
|
+
this.traceId = init.problem.trace_id;
|
|
1604
|
+
this.instance = init.problem.instance;
|
|
1605
|
+
this.errors = init.problem.errors;
|
|
1606
|
+
this.extensions = init.extensions ?? extractProblemExtensions(init.problem);
|
|
1607
|
+
this.requestId = init.requestId ?? init.problem.trace_id;
|
|
1608
|
+
this.retryAfterSeconds = init.retryAfterSeconds;
|
|
1609
|
+
}
|
|
1610
|
+
};
|
|
1611
|
+
|
|
1612
|
+
// src/client/batch-empty-error.ts
|
|
1613
|
+
var BatchEmptyError = class extends Label309HttpError {
|
|
1614
|
+
constructor(init) {
|
|
1615
|
+
super(init);
|
|
1616
|
+
this.name = "BatchEmptyError";
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1619
|
+
|
|
1620
|
+
// src/client/batch-too-large-error.ts
|
|
1621
|
+
function readInt(value) {
|
|
1622
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1623
1623
|
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1624
|
+
var BatchTooLargeError = class extends Label309HttpError {
|
|
1625
|
+
max;
|
|
1626
|
+
got;
|
|
1627
|
+
constructor(init) {
|
|
1628
|
+
super(init);
|
|
1629
|
+
this.name = "BatchTooLargeError";
|
|
1630
|
+
this.max = readInt(this.extensions["max"]);
|
|
1631
|
+
this.got = readInt(this.extensions["got"]);
|
|
1632
|
+
}
|
|
1633
|
+
};
|
|
1634
|
+
|
|
1635
|
+
// src/client/forbidden-error.ts
|
|
1636
|
+
var ForbiddenError = class extends Label309HttpError {
|
|
1637
|
+
constructor(init) {
|
|
1638
|
+
super(init);
|
|
1639
|
+
this.name = "ForbiddenError";
|
|
1640
|
+
}
|
|
1641
|
+
};
|
|
1642
|
+
|
|
1643
|
+
// src/client/idempotency-conflict-error.ts
|
|
1644
|
+
var IdempotencyConflictError = class extends Label309HttpError {
|
|
1645
|
+
constructor(init) {
|
|
1646
|
+
super(init);
|
|
1647
|
+
this.name = "IdempotencyConflictError";
|
|
1648
|
+
}
|
|
1649
|
+
};
|
|
1650
|
+
|
|
1651
|
+
// src/client/insufficient-funds-error.ts
|
|
1652
|
+
function readBigIntString(value) {
|
|
1653
|
+
if (typeof value !== "string") return void 0;
|
|
1654
|
+
if (!/^-?[0-9]+$/.test(value)) return void 0;
|
|
1655
|
+
try {
|
|
1656
|
+
return BigInt(value);
|
|
1657
|
+
} catch {
|
|
1658
|
+
return void 0;
|
|
1659
|
+
}
|
|
1626
1660
|
}
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1661
|
+
function readString(value) {
|
|
1662
|
+
return typeof value === "string" ? value : void 0;
|
|
1663
|
+
}
|
|
1664
|
+
var InsufficientFundsError = class extends Label309HttpError {
|
|
1665
|
+
balanceUsdMicros;
|
|
1666
|
+
requiredUsdMicros;
|
|
1667
|
+
topUpUrl;
|
|
1668
|
+
constructor(init) {
|
|
1669
|
+
super(init);
|
|
1670
|
+
this.name = "InsufficientFundsError";
|
|
1671
|
+
this.balanceUsdMicros = readBigIntString(this.extensions["balance_usd_micros"]);
|
|
1672
|
+
this.requiredUsdMicros = readBigIntString(this.extensions["required_usd_micros"]);
|
|
1673
|
+
this.topUpUrl = readString(this.extensions["top_up_url"]);
|
|
1635
1674
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
// src/client/insufficient-scope-error.ts
|
|
1678
|
+
function readScopeArray(value) {
|
|
1679
|
+
if (!Array.isArray(value)) return [];
|
|
1680
|
+
return value.filter((entry) => typeof entry === "string");
|
|
1681
|
+
}
|
|
1682
|
+
var InsufficientScopeError = class extends Label309HttpError {
|
|
1683
|
+
requiredScopes;
|
|
1684
|
+
grantedScopes;
|
|
1685
|
+
constructor(init) {
|
|
1686
|
+
super(init);
|
|
1687
|
+
this.name = "InsufficientScopeError";
|
|
1688
|
+
this.requiredScopes = readScopeArray(this.extensions["required"]);
|
|
1689
|
+
this.grantedScopes = readScopeArray(this.extensions["granted"]);
|
|
1640
1690
|
}
|
|
1641
|
-
|
|
1642
|
-
|
|
1691
|
+
/** Convenience for the single-scope case; first entry of `requiredScopes`. */
|
|
1692
|
+
get requiredScope() {
|
|
1693
|
+
return this.requiredScopes[0];
|
|
1694
|
+
}
|
|
1695
|
+
};
|
|
1696
|
+
|
|
1697
|
+
// src/client/internal-server-error.ts
|
|
1698
|
+
var InternalServerError = class extends Label309HttpError {
|
|
1699
|
+
constructor(init) {
|
|
1700
|
+
super(init);
|
|
1701
|
+
this.name = "InternalServerError";
|
|
1702
|
+
}
|
|
1703
|
+
};
|
|
1704
|
+
|
|
1705
|
+
// src/client/invalid-body-error.ts
|
|
1706
|
+
var InvalidBodyError = class extends Label309HttpError {
|
|
1707
|
+
constructor(init) {
|
|
1708
|
+
super(init);
|
|
1709
|
+
this.name = "InvalidBodyError";
|
|
1710
|
+
}
|
|
1711
|
+
};
|
|
1712
|
+
|
|
1713
|
+
// src/client/malformed-cbor-error.ts
|
|
1714
|
+
var MalformedCborError = class extends Label309HttpError {
|
|
1715
|
+
constructor(init) {
|
|
1716
|
+
super(init);
|
|
1717
|
+
this.name = "MalformedCborError";
|
|
1718
|
+
}
|
|
1719
|
+
};
|
|
1720
|
+
|
|
1721
|
+
// src/client/not-found-error.ts
|
|
1722
|
+
var NotFoundError = class extends Label309HttpError {
|
|
1723
|
+
constructor(init) {
|
|
1724
|
+
super(init);
|
|
1725
|
+
this.name = "NotFoundError";
|
|
1726
|
+
}
|
|
1727
|
+
};
|
|
1728
|
+
|
|
1729
|
+
// src/client/quote-already-consumed-error.ts
|
|
1730
|
+
function readString2(value) {
|
|
1731
|
+
return typeof value === "string" ? value : void 0;
|
|
1643
1732
|
}
|
|
1644
|
-
var
|
|
1645
|
-
|
|
1646
|
-
constructor(
|
|
1647
|
-
super(
|
|
1648
|
-
this.name = "
|
|
1733
|
+
var QuoteAlreadyConsumedError = class extends Label309HttpError {
|
|
1734
|
+
quoteId;
|
|
1735
|
+
constructor(init) {
|
|
1736
|
+
super(init);
|
|
1737
|
+
this.name = "QuoteAlreadyConsumedError";
|
|
1738
|
+
this.quoteId = readString2(this.extensions["quote_id"]);
|
|
1649
1739
|
}
|
|
1650
1740
|
};
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1741
|
+
|
|
1742
|
+
// src/client/quote-expired-error.ts
|
|
1743
|
+
function readString3(value) {
|
|
1744
|
+
return typeof value === "string" ? value : void 0;
|
|
1654
1745
|
}
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1746
|
+
var QuoteExpiredError = class extends Label309HttpError {
|
|
1747
|
+
quoteId;
|
|
1748
|
+
constructor(init) {
|
|
1749
|
+
super(init);
|
|
1750
|
+
this.name = "QuoteExpiredError";
|
|
1751
|
+
this.quoteId = readString3(this.extensions["quote_id"]);
|
|
1752
|
+
}
|
|
1753
|
+
};
|
|
1754
|
+
|
|
1755
|
+
// src/client/quote-not-found-error.ts
|
|
1756
|
+
function readString4(value) {
|
|
1757
|
+
return typeof value === "string" ? value : void 0;
|
|
1758
|
+
}
|
|
1759
|
+
var QuoteNotFoundError = class extends Label309HttpError {
|
|
1760
|
+
quoteId;
|
|
1761
|
+
constructor(init) {
|
|
1762
|
+
super(init);
|
|
1763
|
+
this.name = "QuoteNotFoundError";
|
|
1764
|
+
this.quoteId = readString4(this.extensions["quote_id"]);
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
|
|
1768
|
+
// src/client/rate-limited-error.ts
|
|
1769
|
+
var RateLimitedError = class extends Label309HttpError {
|
|
1770
|
+
constructor(init) {
|
|
1771
|
+
super(init);
|
|
1772
|
+
this.name = "RateLimitedError";
|
|
1663
1773
|
}
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
this.
|
|
1774
|
+
};
|
|
1775
|
+
|
|
1776
|
+
// src/client/record-not-found-error.ts
|
|
1777
|
+
var RecordNotFoundError = class extends Label309HttpError {
|
|
1778
|
+
constructor(init) {
|
|
1779
|
+
super(init);
|
|
1780
|
+
this.name = "RecordNotFoundError";
|
|
1671
1781
|
}
|
|
1672
1782
|
};
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
});
|
|
1680
|
-
}
|
|
1681
|
-
var CHUNK_MAX_BYTES2 = 64;
|
|
1682
|
-
function chunkKemCt(value) {
|
|
1683
|
-
if (value.length === 0) {
|
|
1684
|
-
throw new Error("chunkKemCt: refusing to chunk an empty byte string");
|
|
1783
|
+
|
|
1784
|
+
// src/client/service-unavailable-error.ts
|
|
1785
|
+
var ServiceUnavailableError = class extends Label309HttpError {
|
|
1786
|
+
constructor(init) {
|
|
1787
|
+
super(init);
|
|
1788
|
+
this.name = "ServiceUnavailableError";
|
|
1685
1789
|
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1790
|
+
};
|
|
1791
|
+
|
|
1792
|
+
// src/client/unauthorized-error.ts
|
|
1793
|
+
var UnauthorizedError = class extends Label309HttpError {
|
|
1794
|
+
constructor(init) {
|
|
1795
|
+
super(init);
|
|
1796
|
+
this.name = "UnauthorizedError";
|
|
1689
1797
|
}
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
for (const c of chunks) {
|
|
1698
|
-
out.set(c, offset);
|
|
1699
|
-
offset += c.length;
|
|
1798
|
+
};
|
|
1799
|
+
|
|
1800
|
+
// src/client/validation-failed-error.ts
|
|
1801
|
+
var ValidationFailedError = class extends Label309HttpError {
|
|
1802
|
+
constructor(init) {
|
|
1803
|
+
super(init);
|
|
1804
|
+
this.name = "ValidationFailedError";
|
|
1700
1805
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
value = slots.map((s) => ({ epk: s.epk, wrap: s.wrap }));
|
|
1707
|
-
} else {
|
|
1708
|
-
value = slots.map((s) => ({
|
|
1709
|
-
// Canonicalize the chunk boundaries before the MAC commits to them:
|
|
1710
|
-
// reassemble the logical ciphertext and re-split into canonical ≤ 64-byte
|
|
1711
|
-
// chunks. The on-wire `kem_ct` array is a transport detail (the Cardano
|
|
1712
|
-
// ledger's 64-byte metadatum cap), and a hostile or non-canonical chunking
|
|
1713
|
-
// ([1, 63, …] instead of [64, …]) reassembles to the SAME bytes — so the
|
|
1714
|
-
// MAC must be invariant to it. Committing to the verbatim wire chunks would
|
|
1715
|
-
// let an attacker re-chunk an honest envelope and break the slots_mac match
|
|
1716
|
-
// for an honest recipient. Honest (already-64B-chunked) records are
|
|
1717
|
-
// unchanged; a real byte flip still changes the reassembled bytes and is
|
|
1718
|
-
// still rejected.
|
|
1719
|
-
kem_ct: chunkKemCt(joinKemCt(s.kem_ct)),
|
|
1720
|
-
wrap: s.wrap
|
|
1721
|
-
}));
|
|
1722
|
-
}
|
|
1723
|
-
return encodeCanonicalCbor4(value);
|
|
1724
|
-
}
|
|
1725
|
-
var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
|
|
1726
|
-
var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
|
|
1727
|
-
"cardano-poe-kek-mlkem768x25519-v1"
|
|
1728
|
-
);
|
|
1729
|
-
var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
|
|
1730
|
-
"cardano-poe-slots-mac-v1"
|
|
1731
|
-
);
|
|
1732
|
-
var ZERO_NONCE_12 = new Uint8Array(12);
|
|
1733
|
-
var EMPTY_SALT = new Uint8Array(0);
|
|
1734
|
-
var X25519_PUBLIC_KEY_LENGTH = 32;
|
|
1735
|
-
var X25519_SECRET_KEY_LENGTH = 32;
|
|
1736
|
-
var CEK_LENGTH = 32;
|
|
1737
|
-
var NONCE_LENGTH = 24;
|
|
1738
|
-
var WRAP_LENGTH = 48;
|
|
1739
|
-
var SLOTS_MAC_LENGTH = 32;
|
|
1740
|
-
if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
|
|
1741
|
-
throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
|
|
1742
|
-
}
|
|
1743
|
-
if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
|
|
1744
|
-
throw new Error(
|
|
1745
|
-
"CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
|
|
1746
|
-
);
|
|
1747
|
-
}
|
|
1748
|
-
if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
|
|
1749
|
-
throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
|
|
1806
|
+
};
|
|
1807
|
+
|
|
1808
|
+
// src/client/parse-http-error.ts
|
|
1809
|
+
function asString(value) {
|
|
1810
|
+
return typeof value === "string" ? value : void 0;
|
|
1750
1811
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1812
|
+
function asNumber(value) {
|
|
1813
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1753
1814
|
}
|
|
1754
|
-
function
|
|
1755
|
-
|
|
1756
|
-
out
|
|
1757
|
-
|
|
1815
|
+
function asProblemErrorEntries(value) {
|
|
1816
|
+
if (!Array.isArray(value)) return void 0;
|
|
1817
|
+
const out = [];
|
|
1818
|
+
for (const entry of value) {
|
|
1819
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
1820
|
+
const e = entry;
|
|
1821
|
+
out.push({
|
|
1822
|
+
field: typeof e["field"] === "string" ? e["field"] : "",
|
|
1823
|
+
code: typeof e["code"] === "string" ? e["code"] : "",
|
|
1824
|
+
detail: typeof e["detail"] === "string" ? e["detail"] : ""
|
|
1825
|
+
});
|
|
1826
|
+
}
|
|
1758
1827
|
return out;
|
|
1759
1828
|
}
|
|
1760
|
-
function
|
|
1761
|
-
const
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1829
|
+
function synthesiseProblem(httpStatus, requestId) {
|
|
1830
|
+
const code = `http-${httpStatus}`;
|
|
1831
|
+
return {
|
|
1832
|
+
type: `about:blank`,
|
|
1833
|
+
title: `HTTP ${httpStatus}`,
|
|
1834
|
+
status: httpStatus,
|
|
1835
|
+
detail: `Server returned HTTP ${httpStatus} without a problem+json body.`,
|
|
1836
|
+
code,
|
|
1837
|
+
trace_id: requestId ?? ""
|
|
1838
|
+
};
|
|
1769
1839
|
}
|
|
1770
|
-
function
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1840
|
+
function toProblemDetails(httpStatus, body, requestId) {
|
|
1841
|
+
if (body === null || typeof body !== "object") {
|
|
1842
|
+
return synthesiseProblem(httpStatus, requestId);
|
|
1843
|
+
}
|
|
1844
|
+
const b = body;
|
|
1845
|
+
const code = asString(b["code"]);
|
|
1846
|
+
const status = asNumber(b["status"]) ?? httpStatus;
|
|
1847
|
+
const title = asString(b["title"]);
|
|
1848
|
+
if (code === void 0 && title === void 0) {
|
|
1849
|
+
return synthesiseProblem(httpStatus, requestId);
|
|
1776
1850
|
}
|
|
1851
|
+
const errors = asProblemErrorEntries(b["errors"]);
|
|
1852
|
+
const base = {
|
|
1853
|
+
...b,
|
|
1854
|
+
// RFC 7807 §4.2: `about:blank` is the default when no type URI is supplied.
|
|
1855
|
+
// The client is gateway-agnostic, so it must not invent a vendor-specific
|
|
1856
|
+
// problem-type namespace; the machine-readable discriminator is `code`.
|
|
1857
|
+
type: asString(b["type"]) ?? "about:blank",
|
|
1858
|
+
title: title ?? `HTTP ${status}`,
|
|
1859
|
+
status,
|
|
1860
|
+
detail: asString(b["detail"]) ?? "",
|
|
1861
|
+
code: code ?? `http-${status}`,
|
|
1862
|
+
trace_id: asString(b["trace_id"]) ?? requestId ?? ""
|
|
1863
|
+
};
|
|
1864
|
+
if (errors !== void 0) base["errors"] = errors;
|
|
1865
|
+
return base;
|
|
1777
1866
|
}
|
|
1778
|
-
function
|
|
1779
|
-
const
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1867
|
+
function parseHttpError(args) {
|
|
1868
|
+
const problem = toProblemDetails(args.httpStatus, args.body, args.requestId);
|
|
1869
|
+
const extensions = extractProblemExtensions(problem);
|
|
1870
|
+
const init = {
|
|
1871
|
+
problem,
|
|
1872
|
+
extensions,
|
|
1873
|
+
requestId: args.requestId,
|
|
1874
|
+
retryAfterSeconds: args.retryAfterSeconds
|
|
1875
|
+
};
|
|
1876
|
+
switch (problem.code) {
|
|
1877
|
+
case "unauthorized":
|
|
1878
|
+
return new UnauthorizedError(init);
|
|
1879
|
+
case "forbidden":
|
|
1880
|
+
case "csrf-invalid":
|
|
1881
|
+
return new ForbiddenError(init);
|
|
1882
|
+
case "insufficient-scope":
|
|
1883
|
+
return new InsufficientScopeError(init);
|
|
1884
|
+
case "insufficient-funds":
|
|
1885
|
+
return new InsufficientFundsError(init);
|
|
1886
|
+
case "quote-expired":
|
|
1887
|
+
return new QuoteExpiredError(init);
|
|
1888
|
+
case "quote-not-found":
|
|
1889
|
+
return new QuoteNotFoundError(init);
|
|
1890
|
+
case "quote-already-consumed":
|
|
1891
|
+
return new QuoteAlreadyConsumedError(init);
|
|
1892
|
+
case "not-found":
|
|
1893
|
+
return new NotFoundError(init);
|
|
1894
|
+
case "record-not-found":
|
|
1895
|
+
return new RecordNotFoundError(init);
|
|
1896
|
+
case "idempotency-key-conflict":
|
|
1897
|
+
return new IdempotencyConflictError(init);
|
|
1898
|
+
case "rate-limited":
|
|
1899
|
+
return new RateLimitedError(init);
|
|
1900
|
+
case "validation-failed":
|
|
1901
|
+
return new ValidationFailedError(init);
|
|
1902
|
+
case "invalid-body":
|
|
1903
|
+
return new InvalidBodyError(init);
|
|
1904
|
+
case "malformed-cbor":
|
|
1905
|
+
return new MalformedCborError(init);
|
|
1906
|
+
case "batch-too-large":
|
|
1907
|
+
return new BatchTooLargeError(init);
|
|
1908
|
+
case "batch-empty":
|
|
1909
|
+
return new BatchEmptyError(init);
|
|
1910
|
+
case "internal-error":
|
|
1911
|
+
return new InternalServerError(init);
|
|
1912
|
+
// A gateway that prices on a live FX oracle may surface a transient
|
|
1913
|
+
// `fx-stale` pricing outage; to a vendor-neutral client that is just a
|
|
1914
|
+
// temporary inability to serve, i.e. a service-unavailable condition.
|
|
1915
|
+
case "service-unavailable":
|
|
1916
|
+
case "fx-stale":
|
|
1917
|
+
return new ServiceUnavailableError(init);
|
|
1918
|
+
default:
|
|
1919
|
+
return new Label309HttpError(init);
|
|
1785
1920
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
nonce: ZERO_NONCE_12,
|
|
1797
|
-
aad: CARDANO_POE_HKDF_INFO_KEK,
|
|
1798
|
-
plaintext: args.cek
|
|
1799
|
-
});
|
|
1800
|
-
if (wrap.length !== WRAP_LENGTH) {
|
|
1801
|
-
throw new Error(`internal: wrap.length=${wrap.length}, expected ${WRAP_LENGTH}`);
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
// src/client/http-helpers.ts
|
|
1924
|
+
async function readJson(response) {
|
|
1925
|
+
const text = await response.text();
|
|
1926
|
+
if (text.length === 0) return null;
|
|
1927
|
+
try {
|
|
1928
|
+
return JSON.parse(text);
|
|
1929
|
+
} catch {
|
|
1930
|
+
return null;
|
|
1802
1931
|
}
|
|
1803
|
-
return { epk, wrap };
|
|
1804
1932
|
}
|
|
1805
|
-
function
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
const
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
plaintext: args.cek
|
|
1933
|
+
function parseRetryAfter(header) {
|
|
1934
|
+
if (header === null) return void 0;
|
|
1935
|
+
const parsed = Number(header);
|
|
1936
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
1937
|
+
}
|
|
1938
|
+
async function throwIfNotOk(response) {
|
|
1939
|
+
if (response.ok) return;
|
|
1940
|
+
const body = await readJson(response);
|
|
1941
|
+
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
1942
|
+
const retryAfterSeconds = parseRetryAfter(response.headers.get("retry-after"));
|
|
1943
|
+
throw parseHttpError({ httpStatus: response.status, body, requestId, retryAfterSeconds });
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
// src/client/account.ts
|
|
1947
|
+
function buildHeaders(apiKey) {
|
|
1948
|
+
const headers = new Headers({
|
|
1949
|
+
"content-type": "application/json",
|
|
1950
|
+
accept: "application/json"
|
|
1824
1951
|
});
|
|
1825
|
-
if (
|
|
1826
|
-
|
|
1827
|
-
}
|
|
1828
|
-
return { kem_ct: chunkKemCt(enc), wrap };
|
|
1952
|
+
if (apiKey !== void 0) headers.set("authorization", `Bearer ${apiKey}`);
|
|
1953
|
+
return headers;
|
|
1829
1954
|
}
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
if (n < 1) {
|
|
1835
|
-
throw new EciesSealedPoeError(
|
|
1836
|
-
"ENC_SLOTS_EMPTY",
|
|
1837
|
-
`recipientPublicKeys.length=${n} must be >= 1`
|
|
1838
|
-
);
|
|
1955
|
+
var AccountNamespace = class {
|
|
1956
|
+
config;
|
|
1957
|
+
constructor(config) {
|
|
1958
|
+
this.config = config;
|
|
1839
1959
|
}
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1960
|
+
/**
|
|
1961
|
+
* Fetch the caller's current prepaid USD balance.
|
|
1962
|
+
*
|
|
1963
|
+
* Returns `{ balanceUsdMicros }`, the gateway's `balance_usd_micros` field
|
|
1964
|
+
* (USD micro-cents as a decimal string). The string is preserved verbatim —
|
|
1965
|
+
* never parsed into a number — so no precision is lost. An account with no
|
|
1966
|
+
* ledger activity yet reads `"0"`.
|
|
1967
|
+
*
|
|
1968
|
+
* Requires authentication: 401 (UnauthorizedError) when anonymous, 403
|
|
1969
|
+
* (InsufficientScopeError) when the Bearer key lacks the `account:read`
|
|
1970
|
+
* scope.
|
|
1971
|
+
*/
|
|
1972
|
+
async balance() {
|
|
1973
|
+
const response = await this.config.fetch(`${this.config.baseUrl}/api/v1/account/balance`, {
|
|
1974
|
+
method: "GET",
|
|
1975
|
+
headers: buildHeaders(this.config.apiKey)
|
|
1976
|
+
});
|
|
1977
|
+
await throwIfNotOk(response);
|
|
1978
|
+
const body = await readJson(response);
|
|
1979
|
+
return { balanceUsdMicros: body.balance_usd_micros };
|
|
1849
1980
|
}
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
throw new EciesSealedPoeError(
|
|
1859
|
-
"EPHEMERAL_SECRETS_COUNT_MISMATCH",
|
|
1860
|
-
`ephemeralSecrets.length=${args.ephemeralSecrets.length} must match recipientPublicKeys.length=${n}`
|
|
1861
|
-
);
|
|
1862
|
-
}
|
|
1863
|
-
} else {
|
|
1864
|
-
if (args.ephemeralSecrets !== void 0) {
|
|
1865
|
-
throw new EciesSealedPoeError(
|
|
1866
|
-
"EPHEMERAL_SECRETS_COUNT_MISMATCH",
|
|
1867
|
-
"ephemeralSecrets is an X25519 override and MUST NOT be supplied for kem='mlkem768x25519'"
|
|
1868
|
-
);
|
|
1869
|
-
}
|
|
1870
|
-
if (args.eseeds !== void 0) {
|
|
1871
|
-
if (args.eseeds.length !== n) {
|
|
1872
|
-
throw new EciesSealedPoeError(
|
|
1873
|
-
"EPHEMERAL_SECRETS_COUNT_MISMATCH",
|
|
1874
|
-
`eseeds.length=${args.eseeds.length} must match recipientPublicKeys.length=${n}`
|
|
1875
|
-
);
|
|
1876
|
-
}
|
|
1877
|
-
for (let i = 0; i < n; i++) {
|
|
1878
|
-
const eseed = args.eseeds[i];
|
|
1879
|
-
if (eseed.length !== MLKEM768X25519_ESEED_LENGTH) {
|
|
1880
|
-
throw new EciesSealedPoeError(
|
|
1881
|
-
"INVALID_EPHEMERAL_SECRET_LENGTH",
|
|
1882
|
-
`eseeds[${i}] MUST be exactly ${MLKEM768X25519_ESEED_LENGTH} bytes, got ${eseed.length}`
|
|
1883
|
-
);
|
|
1884
|
-
}
|
|
1885
|
-
}
|
|
1886
|
-
}
|
|
1981
|
+
};
|
|
1982
|
+
|
|
1983
|
+
// src/client/invalid-client-config-error.ts
|
|
1984
|
+
var InvalidClientConfigError = class extends Error {
|
|
1985
|
+
code = "INVALID_CLIENT_CONFIG";
|
|
1986
|
+
constructor(message) {
|
|
1987
|
+
super(message);
|
|
1988
|
+
this.name = "InvalidClientConfigError";
|
|
1887
1989
|
}
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1990
|
+
};
|
|
1991
|
+
|
|
1992
|
+
// src/hex.ts
|
|
1993
|
+
function bytesToHex(bytes) {
|
|
1994
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
1995
|
+
}
|
|
1996
|
+
function encodeCanonicalCbor4(value) {
|
|
1997
|
+
return encode(value, {
|
|
1998
|
+
cde: true,
|
|
1999
|
+
collapseBigInts: true,
|
|
2000
|
+
rejectDuplicateKeys: true,
|
|
2001
|
+
sortKeys: sortCoreDeterministic
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
var LEAVES_LIST_FORMAT_V1 = "cardano-poe-merkle-leaves-v1";
|
|
2005
|
+
var TREE_ALG_RFC9162 = "rfc9162-sha256";
|
|
2006
|
+
var DIGEST_LENGTH2 = 32;
|
|
2007
|
+
var MerkleLeavesListError = class extends Error {
|
|
2008
|
+
code;
|
|
2009
|
+
constructor(code, message) {
|
|
2010
|
+
super(message ? `${code}: ${message}` : code);
|
|
2011
|
+
this.code = code;
|
|
2012
|
+
this.name = "MerkleLeavesListError";
|
|
2013
|
+
}
|
|
2014
|
+
};
|
|
2015
|
+
function encodeLeavesList(args) {
|
|
2016
|
+
if (!(args.root instanceof Uint8Array) || args.root.length !== DIGEST_LENGTH2) {
|
|
2017
|
+
throw new MerkleLeavesListError(
|
|
2018
|
+
"SCHEMA_MERKLE_LEAVES_MALFORMED",
|
|
2019
|
+
`root must be a Uint8Array(${DIGEST_LENGTH2})`
|
|
1894
2020
|
);
|
|
1895
2021
|
}
|
|
1896
|
-
if (
|
|
1897
|
-
throw new
|
|
1898
|
-
"
|
|
1899
|
-
|
|
2022
|
+
if (args.leaves.length < 1) {
|
|
2023
|
+
throw new MerkleLeavesListError(
|
|
2024
|
+
"SCHEMA_MERKLE_LEAVES_MALFORMED",
|
|
2025
|
+
"leaves array must be non-empty"
|
|
1900
2026
|
);
|
|
1901
2027
|
}
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
const
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
privEph: args.ephemeralSecrets ? args.ephemeralSecrets[i] : void 0,
|
|
1910
|
-
cek,
|
|
1911
|
-
slotIdx: i
|
|
1912
|
-
})
|
|
1913
|
-
);
|
|
1914
|
-
}
|
|
1915
|
-
if (args.skipShuffle !== true) {
|
|
1916
|
-
csprngShuffle(slots);
|
|
1917
|
-
}
|
|
1918
|
-
const slotsMac = computeSlotsMac(cek, slots, "x25519");
|
|
1919
|
-
envelope = {
|
|
1920
|
-
scheme: 1,
|
|
1921
|
-
aead: "xchacha20-poly1305",
|
|
1922
|
-
kem: "x25519",
|
|
1923
|
-
nonce,
|
|
1924
|
-
slots,
|
|
1925
|
-
slots_mac: slotsMac
|
|
1926
|
-
};
|
|
1927
|
-
} else {
|
|
1928
|
-
const slots = [];
|
|
1929
|
-
for (let i = 0; i < n; i++) {
|
|
1930
|
-
slots.push(
|
|
1931
|
-
wrapSlotMlkem768X25519({
|
|
1932
|
-
pubR: recipientPublicKeys[i],
|
|
1933
|
-
eseed: args.eseeds ? args.eseeds[i] : void 0,
|
|
1934
|
-
cek
|
|
1935
|
-
})
|
|
2028
|
+
const leavesCopy = [];
|
|
2029
|
+
for (let i = 0; i < args.leaves.length; i++) {
|
|
2030
|
+
const leaf = args.leaves[i];
|
|
2031
|
+
if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH2) {
|
|
2032
|
+
throw new MerkleLeavesListError(
|
|
2033
|
+
"SCHEMA_MERKLE_LEAVES_MALFORMED",
|
|
2034
|
+
`leaves[${i}] must be a Uint8Array(${DIGEST_LENGTH2})`
|
|
1936
2035
|
);
|
|
1937
2036
|
}
|
|
1938
|
-
|
|
1939
|
-
csprngShuffle(slots);
|
|
1940
|
-
}
|
|
1941
|
-
const slotsMac = computeSlotsMac(cek, slots, "mlkem768x25519");
|
|
1942
|
-
envelope = {
|
|
1943
|
-
scheme: 1,
|
|
1944
|
-
aead: "xchacha20-poly1305",
|
|
1945
|
-
kem: "mlkem768x25519",
|
|
1946
|
-
nonce,
|
|
1947
|
-
slots,
|
|
1948
|
-
slots_mac: slotsMac
|
|
1949
|
-
};
|
|
2037
|
+
leavesCopy.push(leaf);
|
|
1950
2038
|
}
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
plaintext
|
|
1957
|
-
});
|
|
1958
|
-
return { envelope, ciphertext };
|
|
1959
|
-
}
|
|
1960
|
-
function computeSlotsMac(cek, slots, kem) {
|
|
1961
|
-
const hmacKey = hkdfSha256({
|
|
1962
|
-
ikm: cek,
|
|
1963
|
-
salt: EMPTY_SALT,
|
|
1964
|
-
info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
|
|
1965
|
-
length: 32
|
|
1966
|
-
});
|
|
1967
|
-
const slotsCbor = slotsToMacCbor(slots, kem);
|
|
1968
|
-
const slotsMac = hmac(sha256$1, hmacKey, slotsCbor);
|
|
1969
|
-
if (slotsMac.length !== SLOTS_MAC_LENGTH) {
|
|
1970
|
-
throw new Error(`internal: slots_mac.length=${slotsMac.length}, expected ${SLOTS_MAC_LENGTH}`);
|
|
2039
|
+
if (args.leafAlg !== void 0 && typeof args.leafAlg !== "string") {
|
|
2040
|
+
throw new MerkleLeavesListError(
|
|
2041
|
+
"SCHEMA_MERKLE_LEAVES_MALFORMED",
|
|
2042
|
+
"leaf_alg must be a string when present"
|
|
2043
|
+
);
|
|
1971
2044
|
}
|
|
1972
|
-
|
|
2045
|
+
const map = {
|
|
2046
|
+
format: LEAVES_LIST_FORMAT_V1,
|
|
2047
|
+
tree_alg: TREE_ALG_RFC9162,
|
|
2048
|
+
root: args.root,
|
|
2049
|
+
leaves: leavesCopy,
|
|
2050
|
+
leaf_count: leavesCopy.length
|
|
2051
|
+
};
|
|
2052
|
+
if (args.leafAlg !== void 0) {
|
|
2053
|
+
map["leaf_alg"] = args.leafAlg;
|
|
2054
|
+
}
|
|
2055
|
+
return encodeCanonicalCbor4(map);
|
|
1973
2056
|
}
|
|
1974
2057
|
|
|
1975
2058
|
// src/client/partial-upload-error.ts
|