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