@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.
Files changed (38) hide show
  1. package/README.md +14 -14
  2. package/dist/client/index.cjs +1621 -1538
  3. package/dist/client/index.cjs.map +1 -1
  4. package/dist/client/index.d.cts +52 -52
  5. package/dist/client/index.d.ts +52 -52
  6. package/dist/client/index.js +1620 -1537
  7. package/dist/client/index.js.map +1 -1
  8. package/dist/conformance/cli.cjs +2367 -2106
  9. package/dist/conformance/cli.cjs.map +1 -1
  10. package/dist/conformance/cli.js +2367 -2106
  11. package/dist/conformance/cli.js.map +1 -1
  12. package/dist/identity/index.cjs +219 -104
  13. package/dist/identity/index.cjs.map +1 -1
  14. package/dist/identity/index.d.cts +1 -1
  15. package/dist/identity/index.d.ts +1 -1
  16. package/dist/identity/index.js +219 -104
  17. package/dist/identity/index.js.map +1 -1
  18. package/dist/ids/index.cjs.map +1 -1
  19. package/dist/ids/index.js.map +1 -1
  20. package/dist/index.cjs +2808 -2530
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +3 -3
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.js +2805 -2527
  25. package/dist/index.js.map +1 -1
  26. package/dist/merkle/index.cjs +1 -1
  27. package/dist/merkle/index.cjs.map +1 -1
  28. package/dist/merkle/index.js +1 -1
  29. package/dist/merkle/index.js.map +1 -1
  30. package/dist/{types-BQMtbRCb.d.cts → types-DGsZTMuZ.d.cts} +6 -6
  31. package/dist/{types-BQMtbRCb.d.ts → types-DGsZTMuZ.d.ts} +6 -6
  32. package/dist/verifier/index.cjs +2368 -2107
  33. package/dist/verifier/index.cjs.map +1 -1
  34. package/dist/verifier/index.d.cts +3 -3
  35. package/dist/verifier/index.d.ts +3 -3
  36. package/dist/verifier/index.js +2369 -2108
  37. package/dist/verifier/index.js.map +1 -1
  38. package/package.json +8 -8
@@ -6,11 +6,10 @@ var sorts = require('cbor2/sorts');
6
6
  var blake2_js = require('@noble/hashes/blake2.js');
7
7
  var ed = require('@noble/ed25519');
8
8
  var sha2_js = require('@noble/hashes/sha2.js');
9
- var hkdf_js = require('@noble/hashes/hkdf.js');
10
- var hashWasm = require('hash-wasm');
11
- var chacha_js = require('@noble/ciphers/chacha.js');
12
9
  require('@noble/ciphers/utils.js');
13
10
  var hmac_js = require('@noble/hashes/hmac.js');
11
+ var chacha_js = require('@noble/ciphers/chacha.js');
12
+ var hkdf_js = require('@noble/hashes/hkdf.js');
14
13
  require('@noble/curves/abstract/edwards.js');
15
14
  require('@noble/curves/abstract/montgomery.js');
16
15
  require('@noble/curves/abstract/weierstrass.js');
@@ -20,6 +19,7 @@ var utils_js$1 = require('@noble/curves/utils.js');
20
19
  var sha3_js = require('@noble/hashes/sha3.js');
21
20
  var utils_js = require('@noble/hashes/utils.js');
22
21
  var fft_js = require('@noble/curves/abstract/fft.js');
22
+ var hashWasm = require('hash-wasm');
23
23
 
24
24
  function _interopNamespace(e) {
25
25
  if (e && e.__esModule) return e;
@@ -172,7 +172,7 @@ function decodeCanonicalCbor(bytes) {
172
172
  ...cbor2.cdeDecodeOptions,
173
173
  rejectStreaming: true,
174
174
  rejectDuplicateKeys: true,
175
- // A CIP-309 record carries integers, byte/text strings, arrays, maps and
175
+ // A Label 309 record carries integers, byte/text strings, arrays, maps and
176
176
  // `null` — and nothing else. Without these rejections the major-type-7
177
177
  // surface leaks into the decoder: a float16/32/64 that happens to hold an
178
178
  // integral value (e.g. 1.0) silently decodes to the integer 1 and passes
@@ -298,7 +298,7 @@ function decodeCanonicalCbor2(bytes) {
298
298
  ...cbor2.cdeDecodeOptions,
299
299
  rejectStreaming: true,
300
300
  rejectDuplicateKeys: true,
301
- // A CIP-309 record carries integers, byte/text strings, arrays, maps and
301
+ // A Label 309 record carries integers, byte/text strings, arrays, maps and
302
302
  // `null` — and nothing else. Without these rejections the major-type-7
303
303
  // surface leaks into the decoder: a float16/32/64 that happens to hold an
304
304
  // integral value (e.g. 1.0) silently decodes to the integer 1 and passes
@@ -399,7 +399,7 @@ function buildSigStructure(args) {
399
399
  args.payload
400
400
  ]);
401
401
  }
402
- function buildCip309SigStructure(args) {
402
+ function buildLabel309SigStructure(args) {
403
403
  const toSign = new Uint8Array(
404
404
  CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES.length + args.recordBodyCbor.length
405
405
  );
@@ -473,7 +473,7 @@ function decodeCoseSign1(bytes) {
473
473
  signature: signatureRaw
474
474
  };
475
475
  }
476
- function coseSign1Cip309Verify(args) {
476
+ function coseSign1Label309Verify(args) {
477
477
  let decoded;
478
478
  try {
479
479
  decoded = decodeCoseSign1(args.message);
@@ -540,7 +540,7 @@ function coseSign1Cip309Verify(args) {
540
540
  payload: hashedPayload
541
541
  });
542
542
  } else {
543
- sigStructureBytes = buildCip309SigStructure({
543
+ sigStructureBytes = buildLabel309SigStructure({
544
544
  bodyProtectedBytes: decoded.protectedBytes,
545
545
  recordBodyCbor: args.detachedRecordBodyCbor
546
546
  });
@@ -594,2231 +594,2431 @@ function parseCoseKeyEd25519(blob) {
594
594
  if (!(x instanceof Uint8Array) || x.length !== ED25519_PUBLIC_KEY_LENGTH) return null;
595
595
  return x;
596
596
  }
597
-
598
- // ../poe-standard/src/chunked.ts
599
- var UTF8_ENCODER2 = new TextEncoder();
600
- function bytesChunkArrayConcat(chunks) {
601
- let total = 0;
602
- for (const c of chunks) total += c.length;
603
- const out = new Uint8Array(total);
604
- let offset = 0;
605
- for (const c of chunks) {
606
- out.set(c, offset);
607
- offset += c.length;
608
- }
609
- return out;
597
+ var abytesDoc = utils_js.abytes;
598
+ var randomBytes = utils_js.randomBytes;
599
+ function equalBytes(a, b) {
600
+ if (a.length !== b.length)
601
+ return false;
602
+ let diff = 0;
603
+ for (let i = 0; i < a.length; i++)
604
+ diff |= a[i] ^ b[i];
605
+ return diff === 0;
610
606
  }
611
- function reconstructChunkedUri(chunks) {
612
- const merged = bytesChunkArrayConcat(chunks.map((c) => UTF8_ENCODER2.encode(c)));
613
- try {
614
- const uri = new TextDecoder("utf-8", { fatal: true }).decode(merged);
615
- return { ok: true, uri };
616
- } catch (cause) {
617
- return {
618
- ok: false,
619
- code: "INVALID_URI",
620
- reason: cause instanceof Error ? cause.message : String(cause)
621
- };
622
- }
607
+ function copyBytes(bytes) {
608
+ return Uint8Array.from(utils_js.abytes(bytes));
623
609
  }
624
- var SEVERITY = Object.freeze({
625
- // --- Part A ---
626
- MALFORMED_CBOR: "error",
627
- SCHEMA_TYPE_MISMATCH: "error",
628
- SCHEMA_MISSING_REQUIRED: "error",
629
- SCHEMA_UNKNOWN_FIELD: "error",
630
- SCHEMA_INVALID_LITERAL: "error",
631
- SCHEMA_EMPTY_RECORD: "error",
632
- HASH_DIGEST_LENGTH_MISMATCH: "error",
633
- UNSUPPORTED_HASH_ALG: "error",
634
- UNSUPPORTED_MERKLE_COMMIT_ALG: "error",
635
- INVALID_URI: "error",
636
- CHUNK_TOO_LARGE: "error",
637
- UNAUTHENTICATED_CIPHER_FORBIDDEN: "error",
638
- UNSUPPORTED_AEAD_ALG: "error",
639
- NONCE_LENGTH_MISMATCH: "error",
640
- UNSUPPORTED_ENVELOPE_SCHEME: "error",
641
- ENC_SLOTS_EMPTY: "error",
642
- ENC_SLOT_INVALID_SHAPE: "error",
643
- UNSUPPORTED_KEM_ALG: "error",
644
- ENC_KEM_REQUIRED: "error",
645
- KEM_EPK_LENGTH_MISMATCH: "error",
646
- KEM_CT_LENGTH_MISMATCH: "error",
647
- WRAP_LENGTH_MISMATCH: "error",
648
- ENC_SLOTS_MAC_INVALID_LENGTH: "error",
649
- ENC_SLOTS_MAC_REQUIRED: "error",
650
- ENC_SLOTS_REQUIRED: "error",
651
- ENC_EXCLUSIVITY_VIOLATION: "error",
652
- ENC_NO_KEY_PATH: "error",
653
- ENC_REQUIRES_CONTENT_HASH: "error",
654
- ENC_PASSPHRASE_ALG_UNSUPPORTED: "error",
655
- ENC_PASSPHRASE_SALT_TOO_SHORT: "error",
656
- ENC_PASSPHRASE_SALT_TOO_LONG: "error",
657
- ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW: "error",
658
- ENC_PASSPHRASE_PARAMS_EXCEED_POLICY: "error",
659
- MALFORMED_SIG_COSE_SIGN1: "error",
660
- SIGNATURE_UNSUPPORTED: "info",
661
- SIG_ENTRY_INVALID_SHAPE: "error",
662
- SIG_ENTRY_KID_COSE_KEY_CONFLICT: "error",
663
- SIG_PRIVATE_KEY_LEAKED: "error",
664
- SUPERSEDES_TX_INVALID_LENGTH: "error",
665
- EXTENSION_UNSUPPORTED_CRITICAL: "error",
666
- CRIT_SHAPE_INVALID: "error",
667
- // --- Part B ---
668
- METADATA_NOT_FOUND: "error",
669
- INSUFFICIENT_CONFIRMATIONS: "info",
670
- SIGNATURE_INVALID: "error",
671
- SIGNER_KEY_UNRESOLVED: "error",
672
- WALLET_ADDRESS_MISMATCH: "error",
673
- URI_TARGET_FORBIDDEN: "error",
674
- URI_INTEGRITY_MISMATCH: "error",
675
- URI_FETCH_FAILED: "warning",
676
- CONTENT_UNAVAILABLE: "error",
677
- CIPHERTEXT_UNAVAILABLE: "error",
678
- PROVIDER_UNAVAILABLE: "error",
679
- SERVICE_INDEPENDENCE_VIOLATION: "error",
680
- WRONG_DECRYPTION_INPUT_SHAPE: "error",
681
- WRONG_RECIPIENT_KEY: "error",
682
- TAMPERED_HEADER: "error",
683
- TAMPERED_CIPHERTEXT: "error",
684
- KDF_DERIVATION_FAILED: "error",
685
- SCHEMA_MERKLE_LEAF_COUNT_MISMATCH: "error",
686
- SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED: "error",
687
- SCHEMA_MERKLE_LEAVES_MALFORMED: "error",
688
- MERKLE_ROOT_MISMATCH: "error",
689
- MERKLE_LEAVES_UNAVAILABLE: "warning",
690
- MERKLE_LEAVES_INFORMATIVE_FORM: "info",
691
- // Dual-severity — default reading is `info`; the verifier promotes to
692
- // `error` for merkle-only records (no `items[]` content claim was
693
- // validated in the same record).
694
- MERKLE_UNSUPPORTED: "info",
695
- // Dual-severity — default reading is `info` (render mode); strict
696
- // end-to-end verifiers promote to `error`.
697
- OUT_OF_PROFILE_SKIPPED: "info"
698
- });
699
-
700
- // ../poe-standard/src/validator.ts
701
- var HASH_ALG_LENGTHS = {
702
- "sha2-256": 32,
703
- "blake2b-256": 32
704
- };
705
- var MERKLE_COMMIT_ALG_LENGTHS = {
706
- "rfc9162-sha256": 32
707
- };
708
- var AEAD_NONCE_LENGTHS = {
709
- "xchacha20-poly1305": 24
710
- };
711
- var UNAUTHENTICATED_CIPHER_RE = /(?:^|[-_])(?:cbc|ctr|ecb|cfb|ofb)(?:[-_]|\n?$)|^(?:rc4|des|3des)(?:[-_]|\n?$)/i;
712
- var KEM_SLOT_DESCRIPTORS = {
713
- x25519: { field: "epk", fieldLength: 32, wrapLength: 48 },
714
- mlkem768x25519: { field: "kem_ct", fieldLength: 1120, wrapLength: 48 }
715
- };
716
- var KEM_FIELD_LENGTH_CODE = {
717
- epk: "KEM_EPK_LENGTH_MISMATCH",
718
- kem_ct: "KEM_CT_LENGTH_MISMATCH"
719
- };
720
- var PASSPHRASE_KDF_ALGS = /* @__PURE__ */ new Set(["argon2id"]);
721
- var KNOWN_SIG_ALG_IDS = /* @__PURE__ */ new Set([-8, -19]);
722
- function validatePoeRecord(bytes) {
723
- let decoded;
724
- try {
725
- decoded = decodeCanonicalCbor(bytes);
726
- } catch (cause) {
727
- return {
728
- ok: false,
729
- issues: [
730
- {
731
- code: "MALFORMED_CBOR",
732
- path: [],
733
- message: cause instanceof Error ? cause.message : String(cause),
734
- severity: "error"
735
- }
736
- ]
737
- };
738
- }
739
- const parse = PoeRecordSchema.safeParse(decoded);
740
- if (!parse.success) {
741
- const issues = parse.error.issues.map((issue2) => mapZodIssue(issue2, decoded)).sort(compareIssuePath);
742
- return { ok: false, issues };
743
- }
744
- const record = parse.data;
745
- const errors = [];
746
- const warnings = [];
747
- const info = [];
748
- const itemsLen = Array.isArray(record.items) ? record.items.length : 0;
749
- const merkleLen = Array.isArray(record.merkle) ? record.merkle.length : 0;
750
- if (itemsLen === 0 && merkleLen === 0) {
751
- errors.push(
752
- issue(
753
- "SCHEMA_EMPTY_RECORD",
754
- [],
755
- "record must carry at least one of items[] or merkle[] non-empty"
756
- )
757
- );
758
- }
759
- const decodedTopKeys = topLevelKeysOf(decoded);
760
- const critShapeInvalidIndices = checkCritShape(record, decodedTopKeys, errors);
761
- for (const k of decodedTopKeys) {
762
- if (TOP_LEVEL_BASE_KEYS.has(k)) continue;
763
- if (isExtensionKey(k)) continue;
764
- errors.push(issue("SCHEMA_UNKNOWN_FIELD", [k], `unknown top-level field: ${k}`));
765
- }
766
- if (Array.isArray(record.crit)) {
767
- for (let i = 0; i < record.crit.length; i++) {
768
- if (critShapeInvalidIndices.has(i)) continue;
769
- const critName = record.crit[i];
770
- errors.push(
771
- issue(
772
- "EXTENSION_UNSUPPORTED_CRITICAL",
773
- ["crit", i],
774
- `crit lists extension '${critName}' that this validator does not implement`
775
- )
776
- );
777
- }
778
- }
779
- for (let i = 0; i < (record.items ?? []).length; i++) {
780
- const item = record.items[i];
781
- checkItemHashes(item, i, errors);
782
- if (item.uris) checkItemUris(item.uris, ["items", i, "uris"], errors);
783
- if (item.enc !== void 0) checkItemEnc(item, i, errors);
784
- }
785
- for (let i = 0; i < (record.merkle ?? []).length; i++) {
786
- const commit = record.merkle[i];
787
- checkMerkleCommit(commit, i, errors);
788
- }
789
- if (record.sigs) {
790
- for (let i = 0; i < record.sigs.length; i++) {
791
- checkSigEntry(record.sigs[i], i, errors, info);
610
+ function splitCoder(label, ...lengths) {
611
+ const getLength = (c) => typeof c === "number" ? c : c.bytesLen;
612
+ const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0);
613
+ return {
614
+ bytesLen,
615
+ encode: (bufs) => {
616
+ const res = new Uint8Array(bytesLen);
617
+ for (let i = 0, pos = 0; i < lengths.length; i++) {
618
+ const c = lengths[i];
619
+ const l = getLength(c);
620
+ const b = typeof c === "number" ? bufs[i] : c.encode(bufs[i]);
621
+ utils_js.abytes(b, l, label);
622
+ res.set(b, pos);
623
+ if (typeof c !== "number")
624
+ b.fill(0);
625
+ pos += l;
626
+ }
627
+ return res;
628
+ },
629
+ decode: (buf) => {
630
+ utils_js.abytes(buf, bytesLen, label);
631
+ const res = [];
632
+ for (const c of lengths) {
633
+ const l = getLength(c);
634
+ const b = buf.subarray(0, l);
635
+ res.push(typeof c === "number" ? b : c.decode(b));
636
+ buf = buf.subarray(l);
637
+ }
638
+ return res;
792
639
  }
793
- }
794
- if (errors.length > 0) {
795
- return { ok: false, issues: errors.sort(compareIssuePath) };
796
- }
797
- const result = {
798
- ok: true,
799
- record
800
640
  };
801
- if (warnings.length > 0) result.warnings = warnings.sort(compareIssuePath);
802
- if (info.length > 0) result.info = info.sort(compareIssuePath);
803
- return result;
804
641
  }
805
- function mapZodIssue(zissue, decoded) {
806
- const path = zissue.path;
807
- const explicit = zissue.params?.code;
808
- if (explicit !== void 0) {
809
- return issue(explicit, path, zissue.message);
810
- }
811
- const inSigsEntry = path.length >= 2 && path[0] === "sigs" && typeof path[1] === "number";
812
- const isInSlotEntry = (() => {
813
- if (path.length >= 5 && path[0] === "items" && typeof path[1] === "number" && path[2] === "enc" && path[3] === "slots" && typeof path[4] === "number") {
814
- return true;
815
- }
816
- if (path.length >= 2 && path[0] === "slots" && typeof path[1] === "number") {
817
- return true;
818
- }
819
- return false;
820
- })();
821
- const valueAtIssue = valueAtPath(decoded, path);
822
- const isMissing = valueAtIssue === void 0;
823
- switch (zissue.code) {
824
- case "invalid_type":
825
- if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
826
- if (isMissing) {
827
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
828
- return issue("SCHEMA_MISSING_REQUIRED", path, zissue.message);
829
- }
830
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
831
- return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
832
- case "invalid_value":
833
- if (path.length === 1 && path[0] === "v") {
834
- return issue(
835
- isMissing ? "SCHEMA_MISSING_REQUIRED" : "SCHEMA_INVALID_LITERAL",
836
- path,
837
- zissue.message
838
- );
642
+ function vecCoder(c, vecLen) {
643
+ const coder = c;
644
+ const bytesLen = vecLen * coder.bytesLen;
645
+ return {
646
+ bytesLen,
647
+ encode: (u) => {
648
+ if (u.length !== vecLen)
649
+ throw new RangeError(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`);
650
+ const res = new Uint8Array(bytesLen);
651
+ for (let i = 0, pos = 0; i < u.length; i++) {
652
+ const b = coder.encode(u[i]);
653
+ res.set(b, pos);
654
+ b.fill(0);
655
+ pos += b.length;
839
656
  }
840
- return issue("SCHEMA_INVALID_LITERAL", path, zissue.message);
841
- case "unrecognized_keys":
842
- if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
843
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
844
- return issue("SCHEMA_UNKNOWN_FIELD", path, zissue.message);
845
- case "invalid_format":
846
- case "too_big":
847
- case "too_small":
848
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
849
- return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
850
- case "invalid_union":
851
- case "invalid_key":
852
- case "invalid_element":
853
- case "custom":
854
- default:
855
- if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
856
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
857
- return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
858
- }
859
- }
860
- function checkItemHashes(item, idx, errors) {
861
- const entries = Object.entries(item.hashes);
862
- if (entries.length === 0) {
863
- errors.push(
864
- issue(
865
- "SCHEMA_TYPE_MISMATCH",
866
- ["items", idx, "hashes"],
867
- "hashes must be a non-empty CBOR map of <alg-id> -> <digest>"
868
- )
869
- );
870
- return;
871
- }
872
- for (const [alg, digest] of entries) {
873
- if (!(alg in HASH_ALG_LENGTHS)) {
874
- errors.push(
875
- issue("UNSUPPORTED_HASH_ALG", ["items", idx, "hashes", alg], `unknown hash alg: ${alg}`)
876
- );
877
- continue;
878
- }
879
- const expected = HASH_ALG_LENGTHS[alg];
880
- if (digest.length !== expected) {
881
- errors.push(
882
- issue(
883
- "HASH_DIGEST_LENGTH_MISMATCH",
884
- ["items", idx, "hashes", alg],
885
- `hashes['${alg}'] digest length ${digest.length} != ${expected}`
886
- )
887
- );
657
+ return res;
658
+ },
659
+ decode: (a) => {
660
+ utils_js.abytes(a, bytesLen);
661
+ const r = [];
662
+ for (let i = 0; i < a.length; i += coder.bytesLen)
663
+ r.push(coder.decode(a.subarray(i, i + coder.bytesLen)));
664
+ return r;
888
665
  }
666
+ };
667
+ }
668
+ function cleanBytes(...list) {
669
+ for (const t of list) {
670
+ if (Array.isArray(t))
671
+ for (const b of t)
672
+ b.fill(0);
673
+ else
674
+ t.fill(0);
889
675
  }
890
676
  }
891
- function checkItemUris(uris, basePath, errors) {
892
- uris.forEach((chunks, ui) => validateOneUri(chunks, [...basePath, ui], errors));
677
+ function getMask(bits) {
678
+ if (!Number.isSafeInteger(bits) || bits < 0 || bits > 32)
679
+ throw new RangeError(`expected bits in [0..32], got ${bits}`);
680
+ return bits === 32 ? 4294967295 : ~(-1 << bits) >>> 0;
893
681
  }
894
- function validateOneUri(chunks, path, errors) {
895
- const reconstructed = reconstructChunkedUri(chunks);
896
- if (!reconstructed.ok) {
897
- errors.push(issue(reconstructed.code, path, reconstructed.reason));
898
- return;
899
- }
900
- const uri = reconstructed.uri;
901
- if (uri.includes("#")) {
902
- errors.push(
903
- issue("INVALID_URI", path, "URI contains a fragment identifier ('#'), which is forbidden")
904
- );
905
- return;
906
- }
907
- const sepIdx = uri.indexOf("://");
908
- if (sepIdx <= 0 || !/^[a-z][a-z0-9+.-]*$/i.test(uri.slice(0, sepIdx))) {
909
- errors.push(
910
- issue("INVALID_URI", path, "URI is not absolute (missing scheme://hierarchical-part)")
911
- );
912
- return;
913
- }
914
- const scheme = uri.slice(0, sepIdx).toLowerCase();
915
- const rest = uri.slice(sepIdx + "://".length);
916
- if (scheme === "ar") {
917
- if (!/^ar:\/\/[A-Za-z0-9_-]{43}$/.test("ar://" + rest)) {
918
- errors.push(
919
- issue(
920
- "INVALID_URI",
921
- path,
922
- "ar:// URI does not match `^ar://[A-Za-z0-9_-]{43}$` (43-char base64url txid, no path/query/fragment)"
923
- )
924
- );
682
+
683
+ // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/_crystals.js
684
+ var genCrystals = (opts2) => {
685
+ const { newPoly, N: N2, Q: Q2, F: F2, ROOT_OF_UNITY: ROOT_OF_UNITY2, brvBits} = opts2;
686
+ const mod = (a, modulo = Q2) => {
687
+ const result = a % modulo | 0;
688
+ return (result >= 0 ? result | 0 : modulo + result | 0) | 0;
689
+ };
690
+ const smod = (a, modulo = Q2) => {
691
+ const r = mod(a, modulo) | 0;
692
+ return (r > modulo >> 1 ? r - modulo | 0 : r) | 0;
693
+ };
694
+ function getZettas() {
695
+ const out = newPoly(N2);
696
+ for (let i = 0; i < N2; i++) {
697
+ const b = fft_js.reverseBits(i, brvBits);
698
+ const p = BigInt(ROOT_OF_UNITY2) ** BigInt(b) % BigInt(Q2);
699
+ out[i] = Number(p) | 0;
925
700
  }
926
- return;
701
+ return out;
927
702
  }
928
- if (scheme === "ipfs") {
929
- const slashIdx = rest.indexOf("/");
930
- const cid = slashIdx === -1 ? rest : rest.slice(0, slashIdx);
931
- if (!validateCidProfile(cid)) {
932
- errors.push(
933
- issue("INVALID_URI", path, "ipfs:// URI is not a valid CID under the CIP-309 profile")
934
- );
703
+ const nttZetas = getZettas();
704
+ const field = {
705
+ add: (a, b) => mod((a | 0) + (b | 0)) | 0,
706
+ sub: (a, b) => mod((a | 0) - (b | 0)) | 0,
707
+ mul: (a, b) => mod((a | 0) * (b | 0)) | 0,
708
+ inv: (_a) => {
709
+ throw new Error("not implemented");
935
710
  }
936
- return;
937
- }
938
- errors.push(
939
- issue("INVALID_URI", path, "unsupported URI scheme; v1 PoE URI set is {ar://, ipfs://}")
940
- );
941
- }
942
- function checkItemEnc(item, idx, errors) {
943
- const hasContentHash = Object.keys(item.hashes).some((alg) => alg in HASH_ALG_LENGTHS);
944
- if (!hasContentHash) {
945
- errors.push(
946
- issue(
947
- "ENC_REQUIRES_CONTENT_HASH",
948
- ["items", idx, "enc"],
949
- "item carries `enc` but `hashes` has no content-hash entry (sha2-256 or blake2b-256)"
950
- )
951
- );
952
- return;
953
- }
954
- const encParse = EncryptionEnvelopeSchema.safeParse(item.enc);
955
- if (!encParse.success) {
956
- for (const zissue of encParse.error.issues) {
957
- const mapped = mapZodIssue(zissue, item.enc);
958
- errors.push({
959
- ...mapped,
960
- path: ["items", idx, "enc", ...mapped.path]
961
- });
711
+ };
712
+ const nttOpts = {
713
+ N: N2,
714
+ roots: nttZetas,
715
+ invertButterflies: true,
716
+ skipStages: 1 ,
717
+ brp: false
718
+ };
719
+ const dif = fft_js.FFTCore(field, { dit: false, ...nttOpts });
720
+ const dit = fft_js.FFTCore(field, { dit: true, ...nttOpts });
721
+ const NTT = {
722
+ encode: (r) => {
723
+ return dif(r);
724
+ },
725
+ decode: (r) => {
726
+ dit(r);
727
+ for (let i = 0; i < r.length; i++)
728
+ r[i] = mod(F2 * r[i]);
729
+ return r;
962
730
  }
963
- return;
964
- }
965
- const enc = encParse.data;
966
- const basePath = ["items", idx, "enc"];
967
- if (typeof enc.scheme !== "number" || !Number.isInteger(enc.scheme) || enc.scheme !== 1) {
968
- errors.push(
969
- issue(
970
- "UNSUPPORTED_ENVELOPE_SCHEME",
971
- [...basePath, "scheme"],
972
- `enc.scheme must be the unsigned integer 1; got ${String(enc.scheme)}`
973
- )
974
- );
975
- }
976
- if (UNAUTHENTICATED_CIPHER_RE.test(enc.aead)) {
977
- errors.push(
978
- issue(
979
- "UNAUTHENTICATED_CIPHER_FORBIDDEN",
980
- [...basePath, "aead"],
981
- `'${enc.aead}' is an unauthenticated cipher; CIP-309 mandates an authenticated (AEAD) cipher`
982
- )
983
- );
984
- return;
985
- }
986
- if (!(enc.aead in AEAD_NONCE_LENGTHS)) {
987
- errors.push(
988
- issue("UNSUPPORTED_AEAD_ALG", [...basePath, "aead"], `unknown aead alg: ${enc.aead}`)
989
- );
990
- return;
991
- }
992
- const expectedNonceLen = AEAD_NONCE_LENGTHS[enc.aead];
993
- if (enc.nonce.length !== expectedNonceLen) {
994
- errors.push(
995
- issue(
996
- "NONCE_LENGTH_MISMATCH",
997
- [...basePath, "nonce"],
998
- `nonce length ${enc.nonce.length} != ${expectedNonceLen} for ${enc.aead}`
999
- )
1000
- );
1001
- }
1002
- if (enc.kem !== void 0 && !(enc.kem in KEM_SLOT_DESCRIPTORS)) {
1003
- errors.push(issue("UNSUPPORTED_KEM_ALG", [...basePath, "kem"], `unknown kem alg: ${enc.kem}`));
1004
- }
1005
- const hasSlots = enc.slots !== void 0;
1006
- const hasSlotsMac = enc.slots_mac !== void 0;
1007
- const hasPassphrase = enc.passphrase !== void 0;
1008
- if (hasSlots && hasPassphrase) {
1009
- errors.push(
1010
- issue("ENC_EXCLUSIVITY_VIOLATION", basePath, "enc combines slots with passphrase; pick one")
1011
- );
1012
- }
1013
- if (hasSlots && !hasSlotsMac) {
1014
- errors.push(
1015
- issue("ENC_SLOTS_MAC_REQUIRED", basePath, "enc.slots present but enc.slots_mac absent")
1016
- );
1017
- }
1018
- if (hasSlotsMac && !hasSlots) {
1019
- errors.push(
1020
- issue("ENC_SLOTS_REQUIRED", basePath, "enc.slots_mac present but enc.slots absent")
1021
- );
1022
- }
1023
- if (hasSlots && enc.kem === void 0) {
1024
- errors.push(issue("ENC_KEM_REQUIRED", basePath, "enc.slots present but enc.kem absent"));
1025
- }
1026
- if (!hasSlots && !hasPassphrase) {
1027
- errors.push(
1028
- issue(
1029
- "ENC_NO_KEY_PATH",
1030
- basePath,
1031
- "enc requires either slots or passphrase \u2014 no on-chain key path otherwise"
1032
- )
1033
- );
1034
- }
1035
- if (hasSlots) {
1036
- if (enc.slots.length < 1) {
1037
- errors.push(
1038
- issue("ENC_SLOTS_EMPTY", [...basePath, "slots"], `slots length ${enc.slots.length} < 1`)
1039
- );
1040
- }
1041
- const descriptor = enc.kem !== void 0 ? KEM_SLOT_DESCRIPTORS[enc.kem] : void 0;
1042
- if (descriptor !== void 0) {
1043
- const rawSlotKeys = rawSlotKeySets(item.enc);
1044
- enc.slots.forEach((slot, si) => {
1045
- checkSlotShape(
1046
- slot,
1047
- rawSlotKeys[si] ?? /* @__PURE__ */ new Set(),
1048
- descriptor,
1049
- enc.kem,
1050
- [...basePath, "slots", si],
1051
- errors
1052
- );
1053
- });
1054
- }
1055
- }
1056
- if (hasPassphrase) {
1057
- const pp = enc.passphrase;
1058
- const ppPath = [...basePath, "passphrase"];
1059
- if (!PASSPHRASE_KDF_ALGS.has(pp.alg)) {
1060
- errors.push(
1061
- issue(
1062
- "ENC_PASSPHRASE_ALG_UNSUPPORTED",
1063
- [...ppPath, "alg"],
1064
- `unknown passphrase kdf alg: ${pp.alg}`
1065
- )
1066
- );
1067
- return;
1068
- }
1069
- if (pp.alg === "argon2id") {
1070
- const allowed = /* @__PURE__ */ new Set(["m", "t", "p"]);
1071
- for (const k of Object.keys(pp.params)) {
1072
- if (!allowed.has(k)) {
1073
- errors.push(
1074
- issue(
1075
- "SCHEMA_UNKNOWN_FIELD",
1076
- [...ppPath, "params", k],
1077
- `unknown argon2id params field: ${k}`
1078
- )
1079
- );
731
+ };
732
+ const bitsCoder = (d, c) => {
733
+ const mask = getMask(d);
734
+ const bytesLen = d * (N2 / 8);
735
+ return {
736
+ bytesLen,
737
+ encode: (poly_) => {
738
+ const poly = poly_;
739
+ const r = new Uint8Array(bytesLen);
740
+ for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) {
741
+ buf |= (c.encode(poly[i]) & mask) << bufLen;
742
+ bufLen += d;
743
+ for (; bufLen >= 8; bufLen -= 8, buf >>= 8)
744
+ r[pos++] = buf & getMask(bufLen);
1080
745
  }
1081
- }
1082
- const p = pp.params;
1083
- const argonInt = (val, name) => {
1084
- if (typeof val !== "number" || !Number.isInteger(val)) {
1085
- errors.push(
1086
- issue(
1087
- "SCHEMA_TYPE_MISMATCH",
1088
- [...ppPath, "params", name],
1089
- `argon2id params.${name} must be a CBOR unsigned integer`
1090
- )
1091
- );
1092
- return null;
746
+ return r;
747
+ },
748
+ decode: (bytes) => {
749
+ const r = newPoly(N2);
750
+ for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) {
751
+ buf |= bytes[i] << bufLen;
752
+ bufLen += 8;
753
+ for (; bufLen >= d; bufLen -= d, buf >>= d)
754
+ r[pos++] = c.decode(buf & mask);
1093
755
  }
1094
- return val;
1095
- };
1096
- const mVal = argonInt(p.m, "m");
1097
- const tVal = argonInt(p.t, "t");
1098
- const pVal = argonInt(p.p, "p");
1099
- if (mVal !== null && mVal < 65536) {
1100
- errors.push(
1101
- issue(
1102
- "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
1103
- [...ppPath, "params", "m"],
1104
- "argon2id requires m >= 65536 KiB"
1105
- )
1106
- );
1107
- }
1108
- if (tVal !== null && tVal < 3) {
1109
- errors.push(
1110
- issue(
1111
- "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
1112
- [...ppPath, "params", "t"],
1113
- "argon2id requires t >= 3"
1114
- )
1115
- );
1116
- }
1117
- if (pVal !== null && pVal < 1) {
1118
- errors.push(
1119
- issue(
1120
- "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
1121
- [...ppPath, "params", "p"],
1122
- "argon2id requires p >= 1"
1123
- )
1124
- );
756
+ return r;
1125
757
  }
758
+ };
759
+ };
760
+ return {
761
+ mod,
762
+ smod,
763
+ nttZetas,
764
+ NTT: {
765
+ encode: (r) => NTT.encode(r),
766
+ decode: (r) => NTT.decode(r)
767
+ },
768
+ bitsCoder
769
+ };
770
+ };
771
+ var createXofShake = (shake) => (seed, blockLen) => {
772
+ if (!blockLen)
773
+ blockLen = shake.blockLen;
774
+ const _seed = new Uint8Array(seed.length + 2);
775
+ _seed.set(seed);
776
+ const seedLen = seed.length;
777
+ const buf = new Uint8Array(blockLen);
778
+ let h = shake.create({});
779
+ let calls = 0;
780
+ let xofs = 0;
781
+ return {
782
+ stats: () => ({ calls, xofs }),
783
+ get: (x, y) => {
784
+ _seed[seedLen + 0] = x;
785
+ _seed[seedLen + 1] = y;
786
+ h.destroy();
787
+ h = shake.create({}).update(_seed);
788
+ calls++;
789
+ return () => {
790
+ xofs++;
791
+ return h.xofInto(buf);
792
+ };
793
+ },
794
+ clean: () => {
795
+ h.destroy();
796
+ cleanBytes(buf, _seed);
1126
797
  }
1127
- }
798
+ };
799
+ };
800
+ var XOF128 = /* @__PURE__ */ createXofShake(sha3_js.shake128);
801
+
802
+ // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/ml-kem.js
803
+ var N = 256;
804
+ var Q = 3329;
805
+ var F = 3303;
806
+ var ROOT_OF_UNITY = 17;
807
+ var crystals = /* @__PURE__ */ genCrystals({
808
+ N,
809
+ Q,
810
+ F,
811
+ ROOT_OF_UNITY,
812
+ newPoly: (n) => new Uint16Array(n),
813
+ brvBits: 7});
814
+ var PARAMS = /* @__PURE__ */ (() => Object.freeze({
815
+ 512: Object.freeze({ N, Q, K: 2, ETA1: 3, ETA2: 2, du: 10, dv: 4, RBGstrength: 128 }),
816
+ 768: Object.freeze({ N, Q, K: 3, ETA1: 2, ETA2: 2, du: 10, dv: 4, RBGstrength: 192 }),
817
+ 1024: Object.freeze({ N, Q, K: 4, ETA1: 2, ETA2: 2, du: 11, dv: 5, RBGstrength: 256 })
818
+ }))();
819
+ var compress = (d) => {
820
+ if (d >= 12)
821
+ return { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i };
822
+ const a = 2 ** (d - 1);
823
+ return {
824
+ // This only matches standalone Compress_d after bitsCoder masks the result into Z_(2^d).
825
+ encode: (i) => ((i << d) + Q / 2) / Q,
826
+ // const decompress = (i: number) => round((Q / 2 ** d) * i);
827
+ decode: (i) => i * Q + a >>> d
828
+ };
829
+ };
830
+ var byteCoder = (d) => crystals.bitsCoder(d, { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i } );
831
+ var polyCoder = (d) => d === 12 ? byteCoder(12) : crystals.bitsCoder(d, compress(d));
832
+ function polyAdd(a_, b_) {
833
+ const a = a_;
834
+ const b = b_;
835
+ for (let i = 0; i < N; i++)
836
+ a[i] = crystals.mod(a[i] + b[i]);
1128
837
  }
1129
- var SLOT_KEY_UNIVERSE = /* @__PURE__ */ new Set(["epk", "kem_ct", "wrap"]);
1130
- function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath, errors) {
1131
- const foreignField = descriptor.field === "epk" ? "kem_ct" : "epk";
1132
- if (rawKeys.has(foreignField)) {
1133
- errors.push(
1134
- issue(
1135
- "ENC_SLOT_INVALID_SHAPE",
1136
- [...slotPath, foreignField],
1137
- `slot carries '${foreignField}' but kem='${kem}' expects '${descriptor.field}'`
1138
- )
1139
- );
1140
- }
1141
- for (const k of rawKeys) {
1142
- if (!SLOT_KEY_UNIVERSE.has(k)) {
1143
- errors.push(
1144
- issue(
1145
- "ENC_SLOT_INVALID_SHAPE",
1146
- [...slotPath, k],
1147
- `slot carries unexpected key '${k}'; a slot is a 2-key map {${descriptor.field}, wrap}`
1148
- )
1149
- );
1150
- }
1151
- }
1152
- if (descriptor.field === "epk") {
1153
- if (slot.epk === void 0) {
1154
- errors.push(
1155
- issue(
1156
- "ENC_SLOT_INVALID_SHAPE",
1157
- [...slotPath, "epk"],
1158
- `slot for kem='${kem}' is missing required 'epk'`
1159
- )
1160
- );
1161
- } else if (slot.epk.length !== descriptor.fieldLength) {
1162
- errors.push(
1163
- issue(
1164
- KEM_FIELD_LENGTH_CODE.epk,
1165
- [...slotPath, "epk"],
1166
- `slot.epk length ${slot.epk.length} != ${descriptor.fieldLength} for ${kem}`
1167
- )
1168
- );
1169
- }
1170
- } else {
1171
- if (slot.kem_ct === void 0) {
1172
- errors.push(
1173
- issue(
1174
- "ENC_SLOT_INVALID_SHAPE",
1175
- [...slotPath, "kem_ct"],
1176
- `slot for kem='${kem}' is missing required 'kem_ct'`
1177
- )
1178
- );
1179
- } else {
1180
- const reassembled = bytesChunkArrayConcat(slot.kem_ct).length;
1181
- if (reassembled !== descriptor.fieldLength) {
1182
- errors.push(
1183
- issue(
1184
- KEM_FIELD_LENGTH_CODE.kem_ct,
1185
- [...slotPath, "kem_ct"],
1186
- `slot.kem_ct reassembles to ${reassembled} bytes != ${descriptor.fieldLength} for ${kem}`
1187
- )
1188
- );
1189
- }
1190
- }
1191
- }
1192
- if (slot.wrap === void 0) {
1193
- errors.push(
1194
- issue(
1195
- "ENC_SLOT_INVALID_SHAPE",
1196
- [...slotPath, "wrap"],
1197
- `slot for kem='${kem}' is missing required 'wrap'`
1198
- )
1199
- );
1200
- } else if (slot.wrap.length !== descriptor.wrapLength) {
1201
- errors.push(
1202
- issue(
1203
- "WRAP_LENGTH_MISMATCH",
1204
- [...slotPath, "wrap"],
1205
- `slot.wrap length ${slot.wrap.length} != ${descriptor.wrapLength}`
1206
- )
1207
- );
838
+ function polySub(a_, b_) {
839
+ const a = a_;
840
+ const b = b_;
841
+ for (let i = 0; i < N; i++)
842
+ a[i] = crystals.mod(a[i] - b[i]);
843
+ }
844
+ function BaseCaseMultiply(a0, a1, b0, b1, zeta) {
845
+ const c0 = crystals.mod(a1 * b1 * zeta + a0 * b0);
846
+ const c1 = crystals.mod(a0 * b1 + a1 * b0);
847
+ return { c0, c1 };
848
+ }
849
+ function MultiplyNTTs(f_, g_) {
850
+ const f = f_;
851
+ const g = g_;
852
+ for (let i = 0; i < N / 2; i++) {
853
+ let z3 = crystals.nttZetas[64 + (i >> 1)];
854
+ if (i & 1)
855
+ z3 = -z3;
856
+ const { c0, c1 } = BaseCaseMultiply(f[2 * i + 0], f[2 * i + 1], g[2 * i + 0], g[2 * i + 1], z3);
857
+ f[2 * i + 0] = c0;
858
+ f[2 * i + 1] = c1;
1208
859
  }
860
+ return f;
1209
861
  }
1210
- function rawSlotKeySets(rawEnc) {
1211
- const slots = mapLikeGet(rawEnc, "slots");
1212
- if (!Array.isArray(slots)) return [];
1213
- return slots.map((slot) => {
1214
- const keys = /* @__PURE__ */ new Set();
1215
- if (slot instanceof Map) {
1216
- for (const k of slot.keys()) if (typeof k === "string") keys.add(k);
1217
- } else if (typeof slot === "object" && slot !== null) {
1218
- for (const k of Object.keys(slot)) keys.add(k);
862
+ function SampleNTT(xof_) {
863
+ const xof = xof_;
864
+ const r = new Uint16Array(N);
865
+ for (let j = 0; j < N; ) {
866
+ const b = xof();
867
+ if (b.length % 3)
868
+ throw new Error("SampleNTT: unaligned block");
869
+ for (let i = 0; j < N && i + 3 <= b.length; i += 3) {
870
+ const d1 = (b[i + 0] >> 0 | b[i + 1] << 8) & 4095;
871
+ const d2 = (b[i + 1] >> 4 | b[i + 2] << 4) & 4095;
872
+ if (d1 < Q)
873
+ r[j++] = d1;
874
+ if (j < N && d2 < Q)
875
+ r[j++] = d2;
1219
876
  }
1220
- return keys;
1221
- });
1222
- }
1223
- function mapLikeGet(value, key) {
1224
- if (value instanceof Map) return value.get(key);
1225
- if (typeof value === "object" && value !== null) {
1226
- return value[key];
1227
- }
1228
- return void 0;
1229
- }
1230
- function checkMerkleCommit(commit, idx, errors) {
1231
- const basePath = ["merkle", idx];
1232
- if (!(commit.alg in MERKLE_COMMIT_ALG_LENGTHS)) {
1233
- errors.push(
1234
- issue(
1235
- "UNSUPPORTED_MERKLE_COMMIT_ALG",
1236
- [...basePath, "alg"],
1237
- `unknown merkle commitment alg: ${commit.alg}`
1238
- )
1239
- );
1240
- return;
1241
- }
1242
- const expected = MERKLE_COMMIT_ALG_LENGTHS[commit.alg];
1243
- if (commit.root.length !== expected) {
1244
- errors.push(
1245
- issue(
1246
- "HASH_DIGEST_LENGTH_MISMATCH",
1247
- [...basePath, "root"],
1248
- `merkle entry root length ${commit.root.length} != ${expected} for ${commit.alg}`
1249
- )
1250
- );
1251
- }
1252
- if (commit.uris) {
1253
- checkItemUris(commit.uris, [...basePath, "uris"], errors);
1254
877
  }
878
+ return r;
1255
879
  }
1256
- function checkSigEntry(entry, idx, errors, info) {
1257
- if (entry.cose_key !== void 0) {
1258
- const keyIssue = inspectCoseKey(entry.cose_key, idx);
1259
- if (keyIssue !== null) {
1260
- errors.push(keyIssue);
1261
- return;
880
+ var sampleCBDBytes = (buf, eta) => {
881
+ const r = new Uint16Array(N);
882
+ const b32 = utils_js.u32(buf);
883
+ utils_js.swap32IfBE(b32);
884
+ let len = 0;
885
+ for (let i = 0, p = 0, bb = 0, t0 = 0; i < b32.length; i++) {
886
+ let b = b32[i];
887
+ for (let j = 0; j < 32; j++) {
888
+ bb += b & 1;
889
+ b >>= 1;
890
+ len += 1;
891
+ if (len === eta) {
892
+ t0 = bb;
893
+ bb = 0;
894
+ } else if (len === 2 * eta) {
895
+ r[p++] = crystals.mod(t0 - bb);
896
+ bb = 0;
897
+ len = 0;
898
+ }
1262
899
  }
1263
900
  }
1264
- const merged = bytesChunkArrayConcat(entry.cose_sign1);
1265
- let cose;
1266
- try {
1267
- cose = decodeCoseSign1(merged);
1268
- } catch (cause) {
1269
- errors.push(
1270
- issue(
1271
- "MALFORMED_SIG_COSE_SIGN1",
1272
- ["sigs", idx],
1273
- cause instanceof CoseVerifyError || cause instanceof Error ? cause.message : String(cause)
1274
- )
1275
- );
1276
- return;
1277
- }
1278
- if (cose.payload !== null) {
1279
- errors.push(
1280
- issue(
1281
- "MALFORMED_SIG_COSE_SIGN1",
1282
- ["sigs", idx],
1283
- "COSE_Sign1 payload must be null (detached); attached form forbidden"
1284
- )
1285
- );
1286
- return;
1287
- }
1288
- const alg = cose.protectedHeader.get(1);
1289
- if (typeof alg !== "number" || !KNOWN_SIG_ALG_IDS.has(alg)) {
1290
- info.push(
1291
- issue(
1292
- "SIGNATURE_UNSUPPORTED",
1293
- ["sigs", idx],
1294
- `COSE_Sign1 protected alg ${String(alg)} not in {-8, -19}`
1295
- )
1296
- );
1297
- }
1298
- const protectedKid = cose.protectedHeader.get(4);
1299
- if (protectedKid instanceof Uint8Array && protectedKid.length === 32 && entry.cose_key !== void 0) {
1300
- errors.push(
1301
- issue(
1302
- "SIG_ENTRY_KID_COSE_KEY_CONFLICT",
1303
- ["sigs", idx],
1304
- "sigs[i] carries both a 32-byte protected `kid` (path 1) and an inline `cose_key` (path 2); paths are mutually exclusive"
1305
- )
1306
- );
1307
- }
901
+ utils_js.swap32IfBE(b32);
902
+ if (len)
903
+ throw new Error(`sampleCBD: leftover bits: ${len}`);
904
+ return r;
905
+ };
906
+ function sampleCBD(PRF_, seed, nonce, eta) {
907
+ const PRF = PRF_;
908
+ return sampleCBDBytes(PRF(eta * N / 4, seed, nonce), eta);
1308
909
  }
1309
- function inspectCoseKey(keyChunks, i) {
1310
- let decoded;
1311
- try {
1312
- decoded = decodeCanonicalCbor(bytesChunkArrayConcat(keyChunks));
1313
- } catch (cause) {
1314
- return issue(
1315
- "MALFORMED_SIG_COSE_SIGN1",
1316
- ["sigs", i, "cose_key"],
1317
- `sigs[${i}].cose_key failed to decode as cbor<COSE_Key>: ${cause instanceof Error ? cause.message : String(cause)}`
1318
- );
1319
- }
1320
- const getLabel = (label) => {
1321
- if (decoded instanceof Map) return decoded.get(label);
1322
- if (typeof decoded === "object" && decoded !== null) {
1323
- return decoded[String(label)];
1324
- }
1325
- return void 0;
1326
- };
1327
- const hasLabel = (label) => {
1328
- if (decoded instanceof Map) return decoded.has(label);
1329
- if (typeof decoded === "object" && decoded !== null) {
1330
- return Object.prototype.hasOwnProperty.call(decoded, String(label));
1331
- }
1332
- return false;
1333
- };
1334
- if (hasLabel(-4)) {
1335
- return issue(
1336
- "SIG_PRIVATE_KEY_LEAKED",
1337
- ["sigs", i, "cose_key"],
1338
- "cose_key carries COSE_Key private-key material (label -4, the OKP/EC2 private scalar d); publishing a private key on the permanent ledger is forbidden"
1339
- );
1340
- }
1341
- const kty = getLabel(1);
1342
- if (kty !== 1) {
1343
- return issue(
1344
- "MALFORMED_SIG_COSE_SIGN1",
1345
- ["sigs", i, "cose_key"],
1346
- `sigs[${i}].cose_key COSE_Key kty (label 1) must be 1 (OKP); got ${String(kty)}`
1347
- );
1348
- }
1349
- const crv = getLabel(-1);
1350
- if (crv !== 6) {
1351
- return issue(
1352
- "MALFORMED_SIG_COSE_SIGN1",
1353
- ["sigs", i, "cose_key"],
1354
- `sigs[${i}].cose_key COSE_Key crv (label -1) must be 6 (Ed25519); got ${String(crv)}`
1355
- );
1356
- }
1357
- if (!hasLabel(-2)) {
1358
- return issue(
1359
- "MALFORMED_SIG_COSE_SIGN1",
1360
- ["sigs", i, "cose_key"],
1361
- `sigs[${i}].cose_key COSE_Key missing label -2 (Ed25519 public-key bytes)`
1362
- );
1363
- }
1364
- const x = getLabel(-2);
1365
- if (!(x instanceof Uint8Array) || x.length !== 32) {
1366
- const got = x instanceof Uint8Array ? `${x.length}-byte bstr` : typeof x;
1367
- return issue(
1368
- "MALFORMED_SIG_COSE_SIGN1",
1369
- ["sigs", i, "cose_key"],
1370
- `sigs[${i}].cose_key COSE_Key label -2 must be a 32-byte byte string (Ed25519 public key); got ${got}`
1371
- );
910
+ var genKPKE = (opts_) => {
911
+ const opts2 = opts_;
912
+ const { K, PRF, XOF, HASH512, ETA1, ETA2, du, dv } = opts2;
913
+ const poly1 = polyCoder(1);
914
+ const polyV = polyCoder(dv);
915
+ const polyU = polyCoder(du);
916
+ const publicCoder = splitCoder("publicKey", vecCoder(polyCoder(12), K), 32);
917
+ const secretCoder = vecCoder(polyCoder(12), K);
918
+ const cipherCoder = splitCoder("ciphertext", vecCoder(polyU, K), polyV);
919
+ const seedCoder = splitCoder("seed", 32, 32);
920
+ return {
921
+ secretCoder,
922
+ lengths: {
923
+ secretKey: secretCoder.bytesLen,
924
+ publicKey: publicCoder.bytesLen,
925
+ cipherText: cipherCoder.bytesLen
926
+ },
927
+ keygen: (seed) => {
928
+ abytesDoc(seed, 32, "seed");
929
+ const seedDst = new Uint8Array(33);
930
+ seedDst.set(seed);
931
+ seedDst[32] = K;
932
+ const seedHash = HASH512(seedDst);
933
+ const [rho, sigma] = seedCoder.decode(seedHash);
934
+ const sHat = [];
935
+ const tHat = [];
936
+ for (let i = 0; i < K; i++)
937
+ sHat.push(crystals.NTT.encode(sampleCBD(PRF, sigma, i, ETA1)));
938
+ const x = XOF(rho);
939
+ for (let i = 0; i < K; i++) {
940
+ const e = crystals.NTT.encode(sampleCBD(PRF, sigma, K + i, ETA1));
941
+ for (let j = 0; j < K; j++) {
942
+ const aji = SampleNTT(x.get(j, i));
943
+ polyAdd(e, MultiplyNTTs(aji, sHat[j]));
944
+ }
945
+ tHat.push(e);
946
+ }
947
+ x.clean();
948
+ const res = {
949
+ publicKey: publicCoder.encode([tHat, rho]),
950
+ secretKey: secretCoder.encode(sHat)
951
+ };
952
+ cleanBytes(rho, sigma, sHat, tHat, seedDst, seedHash);
953
+ return res;
954
+ },
955
+ encrypt: (publicKey, msg, seed) => {
956
+ const [tHat, rho] = publicCoder.decode(publicKey);
957
+ const rHat = [];
958
+ for (let i = 0; i < K; i++)
959
+ rHat.push(crystals.NTT.encode(sampleCBD(PRF, seed, i, ETA1)));
960
+ const x = XOF(rho);
961
+ const tmp2 = new Uint16Array(N);
962
+ const u = [];
963
+ for (let i = 0; i < K; i++) {
964
+ const e1 = sampleCBD(PRF, seed, K + i, ETA2);
965
+ const tmp = new Uint16Array(N);
966
+ for (let j = 0; j < K; j++) {
967
+ const aij = SampleNTT(x.get(i, j));
968
+ polyAdd(tmp, MultiplyNTTs(aij, rHat[j]));
969
+ }
970
+ polyAdd(e1, crystals.NTT.decode(tmp));
971
+ u.push(e1);
972
+ polyAdd(tmp2, MultiplyNTTs(tHat[i], rHat[i]));
973
+ cleanBytes(tmp);
974
+ }
975
+ x.clean();
976
+ const e2 = sampleCBD(PRF, seed, 2 * K, ETA2);
977
+ polyAdd(e2, crystals.NTT.decode(tmp2));
978
+ const v = poly1.decode(msg);
979
+ polyAdd(v, e2);
980
+ cleanBytes(tHat, rHat, tmp2, e2);
981
+ return cipherCoder.encode([u, v]);
982
+ },
983
+ decrypt: (cipherText, privateKey) => {
984
+ const [u, v] = cipherCoder.decode(cipherText);
985
+ const sk = secretCoder.decode(privateKey);
986
+ const tmp = new Uint16Array(N);
987
+ for (let i = 0; i < K; i++)
988
+ polyAdd(tmp, MultiplyNTTs(sk[i], crystals.NTT.encode(u[i])));
989
+ polySub(v, crystals.NTT.decode(tmp));
990
+ cleanBytes(tmp, sk, u);
991
+ return poly1.encode(v);
992
+ }
993
+ };
994
+ };
995
+ function createKyber(opts2) {
996
+ const rawOpts = opts2;
997
+ const KPKE = genKPKE(rawOpts);
998
+ const { HASH256, HASH512, KDF } = rawOpts;
999
+ const { secretCoder: KPKESecretCoder, lengths } = KPKE;
1000
+ const secretCoder = splitCoder("secretKey", lengths.secretKey, lengths.publicKey, 32, 32);
1001
+ const msgLen = 32;
1002
+ const seedLen = 64;
1003
+ const kemLengths = Object.freeze({
1004
+ ...lengths,
1005
+ seed: 64,
1006
+ msg: msgLen,
1007
+ msgRand: msgLen,
1008
+ secretKey: secretCoder.bytesLen
1009
+ });
1010
+ return Object.freeze({
1011
+ info: Object.freeze({ type: "ml-kem" }),
1012
+ lengths: kemLengths,
1013
+ keygen: (seed = randomBytes(seedLen)) => {
1014
+ abytesDoc(seed, seedLen, "seed");
1015
+ const { publicKey, secretKey: sk } = KPKE.keygen(seed.subarray(0, 32));
1016
+ const publicKeyHash = HASH256(publicKey);
1017
+ const secretKey = secretCoder.encode([sk, publicKey, publicKeyHash, seed.subarray(32)]);
1018
+ cleanBytes(sk, publicKeyHash);
1019
+ return {
1020
+ publicKey,
1021
+ secretKey
1022
+ };
1023
+ },
1024
+ getPublicKey: (secretKey) => {
1025
+ const [_sk, publicKey, _publicKeyHash, _z] = secretCoder.decode(secretKey);
1026
+ return Uint8Array.from(publicKey);
1027
+ },
1028
+ encapsulate: (publicKey, msg = randomBytes(msgLen)) => {
1029
+ abytesDoc(publicKey, lengths.publicKey, "publicKey");
1030
+ abytesDoc(msg, msgLen, "message");
1031
+ const eke = publicKey.subarray(0, 384 * opts2.K);
1032
+ const ek = KPKESecretCoder.encode(KPKESecretCoder.decode(copyBytes(eke)));
1033
+ if (!equalBytes(ek, eke)) {
1034
+ cleanBytes(ek);
1035
+ throw new Error("ML-KEM.encapsulate: wrong publicKey modulus");
1036
+ }
1037
+ cleanBytes(ek);
1038
+ const kr = HASH512.create().update(msg).update(HASH256(publicKey)).digest();
1039
+ const cipherText = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
1040
+ cleanBytes(kr.subarray(32));
1041
+ return {
1042
+ cipherText,
1043
+ sharedSecret: kr.subarray(0, 32)
1044
+ };
1045
+ },
1046
+ decapsulate: (cipherText, secretKey) => {
1047
+ abytesDoc(secretKey, secretCoder.bytesLen, "secretKey");
1048
+ abytesDoc(cipherText, lengths.cipherText, "cipherText");
1049
+ const k768 = secretCoder.bytesLen - 96;
1050
+ const start = k768 + 32;
1051
+ const test = HASH256(secretKey.subarray(k768 / 2, start));
1052
+ if (!equalBytes(test, secretKey.subarray(start, start + 32)))
1053
+ throw new Error("invalid secretKey: hash check failed");
1054
+ const [sk, publicKey, publicKeyHash, z3] = secretCoder.decode(secretKey);
1055
+ const msg = KPKE.decrypt(cipherText, sk);
1056
+ const kr = HASH512.create().update(msg).update(publicKeyHash).digest();
1057
+ const Khat = kr.subarray(0, 32);
1058
+ const cipherText2 = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
1059
+ const isValid = equalBytes(cipherText, cipherText2);
1060
+ const Kbar = KDF.create({ dkLen: 32 }).update(z3).update(cipherText).digest();
1061
+ cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar);
1062
+ return isValid ? Khat : Kbar;
1063
+ }
1064
+ });
1065
+ }
1066
+ function shakePRF(dkLen, key, nonce) {
1067
+ return sha3_js.shake256.create({ dkLen }).update(key).update(new Uint8Array([nonce])).digest();
1068
+ }
1069
+ var opts = /* @__PURE__ */ (() => ({
1070
+ HASH256: sha3_js.sha3_256,
1071
+ HASH512: sha3_js.sha3_512,
1072
+ KDF: sha3_js.shake256,
1073
+ XOF: XOF128,
1074
+ PRF: shakePRF
1075
+ }))();
1076
+ var mk = (params) => createKyber({
1077
+ ...opts,
1078
+ ...params
1079
+ });
1080
+ var ml_kem768 = /* @__PURE__ */ (() => mk(PARAMS[768]))();
1081
+
1082
+ // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/hybrid.js
1083
+ function ecKeygen(curve, allowZeroKey = false) {
1084
+ const lengths = curve.lengths;
1085
+ let keygen = curve.keygen;
1086
+ if (allowZeroKey) {
1087
+ if (!("getSharedSecret" in curve && "sign" in curve && "verify" in curve))
1088
+ throw new Error("allowZeroKey requires a Weierstrass curve");
1089
+ const wCurve = curve;
1090
+ const Fn = wCurve.Point.Fn;
1091
+ keygen = (seed = randomBytes(lengths.seed)) => {
1092
+ utils_js.abytes(seed, lengths.seed, "seed");
1093
+ const seedScalar = Fn.isLE ? utils_js$1.bytesToNumberLE(seed) : utils_js$1.bytesToNumberBE(seed);
1094
+ const secretKey = Fn.toBytes(Fn.create(seedScalar));
1095
+ return {
1096
+ secretKey,
1097
+ publicKey: curve.getPublicKey(secretKey)
1098
+ };
1099
+ };
1372
1100
  }
1373
- return null;
1101
+ return {
1102
+ lengths: { secretKey: lengths.secretKey, publicKey: lengths.publicKey, seed: lengths.seed },
1103
+ keygen: (seed) => keygen(seed),
1104
+ getPublicKey: (secretKey) => curve.getPublicKey(secretKey)
1105
+ };
1374
1106
  }
1375
- var ACCEPTED_CIDV1_MULTIBASE = /* @__PURE__ */ new Set(["b", "B", "f", "F", "z"]);
1376
- var ACCEPTED_MULTICODECS = /* @__PURE__ */ new Set([85, 112, 113]);
1377
- var ACCEPTED_MULTIHASHES = /* @__PURE__ */ new Map([
1378
- [18, 32],
1379
- [45600, 32]
1380
- ]);
1381
- function validateCidProfile(cid) {
1382
- if (cid.length === 0) return false;
1383
- if (cid.startsWith("Qm")) {
1384
- let decoded;
1107
+ function ecdhKem(curve, allowZeroKey = false) {
1108
+ const kg = ecKeygen(curve, allowZeroKey);
1109
+ if (!curve.getSharedSecret)
1110
+ throw new Error("wrong curve");
1111
+ return {
1112
+ lengths: { ...kg.lengths, msg: kg.lengths.seed, cipherText: kg.lengths.publicKey },
1113
+ keygen: kg.keygen,
1114
+ getPublicKey: kg.getPublicKey,
1115
+ encapsulate(publicKey, rand = randomBytes(curve.lengths.seed)) {
1116
+ const seed = copyBytes(rand);
1117
+ let ek = void 0;
1118
+ try {
1119
+ ek = this.keygen(seed).secretKey;
1120
+ const sharedSecret = this.decapsulate(publicKey, ek);
1121
+ const cipherText = curve.getPublicKey(ek);
1122
+ return { sharedSecret, cipherText };
1123
+ } finally {
1124
+ cleanBytes(seed);
1125
+ if (ek)
1126
+ cleanBytes(ek);
1127
+ }
1128
+ },
1129
+ decapsulate(cipherText, secretKey) {
1130
+ const res = curve.getSharedSecret(secretKey, cipherText);
1131
+ return curve.lengths.publicKeyHasPrefix ? res.subarray(1) : res;
1132
+ }
1133
+ };
1134
+ }
1135
+ function splitLengths(lst, name) {
1136
+ return splitCoder(name, ...lst.map((i) => {
1137
+ if (typeof i.lengths[name] !== "number")
1138
+ throw new Error("wrong length: " + name);
1139
+ return i.lengths[name];
1140
+ }));
1141
+ }
1142
+ function expandSeedXof(xof) {
1143
+ return ((seed, seedLen) => xof(seed, { dkLen: seedLen }));
1144
+ }
1145
+ function combineKeys(realSeedLen, expandSeed_, ...ck_) {
1146
+ const expandSeed = expandSeed_;
1147
+ const ck = ck_;
1148
+ const seedCoder = splitLengths(ck, "seed");
1149
+ const pkCoder = splitLengths(ck, "publicKey");
1150
+ utils_js.anumber(realSeedLen);
1151
+ function expandDecapsulationKey(seed) {
1152
+ utils_js.abytes(seed, realSeedLen);
1153
+ const expandedRaw = expandSeed(seed, seedCoder.bytesLen);
1154
+ const expandedSeed = expandedRaw.buffer === seed.buffer ? copyBytes(expandedRaw) : expandedRaw;
1155
+ const expanded = [];
1156
+ const keySecret = [];
1157
+ const secretKey = [];
1158
+ const publicKey = [];
1159
+ let ok = false;
1385
1160
  try {
1386
- decoded = decodeBase58btc(cid);
1387
- } catch {
1388
- return false;
1161
+ for (const part of seedCoder.decode(expandedSeed))
1162
+ expanded.push(copyBytes(part));
1163
+ for (let i = 0; i < ck.length; i++) {
1164
+ const keys = ck[i].keygen(expanded[i]);
1165
+ keySecret.push(keys.secretKey);
1166
+ secretKey.push(copyBytes(keys.secretKey));
1167
+ publicKey.push(keys.publicKey);
1168
+ }
1169
+ ok = true;
1170
+ return { secretKey, publicKey };
1171
+ } finally {
1172
+ cleanBytes(expandedSeed, expanded, keySecret);
1173
+ if (!ok)
1174
+ cleanBytes(secretKey);
1389
1175
  }
1390
- return decoded.length === 34 && decoded[0] === 18 && decoded[1] === 32;
1391
1176
  }
1392
- const mbPrefix = cid[0];
1393
- if (!ACCEPTED_CIDV1_MULTIBASE.has(mbPrefix)) return false;
1394
- let bytes;
1177
+ return {
1178
+ info: { lengths: { seed: realSeedLen, publicKey: pkCoder.bytesLen, secretKey: realSeedLen } },
1179
+ getPublicKey(secretKey) {
1180
+ return this.keygen(secretKey).publicKey;
1181
+ },
1182
+ keygen(seed = randomBytes(realSeedLen)) {
1183
+ const { publicKey: pk, secretKey } = expandDecapsulationKey(seed);
1184
+ try {
1185
+ const publicKey = pkCoder.encode(pk);
1186
+ return { secretKey: seed, publicKey };
1187
+ } finally {
1188
+ cleanBytes(pk);
1189
+ cleanBytes(secretKey);
1190
+ }
1191
+ },
1192
+ expandDecapsulationKey,
1193
+ realSeedLen
1194
+ };
1195
+ }
1196
+ function combineKEMS(realSeedLen, realMsgLen, expandSeed, combiner, ...kems) {
1197
+ const rawCombiner = combiner;
1198
+ const rawKems = kems;
1199
+ const keys = combineKeys(realSeedLen, expandSeed, ...rawKems);
1200
+ const ctCoder = splitLengths(rawKems, "cipherText");
1201
+ const pkCoder = splitLengths(rawKems, "publicKey");
1202
+ const msgCoder = splitLengths(rawKems, "msg");
1203
+ utils_js.anumber(realMsgLen);
1204
+ const lengths = Object.freeze({
1205
+ ...keys.info.lengths,
1206
+ msg: realMsgLen,
1207
+ msgRand: msgCoder.bytesLen,
1208
+ cipherText: ctCoder.bytesLen
1209
+ });
1210
+ return Object.freeze({
1211
+ lengths,
1212
+ getPublicKey: keys.getPublicKey,
1213
+ keygen: keys.keygen,
1214
+ encapsulate(pk, randomness = randomBytes(msgCoder.bytesLen)) {
1215
+ const pks = pkCoder.decode(pk);
1216
+ const rand = msgCoder.decode(randomness);
1217
+ const sharedSecret = [];
1218
+ const cipherText = [];
1219
+ try {
1220
+ for (let i = 0; i < rawKems.length; i++) {
1221
+ const enc = rawKems[i].encapsulate(pks[i], rand[i]);
1222
+ sharedSecret.push(enc.sharedSecret);
1223
+ cipherText.push(enc.cipherText);
1224
+ }
1225
+ return {
1226
+ // Detach the combiner result before cleanup: a caller-provided combiner may alias one of
1227
+ // the child sharedSecret buffers, and those child buffers are zeroized immediately below.
1228
+ sharedSecret: copyBytes(rawCombiner(pks, cipherText, sharedSecret)),
1229
+ cipherText: ctCoder.encode(cipherText)
1230
+ };
1231
+ } finally {
1232
+ cleanBytes(sharedSecret, cipherText);
1233
+ }
1234
+ },
1235
+ decapsulate(ct, seed) {
1236
+ const cts = ctCoder.decode(ct);
1237
+ const { publicKey, secretKey } = keys.expandDecapsulationKey(seed);
1238
+ const sharedSecret = rawKems.map((i, j) => i.decapsulate(cts[j], secretKey[j]));
1239
+ try {
1240
+ return copyBytes(rawCombiner(publicKey, cts, sharedSecret));
1241
+ } finally {
1242
+ cleanBytes(secretKey, sharedSecret);
1243
+ }
1244
+ }
1245
+ });
1246
+ }
1247
+ var x25519kem = /* @__PURE__ */ ecdhKem(ed25519_js.x25519);
1248
+ var ml_kem768_x25519 = /* @__PURE__ */ (() => combineKEMS(
1249
+ 32,
1250
+ 32,
1251
+ expandSeedXof(sha3_js.shake256),
1252
+ // Awesome label, so much escaping hell in a single line.
1253
+ (pk, ct, ss) => sha3_js.sha3_256(utils_js$1.concatBytes(ss[0], ss[1], ct[1], pk[1], utils_js$1.asciiToBytes("\\.//^\\"))),
1254
+ ml_kem768,
1255
+ x25519kem
1256
+ ))();
1257
+ var XWing = /* @__PURE__ */ (() => ml_kem768_x25519)();
1258
+ var AeadVerificationError = class extends Error {
1259
+ code = "aead_verification_failed";
1260
+ constructor(message, options) {
1261
+ super(message, options);
1262
+ this.name = "AeadVerificationError";
1263
+ }
1264
+ };
1265
+ function chacha20Poly1305Decrypt(opts2) {
1395
1266
  try {
1396
- bytes = decodeMultibase(mbPrefix, cid.slice(1));
1397
- } catch {
1398
- return false;
1267
+ return chacha_js.chacha20poly1305(opts2.key, opts2.nonce, opts2.aad).decrypt(opts2.ciphertext);
1268
+ } catch (cause) {
1269
+ throw new AeadVerificationError("chacha20-poly1305 decrypt failed", { cause });
1270
+ }
1271
+ }
1272
+ function xchacha20Poly1305Decrypt(opts2) {
1273
+ try {
1274
+ return chacha_js.xchacha20poly1305(opts2.key, opts2.nonce, opts2.aad).decrypt(opts2.ciphertext);
1275
+ } catch (cause) {
1276
+ throw new AeadVerificationError("xchacha20-poly1305 decrypt failed", { cause });
1277
+ }
1278
+ }
1279
+ function hkdfSha256(opts2) {
1280
+ return hkdf_js.hkdf(sha2_js.sha256, opts2.ikm, opts2.salt, opts2.info, opts2.length);
1281
+ }
1282
+ var MLKEM768X25519_ENC_LENGTH = 1120;
1283
+ var MLKEM768X25519_SEED_LENGTH = 32;
1284
+ function mlkem768x25519Keygen(seed) {
1285
+ if (seed.length !== MLKEM768X25519_SEED_LENGTH) {
1286
+ throw new Error(
1287
+ `mlkem768x25519 seed must be ${MLKEM768X25519_SEED_LENGTH} bytes, got ${seed.length}`
1288
+ );
1289
+ }
1290
+ const { secretKey, publicKey } = XWing.keygen(seed);
1291
+ return { secretSeed: secretKey, publicKey };
1292
+ }
1293
+ function mlkem768x25519Decapsulate(opts2) {
1294
+ if (opts2.secretSeed.length !== MLKEM768X25519_SEED_LENGTH) {
1295
+ throw new Error(
1296
+ `mlkem768x25519 secret seed must be ${MLKEM768X25519_SEED_LENGTH} bytes, got ${opts2.secretSeed.length}`
1297
+ );
1298
+ }
1299
+ if (opts2.enc.length !== MLKEM768X25519_ENC_LENGTH) {
1300
+ throw new Error(
1301
+ `mlkem768x25519 enc must be ${MLKEM768X25519_ENC_LENGTH} bytes, got ${opts2.enc.length}`
1302
+ );
1303
+ }
1304
+ return XWing.decapsulate(opts2.enc, opts2.secretSeed);
1305
+ }
1306
+ var X25519LowOrderPointError = class extends Error {
1307
+ code = "X25519_LOW_ORDER_POINT";
1308
+ constructor(options) {
1309
+ super("x25519 ECDH rejected: peer public key is a small-order point", options);
1310
+ this.name = "X25519LowOrderPointError";
1311
+ }
1312
+ };
1313
+ var NOBLE_LOW_ORDER_MESSAGE = "invalid private or public key received";
1314
+ function x25519PublicKey(opts2) {
1315
+ return ed25519_js.x25519.getPublicKey(opts2.secretKey);
1316
+ }
1317
+ function x25519Ecdh(opts2) {
1318
+ try {
1319
+ return ed25519_js.x25519.getSharedSecret(opts2.secretKey, opts2.theirPublicKey);
1320
+ } catch (e) {
1321
+ if (e instanceof Error && e.message === NOBLE_LOW_ORDER_MESSAGE) {
1322
+ throw new X25519LowOrderPointError({ cause: e });
1323
+ }
1324
+ throw e;
1325
+ }
1326
+ }
1327
+ var EciesSealedPoeError = class extends Error {
1328
+ code;
1329
+ constructor(code, message, options) {
1330
+ super(message, options);
1331
+ this.name = "EciesSealedPoeError";
1332
+ this.code = code;
1333
+ }
1334
+ };
1335
+ var CHUNK_MAX_BYTES = 64;
1336
+ function chunkKemCt(value) {
1337
+ if (value.length === 0) {
1338
+ throw new Error("chunkKemCt: refusing to chunk an empty byte string");
1339
+ }
1340
+ const chunks = [];
1341
+ for (let i = 0; i < value.length; i += CHUNK_MAX_BYTES) {
1342
+ chunks.push(value.subarray(i, Math.min(i + CHUNK_MAX_BYTES, value.length)));
1343
+ }
1344
+ return chunks;
1345
+ }
1346
+ function joinKemCt(chunks) {
1347
+ let total = 0;
1348
+ for (const c of chunks) total += c.length;
1349
+ const out = new Uint8Array(total);
1350
+ let offset = 0;
1351
+ for (const c of chunks) {
1352
+ out.set(c, offset);
1353
+ offset += c.length;
1399
1354
  }
1400
- if (bytes.length < 4) return false;
1401
- const versionParse = readVarint(bytes, 0);
1402
- if (versionParse === null || versionParse.value !== 1) return false;
1403
- const codecParse = readVarint(bytes, versionParse.next);
1404
- if (codecParse === null) return false;
1405
- if (!ACCEPTED_MULTICODECS.has(codecParse.value)) return false;
1406
- const mhParse = readVarint(bytes, codecParse.next);
1407
- if (mhParse === null) return false;
1408
- const lenParse = readVarint(bytes, mhParse.next);
1409
- if (lenParse === null) return false;
1410
- const digestLen = lenParse.value;
1411
- const expectedLen = ACCEPTED_MULTIHASHES.get(mhParse.value);
1412
- if (expectedLen === void 0 || digestLen !== expectedLen) return false;
1413
- if (lenParse.next + digestLen !== bytes.length) return false;
1414
- return true;
1355
+ return out;
1415
1356
  }
1416
- function readVarint(bytes, start) {
1417
- let value = 0;
1418
- let shift = 0;
1419
- let i = start;
1420
- while (i < bytes.length) {
1421
- const b = bytes[i];
1422
- value |= (b & 127) << shift;
1423
- i++;
1424
- if ((b & 128) === 0) return { value, next: i };
1425
- shift += 7;
1426
- if (shift > 28) return null;
1357
+ function canonicalizeSlots(slots, kem) {
1358
+ if (kem === "x25519") {
1359
+ return slots.map((s) => ({ epk: s.epk, wrap: s.wrap }));
1427
1360
  }
1428
- return null;
1361
+ return slots.map((s) => ({
1362
+ kem_ct: chunkKemCt(joinKemCt(s.kem_ct)),
1363
+ wrap: s.wrap
1364
+ }));
1429
1365
  }
1430
- function decodeMultibase(prefix, body) {
1431
- switch (prefix) {
1432
- case "b":
1433
- return decodeBase32(body.toLowerCase(), "rfc4648-lower");
1434
- case "B":
1435
- return decodeBase32(body.toUpperCase(), "rfc4648-upper");
1436
- case "f":
1437
- return decodeBase16(body.toLowerCase());
1438
- case "F":
1439
- return decodeBase16(body.toUpperCase());
1440
- case "z":
1441
- return decodeBase58btc(body);
1442
- default:
1443
- throw new Error(`unsupported multibase prefix ${prefix}`);
1366
+ function encodeCanonicalCbor3(value) {
1367
+ return cbor2.encode(value, {
1368
+ cde: true,
1369
+ collapseBigInts: true,
1370
+ rejectDuplicateKeys: true,
1371
+ sortKeys: sorts.sortCoreDeterministic
1372
+ });
1373
+ }
1374
+ var CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX = new TextEncoder().encode(
1375
+ "cardano-poe-slots-transcript-v1"
1376
+ );
1377
+ var CARDANO_POE_HKDF_INFO_PAYLOAD = new TextEncoder().encode(
1378
+ "cardano-poe-payload-v1"
1379
+ );
1380
+ var CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE = new TextEncoder().encode(
1381
+ "cardano-poe-payload-passphrase-v1"
1382
+ );
1383
+ var CARDANO_POE_XWING_KEK_SALT_PREFIX = new TextEncoder().encode(
1384
+ "cardano-poe-xwing-kek-salt-v1"
1385
+ );
1386
+ if (CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length !== 31) {
1387
+ throw new Error(
1388
+ "CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX byte-length invariant violated (expected 31)"
1389
+ );
1390
+ }
1391
+ if (CARDANO_POE_HKDF_INFO_PAYLOAD.length !== 22) {
1392
+ throw new Error("CARDANO_POE_HKDF_INFO_PAYLOAD byte-length invariant violated (expected 22)");
1393
+ }
1394
+ if (CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE.length !== 33) {
1395
+ throw new Error(
1396
+ "CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE byte-length invariant violated (expected 33)"
1397
+ );
1398
+ }
1399
+ if (CARDANO_POE_XWING_KEK_SALT_PREFIX.length !== 29) {
1400
+ throw new Error("CARDANO_POE_XWING_KEK_SALT_PREFIX byte-length invariant violated (expected 29)");
1401
+ }
1402
+ var CARDANO_POE_PW_NORM_PROFILE = "cardano-poe-pw-norm-v1";
1403
+ var MAX_SLOTS = 1024;
1404
+ var MAX_DECODED_ENVELOPE_BYTES = 65536;
1405
+ var MAX_SEALED_PLAINTEXT = 274877906880;
1406
+ var MAX_SEALED_CIPHERTEXT = MAX_SEALED_PLAINTEXT + 16;
1407
+ function assertCiphertextWithinBound(ciphertextLength) {
1408
+ if (ciphertextLength >= MAX_SEALED_CIPHERTEXT) {
1409
+ throw new SealedPayloadTooLargeError(
1410
+ `ciphertext length ${ciphertextLength} is at or above the maximum sealed ciphertext size ${MAX_SEALED_CIPHERTEXT}`
1411
+ );
1444
1412
  }
1445
1413
  }
1446
- var BASE16_LOWER = "0123456789abcdef";
1447
- var BASE16_UPPER = "0123456789ABCDEF";
1448
- function decodeBase16(s) {
1449
- if (s.length % 2 !== 0) throw new Error("base16: odd-length");
1450
- const out = new Uint8Array(s.length / 2);
1451
- const alphabet = s === s.toLowerCase() ? BASE16_LOWER : BASE16_UPPER;
1452
- for (let i = 0; i < out.length; i++) {
1453
- const hi = alphabet.indexOf(s[i * 2]);
1454
- const lo = alphabet.indexOf(s[i * 2 + 1]);
1455
- if (hi < 0 || lo < 0) throw new Error(`base16: non-hex char at ${i * 2}`);
1456
- out[i] = hi << 4 | lo;
1414
+ var SealedPayloadTooLargeError = class extends Error {
1415
+ constructor(message) {
1416
+ super(message);
1417
+ this.name = "SealedPayloadTooLargeError";
1457
1418
  }
1419
+ };
1420
+ function computeSlotsHash(args) {
1421
+ const transcript = {
1422
+ scheme: 1,
1423
+ path: "slots",
1424
+ aead: "xchacha20-poly1305",
1425
+ kem: args.kem,
1426
+ nonce: args.nonce,
1427
+ slots: canonicalizeSlots(args.slots, args.kem)
1428
+ };
1429
+ const encoded = encodeCanonicalCbor3(transcript);
1430
+ const message = new Uint8Array(CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length + encoded.length);
1431
+ message.set(CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX, 0);
1432
+ message.set(encoded, CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length);
1433
+ return sha2_js.sha256(message);
1434
+ }
1435
+ function adContentSlots(args) {
1436
+ const ad = {
1437
+ scheme: 1,
1438
+ path: "slots",
1439
+ aead: "xchacha20-poly1305",
1440
+ kem: args.kem,
1441
+ nonce: args.nonce,
1442
+ slots_hash: args.slotsHash,
1443
+ slots_mac: args.slotsMac
1444
+ };
1445
+ return encodeCanonicalCbor3(ad);
1446
+ }
1447
+ function adContentPassphrase(args) {
1448
+ const ad = {
1449
+ scheme: 1,
1450
+ path: "passphrase",
1451
+ aead: "xchacha20-poly1305",
1452
+ nonce: args.nonce,
1453
+ passphrase: {
1454
+ alg: args.passphrase.alg,
1455
+ salt: args.passphrase.salt,
1456
+ params: {
1457
+ m: args.passphrase.params.m,
1458
+ t: args.passphrase.params.t,
1459
+ p: args.passphrase.params.p
1460
+ },
1461
+ normalization: CARDANO_POE_PW_NORM_PROFILE
1462
+ }
1463
+ };
1464
+ return encodeCanonicalCbor3(ad);
1465
+ }
1466
+ function slotsPayloadKey(args) {
1467
+ return hkdfSha256({
1468
+ ikm: args.cek,
1469
+ salt: args.nonce,
1470
+ info: CARDANO_POE_HKDF_INFO_PAYLOAD,
1471
+ length: 32
1472
+ });
1473
+ }
1474
+ function passphrasePayloadKey(args) {
1475
+ return hkdfSha256({
1476
+ ikm: args.cek,
1477
+ salt: args.nonce,
1478
+ info: CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE,
1479
+ length: 32
1480
+ });
1481
+ }
1482
+ function xwingKekSalt(args) {
1483
+ const message = new Uint8Array(
1484
+ CARDANO_POE_XWING_KEK_SALT_PREFIX.length + args.kemCt.length + args.pubR.length
1485
+ );
1486
+ let offset = 0;
1487
+ message.set(CARDANO_POE_XWING_KEK_SALT_PREFIX, offset);
1488
+ offset += CARDANO_POE_XWING_KEK_SALT_PREFIX.length;
1489
+ message.set(args.kemCt, offset);
1490
+ offset += args.kemCt.length;
1491
+ message.set(args.pubR, offset);
1492
+ return sha2_js.sha256(message);
1493
+ }
1494
+ var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
1495
+ var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
1496
+ "cardano-poe-kek-mlkem768x25519-v1"
1497
+ );
1498
+ var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
1499
+ "cardano-poe-slots-mac-v1"
1500
+ );
1501
+ var ZERO_NONCE_12 = new Uint8Array(12);
1502
+ if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
1503
+ throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
1504
+ }
1505
+ if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
1506
+ throw new Error(
1507
+ "CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
1508
+ );
1509
+ }
1510
+ if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
1511
+ throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
1512
+ }
1513
+ if (ZERO_NONCE_12.length !== 12) {
1514
+ throw new Error("ZERO_NONCE_12 byte-length invariant violated (expected 12)");
1515
+ }
1516
+ function compareCt2(a, b) {
1517
+ if (a.length !== b.length) return false;
1518
+ let diff = 0;
1519
+ for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
1520
+ return diff === 0;
1521
+ }
1522
+ function selectBundleSecrets(envelope, bundle) {
1523
+ return envelope.kem === "x25519" ? bundle.x25519PrivateKeys : bundle.mlkem768x25519SecretSeeds;
1524
+ }
1525
+ var ZERO_NONCE_122 = new Uint8Array(12);
1526
+ var EMPTY_SALT2 = new Uint8Array(0);
1527
+ var X25519_SECRET_KEY_LENGTH2 = 32;
1528
+ var X25519_PUBLIC_KEY_LENGTH2 = 32;
1529
+ var NONCE_LENGTH2 = 24;
1530
+ var WRAP_LENGTH2 = 48;
1531
+ var SLOTS_MAC_LENGTH2 = 32;
1532
+ function concat2(a, b) {
1533
+ const out = new Uint8Array(a.length + b.length);
1534
+ out.set(a, 0);
1535
+ out.set(b, a.length);
1458
1536
  return out;
1459
1537
  }
1460
- var BASE32_RFC4648_LOWER = "abcdefghijklmnopqrstuvwxyz234567";
1461
- var BASE32_RFC4648_UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
1462
- function decodeBase32(s, variant) {
1463
- const alphabet = variant === "rfc4648-lower" ? BASE32_RFC4648_LOWER : BASE32_RFC4648_UPPER;
1464
- const trimmed = s.replace(/=+$/, "");
1465
- const out = [];
1466
- let buf = 0;
1467
- let bits = 0;
1468
- for (const ch of trimmed) {
1469
- const idx = alphabet.indexOf(ch);
1470
- if (idx < 0) throw new Error(`base32: invalid char '${ch}'`);
1471
- buf = buf << 5 | idx;
1472
- bits += 5;
1473
- if (bits >= 8) {
1474
- bits -= 8;
1475
- out.push(buf >> bits & 255);
1476
- }
1538
+ function bytesKey(bytes) {
1539
+ let s = "";
1540
+ for (let i = 0; i < bytes.length; i++) {
1541
+ s += String.fromCharCode(bytes[i]);
1477
1542
  }
1478
- return Uint8Array.from(out);
1543
+ return s;
1479
1544
  }
1480
- var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
1481
- function decodeBase58btc(s) {
1482
- if (s.length === 0) return new Uint8Array(0);
1483
- let zeros = 0;
1484
- while (zeros < s.length && s[zeros] === "1") zeros++;
1485
- const size = Math.floor((s.length - zeros) * 733 / 1e3) + 1;
1486
- const b256 = new Uint8Array(size);
1487
- let length = 0;
1488
- for (let i = zeros; i < s.length; i++) {
1489
- const ch = s[i];
1490
- const carryIdx = BASE58_ALPHABET.indexOf(ch);
1491
- if (carryIdx < 0) throw new Error(`base58: invalid char '${ch}'`);
1492
- let carry = carryIdx;
1493
- let k = 0;
1494
- for (let j2 = size - 1; (carry !== 0 || k < length) && j2 >= 0; j2--, k++) {
1495
- carry += 58 * b256[j2];
1496
- b256[j2] = carry % 256;
1497
- carry = Math.floor(carry / 256);
1498
- }
1499
- length = k;
1545
+ function assertEnvelopeStructure(envelope, multiPrivKeys, singlePrivKey) {
1546
+ if (envelope.scheme !== 1) {
1547
+ throw new EciesSealedPoeError(
1548
+ "UNSUPPORTED_ENC_VERSION",
1549
+ `envelope.scheme=${String(envelope.scheme)} unsupported (expected 1)`
1550
+ );
1500
1551
  }
1501
- let it = size - length;
1502
- while (it < size && b256[it] === 0) it++;
1503
- const out = new Uint8Array(zeros + (size - it));
1504
- let j = zeros;
1505
- while (it < size) {
1506
- out[j++] = b256[it++];
1552
+ if (envelope.aead !== "xchacha20-poly1305") {
1553
+ throw new EciesSealedPoeError(
1554
+ "UNSUPPORTED_AEAD_ALG",
1555
+ `envelope.aead=${String(envelope.aead)} unsupported (expected 'xchacha20-poly1305')`
1556
+ );
1507
1557
  }
1508
- return out;
1509
- }
1510
- function checkCritShape(record, decodedTopKeys, errors) {
1511
- const invalid = /* @__PURE__ */ new Set();
1512
- if (!Array.isArray(record.crit)) return invalid;
1513
- if (record.crit.length === 0) {
1514
- errors.push(
1515
- issue("SCHEMA_TYPE_MISMATCH", ["crit"], "crit[] must carry at least one entry when present")
1558
+ if (envelope.kem !== "x25519" && envelope.kem !== "mlkem768x25519") {
1559
+ throw new EciesSealedPoeError(
1560
+ "UNSUPPORTED_KEM_ALG",
1561
+ `envelope.kem=${String(envelope.kem)} unsupported (expected 'x25519' or 'mlkem768x25519')`
1562
+ );
1563
+ }
1564
+ const n = envelope.slots.length;
1565
+ if (n < 1) {
1566
+ throw new EciesSealedPoeError("ENC_SLOTS_EMPTY", `envelope.slots.length=${n} must be >= 1`);
1567
+ }
1568
+ if (n > MAX_SLOTS) {
1569
+ throw new EciesSealedPoeError(
1570
+ "ENC_SLOTS_TOO_MANY",
1571
+ `envelope.slots.length=${n} exceeds MAX_SLOTS=${MAX_SLOTS}`
1572
+ );
1573
+ }
1574
+ if (envelope.nonce.length !== NONCE_LENGTH2) {
1575
+ throw new EciesSealedPoeError(
1576
+ "NONCE_LENGTH_MISMATCH",
1577
+ `envelope.nonce MUST be exactly ${NONCE_LENGTH2} bytes, got ${envelope.nonce.length}`
1578
+ );
1579
+ }
1580
+ if (envelope.slots_mac.length !== SLOTS_MAC_LENGTH2) {
1581
+ throw new EciesSealedPoeError(
1582
+ "ENC_SLOTS_MAC_INVALID_LENGTH",
1583
+ `envelope.slots_mac MUST be exactly ${SLOTS_MAC_LENGTH2} bytes, got ${envelope.slots_mac.length}`
1584
+ );
1585
+ }
1586
+ const seenKemMaterial = /* @__PURE__ */ new Set();
1587
+ if (envelope.kem === "x25519") {
1588
+ for (let i = 0; i < n; i++) {
1589
+ const slot = envelope.slots[i];
1590
+ if (slot.epk.length !== X25519_PUBLIC_KEY_LENGTH2) {
1591
+ throw new EciesSealedPoeError(
1592
+ "KEM_EPK_LENGTH_MISMATCH",
1593
+ `envelope.slots[${i}].epk MUST be exactly ${X25519_PUBLIC_KEY_LENGTH2} bytes, got ${slot.epk.length}`
1594
+ );
1595
+ }
1596
+ if (slot.wrap.length !== WRAP_LENGTH2) {
1597
+ throw new EciesSealedPoeError(
1598
+ "WRAP_LENGTH_MISMATCH",
1599
+ `envelope.slots[${i}].wrap MUST be exactly ${WRAP_LENGTH2} bytes, got ${slot.wrap.length}`
1600
+ );
1601
+ }
1602
+ const key = bytesKey(slot.epk);
1603
+ if (seenKemMaterial.has(key)) {
1604
+ throw new EciesSealedPoeError(
1605
+ "ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
1606
+ `envelope.slots[${i}].epk duplicates an earlier slot \u2014 per-slot KEK uniqueness is violated`
1607
+ );
1608
+ }
1609
+ seenKemMaterial.add(key);
1610
+ }
1611
+ } else {
1612
+ for (let i = 0; i < n; i++) {
1613
+ const slot = envelope.slots[i];
1614
+ const enc = joinKemCt(slot.kem_ct);
1615
+ if (enc.length !== MLKEM768X25519_ENC_LENGTH) {
1616
+ throw new EciesSealedPoeError(
1617
+ "KEM_CT_LENGTH_MISMATCH",
1618
+ `envelope.slots[${i}].kem_ct MUST reassemble to exactly ${MLKEM768X25519_ENC_LENGTH} bytes, got ${enc.length}`
1619
+ );
1620
+ }
1621
+ if (slot.wrap.length !== WRAP_LENGTH2) {
1622
+ throw new EciesSealedPoeError(
1623
+ "WRAP_LENGTH_MISMATCH",
1624
+ `envelope.slots[${i}].wrap MUST be exactly ${WRAP_LENGTH2} bytes, got ${slot.wrap.length}`
1625
+ );
1626
+ }
1627
+ const key = bytesKey(enc);
1628
+ if (seenKemMaterial.has(key)) {
1629
+ throw new EciesSealedPoeError(
1630
+ "ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
1631
+ `envelope.slots[${i}].kem_ct duplicates an earlier slot \u2014 per-slot KEK uniqueness is violated`
1632
+ );
1633
+ }
1634
+ seenKemMaterial.add(key);
1635
+ }
1636
+ }
1637
+ const perSlotBytes = envelope.kem === "x25519" ? X25519_PUBLIC_KEY_LENGTH2 + WRAP_LENGTH2 : MLKEM768X25519_ENC_LENGTH + WRAP_LENGTH2;
1638
+ const decodedEnvelopeBytes = NONCE_LENGTH2 + SLOTS_MAC_LENGTH2 + n * perSlotBytes;
1639
+ if (decodedEnvelopeBytes > MAX_DECODED_ENVELOPE_BYTES) {
1640
+ throw new EciesSealedPoeError(
1641
+ "ENC_ENVELOPE_TOO_LARGE",
1642
+ `decoded envelope size ${decodedEnvelopeBytes} exceeds MAX_DECODED_ENVELOPE_BYTES=${MAX_DECODED_ENVELOPE_BYTES}`
1516
1643
  );
1517
- return invalid;
1518
1644
  }
1519
- const seen = /* @__PURE__ */ new Set();
1520
- for (let i = 0; i < record.crit.length; i++) {
1521
- const critName = record.crit[i];
1522
- let reason = null;
1523
- if (TOP_LEVEL_BASE_KEYS.has(critName)) {
1524
- reason = `'${critName}' is a base key and MUST NOT appear in crit[]`;
1525
- } else if (!isExtensionKey(critName)) {
1526
- reason = `'${critName}' does not match the extension-key regex (^x-.+ or ^[a-z]+-.+)`;
1527
- } else if (!decodedTopKeys.has(critName)) {
1528
- reason = `'${critName}' is named in crit but absent from the record map`;
1529
- } else if (seen.has(critName)) {
1530
- reason = `'${critName}' appears more than once in crit[]`;
1645
+ if (multiPrivKeys !== void 0) {
1646
+ for (let i = 0; i < multiPrivKeys.length; i++) {
1647
+ if (multiPrivKeys[i].length !== X25519_SECRET_KEY_LENGTH2) {
1648
+ throw new EciesSealedPoeError(
1649
+ "INVALID_RECIPIENT_KEY",
1650
+ `recipientSecretKeys[${i}] MUST be exactly ${X25519_SECRET_KEY_LENGTH2} bytes, got ${multiPrivKeys[i].length}`
1651
+ );
1652
+ }
1531
1653
  }
1532
- seen.add(critName);
1533
- if (reason !== null) {
1534
- invalid.add(i);
1535
- errors.push(issue("CRIT_SHAPE_INVALID", ["crit", i], reason));
1654
+ } else if (singlePrivKey !== void 0) {
1655
+ if (singlePrivKey.length !== X25519_SECRET_KEY_LENGTH2) {
1656
+ throw new EciesSealedPoeError(
1657
+ "INVALID_RECIPIENT_KEY",
1658
+ `recipientSecretKey MUST be exactly ${X25519_SECRET_KEY_LENGTH2} bytes, got ${singlePrivKey.length}`
1659
+ );
1536
1660
  }
1537
1661
  }
1538
- return invalid;
1539
1662
  }
1540
- function topLevelKeysOf(decoded) {
1541
- if (decoded === null || typeof decoded !== "object") return /* @__PURE__ */ new Set();
1542
- if (decoded instanceof Map) {
1543
- const out = /* @__PURE__ */ new Set();
1544
- for (const k of decoded.keys()) {
1545
- if (typeof k === "string") out.add(k);
1546
- }
1547
- return out;
1663
+ var ZERO_IKM_32 = new Uint8Array(32);
1664
+ function tryX25519Slot(args) {
1665
+ const salt = concat2(args.slot.epk, args.pubRLocal);
1666
+ let shared;
1667
+ try {
1668
+ shared = x25519Ecdh({
1669
+ secretKey: args.recipientSecretKey,
1670
+ theirPublicKey: args.slot.epk
1671
+ });
1672
+ } catch (e) {
1673
+ if (!(e instanceof X25519LowOrderPointError)) throw e;
1674
+ hkdfSha256({ ikm: ZERO_IKM_32, salt, info: CARDANO_POE_HKDF_INFO_KEK, length: 32 });
1675
+ return null;
1548
1676
  }
1549
- return new Set(Object.keys(decoded));
1550
- }
1551
- function issue(code, path, message) {
1552
- return { code, path, message, severity: SEVERITY[code] };
1553
- }
1554
- function compareIssuePath(a, b) {
1555
- return a.path.join(".").localeCompare(b.path.join("."));
1556
- }
1557
- function valueAtPath(root, path) {
1558
- let cur = root;
1559
- for (const seg of path) {
1560
- if (cur === null || cur === void 0) return void 0;
1561
- if (cur instanceof Map) {
1562
- cur = cur.get(seg);
1563
- continue;
1564
- }
1565
- if (typeof cur !== "object") return void 0;
1566
- cur = cur[seg];
1677
+ const kek = hkdfSha256({ ikm: shared, salt, info: CARDANO_POE_HKDF_INFO_KEK, length: 32 });
1678
+ try {
1679
+ return chacha20Poly1305Decrypt({
1680
+ key: kek,
1681
+ nonce: ZERO_NONCE_122,
1682
+ aad: CARDANO_POE_HKDF_INFO_KEK,
1683
+ ciphertext: args.slot.wrap
1684
+ });
1685
+ } catch (e) {
1686
+ if (!(e instanceof AeadVerificationError)) throw e;
1687
+ return null;
1567
1688
  }
1568
- return cur;
1569
1689
  }
1570
- async function argon2idV13(opts2) {
1571
- return await hashWasm.argon2id({
1572
- password: opts2.password,
1573
- salt: opts2.salt,
1574
- parallelism: opts2.parallelism,
1575
- iterations: opts2.iterations,
1576
- memorySize: opts2.memSizeKB,
1577
- hashLength: opts2.outBytes,
1578
- outputType: "binary"
1690
+ function tryMlkem768X25519Slot(args) {
1691
+ const enc = joinKemCt(args.slot.kem_ct);
1692
+ const ss = mlkem768x25519Decapsulate({ secretSeed: args.recipientSecretKey, enc });
1693
+ const kek = hkdfSha256({
1694
+ ikm: ss,
1695
+ salt: xwingKekSalt({ kemCt: enc, pubR: args.pubR }),
1696
+ info: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
1697
+ length: 32
1579
1698
  });
1580
- }
1581
- var AeadVerificationError = class extends Error {
1582
- code = "aead_verification_failed";
1583
- constructor(message, options) {
1584
- super(message, options);
1585
- this.name = "AeadVerificationError";
1586
- }
1587
- };
1588
- function xchacha20Poly1305Decrypt(opts2) {
1589
1699
  try {
1590
- return chacha_js.xchacha20poly1305(opts2.key, opts2.nonce, opts2.aad).decrypt(opts2.ciphertext);
1591
- } catch (cause) {
1592
- throw new AeadVerificationError("xchacha20-poly1305 decrypt failed", { cause });
1700
+ return chacha20Poly1305Decrypt({
1701
+ key: kek,
1702
+ nonce: ZERO_NONCE_122,
1703
+ aad: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
1704
+ ciphertext: args.slot.wrap
1705
+ });
1706
+ } catch (e) {
1707
+ if (!(e instanceof AeadVerificationError)) throw e;
1708
+ return null;
1593
1709
  }
1594
1710
  }
1595
- function sha2562(input) {
1596
- return sha2_js.sha256(input);
1597
- }
1598
- function blake2b256(input) {
1599
- return blake2_js.blake2b(input, { dkLen: 32 });
1711
+ function tryRecipientUnwrapWithIdx(envelope, recipientSecretKey, constantTimeN, slotsAttemptedOut) {
1712
+ const n = envelope.slots.length;
1713
+ let cek = null;
1714
+ let matchedSlotIdx = -1;
1715
+ let cekConflict = false;
1716
+ const recordMatch = (candidate, i) => {
1717
+ if (candidate === null) return;
1718
+ if (cek === null) {
1719
+ cek = candidate;
1720
+ matchedSlotIdx = i;
1721
+ } else if (!compareCt2(candidate, cek)) {
1722
+ cekConflict = true;
1723
+ }
1724
+ };
1725
+ if (envelope.kem === "x25519") {
1726
+ const pubRLocal = x25519PublicKey({ secretKey: recipientSecretKey });
1727
+ for (let i = 0; i < n; i++) {
1728
+ if (slotsAttemptedOut !== void 0) {
1729
+ slotsAttemptedOut.count = i + 1;
1730
+ }
1731
+ recordMatch(tryX25519Slot({ slot: envelope.slots[i], recipientSecretKey, pubRLocal }), i);
1732
+ if (cek !== null && !constantTimeN) break;
1733
+ }
1734
+ } else {
1735
+ const pubR = mlkem768x25519Keygen(recipientSecretKey).publicKey;
1736
+ for (let i = 0; i < n; i++) {
1737
+ if (slotsAttemptedOut !== void 0) {
1738
+ slotsAttemptedOut.count = i + 1;
1739
+ }
1740
+ recordMatch(tryMlkem768X25519Slot({ slot: envelope.slots[i], recipientSecretKey, pubR }), i);
1741
+ if (cek !== null && !constantTimeN) break;
1742
+ }
1743
+ }
1744
+ return cek === null ? null : { cek, slotIdx: matchedSlotIdx, cekConflict };
1600
1745
  }
1601
- function blake2b2242(input) {
1602
- return blake2_js.blake2b(input, { dkLen: 28 });
1746
+ function slotsHashBytes(envelope) {
1747
+ return computeSlotsHash({
1748
+ kem: envelope.kem,
1749
+ nonce: envelope.nonce,
1750
+ slots: envelope.slots
1751
+ });
1603
1752
  }
1604
- var LEAF_PREFIX = 0;
1605
- var NODE_PREFIX = 1;
1606
- var DIGEST_LENGTH = 32;
1607
- function validateLeaves(leaves, fnName) {
1608
- if (leaves.length === 0) {
1609
- throw new Error(`${fnName}: empty leaf list (n == 0 is forbidden by RFC 9162 \xA72.1.1)`);
1753
+ function eciesSealedPoeUnwrap(args) {
1754
+ const { envelope, ciphertext } = args;
1755
+ const constantTimeN = args.constantTimeN ?? true;
1756
+ const hasSingle = "recipientSecretKey" in args;
1757
+ const hasBundle = "recipientKeyBundle" in args;
1758
+ const multiPrivKeys = hasBundle ? selectBundleSecrets(envelope, args.recipientKeyBundle) : "recipientSecretKeys" in args ? args.recipientSecretKeys : void 0;
1759
+ const hasMulti = multiPrivKeys !== void 0;
1760
+ if (hasSingle === hasMulti) {
1761
+ throw new EciesSealedPoeError(
1762
+ "INVALID_RECIPIENT_KEY",
1763
+ "exactly one of recipientSecretKey / recipientSecretKeys / recipientKeyBundle MUST be supplied"
1764
+ );
1610
1765
  }
1611
- for (let i = 0; i < leaves.length; i++) {
1612
- const leaf = leaves[i];
1613
- if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH) {
1614
- throw new Error(
1615
- `${fnName}: leaf[${i}] must be a Uint8Array(${DIGEST_LENGTH}); got length ${leaf instanceof Uint8Array ? leaf.length : "non-Uint8Array"}`
1616
- );
1766
+ if (hasMulti && multiPrivKeys.length === 0) {
1767
+ if (hasBundle) {
1768
+ return { matched: false, reason: "WRONG_RECIPIENT_KEY" };
1617
1769
  }
1770
+ throw new EciesSealedPoeError(
1771
+ "INVALID_RECIPIENT_KEY",
1772
+ "recipientSecretKeys MUST be a non-empty array, got length=0"
1773
+ );
1618
1774
  }
1619
- }
1620
- function merkleSha2256Root(leaves) {
1621
- validateLeaves(leaves, "merkleSha2256Root");
1622
- return mthRecursive(leaves, 0, leaves.length);
1623
- }
1624
- function largestPow2Lt(n) {
1625
- let k = 1;
1626
- while (k * 2 < n) k *= 2;
1627
- return k;
1628
- }
1629
- function hashLeaf(d) {
1630
- const buf = new Uint8Array(1 + d.length);
1631
- buf[0] = LEAF_PREFIX;
1632
- buf.set(d, 1);
1633
- return sha2_js.sha256(buf);
1634
- }
1635
- function hashNode(left, right) {
1636
- const buf = new Uint8Array(1 + left.length + right.length);
1637
- buf[0] = NODE_PREFIX;
1638
- buf.set(left, 1);
1639
- buf.set(right, 1 + left.length);
1640
- return sha2_js.sha256(buf);
1641
- }
1642
- function mthRecursive(leaves, start, end) {
1643
- const n = end - start;
1644
- if (n === 1) {
1645
- return hashLeaf(leaves[start]);
1775
+ if (hasMulti) {
1776
+ assertEnvelopeStructure(envelope, multiPrivKeys, void 0);
1777
+ } else {
1778
+ assertEnvelopeStructure(envelope, void 0, args.recipientSecretKey);
1646
1779
  }
1647
- const k = largestPow2Lt(n);
1648
- const left = mthRecursive(leaves, start, start + k);
1649
- const right = mthRecursive(leaves, start + k, end);
1650
- return hashNode(left, right);
1651
- }
1652
- var abytesDoc = utils_js.abytes;
1653
- var randomBytes = utils_js.randomBytes;
1654
- function equalBytes(a, b) {
1655
- if (a.length !== b.length)
1656
- return false;
1657
- let diff = 0;
1658
- for (let i = 0; i < a.length; i++)
1659
- diff |= a[i] ^ b[i];
1660
- return diff === 0;
1661
- }
1662
- function copyBytes(bytes) {
1663
- return Uint8Array.from(utils_js.abytes(bytes));
1664
- }
1665
- function splitCoder(label, ...lengths) {
1666
- const getLength = (c) => typeof c === "number" ? c : c.bytesLen;
1667
- const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0);
1668
- return {
1669
- bytesLen,
1670
- encode: (bufs) => {
1671
- const res = new Uint8Array(bytesLen);
1672
- for (let i = 0, pos = 0; i < lengths.length; i++) {
1673
- const c = lengths[i];
1674
- const l = getLength(c);
1675
- const b = typeof c === "number" ? bufs[i] : c.encode(bufs[i]);
1676
- utils_js.abytes(b, l, label);
1677
- res.set(b, pos);
1678
- if (typeof c !== "number")
1679
- b.fill(0);
1680
- pos += l;
1780
+ assertCiphertextWithinBound(ciphertext.length);
1781
+ const slotsHash = slotsHashBytes(envelope);
1782
+ let matchedCek = null;
1783
+ let anyCandidateRecovered = false;
1784
+ if (hasSingle) {
1785
+ const recipientSecretKey = args.recipientSecretKey;
1786
+ const candidate = tryRecipientUnwrapWithIdx(
1787
+ envelope,
1788
+ recipientSecretKey,
1789
+ constantTimeN,
1790
+ args._slotsAttemptedOut
1791
+ );
1792
+ if (candidate === null) {
1793
+ return { matched: false, reason: "WRONG_RECIPIENT_KEY" };
1794
+ }
1795
+ if (candidate.cekConflict) {
1796
+ return { matched: false, reason: "TAMPERED_HEADER" };
1797
+ }
1798
+ const hmacKey = hkdfSha256({
1799
+ ikm: candidate.cek,
1800
+ salt: EMPTY_SALT2,
1801
+ info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
1802
+ length: 32
1803
+ });
1804
+ const slotsMacCalc = hmac_js.hmac(sha2_js.sha256, hmacKey, slotsHash);
1805
+ if (!compareCt2(slotsMacCalc, envelope.slots_mac)) {
1806
+ return { matched: false, reason: "TAMPERED_HEADER" };
1807
+ }
1808
+ matchedCek = candidate.cek;
1809
+ } else {
1810
+ const recipientSecretKeys = multiPrivKeys;
1811
+ let cekConflict = false;
1812
+ for (let k = 0; k < recipientSecretKeys.length; k++) {
1813
+ if (args._privsAttemptedOut !== void 0) {
1814
+ args._privsAttemptedOut.count = k + 1;
1681
1815
  }
1682
- return res;
1683
- },
1684
- decode: (buf) => {
1685
- utils_js.abytes(buf, bytesLen, label);
1686
- const res = [];
1687
- for (const c of lengths) {
1688
- const l = getLength(c);
1689
- const b = buf.subarray(0, l);
1690
- res.push(typeof c === "number" ? b : c.decode(b));
1691
- buf = buf.subarray(l);
1816
+ if (args._slotsAttemptedOut !== void 0) {
1817
+ args._slotsAttemptedOut.count = 0;
1692
1818
  }
1693
- return res;
1694
- }
1695
- };
1696
- }
1697
- function vecCoder(c, vecLen) {
1698
- const coder = c;
1699
- const bytesLen = vecLen * coder.bytesLen;
1700
- return {
1701
- bytesLen,
1702
- encode: (u) => {
1703
- if (u.length !== vecLen)
1704
- throw new RangeError(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`);
1705
- const res = new Uint8Array(bytesLen);
1706
- for (let i = 0, pos = 0; i < u.length; i++) {
1707
- const b = coder.encode(u[i]);
1708
- res.set(b, pos);
1709
- b.fill(0);
1710
- pos += b.length;
1819
+ const candidate = tryRecipientUnwrapWithIdx(
1820
+ envelope,
1821
+ recipientSecretKeys[k],
1822
+ constantTimeN,
1823
+ args._slotsAttemptedOut
1824
+ );
1825
+ if (args._slotsAttemptedOut?.perPrivCounts !== void 0) {
1826
+ args._slotsAttemptedOut.perPrivCounts.push(args._slotsAttemptedOut.count);
1711
1827
  }
1712
- return res;
1713
- },
1714
- decode: (a) => {
1715
- utils_js.abytes(a, bytesLen);
1716
- const r = [];
1717
- for (let i = 0; i < a.length; i += coder.bytesLen)
1718
- r.push(coder.decode(a.subarray(i, i + coder.bytesLen)));
1719
- return r;
1828
+ if (candidate === null) continue;
1829
+ if (candidate.cekConflict) cekConflict = true;
1830
+ const cek = candidate.cek;
1831
+ const hmacKey = hkdfSha256({
1832
+ ikm: cek,
1833
+ salt: EMPTY_SALT2,
1834
+ info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
1835
+ length: 32
1836
+ });
1837
+ const slotsMacCalc = hmac_js.hmac(sha2_js.sha256, hmacKey, slotsHash);
1838
+ if (compareCt2(slotsMacCalc, envelope.slots_mac)) {
1839
+ matchedCek = cek;
1840
+ break;
1841
+ }
1842
+ anyCandidateRecovered = true;
1843
+ }
1844
+ if (matchedCek !== null && cekConflict) {
1845
+ return { matched: false, reason: "TAMPERED_HEADER" };
1846
+ }
1847
+ if (matchedCek === null) {
1848
+ return {
1849
+ matched: false,
1850
+ reason: anyCandidateRecovered ? "TAMPERED_HEADER" : "WRONG_RECIPIENT_KEY"
1851
+ };
1720
1852
  }
1721
- };
1722
- }
1723
- function cleanBytes(...list) {
1724
- for (const t of list) {
1725
- if (Array.isArray(t))
1726
- for (const b of t)
1727
- b.fill(0);
1728
- else
1729
- t.fill(0);
1853
+ }
1854
+ const payloadKey = slotsPayloadKey({ cek: matchedCek, nonce: envelope.nonce });
1855
+ const adContent = adContentSlots({
1856
+ kem: envelope.kem,
1857
+ nonce: envelope.nonce,
1858
+ slotsHash,
1859
+ slotsMac: envelope.slots_mac
1860
+ });
1861
+ try {
1862
+ const plaintext = xchacha20Poly1305Decrypt({
1863
+ key: payloadKey,
1864
+ nonce: envelope.nonce,
1865
+ aad: adContent,
1866
+ ciphertext
1867
+ });
1868
+ return { matched: true, plaintext };
1869
+ } catch (e) {
1870
+ if (!(e instanceof AeadVerificationError)) throw e;
1871
+ return { matched: false, reason: "TAMPERED_CIPHERTEXT" };
1730
1872
  }
1731
1873
  }
1732
- function getMask(bits) {
1733
- if (!Number.isSafeInteger(bits) || bits < 0 || bits > 32)
1734
- throw new RangeError(`expected bits in [0..32], got ${bits}`);
1735
- return bits === 32 ? 4294967295 : ~(-1 << bits) >>> 0;
1736
- }
1737
-
1738
- // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/_crystals.js
1739
- var genCrystals = (opts2) => {
1740
- const { newPoly, N: N2, Q: Q2, F: F2, ROOT_OF_UNITY: ROOT_OF_UNITY2, brvBits} = opts2;
1741
- const mod = (a, modulo = Q2) => {
1742
- const result = a % modulo | 0;
1743
- return (result >= 0 ? result | 0 : modulo + result | 0) | 0;
1744
- };
1745
- const smod = (a, modulo = Q2) => {
1746
- const r = mod(a, modulo) | 0;
1747
- return (r > modulo >> 1 ? r - modulo | 0 : r) | 0;
1748
- };
1749
- function getZettas() {
1750
- const out = newPoly(N2);
1751
- for (let i = 0; i < N2; i++) {
1752
- const b = fft_js.reverseBits(i, brvBits);
1753
- const p = BigInt(ROOT_OF_UNITY2) ** BigInt(b) % BigInt(Q2);
1754
- out[i] = Number(p) | 0;
1874
+ function sealedEnvelopeFromParsed(enc) {
1875
+ if (enc.scheme !== 1 || enc.aead !== "xchacha20-poly1305") return null;
1876
+ if (enc.nonce === void 0 || enc.slots_mac === void 0) return null;
1877
+ const slots = enc.slots;
1878
+ if (slots === void 0 || slots.length < 1) return null;
1879
+ if (enc.kem === "x25519") {
1880
+ const x25519Slots = [];
1881
+ for (const s of slots) {
1882
+ if (s.epk === void 0 || s.wrap === void 0) return null;
1883
+ x25519Slots.push({ epk: s.epk, wrap: s.wrap });
1755
1884
  }
1756
- return out;
1885
+ return {
1886
+ scheme: 1,
1887
+ aead: "xchacha20-poly1305",
1888
+ kem: "x25519",
1889
+ nonce: enc.nonce,
1890
+ slots: x25519Slots,
1891
+ slots_mac: enc.slots_mac
1892
+ };
1757
1893
  }
1758
- const nttZetas = getZettas();
1759
- const field = {
1760
- add: (a, b) => mod((a | 0) + (b | 0)) | 0,
1761
- sub: (a, b) => mod((a | 0) - (b | 0)) | 0,
1762
- mul: (a, b) => mod((a | 0) * (b | 0)) | 0,
1763
- inv: (_a) => {
1764
- throw new Error("not implemented");
1765
- }
1766
- };
1767
- const nttOpts = {
1768
- N: N2,
1769
- roots: nttZetas,
1770
- invertButterflies: true,
1771
- skipStages: 1 ,
1772
- brp: false
1773
- };
1774
- const dif = fft_js.FFTCore(field, { dit: false, ...nttOpts });
1775
- const dit = fft_js.FFTCore(field, { dit: true, ...nttOpts });
1776
- const NTT = {
1777
- encode: (r) => {
1778
- return dif(r);
1779
- },
1780
- decode: (r) => {
1781
- dit(r);
1782
- for (let i = 0; i < r.length; i++)
1783
- r[i] = mod(F2 * r[i]);
1784
- return r;
1894
+ if (enc.kem === "mlkem768x25519") {
1895
+ const hybridSlots = [];
1896
+ for (const s of slots) {
1897
+ if (s.kem_ct === void 0 || s.wrap === void 0) return null;
1898
+ hybridSlots.push({ kem_ct: s.kem_ct, wrap: s.wrap });
1785
1899
  }
1786
- };
1787
- const bitsCoder = (d, c) => {
1788
- const mask = getMask(d);
1789
- const bytesLen = d * (N2 / 8);
1790
1900
  return {
1791
- bytesLen,
1792
- encode: (poly_) => {
1793
- const poly = poly_;
1794
- const r = new Uint8Array(bytesLen);
1795
- for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) {
1796
- buf |= (c.encode(poly[i]) & mask) << bufLen;
1797
- bufLen += d;
1798
- for (; bufLen >= 8; bufLen -= 8, buf >>= 8)
1799
- r[pos++] = buf & getMask(bufLen);
1800
- }
1801
- return r;
1802
- },
1803
- decode: (bytes) => {
1804
- const r = newPoly(N2);
1805
- for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) {
1806
- buf |= bytes[i] << bufLen;
1807
- bufLen += 8;
1808
- for (; bufLen >= d; bufLen -= d, buf >>= d)
1809
- r[pos++] = c.decode(buf & mask);
1901
+ scheme: 1,
1902
+ aead: "xchacha20-poly1305",
1903
+ kem: "mlkem768x25519",
1904
+ nonce: enc.nonce,
1905
+ slots: hybridSlots,
1906
+ slots_mac: enc.slots_mac
1907
+ };
1908
+ }
1909
+ return null;
1910
+ }
1911
+
1912
+ // ../poe-standard/src/chunked.ts
1913
+ var UTF8_ENCODER2 = new TextEncoder();
1914
+ function bytesChunkArrayConcat(chunks) {
1915
+ let total = 0;
1916
+ for (const c of chunks) total += c.length;
1917
+ const out = new Uint8Array(total);
1918
+ let offset = 0;
1919
+ for (const c of chunks) {
1920
+ out.set(c, offset);
1921
+ offset += c.length;
1922
+ }
1923
+ return out;
1924
+ }
1925
+ function reconstructChunkedUri(chunks) {
1926
+ const merged = bytesChunkArrayConcat(chunks.map((c) => UTF8_ENCODER2.encode(c)));
1927
+ try {
1928
+ const uri = new TextDecoder("utf-8", { fatal: true }).decode(merged);
1929
+ return { ok: true, uri };
1930
+ } catch (cause) {
1931
+ return {
1932
+ ok: false,
1933
+ code: "INVALID_URI",
1934
+ reason: cause instanceof Error ? cause.message : String(cause)
1935
+ };
1936
+ }
1937
+ }
1938
+ var SEVERITY = Object.freeze({
1939
+ // --- Part A ---
1940
+ MALFORMED_CBOR: "error",
1941
+ SCHEMA_TYPE_MISMATCH: "error",
1942
+ SCHEMA_MISSING_REQUIRED: "error",
1943
+ SCHEMA_UNKNOWN_FIELD: "error",
1944
+ SCHEMA_INVALID_LITERAL: "error",
1945
+ SCHEMA_EMPTY_RECORD: "error",
1946
+ HASH_DIGEST_LENGTH_MISMATCH: "error",
1947
+ UNSUPPORTED_HASH_ALG: "error",
1948
+ UNSUPPORTED_MERKLE_COMMIT_ALG: "error",
1949
+ INVALID_URI: "error",
1950
+ CHUNK_TOO_LARGE: "error",
1951
+ UNAUTHENTICATED_CIPHER_FORBIDDEN: "error",
1952
+ UNSUPPORTED_AEAD_ALG: "error",
1953
+ NONCE_LENGTH_MISMATCH: "error",
1954
+ UNSUPPORTED_ENVELOPE_SCHEME: "error",
1955
+ ENC_SLOTS_EMPTY: "error",
1956
+ ENC_SLOT_INVALID_SHAPE: "error",
1957
+ ENC_SLOTS_DUPLICATE_KEM_MATERIAL: "error",
1958
+ ENC_SLOTS_TOO_MANY: "error",
1959
+ ENC_ENVELOPE_TOO_LARGE: "error",
1960
+ UNSUPPORTED_KEM_ALG: "error",
1961
+ ENC_KEM_REQUIRED: "error",
1962
+ KEM_EPK_LENGTH_MISMATCH: "error",
1963
+ KEM_CT_LENGTH_MISMATCH: "error",
1964
+ WRAP_LENGTH_MISMATCH: "error",
1965
+ ENC_SLOTS_MAC_INVALID_LENGTH: "error",
1966
+ ENC_SLOTS_MAC_REQUIRED: "error",
1967
+ ENC_SLOTS_REQUIRED: "error",
1968
+ ENC_EXCLUSIVITY_VIOLATION: "error",
1969
+ ENC_NO_KEY_PATH: "error",
1970
+ ENC_REQUIRES_CONTENT_HASH: "error",
1971
+ ENC_PASSPHRASE_ALG_UNSUPPORTED: "error",
1972
+ ENC_PASSPHRASE_SALT_TOO_SHORT: "error",
1973
+ ENC_PASSPHRASE_SALT_TOO_LONG: "error",
1974
+ ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW: "error",
1975
+ ENC_PASSPHRASE_PARAMS_EXCEED_POLICY: "error",
1976
+ MALFORMED_SIG_COSE_SIGN1: "error",
1977
+ SIGNATURE_UNSUPPORTED: "info",
1978
+ SIG_ENTRY_INVALID_SHAPE: "error",
1979
+ SIG_ENTRY_KID_COSE_KEY_CONFLICT: "error",
1980
+ SIG_PRIVATE_KEY_LEAKED: "error",
1981
+ SUPERSEDES_TX_INVALID_LENGTH: "error",
1982
+ EXTENSION_UNSUPPORTED_CRITICAL: "error",
1983
+ CRIT_SHAPE_INVALID: "error",
1984
+ // --- Part B ---
1985
+ METADATA_NOT_FOUND: "error",
1986
+ INSUFFICIENT_CONFIRMATIONS: "info",
1987
+ SIGNATURE_INVALID: "error",
1988
+ SIGNER_KEY_UNRESOLVED: "error",
1989
+ WALLET_ADDRESS_MISMATCH: "error",
1990
+ URI_TARGET_FORBIDDEN: "error",
1991
+ URI_INTEGRITY_MISMATCH: "error",
1992
+ URI_FETCH_FAILED: "warning",
1993
+ CONTENT_UNAVAILABLE: "error",
1994
+ CIPHERTEXT_UNAVAILABLE: "error",
1995
+ PROVIDER_UNAVAILABLE: "error",
1996
+ SERVICE_INDEPENDENCE_VIOLATION: "error",
1997
+ WRONG_DECRYPTION_INPUT_SHAPE: "error",
1998
+ WRONG_RECIPIENT_KEY: "error",
1999
+ TAMPERED_HEADER: "error",
2000
+ TAMPERED_CIPHERTEXT: "error",
2001
+ KDF_DERIVATION_FAILED: "error",
2002
+ SCHEMA_MERKLE_LEAF_COUNT_MISMATCH: "error",
2003
+ SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED: "error",
2004
+ SCHEMA_MERKLE_LEAVES_MALFORMED: "error",
2005
+ MERKLE_ROOT_MISMATCH: "error",
2006
+ MERKLE_LEAVES_UNAVAILABLE: "warning",
2007
+ MERKLE_LEAVES_INFORMATIVE_FORM: "info",
2008
+ // Dual-severity — default reading is `info`; the verifier promotes to
2009
+ // `error` for merkle-only records (no `items[]` content claim was
2010
+ // validated in the same record).
2011
+ MERKLE_UNSUPPORTED: "info",
2012
+ // Dual-severity — default reading is `info` (render mode); strict
2013
+ // end-to-end verifiers promote to `error`.
2014
+ OUT_OF_PROFILE_SKIPPED: "info"
2015
+ });
2016
+
2017
+ // ../poe-standard/src/validator.ts
2018
+ var HASH_ALG_LENGTHS = {
2019
+ "sha2-256": 32,
2020
+ "blake2b-256": 32
2021
+ };
2022
+ var MERKLE_COMMIT_ALG_LENGTHS = {
2023
+ "rfc9162-sha256": 32
2024
+ };
2025
+ var AEAD_NONCE_LENGTHS = {
2026
+ "xchacha20-poly1305": 24
2027
+ };
2028
+ var UNAUTHENTICATED_CIPHER_RE = /(?:^|[-_])(?:cbc|ctr|ecb|cfb|ofb)(?:[-_]|\n?$)|^(?:rc4|des|3des)(?:[-_]|\n?$)/i;
2029
+ var KEM_SLOT_DESCRIPTORS = {
2030
+ x25519: { field: "epk", fieldLength: 32, wrapLength: 48 },
2031
+ mlkem768x25519: { field: "kem_ct", fieldLength: 1120, wrapLength: 48 }
2032
+ };
2033
+ var KEM_FIELD_LENGTH_CODE = {
2034
+ epk: "KEM_EPK_LENGTH_MISMATCH",
2035
+ kem_ct: "KEM_CT_LENGTH_MISMATCH"
2036
+ };
2037
+ var NONCE_LENGTH = 24;
2038
+ var SLOTS_MAC_LENGTH = 32;
2039
+ var PASSPHRASE_KDF_ALGS = /* @__PURE__ */ new Set(["argon2id"]);
2040
+ var KNOWN_SIG_ALG_IDS = /* @__PURE__ */ new Set([-8, -19]);
2041
+ function validatePoeRecord(bytes) {
2042
+ let decoded;
2043
+ try {
2044
+ decoded = decodeCanonicalCbor(bytes);
2045
+ } catch (cause) {
2046
+ return {
2047
+ ok: false,
2048
+ issues: [
2049
+ {
2050
+ code: "MALFORMED_CBOR",
2051
+ path: [],
2052
+ message: cause instanceof Error ? cause.message : String(cause),
2053
+ severity: "error"
1810
2054
  }
1811
- return r;
1812
- }
2055
+ ]
1813
2056
  };
1814
- };
1815
- return {
1816
- mod,
1817
- smod,
1818
- nttZetas,
1819
- NTT: {
1820
- encode: (r) => NTT.encode(r),
1821
- decode: (r) => NTT.decode(r)
1822
- },
1823
- bitsCoder
1824
- };
1825
- };
1826
- var createXofShake = (shake) => (seed, blockLen) => {
1827
- if (!blockLen)
1828
- blockLen = shake.blockLen;
1829
- const _seed = new Uint8Array(seed.length + 2);
1830
- _seed.set(seed);
1831
- const seedLen = seed.length;
1832
- const buf = new Uint8Array(blockLen);
1833
- let h = shake.create({});
1834
- let calls = 0;
1835
- let xofs = 0;
1836
- return {
1837
- stats: () => ({ calls, xofs }),
1838
- get: (x, y) => {
1839
- _seed[seedLen + 0] = x;
1840
- _seed[seedLen + 1] = y;
1841
- h.destroy();
1842
- h = shake.create({}).update(_seed);
1843
- calls++;
1844
- return () => {
1845
- xofs++;
1846
- return h.xofInto(buf);
1847
- };
1848
- },
1849
- clean: () => {
1850
- h.destroy();
1851
- cleanBytes(buf, _seed);
2057
+ }
2058
+ const parse = PoeRecordSchema.safeParse(decoded);
2059
+ if (!parse.success) {
2060
+ const issues = parse.error.issues.map((issue2) => mapZodIssue(issue2, decoded)).sort(compareIssuePath);
2061
+ return { ok: false, issues };
2062
+ }
2063
+ const record = parse.data;
2064
+ const errors = [];
2065
+ const warnings = [];
2066
+ const info = [];
2067
+ const itemsLen = Array.isArray(record.items) ? record.items.length : 0;
2068
+ const merkleLen = Array.isArray(record.merkle) ? record.merkle.length : 0;
2069
+ if (itemsLen === 0 && merkleLen === 0) {
2070
+ errors.push(
2071
+ issue(
2072
+ "SCHEMA_EMPTY_RECORD",
2073
+ [],
2074
+ "record must carry at least one of items[] or merkle[] non-empty"
2075
+ )
2076
+ );
2077
+ }
2078
+ const decodedTopKeys = topLevelKeysOf(decoded);
2079
+ const critShapeInvalidIndices = checkCritShape(record, decodedTopKeys, errors);
2080
+ for (const k of decodedTopKeys) {
2081
+ if (TOP_LEVEL_BASE_KEYS.has(k)) continue;
2082
+ if (isExtensionKey(k)) continue;
2083
+ errors.push(issue("SCHEMA_UNKNOWN_FIELD", [k], `unknown top-level field: ${k}`));
2084
+ }
2085
+ if (Array.isArray(record.crit)) {
2086
+ for (let i = 0; i < record.crit.length; i++) {
2087
+ if (critShapeInvalidIndices.has(i)) continue;
2088
+ const critName = record.crit[i];
2089
+ errors.push(
2090
+ issue(
2091
+ "EXTENSION_UNSUPPORTED_CRITICAL",
2092
+ ["crit", i],
2093
+ `crit lists extension '${critName}' that this validator does not implement`
2094
+ )
2095
+ );
1852
2096
  }
1853
- };
1854
- };
1855
- var XOF128 = /* @__PURE__ */ createXofShake(sha3_js.shake128);
1856
-
1857
- // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/ml-kem.js
1858
- var N = 256;
1859
- var Q = 3329;
1860
- var F = 3303;
1861
- var ROOT_OF_UNITY = 17;
1862
- var crystals = /* @__PURE__ */ genCrystals({
1863
- N,
1864
- Q,
1865
- F,
1866
- ROOT_OF_UNITY,
1867
- newPoly: (n) => new Uint16Array(n),
1868
- brvBits: 7});
1869
- var PARAMS = /* @__PURE__ */ (() => Object.freeze({
1870
- 512: Object.freeze({ N, Q, K: 2, ETA1: 3, ETA2: 2, du: 10, dv: 4, RBGstrength: 128 }),
1871
- 768: Object.freeze({ N, Q, K: 3, ETA1: 2, ETA2: 2, du: 10, dv: 4, RBGstrength: 192 }),
1872
- 1024: Object.freeze({ N, Q, K: 4, ETA1: 2, ETA2: 2, du: 11, dv: 5, RBGstrength: 256 })
1873
- }))();
1874
- var compress = (d) => {
1875
- if (d >= 12)
1876
- return { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i };
1877
- const a = 2 ** (d - 1);
1878
- return {
1879
- // This only matches standalone Compress_d after bitsCoder masks the result into Z_(2^d).
1880
- encode: (i) => ((i << d) + Q / 2) / Q,
1881
- // const decompress = (i: number) => round((Q / 2 ** d) * i);
1882
- decode: (i) => i * Q + a >>> d
1883
- };
1884
- };
1885
- var byteCoder = (d) => crystals.bitsCoder(d, { encode: (i) => i, decode: (i) => i >= Q ? i - Q : i } );
1886
- var polyCoder = (d) => d === 12 ? byteCoder(12) : crystals.bitsCoder(d, compress(d));
1887
- function polyAdd(a_, b_) {
1888
- const a = a_;
1889
- const b = b_;
1890
- for (let i = 0; i < N; i++)
1891
- a[i] = crystals.mod(a[i] + b[i]);
1892
- }
1893
- function polySub(a_, b_) {
1894
- const a = a_;
1895
- const b = b_;
1896
- for (let i = 0; i < N; i++)
1897
- a[i] = crystals.mod(a[i] - b[i]);
1898
- }
1899
- function BaseCaseMultiply(a0, a1, b0, b1, zeta) {
1900
- const c0 = crystals.mod(a1 * b1 * zeta + a0 * b0);
1901
- const c1 = crystals.mod(a0 * b1 + a1 * b0);
1902
- return { c0, c1 };
1903
- }
1904
- function MultiplyNTTs(f_, g_) {
1905
- const f = f_;
1906
- const g = g_;
1907
- for (let i = 0; i < N / 2; i++) {
1908
- let z3 = crystals.nttZetas[64 + (i >> 1)];
1909
- if (i & 1)
1910
- z3 = -z3;
1911
- const { c0, c1 } = BaseCaseMultiply(f[2 * i + 0], f[2 * i + 1], g[2 * i + 0], g[2 * i + 1], z3);
1912
- f[2 * i + 0] = c0;
1913
- f[2 * i + 1] = c1;
1914
2097
  }
1915
- return f;
1916
- }
1917
- function SampleNTT(xof_) {
1918
- const xof = xof_;
1919
- const r = new Uint16Array(N);
1920
- for (let j = 0; j < N; ) {
1921
- const b = xof();
1922
- if (b.length % 3)
1923
- throw new Error("SampleNTT: unaligned block");
1924
- for (let i = 0; j < N && i + 3 <= b.length; i += 3) {
1925
- const d1 = (b[i + 0] >> 0 | b[i + 1] << 8) & 4095;
1926
- const d2 = (b[i + 1] >> 4 | b[i + 2] << 4) & 4095;
1927
- if (d1 < Q)
1928
- r[j++] = d1;
1929
- if (j < N && d2 < Q)
1930
- r[j++] = d2;
2098
+ for (let i = 0; i < (record.items ?? []).length; i++) {
2099
+ const item = record.items[i];
2100
+ checkItemHashes(item, i, errors);
2101
+ if (item.uris) checkItemUris(item.uris, ["items", i, "uris"], errors);
2102
+ if (item.enc !== void 0) checkItemEnc(item, i, errors);
2103
+ }
2104
+ for (let i = 0; i < (record.merkle ?? []).length; i++) {
2105
+ const commit = record.merkle[i];
2106
+ checkMerkleCommit(commit, i, errors);
2107
+ }
2108
+ if (record.sigs) {
2109
+ for (let i = 0; i < record.sigs.length; i++) {
2110
+ checkSigEntry(record.sigs[i], i, errors, info);
1931
2111
  }
1932
2112
  }
1933
- return r;
1934
- }
1935
- var sampleCBDBytes = (buf, eta) => {
1936
- const r = new Uint16Array(N);
1937
- const b32 = utils_js.u32(buf);
1938
- utils_js.swap32IfBE(b32);
1939
- let len = 0;
1940
- for (let i = 0, p = 0, bb = 0, t0 = 0; i < b32.length; i++) {
1941
- let b = b32[i];
1942
- for (let j = 0; j < 32; j++) {
1943
- bb += b & 1;
1944
- b >>= 1;
1945
- len += 1;
1946
- if (len === eta) {
1947
- t0 = bb;
1948
- bb = 0;
1949
- } else if (len === 2 * eta) {
1950
- r[p++] = crystals.mod(t0 - bb);
1951
- bb = 0;
1952
- len = 0;
1953
- }
1954
- }
2113
+ if (errors.length > 0) {
2114
+ return { ok: false, issues: errors.sort(compareIssuePath) };
1955
2115
  }
1956
- utils_js.swap32IfBE(b32);
1957
- if (len)
1958
- throw new Error(`sampleCBD: leftover bits: ${len}`);
1959
- return r;
1960
- };
1961
- function sampleCBD(PRF_, seed, nonce, eta) {
1962
- const PRF = PRF_;
1963
- return sampleCBDBytes(PRF(eta * N / 4, seed, nonce), eta);
2116
+ const result = {
2117
+ ok: true,
2118
+ record
2119
+ };
2120
+ if (warnings.length > 0) result.warnings = warnings.sort(compareIssuePath);
2121
+ if (info.length > 0) result.info = info.sort(compareIssuePath);
2122
+ return result;
1964
2123
  }
1965
- var genKPKE = (opts_) => {
1966
- const opts2 = opts_;
1967
- const { K, PRF, XOF, HASH512, ETA1, ETA2, du, dv } = opts2;
1968
- const poly1 = polyCoder(1);
1969
- const polyV = polyCoder(dv);
1970
- const polyU = polyCoder(du);
1971
- const publicCoder = splitCoder("publicKey", vecCoder(polyCoder(12), K), 32);
1972
- const secretCoder = vecCoder(polyCoder(12), K);
1973
- const cipherCoder = splitCoder("ciphertext", vecCoder(polyU, K), polyV);
1974
- const seedCoder = splitCoder("seed", 32, 32);
1975
- return {
1976
- secretCoder,
1977
- lengths: {
1978
- secretKey: secretCoder.bytesLen,
1979
- publicKey: publicCoder.bytesLen,
1980
- cipherText: cipherCoder.bytesLen
1981
- },
1982
- keygen: (seed) => {
1983
- abytesDoc(seed, 32, "seed");
1984
- const seedDst = new Uint8Array(33);
1985
- seedDst.set(seed);
1986
- seedDst[32] = K;
1987
- const seedHash = HASH512(seedDst);
1988
- const [rho, sigma] = seedCoder.decode(seedHash);
1989
- const sHat = [];
1990
- const tHat = [];
1991
- for (let i = 0; i < K; i++)
1992
- sHat.push(crystals.NTT.encode(sampleCBD(PRF, sigma, i, ETA1)));
1993
- const x = XOF(rho);
1994
- for (let i = 0; i < K; i++) {
1995
- const e = crystals.NTT.encode(sampleCBD(PRF, sigma, K + i, ETA1));
1996
- for (let j = 0; j < K; j++) {
1997
- const aji = SampleNTT(x.get(j, i));
1998
- polyAdd(e, MultiplyNTTs(aji, sHat[j]));
1999
- }
2000
- tHat.push(e);
2001
- }
2002
- x.clean();
2003
- const res = {
2004
- publicKey: publicCoder.encode([tHat, rho]),
2005
- secretKey: secretCoder.encode(sHat)
2006
- };
2007
- cleanBytes(rho, sigma, sHat, tHat, seedDst, seedHash);
2008
- return res;
2009
- },
2010
- encrypt: (publicKey, msg, seed) => {
2011
- const [tHat, rho] = publicCoder.decode(publicKey);
2012
- const rHat = [];
2013
- for (let i = 0; i < K; i++)
2014
- rHat.push(crystals.NTT.encode(sampleCBD(PRF, seed, i, ETA1)));
2015
- const x = XOF(rho);
2016
- const tmp2 = new Uint16Array(N);
2017
- const u = [];
2018
- for (let i = 0; i < K; i++) {
2019
- const e1 = sampleCBD(PRF, seed, K + i, ETA2);
2020
- const tmp = new Uint16Array(N);
2021
- for (let j = 0; j < K; j++) {
2022
- const aij = SampleNTT(x.get(i, j));
2023
- polyAdd(tmp, MultiplyNTTs(aij, rHat[j]));
2024
- }
2025
- polyAdd(e1, crystals.NTT.decode(tmp));
2026
- u.push(e1);
2027
- polyAdd(tmp2, MultiplyNTTs(tHat[i], rHat[i]));
2028
- cleanBytes(tmp);
2029
- }
2030
- x.clean();
2031
- const e2 = sampleCBD(PRF, seed, 2 * K, ETA2);
2032
- polyAdd(e2, crystals.NTT.decode(tmp2));
2033
- const v = poly1.decode(msg);
2034
- polyAdd(v, e2);
2035
- cleanBytes(tHat, rHat, tmp2, e2);
2036
- return cipherCoder.encode([u, v]);
2037
- },
2038
- decrypt: (cipherText, privateKey) => {
2039
- const [u, v] = cipherCoder.decode(cipherText);
2040
- const sk = secretCoder.decode(privateKey);
2041
- const tmp = new Uint16Array(N);
2042
- for (let i = 0; i < K; i++)
2043
- polyAdd(tmp, MultiplyNTTs(sk[i], crystals.NTT.encode(u[i])));
2044
- polySub(v, crystals.NTT.decode(tmp));
2045
- cleanBytes(tmp, sk, u);
2046
- return poly1.encode(v);
2124
+ function mapZodIssue(zissue, decoded) {
2125
+ const path = zissue.path;
2126
+ const explicit = zissue.params?.code;
2127
+ if (explicit !== void 0) {
2128
+ return issue(explicit, path, zissue.message);
2129
+ }
2130
+ const inSigsEntry = path.length >= 2 && path[0] === "sigs" && typeof path[1] === "number";
2131
+ const isInSlotEntry = (() => {
2132
+ if (path.length >= 5 && path[0] === "items" && typeof path[1] === "number" && path[2] === "enc" && path[3] === "slots" && typeof path[4] === "number") {
2133
+ return true;
2047
2134
  }
2048
- };
2049
- };
2050
- function createKyber(opts2) {
2051
- const rawOpts = opts2;
2052
- const KPKE = genKPKE(rawOpts);
2053
- const { HASH256, HASH512, KDF } = rawOpts;
2054
- const { secretCoder: KPKESecretCoder, lengths } = KPKE;
2055
- const secretCoder = splitCoder("secretKey", lengths.secretKey, lengths.publicKey, 32, 32);
2056
- const msgLen = 32;
2057
- const seedLen = 64;
2058
- const kemLengths = Object.freeze({
2059
- ...lengths,
2060
- seed: 64,
2061
- msg: msgLen,
2062
- msgRand: msgLen,
2063
- secretKey: secretCoder.bytesLen
2064
- });
2065
- return Object.freeze({
2066
- info: Object.freeze({ type: "ml-kem" }),
2067
- lengths: kemLengths,
2068
- keygen: (seed = randomBytes(seedLen)) => {
2069
- abytesDoc(seed, seedLen, "seed");
2070
- const { publicKey, secretKey: sk } = KPKE.keygen(seed.subarray(0, 32));
2071
- const publicKeyHash = HASH256(publicKey);
2072
- const secretKey = secretCoder.encode([sk, publicKey, publicKeyHash, seed.subarray(32)]);
2073
- cleanBytes(sk, publicKeyHash);
2074
- return {
2075
- publicKey,
2076
- secretKey
2077
- };
2078
- },
2079
- getPublicKey: (secretKey) => {
2080
- const [_sk, publicKey, _publicKeyHash, _z] = secretCoder.decode(secretKey);
2081
- return Uint8Array.from(publicKey);
2082
- },
2083
- encapsulate: (publicKey, msg = randomBytes(msgLen)) => {
2084
- abytesDoc(publicKey, lengths.publicKey, "publicKey");
2085
- abytesDoc(msg, msgLen, "message");
2086
- const eke = publicKey.subarray(0, 384 * opts2.K);
2087
- const ek = KPKESecretCoder.encode(KPKESecretCoder.decode(copyBytes(eke)));
2088
- if (!equalBytes(ek, eke)) {
2089
- cleanBytes(ek);
2090
- throw new Error("ML-KEM.encapsulate: wrong publicKey modulus");
2091
- }
2092
- cleanBytes(ek);
2093
- const kr = HASH512.create().update(msg).update(HASH256(publicKey)).digest();
2094
- const cipherText = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
2095
- cleanBytes(kr.subarray(32));
2096
- return {
2097
- cipherText,
2098
- sharedSecret: kr.subarray(0, 32)
2099
- };
2100
- },
2101
- decapsulate: (cipherText, secretKey) => {
2102
- abytesDoc(secretKey, secretCoder.bytesLen, "secretKey");
2103
- abytesDoc(cipherText, lengths.cipherText, "cipherText");
2104
- const k768 = secretCoder.bytesLen - 96;
2105
- const start = k768 + 32;
2106
- const test = HASH256(secretKey.subarray(k768 / 2, start));
2107
- if (!equalBytes(test, secretKey.subarray(start, start + 32)))
2108
- throw new Error("invalid secretKey: hash check failed");
2109
- const [sk, publicKey, publicKeyHash, z3] = secretCoder.decode(secretKey);
2110
- const msg = KPKE.decrypt(cipherText, sk);
2111
- const kr = HASH512.create().update(msg).update(publicKeyHash).digest();
2112
- const Khat = kr.subarray(0, 32);
2113
- const cipherText2 = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
2114
- const isValid = equalBytes(cipherText, cipherText2);
2115
- const Kbar = KDF.create({ dkLen: 32 }).update(z3).update(cipherText).digest();
2116
- cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar);
2117
- return isValid ? Khat : Kbar;
2135
+ if (path.length >= 2 && path[0] === "slots" && typeof path[1] === "number") {
2136
+ return true;
2118
2137
  }
2119
- });
2120
- }
2121
- function shakePRF(dkLen, key, nonce) {
2122
- return sha3_js.shake256.create({ dkLen }).update(key).update(new Uint8Array([nonce])).digest();
2123
- }
2124
- var opts = /* @__PURE__ */ (() => ({
2125
- HASH256: sha3_js.sha3_256,
2126
- HASH512: sha3_js.sha3_512,
2127
- KDF: sha3_js.shake256,
2128
- XOF: XOF128,
2129
- PRF: shakePRF
2130
- }))();
2131
- var mk = (params) => createKyber({
2132
- ...opts,
2133
- ...params
2134
- });
2135
- var ml_kem768 = /* @__PURE__ */ (() => mk(PARAMS[768]))();
2136
-
2137
- // ../../node_modules/.pnpm/@noble+post-quantum@0.6.1/node_modules/@noble/post-quantum/hybrid.js
2138
- function ecKeygen(curve, allowZeroKey = false) {
2139
- const lengths = curve.lengths;
2140
- let keygen = curve.keygen;
2141
- if (allowZeroKey) {
2142
- if (!("getSharedSecret" in curve && "sign" in curve && "verify" in curve))
2143
- throw new Error("allowZeroKey requires a Weierstrass curve");
2144
- const wCurve = curve;
2145
- const Fn = wCurve.Point.Fn;
2146
- keygen = (seed = randomBytes(lengths.seed)) => {
2147
- utils_js.abytes(seed, lengths.seed, "seed");
2148
- const seedScalar = Fn.isLE ? utils_js$1.bytesToNumberLE(seed) : utils_js$1.bytesToNumberBE(seed);
2149
- const secretKey = Fn.toBytes(Fn.create(seedScalar));
2150
- return {
2151
- secretKey,
2152
- publicKey: curve.getPublicKey(secretKey)
2153
- };
2154
- };
2138
+ return false;
2139
+ })();
2140
+ const valueAtIssue = valueAtPath(decoded, path);
2141
+ const isMissing = valueAtIssue === void 0;
2142
+ switch (zissue.code) {
2143
+ case "invalid_type":
2144
+ if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
2145
+ if (isMissing) {
2146
+ if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2147
+ return issue("SCHEMA_MISSING_REQUIRED", path, zissue.message);
2148
+ }
2149
+ if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2150
+ return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
2151
+ case "invalid_value":
2152
+ if (path.length === 1 && path[0] === "v") {
2153
+ return issue(
2154
+ isMissing ? "SCHEMA_MISSING_REQUIRED" : "SCHEMA_INVALID_LITERAL",
2155
+ path,
2156
+ zissue.message
2157
+ );
2158
+ }
2159
+ return issue("SCHEMA_INVALID_LITERAL", path, zissue.message);
2160
+ case "unrecognized_keys":
2161
+ if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
2162
+ if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2163
+ return issue("SCHEMA_UNKNOWN_FIELD", path, zissue.message);
2164
+ case "invalid_format":
2165
+ case "too_big":
2166
+ case "too_small":
2167
+ if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2168
+ return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
2169
+ case "invalid_union":
2170
+ case "invalid_key":
2171
+ case "invalid_element":
2172
+ case "custom":
2173
+ default:
2174
+ if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
2175
+ if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2176
+ return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
2155
2177
  }
2156
- return {
2157
- lengths: { secretKey: lengths.secretKey, publicKey: lengths.publicKey, seed: lengths.seed },
2158
- keygen: (seed) => keygen(seed),
2159
- getPublicKey: (secretKey) => curve.getPublicKey(secretKey)
2160
- };
2161
2178
  }
2162
- function ecdhKem(curve, allowZeroKey = false) {
2163
- const kg = ecKeygen(curve, allowZeroKey);
2164
- if (!curve.getSharedSecret)
2165
- throw new Error("wrong curve");
2166
- return {
2167
- lengths: { ...kg.lengths, msg: kg.lengths.seed, cipherText: kg.lengths.publicKey },
2168
- keygen: kg.keygen,
2169
- getPublicKey: kg.getPublicKey,
2170
- encapsulate(publicKey, rand = randomBytes(curve.lengths.seed)) {
2171
- const seed = copyBytes(rand);
2172
- let ek = void 0;
2173
- try {
2174
- ek = this.keygen(seed).secretKey;
2175
- const sharedSecret = this.decapsulate(publicKey, ek);
2176
- const cipherText = curve.getPublicKey(ek);
2177
- return { sharedSecret, cipherText };
2178
- } finally {
2179
- cleanBytes(seed);
2180
- if (ek)
2181
- cleanBytes(ek);
2182
- }
2183
- },
2184
- decapsulate(cipherText, secretKey) {
2185
- const res = curve.getSharedSecret(secretKey, cipherText);
2186
- return curve.lengths.publicKeyHasPrefix ? res.subarray(1) : res;
2179
+ function checkItemHashes(item, idx, errors) {
2180
+ const entries = Object.entries(item.hashes);
2181
+ if (entries.length === 0) {
2182
+ errors.push(
2183
+ issue(
2184
+ "SCHEMA_TYPE_MISMATCH",
2185
+ ["items", idx, "hashes"],
2186
+ "hashes must be a non-empty CBOR map of <alg-id> -> <digest>"
2187
+ )
2188
+ );
2189
+ return;
2190
+ }
2191
+ for (const [alg, digest] of entries) {
2192
+ if (!(alg in HASH_ALG_LENGTHS)) {
2193
+ errors.push(
2194
+ issue("UNSUPPORTED_HASH_ALG", ["items", idx, "hashes", alg], `unknown hash alg: ${alg}`)
2195
+ );
2196
+ continue;
2187
2197
  }
2188
- };
2198
+ const expected = HASH_ALG_LENGTHS[alg];
2199
+ if (digest.length !== expected) {
2200
+ errors.push(
2201
+ issue(
2202
+ "HASH_DIGEST_LENGTH_MISMATCH",
2203
+ ["items", idx, "hashes", alg],
2204
+ `hashes['${alg}'] digest length ${digest.length} != ${expected}`
2205
+ )
2206
+ );
2207
+ }
2208
+ }
2189
2209
  }
2190
- function splitLengths(lst, name) {
2191
- return splitCoder(name, ...lst.map((i) => {
2192
- if (typeof i.lengths[name] !== "number")
2193
- throw new Error("wrong length: " + name);
2194
- return i.lengths[name];
2195
- }));
2210
+ function checkItemUris(uris, basePath, errors) {
2211
+ uris.forEach((chunks, ui) => validateOneUri(chunks, [...basePath, ui], errors));
2196
2212
  }
2197
- function expandSeedXof(xof) {
2198
- return ((seed, seedLen) => xof(seed, { dkLen: seedLen }));
2213
+ function validateOneUri(chunks, path, errors) {
2214
+ const reconstructed = reconstructChunkedUri(chunks);
2215
+ if (!reconstructed.ok) {
2216
+ errors.push(issue(reconstructed.code, path, reconstructed.reason));
2217
+ return;
2218
+ }
2219
+ const uri = reconstructed.uri;
2220
+ if (uri.includes("#")) {
2221
+ errors.push(
2222
+ issue("INVALID_URI", path, "URI contains a fragment identifier ('#'), which is forbidden")
2223
+ );
2224
+ return;
2225
+ }
2226
+ const sepIdx = uri.indexOf("://");
2227
+ if (sepIdx <= 0 || !/^[a-z][a-z0-9+.-]*$/i.test(uri.slice(0, sepIdx))) {
2228
+ errors.push(
2229
+ issue("INVALID_URI", path, "URI is not absolute (missing scheme://hierarchical-part)")
2230
+ );
2231
+ return;
2232
+ }
2233
+ const scheme = uri.slice(0, sepIdx).toLowerCase();
2234
+ const rest = uri.slice(sepIdx + "://".length);
2235
+ if (scheme === "ar") {
2236
+ if (!/^ar:\/\/[A-Za-z0-9_-]{43}$/.test("ar://" + rest)) {
2237
+ errors.push(
2238
+ issue(
2239
+ "INVALID_URI",
2240
+ path,
2241
+ "ar:// URI does not match `^ar://[A-Za-z0-9_-]{43}$` (43-char base64url txid, no path/query/fragment)"
2242
+ )
2243
+ );
2244
+ }
2245
+ return;
2246
+ }
2247
+ if (scheme === "ipfs") {
2248
+ const slashIdx = rest.indexOf("/");
2249
+ const cid = slashIdx === -1 ? rest : rest.slice(0, slashIdx);
2250
+ if (!validateCidProfile(cid)) {
2251
+ errors.push(
2252
+ issue("INVALID_URI", path, "ipfs:// URI is not a valid CID under the Label 309 profile")
2253
+ );
2254
+ }
2255
+ return;
2256
+ }
2257
+ errors.push(
2258
+ issue("INVALID_URI", path, "unsupported URI scheme; v1 PoE URI set is {ar://, ipfs://}")
2259
+ );
2199
2260
  }
2200
- function combineKeys(realSeedLen, expandSeed_, ...ck_) {
2201
- const expandSeed = expandSeed_;
2202
- const ck = ck_;
2203
- const seedCoder = splitLengths(ck, "seed");
2204
- const pkCoder = splitLengths(ck, "publicKey");
2205
- utils_js.anumber(realSeedLen);
2206
- function expandDecapsulationKey(seed) {
2207
- utils_js.abytes(seed, realSeedLen);
2208
- const expandedRaw = expandSeed(seed, seedCoder.bytesLen);
2209
- const expandedSeed = expandedRaw.buffer === seed.buffer ? copyBytes(expandedRaw) : expandedRaw;
2210
- const expanded = [];
2211
- const keySecret = [];
2212
- const secretKey = [];
2213
- const publicKey = [];
2214
- let ok = false;
2215
- try {
2216
- for (const part of seedCoder.decode(expandedSeed))
2217
- expanded.push(copyBytes(part));
2218
- for (let i = 0; i < ck.length; i++) {
2219
- const keys = ck[i].keygen(expanded[i]);
2220
- keySecret.push(keys.secretKey);
2221
- secretKey.push(copyBytes(keys.secretKey));
2222
- publicKey.push(keys.publicKey);
2261
+ function checkItemEnc(item, idx, errors) {
2262
+ const hasContentHash = Object.keys(item.hashes).some((alg) => alg in HASH_ALG_LENGTHS);
2263
+ if (!hasContentHash) {
2264
+ errors.push(
2265
+ issue(
2266
+ "ENC_REQUIRES_CONTENT_HASH",
2267
+ ["items", idx, "enc"],
2268
+ "item carries `enc` but `hashes` has no content-hash entry (sha2-256 or blake2b-256)"
2269
+ )
2270
+ );
2271
+ return;
2272
+ }
2273
+ const encParse = EncryptionEnvelopeSchema.safeParse(item.enc);
2274
+ if (!encParse.success) {
2275
+ for (const zissue of encParse.error.issues) {
2276
+ const mapped = mapZodIssue(zissue, item.enc);
2277
+ errors.push({
2278
+ ...mapped,
2279
+ path: ["items", idx, "enc", ...mapped.path]
2280
+ });
2281
+ }
2282
+ return;
2283
+ }
2284
+ const enc = encParse.data;
2285
+ const basePath = ["items", idx, "enc"];
2286
+ if (typeof enc.scheme !== "number" || !Number.isInteger(enc.scheme) || enc.scheme !== 1) {
2287
+ errors.push(
2288
+ issue(
2289
+ "UNSUPPORTED_ENVELOPE_SCHEME",
2290
+ [...basePath, "scheme"],
2291
+ `enc.scheme must be the unsigned integer 1; got ${String(enc.scheme)}`
2292
+ )
2293
+ );
2294
+ }
2295
+ if (UNAUTHENTICATED_CIPHER_RE.test(enc.aead)) {
2296
+ errors.push(
2297
+ issue(
2298
+ "UNAUTHENTICATED_CIPHER_FORBIDDEN",
2299
+ [...basePath, "aead"],
2300
+ `'${enc.aead}' is an unauthenticated cipher; Label 309 mandates an authenticated (AEAD) cipher`
2301
+ )
2302
+ );
2303
+ return;
2304
+ }
2305
+ if (!(enc.aead in AEAD_NONCE_LENGTHS)) {
2306
+ errors.push(
2307
+ issue("UNSUPPORTED_AEAD_ALG", [...basePath, "aead"], `unknown aead alg: ${enc.aead}`)
2308
+ );
2309
+ return;
2310
+ }
2311
+ const expectedNonceLen = AEAD_NONCE_LENGTHS[enc.aead];
2312
+ if (enc.nonce.length !== expectedNonceLen) {
2313
+ errors.push(
2314
+ issue(
2315
+ "NONCE_LENGTH_MISMATCH",
2316
+ [...basePath, "nonce"],
2317
+ `nonce length ${enc.nonce.length} != ${expectedNonceLen} for ${enc.aead}`
2318
+ )
2319
+ );
2320
+ }
2321
+ if (enc.kem !== void 0 && !(enc.kem in KEM_SLOT_DESCRIPTORS)) {
2322
+ errors.push(issue("UNSUPPORTED_KEM_ALG", [...basePath, "kem"], `unknown kem alg: ${enc.kem}`));
2323
+ }
2324
+ const hasSlots = enc.slots !== void 0;
2325
+ const hasSlotsMac = enc.slots_mac !== void 0;
2326
+ const hasPassphrase = enc.passphrase !== void 0;
2327
+ if (hasSlots && hasPassphrase) {
2328
+ errors.push(
2329
+ issue("ENC_EXCLUSIVITY_VIOLATION", basePath, "enc combines slots with passphrase; pick one")
2330
+ );
2331
+ }
2332
+ if (hasSlots && !hasSlotsMac) {
2333
+ errors.push(
2334
+ issue("ENC_SLOTS_MAC_REQUIRED", basePath, "enc.slots present but enc.slots_mac absent")
2335
+ );
2336
+ }
2337
+ if (hasSlotsMac && !hasSlots) {
2338
+ errors.push(
2339
+ issue("ENC_SLOTS_REQUIRED", basePath, "enc.slots_mac present but enc.slots absent")
2340
+ );
2341
+ }
2342
+ if (hasSlots && enc.kem === void 0) {
2343
+ errors.push(issue("ENC_KEM_REQUIRED", basePath, "enc.slots present but enc.kem absent"));
2344
+ }
2345
+ if (!hasSlots && !hasPassphrase) {
2346
+ errors.push(
2347
+ issue(
2348
+ "ENC_NO_KEY_PATH",
2349
+ basePath,
2350
+ "enc requires either slots or passphrase \u2014 no on-chain key path otherwise"
2351
+ )
2352
+ );
2353
+ }
2354
+ if (hasSlots) {
2355
+ const slotCount = enc.slots.length;
2356
+ if (slotCount < 1) {
2357
+ errors.push(
2358
+ issue("ENC_SLOTS_EMPTY", [...basePath, "slots"], `slots length ${slotCount} < 1`)
2359
+ );
2360
+ } else if (slotCount > MAX_SLOTS) {
2361
+ errors.push(
2362
+ issue(
2363
+ "ENC_SLOTS_TOO_MANY",
2364
+ [...basePath, "slots"],
2365
+ `slots length ${slotCount} exceeds MAX_SLOTS=${MAX_SLOTS}`
2366
+ )
2367
+ );
2368
+ } else {
2369
+ const descriptor = enc.kem !== void 0 ? KEM_SLOT_DESCRIPTORS[enc.kem] : void 0;
2370
+ if (descriptor !== void 0) {
2371
+ const rawSlotKeys = rawSlotKeySets(item.enc);
2372
+ const seenKemMaterial = /* @__PURE__ */ new Set();
2373
+ enc.slots.forEach((slot, si) => {
2374
+ const slotPath = [...basePath, "slots", si];
2375
+ checkSlotShape(
2376
+ slot,
2377
+ rawSlotKeys[si] ?? /* @__PURE__ */ new Set(),
2378
+ descriptor,
2379
+ enc.kem,
2380
+ slotPath,
2381
+ errors
2382
+ );
2383
+ const material = slotKemMaterial(slot, descriptor);
2384
+ if (material !== void 0) {
2385
+ const key = bytesToHex(material);
2386
+ if (seenKemMaterial.has(key)) {
2387
+ errors.push(
2388
+ issue(
2389
+ "ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
2390
+ [...slotPath, descriptor.field],
2391
+ `slot ${si} ${descriptor.field} duplicates an earlier slot \u2014 per-slot KEK uniqueness is violated`
2392
+ )
2393
+ );
2394
+ } else {
2395
+ seenKemMaterial.add(key);
2396
+ }
2397
+ }
2398
+ });
2399
+ const perSlotBytes = descriptor.fieldLength + descriptor.wrapLength;
2400
+ const decodedEnvelopeBytes = NONCE_LENGTH + SLOTS_MAC_LENGTH + slotCount * perSlotBytes;
2401
+ if (decodedEnvelopeBytes > MAX_DECODED_ENVELOPE_BYTES) {
2402
+ errors.push(
2403
+ issue(
2404
+ "ENC_ENVELOPE_TOO_LARGE",
2405
+ [...basePath, "slots"],
2406
+ `decoded envelope size ${decodedEnvelopeBytes} exceeds MAX_DECODED_ENVELOPE_BYTES=${MAX_DECODED_ENVELOPE_BYTES}`
2407
+ )
2408
+ );
2409
+ }
2223
2410
  }
2224
- ok = true;
2225
- return { secretKey, publicKey };
2226
- } finally {
2227
- cleanBytes(expandedSeed, expanded, keySecret);
2228
- if (!ok)
2229
- cleanBytes(secretKey);
2230
2411
  }
2231
2412
  }
2232
- return {
2233
- info: { lengths: { seed: realSeedLen, publicKey: pkCoder.bytesLen, secretKey: realSeedLen } },
2234
- getPublicKey(secretKey) {
2235
- return this.keygen(secretKey).publicKey;
2236
- },
2237
- keygen(seed = randomBytes(realSeedLen)) {
2238
- const { publicKey: pk, secretKey } = expandDecapsulationKey(seed);
2239
- try {
2240
- const publicKey = pkCoder.encode(pk);
2241
- return { secretKey: seed, publicKey };
2242
- } finally {
2243
- cleanBytes(pk);
2244
- cleanBytes(secretKey);
2413
+ if (hasPassphrase) {
2414
+ const pp = enc.passphrase;
2415
+ const ppPath = [...basePath, "passphrase"];
2416
+ if (!PASSPHRASE_KDF_ALGS.has(pp.alg)) {
2417
+ errors.push(
2418
+ issue(
2419
+ "ENC_PASSPHRASE_ALG_UNSUPPORTED",
2420
+ [...ppPath, "alg"],
2421
+ `unknown passphrase kdf alg: ${pp.alg}`
2422
+ )
2423
+ );
2424
+ return;
2425
+ }
2426
+ if (pp.alg === "argon2id") {
2427
+ const allowed = /* @__PURE__ */ new Set(["m", "t", "p"]);
2428
+ for (const k of Object.keys(pp.params)) {
2429
+ if (!allowed.has(k)) {
2430
+ errors.push(
2431
+ issue(
2432
+ "SCHEMA_UNKNOWN_FIELD",
2433
+ [...ppPath, "params", k],
2434
+ `unknown argon2id params field: ${k}`
2435
+ )
2436
+ );
2437
+ }
2245
2438
  }
2246
- },
2247
- expandDecapsulationKey,
2248
- realSeedLen
2249
- };
2250
- }
2251
- function combineKEMS(realSeedLen, realMsgLen, expandSeed, combiner, ...kems) {
2252
- const rawCombiner = combiner;
2253
- const rawKems = kems;
2254
- const keys = combineKeys(realSeedLen, expandSeed, ...rawKems);
2255
- const ctCoder = splitLengths(rawKems, "cipherText");
2256
- const pkCoder = splitLengths(rawKems, "publicKey");
2257
- const msgCoder = splitLengths(rawKems, "msg");
2258
- utils_js.anumber(realMsgLen);
2259
- const lengths = Object.freeze({
2260
- ...keys.info.lengths,
2261
- msg: realMsgLen,
2262
- msgRand: msgCoder.bytesLen,
2263
- cipherText: ctCoder.bytesLen
2264
- });
2265
- return Object.freeze({
2266
- lengths,
2267
- getPublicKey: keys.getPublicKey,
2268
- keygen: keys.keygen,
2269
- encapsulate(pk, randomness = randomBytes(msgCoder.bytesLen)) {
2270
- const pks = pkCoder.decode(pk);
2271
- const rand = msgCoder.decode(randomness);
2272
- const sharedSecret = [];
2273
- const cipherText = [];
2274
- try {
2275
- for (let i = 0; i < rawKems.length; i++) {
2276
- const enc = rawKems[i].encapsulate(pks[i], rand[i]);
2277
- sharedSecret.push(enc.sharedSecret);
2278
- cipherText.push(enc.cipherText);
2439
+ const p = pp.params;
2440
+ const argonInt = (val, name) => {
2441
+ if (typeof val !== "number" || !Number.isInteger(val)) {
2442
+ errors.push(
2443
+ issue(
2444
+ "SCHEMA_TYPE_MISMATCH",
2445
+ [...ppPath, "params", name],
2446
+ `argon2id params.${name} must be a CBOR unsigned integer`
2447
+ )
2448
+ );
2449
+ return null;
2279
2450
  }
2280
- return {
2281
- // Detach the combiner result before cleanup: a caller-provided combiner may alias one of
2282
- // the child sharedSecret buffers, and those child buffers are zeroized immediately below.
2283
- sharedSecret: copyBytes(rawCombiner(pks, cipherText, sharedSecret)),
2284
- cipherText: ctCoder.encode(cipherText)
2285
- };
2286
- } finally {
2287
- cleanBytes(sharedSecret, cipherText);
2451
+ return val;
2452
+ };
2453
+ const mVal = argonInt(p.m, "m");
2454
+ const tVal = argonInt(p.t, "t");
2455
+ const pVal = argonInt(p.p, "p");
2456
+ if (mVal !== null && mVal < 65536) {
2457
+ errors.push(
2458
+ issue(
2459
+ "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
2460
+ [...ppPath, "params", "m"],
2461
+ "argon2id requires m >= 65536 KiB"
2462
+ )
2463
+ );
2288
2464
  }
2289
- },
2290
- decapsulate(ct, seed) {
2291
- const cts = ctCoder.decode(ct);
2292
- const { publicKey, secretKey } = keys.expandDecapsulationKey(seed);
2293
- const sharedSecret = rawKems.map((i, j) => i.decapsulate(cts[j], secretKey[j]));
2294
- try {
2295
- return copyBytes(rawCombiner(publicKey, cts, sharedSecret));
2296
- } finally {
2297
- cleanBytes(secretKey, sharedSecret);
2465
+ if (tVal !== null && tVal < 3) {
2466
+ errors.push(
2467
+ issue(
2468
+ "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
2469
+ [...ppPath, "params", "t"],
2470
+ "argon2id requires t >= 3"
2471
+ )
2472
+ );
2473
+ }
2474
+ if (pVal !== null && pVal < 1) {
2475
+ errors.push(
2476
+ issue(
2477
+ "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
2478
+ [...ppPath, "params", "p"],
2479
+ "argon2id requires p >= 1"
2480
+ )
2481
+ );
2298
2482
  }
2299
2483
  }
2300
- });
2484
+ }
2301
2485
  }
2302
- var x25519kem = /* @__PURE__ */ ecdhKem(ed25519_js.x25519);
2303
- var ml_kem768_x25519 = /* @__PURE__ */ (() => combineKEMS(
2304
- 32,
2305
- 32,
2306
- expandSeedXof(sha3_js.shake256),
2307
- // Awesome label, so much escaping hell in a single line.
2308
- (pk, ct, ss) => sha3_js.sha3_256(utils_js$1.concatBytes(ss[0], ss[1], ct[1], pk[1], utils_js$1.asciiToBytes("\\.//^\\"))),
2309
- ml_kem768,
2310
- x25519kem
2311
- ))();
2312
- var XWing = /* @__PURE__ */ (() => ml_kem768_x25519)();
2313
- var AeadVerificationError2 = class extends Error {
2314
- code = "aead_verification_failed";
2315
- constructor(message, options) {
2316
- super(message, options);
2317
- this.name = "AeadVerificationError";
2486
+ var SLOT_KEY_UNIVERSE = /* @__PURE__ */ new Set(["epk", "kem_ct", "wrap"]);
2487
+ function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath, errors) {
2488
+ const foreignField = descriptor.field === "epk" ? "kem_ct" : "epk";
2489
+ if (rawKeys.has(foreignField)) {
2490
+ errors.push(
2491
+ issue(
2492
+ "ENC_SLOT_INVALID_SHAPE",
2493
+ [...slotPath, foreignField],
2494
+ `slot carries '${foreignField}' but kem='${kem}' expects '${descriptor.field}'`
2495
+ )
2496
+ );
2318
2497
  }
2319
- };
2320
- function chacha20Poly1305Decrypt(opts2) {
2321
- try {
2322
- return chacha_js.chacha20poly1305(opts2.key, opts2.nonce, opts2.aad).decrypt(opts2.ciphertext);
2323
- } catch (cause) {
2324
- throw new AeadVerificationError2("chacha20-poly1305 decrypt failed", { cause });
2498
+ for (const k of rawKeys) {
2499
+ if (!SLOT_KEY_UNIVERSE.has(k)) {
2500
+ errors.push(
2501
+ issue(
2502
+ "ENC_SLOT_INVALID_SHAPE",
2503
+ [...slotPath, k],
2504
+ `slot carries unexpected key '${k}'; a slot is a 2-key map {${descriptor.field}, wrap}`
2505
+ )
2506
+ );
2507
+ }
2508
+ }
2509
+ if (descriptor.field === "epk") {
2510
+ if (slot.epk === void 0) {
2511
+ errors.push(
2512
+ issue(
2513
+ "ENC_SLOT_INVALID_SHAPE",
2514
+ [...slotPath, "epk"],
2515
+ `slot for kem='${kem}' is missing required 'epk'`
2516
+ )
2517
+ );
2518
+ } else if (slot.epk.length !== descriptor.fieldLength) {
2519
+ errors.push(
2520
+ issue(
2521
+ KEM_FIELD_LENGTH_CODE.epk,
2522
+ [...slotPath, "epk"],
2523
+ `slot.epk length ${slot.epk.length} != ${descriptor.fieldLength} for ${kem}`
2524
+ )
2525
+ );
2526
+ }
2527
+ } else {
2528
+ if (slot.kem_ct === void 0) {
2529
+ errors.push(
2530
+ issue(
2531
+ "ENC_SLOT_INVALID_SHAPE",
2532
+ [...slotPath, "kem_ct"],
2533
+ `slot for kem='${kem}' is missing required 'kem_ct'`
2534
+ )
2535
+ );
2536
+ } else {
2537
+ const reassembled = bytesChunkArrayConcat(slot.kem_ct).length;
2538
+ if (reassembled !== descriptor.fieldLength) {
2539
+ errors.push(
2540
+ issue(
2541
+ KEM_FIELD_LENGTH_CODE.kem_ct,
2542
+ [...slotPath, "kem_ct"],
2543
+ `slot.kem_ct reassembles to ${reassembled} bytes != ${descriptor.fieldLength} for ${kem}`
2544
+ )
2545
+ );
2546
+ }
2547
+ }
2548
+ }
2549
+ if (slot.wrap === void 0) {
2550
+ errors.push(
2551
+ issue(
2552
+ "ENC_SLOT_INVALID_SHAPE",
2553
+ [...slotPath, "wrap"],
2554
+ `slot for kem='${kem}' is missing required 'wrap'`
2555
+ )
2556
+ );
2557
+ } else if (slot.wrap.length !== descriptor.wrapLength) {
2558
+ errors.push(
2559
+ issue(
2560
+ "WRAP_LENGTH_MISMATCH",
2561
+ [...slotPath, "wrap"],
2562
+ `slot.wrap length ${slot.wrap.length} != ${descriptor.wrapLength}`
2563
+ )
2564
+ );
2565
+ }
2566
+ }
2567
+ function slotKemMaterial(slot, descriptor) {
2568
+ if (descriptor.field === "epk") {
2569
+ return slot.epk;
2570
+ }
2571
+ if (slot.kem_ct === void 0) return void 0;
2572
+ return bytesChunkArrayConcat(slot.kem_ct);
2573
+ }
2574
+ function bytesToHex(bytes) {
2575
+ let hex = "";
2576
+ for (let i = 0; i < bytes.length; i++) {
2577
+ hex += bytes[i].toString(16).padStart(2, "0");
2325
2578
  }
2579
+ return hex;
2326
2580
  }
2327
- function xchacha20Poly1305Decrypt2(opts2) {
2328
- try {
2329
- return chacha_js.xchacha20poly1305(opts2.key, opts2.nonce, opts2.aad).decrypt(opts2.ciphertext);
2330
- } catch (cause) {
2331
- throw new AeadVerificationError2("xchacha20-poly1305 decrypt failed", { cause });
2332
- }
2581
+ function rawSlotKeySets(rawEnc) {
2582
+ const slots = mapLikeGet(rawEnc, "slots");
2583
+ if (!Array.isArray(slots)) return [];
2584
+ return slots.map((slot) => {
2585
+ const keys = /* @__PURE__ */ new Set();
2586
+ if (slot instanceof Map) {
2587
+ for (const k of slot.keys()) if (typeof k === "string") keys.add(k);
2588
+ } else if (typeof slot === "object" && slot !== null) {
2589
+ for (const k of Object.keys(slot)) keys.add(k);
2590
+ }
2591
+ return keys;
2592
+ });
2333
2593
  }
2334
- function hkdfSha256(opts2) {
2335
- return hkdf_js.hkdf(sha2_js.sha256, opts2.ikm, opts2.salt, opts2.info, opts2.length);
2594
+ function mapLikeGet(value, key) {
2595
+ if (value instanceof Map) return value.get(key);
2596
+ if (typeof value === "object" && value !== null) {
2597
+ return value[key];
2598
+ }
2599
+ return void 0;
2336
2600
  }
2337
- var MLKEM768X25519_ENC_LENGTH = 1120;
2338
- var MLKEM768X25519_SEED_LENGTH = 32;
2339
- function mlkem768x25519Decapsulate(opts2) {
2340
- if (opts2.secretSeed.length !== MLKEM768X25519_SEED_LENGTH) {
2341
- throw new Error(
2342
- `mlkem768x25519 secret seed must be ${MLKEM768X25519_SEED_LENGTH} bytes, got ${opts2.secretSeed.length}`
2601
+ function checkMerkleCommit(commit, idx, errors) {
2602
+ const basePath = ["merkle", idx];
2603
+ if (!(commit.alg in MERKLE_COMMIT_ALG_LENGTHS)) {
2604
+ errors.push(
2605
+ issue(
2606
+ "UNSUPPORTED_MERKLE_COMMIT_ALG",
2607
+ [...basePath, "alg"],
2608
+ `unknown merkle commitment alg: ${commit.alg}`
2609
+ )
2343
2610
  );
2611
+ return;
2344
2612
  }
2345
- if (opts2.enc.length !== MLKEM768X25519_ENC_LENGTH) {
2346
- throw new Error(
2347
- `mlkem768x25519 enc must be ${MLKEM768X25519_ENC_LENGTH} bytes, got ${opts2.enc.length}`
2613
+ const expected = MERKLE_COMMIT_ALG_LENGTHS[commit.alg];
2614
+ if (commit.root.length !== expected) {
2615
+ errors.push(
2616
+ issue(
2617
+ "HASH_DIGEST_LENGTH_MISMATCH",
2618
+ [...basePath, "root"],
2619
+ `merkle entry root length ${commit.root.length} != ${expected} for ${commit.alg}`
2620
+ )
2348
2621
  );
2349
2622
  }
2350
- return XWing.decapsulate(opts2.enc, opts2.secretSeed);
2351
- }
2352
- var X25519LowOrderPointError = class extends Error {
2353
- code = "X25519_LOW_ORDER_POINT";
2354
- constructor(options) {
2355
- super("x25519 ECDH rejected: peer public key is a small-order point", options);
2356
- this.name = "X25519LowOrderPointError";
2623
+ if (commit.uris) {
2624
+ checkItemUris(commit.uris, [...basePath, "uris"], errors);
2357
2625
  }
2358
- };
2359
- var NOBLE_LOW_ORDER_MESSAGE = "invalid private or public key received";
2360
- function x25519PublicKey(opts2) {
2361
- return ed25519_js.x25519.getPublicKey(opts2.secretKey);
2362
2626
  }
2363
- function x25519Ecdh(opts2) {
2364
- try {
2365
- return ed25519_js.x25519.getSharedSecret(opts2.secretKey, opts2.theirPublicKey);
2366
- } catch (e) {
2367
- if (e instanceof Error && e.message === NOBLE_LOW_ORDER_MESSAGE) {
2368
- throw new X25519LowOrderPointError({ cause: e });
2627
+ function checkSigEntry(entry, idx, errors, info) {
2628
+ if (entry.cose_key !== void 0) {
2629
+ const keyIssue = inspectCoseKey(entry.cose_key, idx);
2630
+ if (keyIssue !== null) {
2631
+ errors.push(keyIssue);
2632
+ return;
2369
2633
  }
2370
- throw e;
2371
2634
  }
2372
- }
2373
- var EciesSealedPoeError = class extends Error {
2374
- code;
2375
- constructor(code, message, options) {
2376
- super(message, options);
2377
- this.name = "EciesSealedPoeError";
2378
- this.code = code;
2635
+ const merged = bytesChunkArrayConcat(entry.cose_sign1);
2636
+ let cose;
2637
+ try {
2638
+ cose = decodeCoseSign1(merged);
2639
+ } catch (cause) {
2640
+ errors.push(
2641
+ issue(
2642
+ "MALFORMED_SIG_COSE_SIGN1",
2643
+ ["sigs", idx],
2644
+ cause instanceof CoseVerifyError || cause instanceof Error ? cause.message : String(cause)
2645
+ )
2646
+ );
2647
+ return;
2379
2648
  }
2380
- };
2381
- function encodeCanonicalCbor3(value) {
2382
- return cbor2.encode(value, {
2383
- cde: true,
2384
- collapseBigInts: true,
2385
- rejectDuplicateKeys: true,
2386
- sortKeys: sorts.sortCoreDeterministic
2387
- });
2388
- }
2389
- var CHUNK_MAX_BYTES = 64;
2390
- function chunkKemCt(value) {
2391
- if (value.length === 0) {
2392
- throw new Error("chunkKemCt: refusing to chunk an empty byte string");
2649
+ if (cose.payload !== null) {
2650
+ errors.push(
2651
+ issue(
2652
+ "MALFORMED_SIG_COSE_SIGN1",
2653
+ ["sigs", idx],
2654
+ "COSE_Sign1 payload must be null (detached); attached form forbidden"
2655
+ )
2656
+ );
2657
+ return;
2393
2658
  }
2394
- const chunks = [];
2395
- for (let i = 0; i < value.length; i += CHUNK_MAX_BYTES) {
2396
- chunks.push(value.subarray(i, Math.min(i + CHUNK_MAX_BYTES, value.length)));
2659
+ const alg = cose.protectedHeader.get(1);
2660
+ if (typeof alg !== "number" || !KNOWN_SIG_ALG_IDS.has(alg)) {
2661
+ info.push(
2662
+ issue(
2663
+ "SIGNATURE_UNSUPPORTED",
2664
+ ["sigs", idx],
2665
+ `COSE_Sign1 protected alg ${String(alg)} not in {-8, -19}`
2666
+ )
2667
+ );
2397
2668
  }
2398
- return chunks;
2399
- }
2400
- function joinKemCt(chunks) {
2401
- let total = 0;
2402
- for (const c of chunks) total += c.length;
2403
- const out = new Uint8Array(total);
2404
- let offset = 0;
2405
- for (const c of chunks) {
2406
- out.set(c, offset);
2407
- offset += c.length;
2669
+ const protectedKid = cose.protectedHeader.get(4);
2670
+ if (protectedKid instanceof Uint8Array && protectedKid.length === 32 && entry.cose_key !== void 0) {
2671
+ errors.push(
2672
+ issue(
2673
+ "SIG_ENTRY_KID_COSE_KEY_CONFLICT",
2674
+ ["sigs", idx],
2675
+ "sigs[i] carries both a 32-byte protected `kid` (path 1) and an inline `cose_key` (path 2); paths are mutually exclusive"
2676
+ )
2677
+ );
2408
2678
  }
2409
- return out;
2410
- }
2411
- function slotsToMacCbor(slots, kem) {
2412
- let value;
2413
- if (kem === "x25519") {
2414
- value = slots.map((s) => ({ epk: s.epk, wrap: s.wrap }));
2415
- } else {
2416
- value = slots.map((s) => ({
2417
- // Canonicalize the chunk boundaries before the MAC commits to them:
2418
- // reassemble the logical ciphertext and re-split into canonical ≤ 64-byte
2419
- // chunks. The on-wire `kem_ct` array is a transport detail (the Cardano
2420
- // ledger's 64-byte metadatum cap), and a hostile or non-canonical chunking
2421
- // ([1, 63, …] instead of [64, …]) reassembles to the SAME bytes — so the
2422
- // MAC must be invariant to it. Committing to the verbatim wire chunks would
2423
- // let an attacker re-chunk an honest envelope and break the slots_mac match
2424
- // for an honest recipient. Honest (already-64B-chunked) records are
2425
- // unchanged; a real byte flip still changes the reassembled bytes and is
2426
- // still rejected.
2427
- kem_ct: chunkKemCt(joinKemCt(s.kem_ct)),
2428
- wrap: s.wrap
2429
- }));
2430
- }
2431
- return encodeCanonicalCbor3(value);
2432
- }
2433
- var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
2434
- var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
2435
- "cardano-poe-kek-mlkem768x25519-v1"
2436
- );
2437
- var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
2438
- "cardano-poe-slots-mac-v1"
2439
- );
2440
- var ZERO_NONCE_12 = new Uint8Array(12);
2441
- if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
2442
- throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
2443
- }
2444
- if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
2445
- throw new Error(
2446
- "CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
2447
- );
2448
- }
2449
- if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
2450
- throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
2451
- }
2452
- if (ZERO_NONCE_12.length !== 12) {
2453
- throw new Error("ZERO_NONCE_12 byte-length invariant violated (expected 12)");
2454
- }
2455
- function compareCt2(a, b) {
2456
- if (a.length !== b.length) return false;
2457
- let diff = 0;
2458
- for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
2459
- return diff === 0;
2460
- }
2461
- function selectBundleSecrets(envelope, bundle) {
2462
- return envelope.kem === "x25519" ? bundle.x25519PrivateKeys : bundle.mlkem768x25519SecretSeeds;
2463
- }
2464
- var ZERO_NONCE_122 = new Uint8Array(12);
2465
- var EMPTY_SALT2 = new Uint8Array(0);
2466
- var X25519_SECRET_KEY_LENGTH2 = 32;
2467
- var X25519_PUBLIC_KEY_LENGTH2 = 32;
2468
- var NONCE_LENGTH2 = 24;
2469
- var WRAP_LENGTH2 = 48;
2470
- var SLOTS_MAC_LENGTH2 = 32;
2471
- function concat2(a, b) {
2472
- const out = new Uint8Array(a.length + b.length);
2473
- out.set(a, 0);
2474
- out.set(b, a.length);
2475
- return out;
2476
2679
  }
2477
- function assertEnvelopeStructure(envelope, multiPrivKeys, singlePrivKey) {
2478
- if (envelope.scheme !== 1) {
2479
- throw new EciesSealedPoeError(
2480
- "UNSUPPORTED_ENC_VERSION",
2481
- `envelope.scheme=${String(envelope.scheme)} unsupported (expected 1)`
2680
+ function inspectCoseKey(keyChunks, i) {
2681
+ let decoded;
2682
+ try {
2683
+ decoded = decodeCanonicalCbor(bytesChunkArrayConcat(keyChunks));
2684
+ } catch (cause) {
2685
+ return issue(
2686
+ "MALFORMED_SIG_COSE_SIGN1",
2687
+ ["sigs", i, "cose_key"],
2688
+ `sigs[${i}].cose_key failed to decode as cbor<COSE_Key>: ${cause instanceof Error ? cause.message : String(cause)}`
2482
2689
  );
2483
2690
  }
2484
- if (envelope.aead !== "xchacha20-poly1305") {
2485
- throw new EciesSealedPoeError(
2486
- "UNSUPPORTED_AEAD_ALG",
2487
- `envelope.aead=${String(envelope.aead)} unsupported (expected 'xchacha20-poly1305')`
2691
+ const getLabel = (label) => {
2692
+ if (decoded instanceof Map) return decoded.get(label);
2693
+ if (typeof decoded === "object" && decoded !== null) {
2694
+ return decoded[String(label)];
2695
+ }
2696
+ return void 0;
2697
+ };
2698
+ const hasLabel = (label) => {
2699
+ if (decoded instanceof Map) return decoded.has(label);
2700
+ if (typeof decoded === "object" && decoded !== null) {
2701
+ return Object.prototype.hasOwnProperty.call(decoded, String(label));
2702
+ }
2703
+ return false;
2704
+ };
2705
+ if (hasLabel(-4)) {
2706
+ return issue(
2707
+ "SIG_PRIVATE_KEY_LEAKED",
2708
+ ["sigs", i, "cose_key"],
2709
+ "cose_key carries COSE_Key private-key material (label -4, the OKP/EC2 private scalar d); publishing a private key on the permanent ledger is forbidden"
2488
2710
  );
2489
2711
  }
2490
- if (envelope.kem !== "x25519" && envelope.kem !== "mlkem768x25519") {
2491
- throw new EciesSealedPoeError(
2492
- "UNSUPPORTED_KEM_ALG",
2493
- `envelope.kem=${String(envelope.kem)} unsupported (expected 'x25519' or 'mlkem768x25519')`
2712
+ const kty = getLabel(1);
2713
+ if (kty !== 1) {
2714
+ return issue(
2715
+ "MALFORMED_SIG_COSE_SIGN1",
2716
+ ["sigs", i, "cose_key"],
2717
+ `sigs[${i}].cose_key COSE_Key kty (label 1) must be 1 (OKP); got ${String(kty)}`
2494
2718
  );
2495
2719
  }
2496
- const n = envelope.slots.length;
2497
- if (n < 1) {
2498
- throw new EciesSealedPoeError("ENC_SLOTS_EMPTY", `envelope.slots.length=${n} must be >= 1`);
2720
+ const crv = getLabel(-1);
2721
+ if (crv !== 6) {
2722
+ return issue(
2723
+ "MALFORMED_SIG_COSE_SIGN1",
2724
+ ["sigs", i, "cose_key"],
2725
+ `sigs[${i}].cose_key COSE_Key crv (label -1) must be 6 (Ed25519); got ${String(crv)}`
2726
+ );
2499
2727
  }
2500
- if (envelope.nonce.length !== NONCE_LENGTH2) {
2501
- throw new EciesSealedPoeError(
2502
- "NONCE_LENGTH_MISMATCH",
2503
- `envelope.nonce MUST be exactly ${NONCE_LENGTH2} bytes, got ${envelope.nonce.length}`
2728
+ if (!hasLabel(-2)) {
2729
+ return issue(
2730
+ "MALFORMED_SIG_COSE_SIGN1",
2731
+ ["sigs", i, "cose_key"],
2732
+ `sigs[${i}].cose_key COSE_Key missing label -2 (Ed25519 public-key bytes)`
2504
2733
  );
2505
2734
  }
2506
- if (envelope.slots_mac.length !== SLOTS_MAC_LENGTH2) {
2507
- throw new EciesSealedPoeError(
2508
- "ENC_SLOTS_MAC_INVALID_LENGTH",
2509
- `envelope.slots_mac MUST be exactly ${SLOTS_MAC_LENGTH2} bytes, got ${envelope.slots_mac.length}`
2735
+ const x = getLabel(-2);
2736
+ if (!(x instanceof Uint8Array) || x.length !== 32) {
2737
+ const got = x instanceof Uint8Array ? `${x.length}-byte bstr` : typeof x;
2738
+ return issue(
2739
+ "MALFORMED_SIG_COSE_SIGN1",
2740
+ ["sigs", i, "cose_key"],
2741
+ `sigs[${i}].cose_key COSE_Key label -2 must be a 32-byte byte string (Ed25519 public key); got ${got}`
2510
2742
  );
2511
2743
  }
2512
- if (envelope.kem === "x25519") {
2513
- for (let i = 0; i < n; i++) {
2514
- const slot = envelope.slots[i];
2515
- if (slot.epk.length !== X25519_PUBLIC_KEY_LENGTH2) {
2516
- throw new EciesSealedPoeError(
2517
- "KEM_EPK_LENGTH_MISMATCH",
2518
- `envelope.slots[${i}].epk MUST be exactly ${X25519_PUBLIC_KEY_LENGTH2} bytes, got ${slot.epk.length}`
2519
- );
2520
- }
2521
- if (slot.wrap.length !== WRAP_LENGTH2) {
2522
- throw new EciesSealedPoeError(
2523
- "WRAP_LENGTH_MISMATCH",
2524
- `envelope.slots[${i}].wrap MUST be exactly ${WRAP_LENGTH2} bytes, got ${slot.wrap.length}`
2525
- );
2526
- }
2527
- }
2528
- } else {
2529
- for (let i = 0; i < n; i++) {
2530
- const slot = envelope.slots[i];
2531
- const enc = joinKemCt(slot.kem_ct);
2532
- if (enc.length !== MLKEM768X25519_ENC_LENGTH) {
2533
- throw new EciesSealedPoeError(
2534
- "KEM_CT_LENGTH_MISMATCH",
2535
- `envelope.slots[${i}].kem_ct MUST reassemble to exactly ${MLKEM768X25519_ENC_LENGTH} bytes, got ${enc.length}`
2536
- );
2537
- }
2538
- if (slot.wrap.length !== WRAP_LENGTH2) {
2539
- throw new EciesSealedPoeError(
2540
- "WRAP_LENGTH_MISMATCH",
2541
- `envelope.slots[${i}].wrap MUST be exactly ${WRAP_LENGTH2} bytes, got ${slot.wrap.length}`
2542
- );
2543
- }
2744
+ return null;
2745
+ }
2746
+ var ACCEPTED_CIDV1_MULTIBASE = /* @__PURE__ */ new Set(["b", "B", "f", "F", "z"]);
2747
+ var ACCEPTED_MULTICODECS = /* @__PURE__ */ new Set([85, 112, 113]);
2748
+ var ACCEPTED_MULTIHASHES = /* @__PURE__ */ new Map([
2749
+ [18, 32],
2750
+ [45600, 32]
2751
+ ]);
2752
+ function validateCidProfile(cid) {
2753
+ if (cid.length === 0) return false;
2754
+ if (cid.startsWith("Qm")) {
2755
+ let decoded;
2756
+ try {
2757
+ decoded = decodeBase58btc(cid);
2758
+ } catch {
2759
+ return false;
2544
2760
  }
2761
+ return decoded.length === 34 && decoded[0] === 18 && decoded[1] === 32;
2545
2762
  }
2546
- if (multiPrivKeys !== void 0) {
2547
- for (let i = 0; i < multiPrivKeys.length; i++) {
2548
- if (multiPrivKeys[i].length !== X25519_SECRET_KEY_LENGTH2) {
2549
- throw new EciesSealedPoeError(
2550
- "INVALID_RECIPIENT_KEY",
2551
- `recipientSecretKeys[${i}] MUST be exactly ${X25519_SECRET_KEY_LENGTH2} bytes, got ${multiPrivKeys[i].length}`
2552
- );
2553
- }
2554
- }
2555
- } else if (singlePrivKey !== void 0) {
2556
- if (singlePrivKey.length !== X25519_SECRET_KEY_LENGTH2) {
2557
- throw new EciesSealedPoeError(
2558
- "INVALID_RECIPIENT_KEY",
2559
- `recipientSecretKey MUST be exactly ${X25519_SECRET_KEY_LENGTH2} bytes, got ${singlePrivKey.length}`
2560
- );
2763
+ const mbPrefix = cid[0];
2764
+ if (!ACCEPTED_CIDV1_MULTIBASE.has(mbPrefix)) return false;
2765
+ let bytes;
2766
+ try {
2767
+ bytes = decodeMultibase(mbPrefix, cid.slice(1));
2768
+ } catch {
2769
+ return false;
2770
+ }
2771
+ if (bytes.length < 4) return false;
2772
+ const versionParse = readVarint(bytes, 0);
2773
+ if (versionParse === null || versionParse.value !== 1) return false;
2774
+ const codecParse = readVarint(bytes, versionParse.next);
2775
+ if (codecParse === null) return false;
2776
+ if (!ACCEPTED_MULTICODECS.has(codecParse.value)) return false;
2777
+ const mhParse = readVarint(bytes, codecParse.next);
2778
+ if (mhParse === null) return false;
2779
+ const lenParse = readVarint(bytes, mhParse.next);
2780
+ if (lenParse === null) return false;
2781
+ const digestLen = lenParse.value;
2782
+ const expectedLen = ACCEPTED_MULTIHASHES.get(mhParse.value);
2783
+ if (expectedLen === void 0 || digestLen !== expectedLen) return false;
2784
+ if (lenParse.next + digestLen !== bytes.length) return false;
2785
+ return true;
2786
+ }
2787
+ function readVarint(bytes, start) {
2788
+ let value = 0;
2789
+ let shift = 0;
2790
+ let i = start;
2791
+ while (i < bytes.length) {
2792
+ const b = bytes[i];
2793
+ value |= (b & 127) << shift;
2794
+ i++;
2795
+ if ((b & 128) === 0) return { value, next: i };
2796
+ shift += 7;
2797
+ if (shift > 28) return null;
2798
+ }
2799
+ return null;
2800
+ }
2801
+ function decodeMultibase(prefix, body) {
2802
+ switch (prefix) {
2803
+ case "b":
2804
+ return decodeBase32(body.toLowerCase(), "rfc4648-lower");
2805
+ case "B":
2806
+ return decodeBase32(body.toUpperCase(), "rfc4648-upper");
2807
+ case "f":
2808
+ return decodeBase16(body.toLowerCase());
2809
+ case "F":
2810
+ return decodeBase16(body.toUpperCase());
2811
+ case "z":
2812
+ return decodeBase58btc(body);
2813
+ default:
2814
+ throw new Error(`unsupported multibase prefix ${prefix}`);
2815
+ }
2816
+ }
2817
+ var BASE16_LOWER = "0123456789abcdef";
2818
+ var BASE16_UPPER = "0123456789ABCDEF";
2819
+ function decodeBase16(s) {
2820
+ if (s.length % 2 !== 0) throw new Error("base16: odd-length");
2821
+ const out = new Uint8Array(s.length / 2);
2822
+ const alphabet = s === s.toLowerCase() ? BASE16_LOWER : BASE16_UPPER;
2823
+ for (let i = 0; i < out.length; i++) {
2824
+ const hi = alphabet.indexOf(s[i * 2]);
2825
+ const lo = alphabet.indexOf(s[i * 2 + 1]);
2826
+ if (hi < 0 || lo < 0) throw new Error(`base16: non-hex char at ${i * 2}`);
2827
+ out[i] = hi << 4 | lo;
2828
+ }
2829
+ return out;
2830
+ }
2831
+ var BASE32_RFC4648_LOWER = "abcdefghijklmnopqrstuvwxyz234567";
2832
+ var BASE32_RFC4648_UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
2833
+ function decodeBase32(s, variant) {
2834
+ const alphabet = variant === "rfc4648-lower" ? BASE32_RFC4648_LOWER : BASE32_RFC4648_UPPER;
2835
+ const trimmed = s.replace(/=+$/, "");
2836
+ const out = [];
2837
+ let buf = 0;
2838
+ let bits = 0;
2839
+ for (const ch of trimmed) {
2840
+ const idx = alphabet.indexOf(ch);
2841
+ if (idx < 0) throw new Error(`base32: invalid char '${ch}'`);
2842
+ buf = buf << 5 | idx;
2843
+ bits += 5;
2844
+ if (bits >= 8) {
2845
+ bits -= 8;
2846
+ out.push(buf >> bits & 255);
2561
2847
  }
2562
2848
  }
2849
+ return Uint8Array.from(out);
2563
2850
  }
2564
- function tryX25519Slot(args) {
2565
- if (args.liveSlot) {
2566
- try {
2567
- const shared = x25519Ecdh({
2568
- secretKey: args.recipientSecretKey,
2569
- theirPublicKey: args.slot.epk
2570
- });
2571
- const kek = hkdfSha256({
2572
- ikm: shared,
2573
- salt: concat2(args.slot.epk, args.pubRLocal),
2574
- info: CARDANO_POE_HKDF_INFO_KEK,
2575
- length: 32
2576
- });
2577
- return chacha20Poly1305Decrypt({
2578
- key: kek,
2579
- nonce: ZERO_NONCE_122,
2580
- aad: CARDANO_POE_HKDF_INFO_KEK,
2581
- ciphertext: args.slot.wrap
2582
- });
2583
- } catch (e) {
2584
- if (!(e instanceof AeadVerificationError2) && !(e instanceof X25519LowOrderPointError)) {
2585
- throw e;
2586
- }
2587
- return null;
2851
+ var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
2852
+ function decodeBase58btc(s) {
2853
+ if (s.length === 0) return new Uint8Array(0);
2854
+ let zeros = 0;
2855
+ while (zeros < s.length && s[zeros] === "1") zeros++;
2856
+ const size = Math.floor((s.length - zeros) * 733 / 1e3) + 1;
2857
+ const b256 = new Uint8Array(size);
2858
+ let length = 0;
2859
+ for (let i = zeros; i < s.length; i++) {
2860
+ const ch = s[i];
2861
+ const carryIdx = BASE58_ALPHABET.indexOf(ch);
2862
+ if (carryIdx < 0) throw new Error(`base58: invalid char '${ch}'`);
2863
+ let carry = carryIdx;
2864
+ let k = 0;
2865
+ for (let j2 = size - 1; (carry !== 0 || k < length) && j2 >= 0; j2--, k++) {
2866
+ carry += 58 * b256[j2];
2867
+ b256[j2] = carry % 256;
2868
+ carry = Math.floor(carry / 256);
2588
2869
  }
2870
+ length = k;
2589
2871
  }
2590
- try {
2591
- const shared = x25519Ecdh({
2592
- secretKey: args.recipientSecretKey,
2593
- theirPublicKey: args.slot.epk
2594
- });
2595
- hkdfSha256({
2596
- ikm: shared,
2597
- salt: concat2(args.slot.epk, args.pubRLocal),
2598
- info: CARDANO_POE_HKDF_INFO_KEK,
2599
- length: 32
2600
- });
2601
- } catch (e) {
2602
- if (!(e instanceof X25519LowOrderPointError)) throw e;
2872
+ let it = size - length;
2873
+ while (it < size && b256[it] === 0) it++;
2874
+ const out = new Uint8Array(zeros + (size - it));
2875
+ let j = zeros;
2876
+ while (it < size) {
2877
+ out[j++] = b256[it++];
2603
2878
  }
2604
- return null;
2879
+ return out;
2605
2880
  }
2606
- function tryMlkem768X25519Slot(args) {
2607
- const enc = joinKemCt(args.slot.kem_ct);
2608
- const ss = mlkem768x25519Decapsulate({ secretSeed: args.recipientSecretKey, enc });
2609
- const kek = hkdfSha256({
2610
- ikm: ss,
2611
- salt: EMPTY_SALT2,
2612
- info: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
2613
- length: 32
2614
- });
2615
- if (!args.liveSlot) {
2616
- return null;
2881
+ function checkCritShape(record, decodedTopKeys, errors) {
2882
+ const invalid = /* @__PURE__ */ new Set();
2883
+ if (!Array.isArray(record.crit)) return invalid;
2884
+ if (record.crit.length === 0) {
2885
+ errors.push(
2886
+ issue("SCHEMA_TYPE_MISMATCH", ["crit"], "crit[] must carry at least one entry when present")
2887
+ );
2888
+ return invalid;
2617
2889
  }
2618
- try {
2619
- return chacha20Poly1305Decrypt({
2620
- key: kek,
2621
- nonce: ZERO_NONCE_122,
2622
- aad: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
2623
- ciphertext: args.slot.wrap
2624
- });
2625
- } catch (e) {
2626
- if (!(e instanceof AeadVerificationError2)) throw e;
2627
- return null;
2890
+ const seen = /* @__PURE__ */ new Set();
2891
+ for (let i = 0; i < record.crit.length; i++) {
2892
+ const critName = record.crit[i];
2893
+ let reason = null;
2894
+ if (TOP_LEVEL_BASE_KEYS.has(critName)) {
2895
+ reason = `'${critName}' is a base key and MUST NOT appear in crit[]`;
2896
+ } else if (!isExtensionKey(critName)) {
2897
+ reason = `'${critName}' does not match the extension-key regex (^x-.+ or ^[a-z]+-.+)`;
2898
+ } else if (!decodedTopKeys.has(critName)) {
2899
+ reason = `'${critName}' is named in crit but absent from the record map`;
2900
+ } else if (seen.has(critName)) {
2901
+ reason = `'${critName}' appears more than once in crit[]`;
2902
+ }
2903
+ seen.add(critName);
2904
+ if (reason !== null) {
2905
+ invalid.add(i);
2906
+ errors.push(issue("CRIT_SHAPE_INVALID", ["crit", i], reason));
2907
+ }
2628
2908
  }
2909
+ return invalid;
2629
2910
  }
2630
- function tryRecipientUnwrapWithIdx(envelope, recipientSecretKey, constantTimeN, slotsAttemptedOut) {
2631
- const n = envelope.slots.length;
2632
- let cek = null;
2633
- let matchedSlotIdx = -1;
2634
- if (envelope.kem === "x25519") {
2635
- const pubRLocal = x25519PublicKey({ secretKey: recipientSecretKey });
2636
- for (let i = 0; i < n; i++) {
2637
- if (slotsAttemptedOut !== void 0) {
2638
- slotsAttemptedOut.count = i + 1;
2639
- }
2640
- const candidate = tryX25519Slot({
2641
- slot: envelope.slots[i],
2642
- recipientSecretKey,
2643
- pubRLocal,
2644
- liveSlot: cek === null
2645
- });
2646
- if (cek === null && candidate !== null) {
2647
- cek = candidate;
2648
- matchedSlotIdx = i;
2649
- }
2650
- if (cek !== null && !constantTimeN) break;
2651
- }
2652
- } else {
2653
- for (let i = 0; i < n; i++) {
2654
- if (slotsAttemptedOut !== void 0) {
2655
- slotsAttemptedOut.count = i + 1;
2656
- }
2657
- const candidate = tryMlkem768X25519Slot({
2658
- slot: envelope.slots[i],
2659
- recipientSecretKey,
2660
- liveSlot: cek === null
2661
- });
2662
- if (cek === null && candidate !== null) {
2663
- cek = candidate;
2664
- matchedSlotIdx = i;
2665
- }
2666
- if (cek !== null && !constantTimeN) break;
2911
+ function topLevelKeysOf(decoded) {
2912
+ if (decoded === null || typeof decoded !== "object") return /* @__PURE__ */ new Set();
2913
+ if (decoded instanceof Map) {
2914
+ const out = /* @__PURE__ */ new Set();
2915
+ for (const k of decoded.keys()) {
2916
+ if (typeof k === "string") out.add(k);
2667
2917
  }
2918
+ return out;
2668
2919
  }
2669
- return cek === null ? null : { cek, slotIdx: matchedSlotIdx };
2920
+ return new Set(Object.keys(decoded));
2670
2921
  }
2671
- function tryRecipientUnwrap(envelope, recipientSecretKey, constantTimeN, slotsAttemptedOut) {
2672
- return tryRecipientUnwrapWithIdx(envelope, recipientSecretKey, constantTimeN, slotsAttemptedOut)?.cek ?? null;
2922
+ function issue(code, path, message) {
2923
+ return { code, path, message, severity: SEVERITY[code] };
2673
2924
  }
2674
- function slotsMacCborBytes(envelope) {
2675
- return slotsToMacCbor(
2676
- envelope.slots,
2677
- envelope.kem
2678
- );
2925
+ function compareIssuePath(a, b) {
2926
+ return a.path.join(".").localeCompare(b.path.join("."));
2679
2927
  }
2680
- function eciesSealedPoeUnwrap(args) {
2681
- const { envelope, ciphertext } = args;
2682
- const constantTimeN = args.constantTimeN ?? true;
2683
- const hasSingle = "recipientSecretKey" in args;
2684
- const hasBundle = "recipientKeyBundle" in args;
2685
- const multiPrivKeys = hasBundle ? selectBundleSecrets(envelope, args.recipientKeyBundle) : "recipientSecretKeys" in args ? args.recipientSecretKeys : void 0;
2686
- const hasMulti = multiPrivKeys !== void 0;
2687
- if (hasSingle === hasMulti) {
2688
- throw new EciesSealedPoeError(
2689
- "INVALID_RECIPIENT_KEY",
2690
- "exactly one of recipientSecretKey / recipientSecretKeys / recipientKeyBundle MUST be supplied"
2691
- );
2692
- }
2693
- if (hasMulti && multiPrivKeys.length === 0) {
2694
- if (hasBundle) {
2695
- return { matched: false, reason: "WRONG_RECIPIENT_KEY" };
2928
+ function valueAtPath(root, path) {
2929
+ let cur = root;
2930
+ for (const seg of path) {
2931
+ if (cur === null || cur === void 0) return void 0;
2932
+ if (cur instanceof Map) {
2933
+ cur = cur.get(seg);
2934
+ continue;
2696
2935
  }
2697
- throw new EciesSealedPoeError(
2698
- "INVALID_RECIPIENT_KEY",
2699
- "recipientSecretKeys MUST be a non-empty array, got length=0"
2700
- );
2701
- }
2702
- if (hasMulti) {
2703
- assertEnvelopeStructure(envelope, multiPrivKeys, void 0);
2704
- } else {
2705
- assertEnvelopeStructure(envelope, void 0, args.recipientSecretKey);
2936
+ if (typeof cur !== "object") return void 0;
2937
+ cur = cur[seg];
2706
2938
  }
2707
- let matchedCek = null;
2708
- let anyCandidateRecovered = false;
2709
- if (hasSingle) {
2710
- const recipientSecretKey = args.recipientSecretKey;
2711
- const cek = tryRecipientUnwrap(
2712
- envelope,
2713
- recipientSecretKey,
2714
- constantTimeN,
2715
- args._slotsAttemptedOut
2716
- );
2717
- if (cek === null) {
2718
- return { matched: false, reason: "WRONG_RECIPIENT_KEY" };
2719
- }
2720
- const slotsCbor = slotsMacCborBytes(envelope);
2721
- const hmacKey = hkdfSha256({
2722
- ikm: cek,
2723
- salt: EMPTY_SALT2,
2724
- info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
2725
- length: 32
2726
- });
2727
- const slotsMacCalc = hmac_js.hmac(sha2_js.sha256, hmacKey, slotsCbor);
2728
- if (!compareCt2(slotsMacCalc, envelope.slots_mac)) {
2729
- return { matched: false, reason: "TAMPERED_HEADER" };
2730
- }
2731
- matchedCek = cek;
2732
- } else {
2733
- const slotsCbor = slotsMacCborBytes(envelope);
2734
- const recipientSecretKeys = multiPrivKeys;
2735
- for (let k = 0; k < recipientSecretKeys.length; k++) {
2736
- if (args._privsAttemptedOut !== void 0) {
2737
- args._privsAttemptedOut.count = k + 1;
2738
- }
2739
- if (args._slotsAttemptedOut !== void 0) {
2740
- args._slotsAttemptedOut.count = 0;
2741
- }
2742
- const cek = tryRecipientUnwrap(
2743
- envelope,
2744
- recipientSecretKeys[k],
2745
- constantTimeN,
2746
- args._slotsAttemptedOut
2747
- );
2748
- if (args._slotsAttemptedOut?.perPrivCounts !== void 0) {
2749
- args._slotsAttemptedOut.perPrivCounts.push(args._slotsAttemptedOut.count);
2750
- }
2751
- if (cek === null) continue;
2752
- const hmacKey = hkdfSha256({
2753
- ikm: cek,
2754
- salt: EMPTY_SALT2,
2755
- info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
2756
- length: 32
2757
- });
2758
- const slotsMacCalc = hmac_js.hmac(sha2_js.sha256, hmacKey, slotsCbor);
2759
- if (compareCt2(slotsMacCalc, envelope.slots_mac)) {
2760
- matchedCek = cek;
2761
- break;
2762
- }
2763
- anyCandidateRecovered = true;
2764
- }
2765
- if (matchedCek === null) {
2766
- return {
2767
- matched: false,
2768
- reason: anyCandidateRecovered ? "TAMPERED_HEADER" : "WRONG_RECIPIENT_KEY"
2769
- };
2770
- }
2939
+ return cur;
2940
+ }
2941
+ async function argon2idV13(opts2) {
2942
+ return await hashWasm.argon2id({
2943
+ password: opts2.password,
2944
+ salt: opts2.salt,
2945
+ parallelism: opts2.parallelism,
2946
+ iterations: opts2.iterations,
2947
+ memorySize: opts2.memSizeKB,
2948
+ hashLength: opts2.outBytes,
2949
+ outputType: "binary"
2950
+ });
2951
+ }
2952
+ var AeadVerificationError2 = class extends Error {
2953
+ code = "aead_verification_failed";
2954
+ constructor(message, options) {
2955
+ super(message, options);
2956
+ this.name = "AeadVerificationError";
2771
2957
  }
2772
- const adContent = concat2(envelope.nonce, envelope.slots_mac);
2958
+ };
2959
+ function xchacha20Poly1305Decrypt2(opts2) {
2773
2960
  try {
2774
- const plaintext = xchacha20Poly1305Decrypt2({
2775
- key: matchedCek,
2776
- nonce: envelope.nonce,
2777
- aad: adContent,
2778
- ciphertext
2779
- });
2780
- return { matched: true, plaintext };
2781
- } catch (e) {
2782
- if (!(e instanceof AeadVerificationError2)) throw e;
2783
- return { matched: false, reason: "TAMPERED_CIPHERTEXT" };
2961
+ return chacha_js.xchacha20poly1305(opts2.key, opts2.nonce, opts2.aad).decrypt(opts2.ciphertext);
2962
+ } catch (cause) {
2963
+ throw new AeadVerificationError2("xchacha20-poly1305 decrypt failed", { cause });
2784
2964
  }
2785
2965
  }
2786
- function sealedEnvelopeFromParsed(enc) {
2787
- if (enc.scheme !== 1 || enc.aead !== "xchacha20-poly1305") return null;
2788
- if (enc.nonce === void 0 || enc.slots_mac === void 0) return null;
2789
- const slots = enc.slots;
2790
- if (slots === void 0 || slots.length < 1) return null;
2791
- if (enc.kem === "x25519") {
2792
- const x25519Slots = [];
2793
- for (const s of slots) {
2794
- if (s.epk === void 0 || s.wrap === void 0) return null;
2795
- x25519Slots.push({ epk: s.epk, wrap: s.wrap });
2796
- }
2797
- return {
2798
- scheme: 1,
2799
- aead: "xchacha20-poly1305",
2800
- kem: "x25519",
2801
- nonce: enc.nonce,
2802
- slots: x25519Slots,
2803
- slots_mac: enc.slots_mac
2804
- };
2966
+ function sha2564(input) {
2967
+ return sha2_js.sha256(input);
2968
+ }
2969
+ function blake2b256(input) {
2970
+ return blake2_js.blake2b(input, { dkLen: 32 });
2971
+ }
2972
+ function blake2b2242(input) {
2973
+ return blake2_js.blake2b(input, { dkLen: 28 });
2974
+ }
2975
+ var LEAF_PREFIX = 0;
2976
+ var NODE_PREFIX = 1;
2977
+ var DIGEST_LENGTH = 32;
2978
+ function validateLeaves(leaves, fnName) {
2979
+ if (leaves.length === 0) {
2980
+ throw new Error(`${fnName}: empty leaf list (n == 0 is forbidden by RFC 9162 \xA72.1.1)`);
2805
2981
  }
2806
- if (enc.kem === "mlkem768x25519") {
2807
- const hybridSlots = [];
2808
- for (const s of slots) {
2809
- if (s.kem_ct === void 0 || s.wrap === void 0) return null;
2810
- hybridSlots.push({ kem_ct: s.kem_ct, wrap: s.wrap });
2982
+ for (let i = 0; i < leaves.length; i++) {
2983
+ const leaf = leaves[i];
2984
+ if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH) {
2985
+ throw new Error(
2986
+ `${fnName}: leaf[${i}] must be a Uint8Array(${DIGEST_LENGTH}); got length ${leaf instanceof Uint8Array ? leaf.length : "non-Uint8Array"}`
2987
+ );
2811
2988
  }
2812
- return {
2813
- scheme: 1,
2814
- aead: "xchacha20-poly1305",
2815
- kem: "mlkem768x25519",
2816
- nonce: enc.nonce,
2817
- slots: hybridSlots,
2818
- slots_mac: enc.slots_mac
2819
- };
2820
2989
  }
2821
- return null;
2990
+ }
2991
+ function merkleSha2256Root(leaves) {
2992
+ validateLeaves(leaves, "merkleSha2256Root");
2993
+ return mthRecursive(leaves, 0, leaves.length);
2994
+ }
2995
+ function largestPow2Lt(n) {
2996
+ let k = 1;
2997
+ while (k * 2 < n) k *= 2;
2998
+ return k;
2999
+ }
3000
+ function hashLeaf(d) {
3001
+ const buf = new Uint8Array(1 + d.length);
3002
+ buf[0] = LEAF_PREFIX;
3003
+ buf.set(d, 1);
3004
+ return sha2_js.sha256(buf);
3005
+ }
3006
+ function hashNode(left, right) {
3007
+ const buf = new Uint8Array(1 + left.length + right.length);
3008
+ buf[0] = NODE_PREFIX;
3009
+ buf.set(left, 1);
3010
+ buf.set(right, 1 + left.length);
3011
+ return sha2_js.sha256(buf);
3012
+ }
3013
+ function mthRecursive(leaves, start, end) {
3014
+ const n = end - start;
3015
+ if (n === 1) {
3016
+ return hashLeaf(leaves[start]);
3017
+ }
3018
+ const k = largestPow2Lt(n);
3019
+ const left = mthRecursive(leaves, start, start + k);
3020
+ const right = mthRecursive(leaves, start + k, end);
3021
+ return hashNode(left, right);
2822
3022
  }
2823
3023
 
2824
3024
  // ../crypto-core/dist/util.js
@@ -3220,7 +3420,53 @@ async function fetchItemCiphertext(args) {
3220
3420
 
3221
3421
  // src/verifier/decrypt.ts
3222
3422
  var PASSPHRASE_KDF_ARGON2ID = "argon2id";
3223
- var EMPTY_AAD = new Uint8Array(0);
3423
+ var MAX_PASSPHRASE_INPUT_BYTES = 4096;
3424
+ var UNICODE_WHITE_SPACE = /* @__PURE__ */ new Set([
3425
+ 9,
3426
+ 10,
3427
+ 11,
3428
+ 12,
3429
+ 13,
3430
+ 32,
3431
+ 133,
3432
+ 160,
3433
+ 5760,
3434
+ 8192,
3435
+ 8193,
3436
+ 8194,
3437
+ 8195,
3438
+ 8196,
3439
+ 8197,
3440
+ 8198,
3441
+ 8199,
3442
+ 8200,
3443
+ 8201,
3444
+ 8202,
3445
+ 8232,
3446
+ 8233,
3447
+ 8239,
3448
+ 8287,
3449
+ 12288
3450
+ ]);
3451
+ function normalizePassphrase(passphrase) {
3452
+ const nfkc = passphrase.normalize("NFKC");
3453
+ let collapsed = "";
3454
+ let inRun = false;
3455
+ for (const ch of nfkc) {
3456
+ if (UNICODE_WHITE_SPACE.has(ch.codePointAt(0))) {
3457
+ if (!inRun) {
3458
+ collapsed += " ";
3459
+ inRun = true;
3460
+ }
3461
+ } else {
3462
+ collapsed += ch;
3463
+ inRun = false;
3464
+ }
3465
+ }
3466
+ if (collapsed.startsWith(" ")) collapsed = collapsed.slice(1);
3467
+ if (collapsed.endsWith(" ")) collapsed = collapsed.slice(0, -1);
3468
+ return new TextEncoder().encode(collapsed);
3469
+ }
3224
3470
  async function tryDecryptions(args) {
3225
3471
  const { record, input } = args;
3226
3472
  const items = record.items ?? [];
@@ -3339,7 +3585,7 @@ async function tryDecryptions(args) {
3339
3585
  passphrase: req.passphrase
3340
3586
  });
3341
3587
  } catch (e) {
3342
- if (e instanceof AeadVerificationError) {
3588
+ if (e instanceof AeadVerificationError2) {
3343
3589
  failure = { verdict: "tampered-ciphertext", reason: "TAMPERED_CIPHERTEXT" };
3344
3590
  } else if (e instanceof Error && e.message.startsWith("KDF_")) {
3345
3591
  failure = { verdict: "kdf-failed", reason: e.message };
@@ -3369,8 +3615,13 @@ async function decryptPassphrase(args) {
3369
3615
  if (enc.passphrase.alg !== PASSPHRASE_KDF_ARGON2ID) {
3370
3616
  throw new Error(`KDF_DERIVATION_FAILED: unsupported passphrase alg ${enc.passphrase.alg}`);
3371
3617
  }
3372
- const normalised = passphrase.normalize("NFKC").replace(/\s+/g, " ").trim();
3373
- const password = new TextEncoder().encode(normalised);
3618
+ const rawPassphraseBytes = new TextEncoder().encode(passphrase).length;
3619
+ if (rawPassphraseBytes > MAX_PASSPHRASE_INPUT_BYTES) {
3620
+ throw new Error(
3621
+ `KDF_DERIVATION_FAILED: passphrase length ${rawPassphraseBytes} bytes exceeds the maximum ${MAX_PASSPHRASE_INPUT_BYTES} bytes`
3622
+ );
3623
+ }
3624
+ const password = normalizePassphrase(passphrase);
3374
3625
  let cek;
3375
3626
  try {
3376
3627
  cek = await argon2idV13({
@@ -3388,10 +3639,20 @@ async function decryptPassphrase(args) {
3388
3639
  if (enc.aead !== "xchacha20-poly1305") {
3389
3640
  throw new Error(`KDF_DERIVATION_FAILED: unsupported aead ${enc.aead}`);
3390
3641
  }
3391
- return xchacha20Poly1305Decrypt({
3392
- key: cek,
3642
+ assertCiphertextWithinBound(ciphertext.length);
3643
+ const payloadKey = passphrasePayloadKey({ cek, nonce: enc.nonce });
3644
+ const aad = adContentPassphrase({
3645
+ nonce: enc.nonce,
3646
+ passphrase: {
3647
+ alg: enc.passphrase.alg,
3648
+ salt: enc.passphrase.salt,
3649
+ params: enc.passphrase.params
3650
+ }
3651
+ });
3652
+ return xchacha20Poly1305Decrypt2({
3653
+ key: payloadKey,
3393
3654
  nonce: enc.nonce,
3394
- aad: EMPTY_AAD,
3655
+ aad,
3395
3656
  ciphertext
3396
3657
  });
3397
3658
  }
@@ -3400,7 +3661,7 @@ function recomputeHashes(item, plaintext) {
3400
3661
  if (entries.length === 0) return false;
3401
3662
  for (const [alg, digest] of entries) {
3402
3663
  if (alg === "sha2-256") {
3403
- if (!compareCt3(sha2562(plaintext), digest)) return false;
3664
+ if (!compareCt3(sha2564(plaintext), digest)) return false;
3404
3665
  } else if (alg === "blake2b-256") {
3405
3666
  if (!compareCt3(blake2b256(plaintext), digest)) return false;
3406
3667
  } else {
@@ -3423,7 +3684,7 @@ function decodeCanonicalCbor3(bytes) {
3423
3684
  ...cbor2.cdeDecodeOptions,
3424
3685
  rejectStreaming: true,
3425
3686
  rejectDuplicateKeys: true,
3426
- // A CIP-309 record carries integers, byte/text strings, arrays, maps and
3687
+ // A Label 309 record carries integers, byte/text strings, arrays, maps and
3427
3688
  // `null` — and nothing else. Without these rejections the major-type-7
3428
3689
  // surface leaks into the decoder: a float16/32/64 that happens to hold an
3429
3690
  // integral value (e.g. 1.0) silently decodes to the integer 1 and passes
@@ -3996,11 +4257,11 @@ function decodeIntKey(h) {
3996
4257
  // src/verifier/resolve.ts
3997
4258
  var KOIOS_MAINNET_URL = "https://api.koios.rest/api/v1";
3998
4259
  var BLOCKFROST_MAINNET_HOST = "https://cardano-mainnet.blockfrost.io/api/v0";
3999
- var NotACip309RecordError = class extends Error {
4260
+ var NotALabel309RecordError = class extends Error {
4000
4261
  code = "METADATA_NOT_FOUND";
4001
4262
  constructor(message) {
4002
4263
  super(message);
4003
- this.name = "NotACip309RecordError";
4264
+ this.name = "NotALabel309RecordError";
4004
4265
  }
4005
4266
  };
4006
4267
  async function resolveCardanoTx(args) {
@@ -4011,7 +4272,7 @@ async function resolveCardanoTx(args) {
4011
4272
  try {
4012
4273
  return await resolveViaKoios(input.txHash, koiosUrl, fetchFn);
4013
4274
  } catch (e) {
4014
- if (e instanceof NotACip309RecordError) throw e;
4275
+ if (e instanceof NotALabel309RecordError) throw e;
4015
4276
  lastErr = e;
4016
4277
  }
4017
4278
  }
@@ -4019,7 +4280,7 @@ async function resolveCardanoTx(args) {
4019
4280
  try {
4020
4281
  return await resolveViaBlockfrost(input.txHash, input.blockfrostProjectId, fetchFn);
4021
4282
  } catch (e) {
4022
- if (e instanceof NotACip309RecordError) throw e;
4283
+ if (e instanceof NotALabel309RecordError) throw e;
4023
4284
  lastErr = e;
4024
4285
  }
4025
4286
  }
@@ -4037,7 +4298,7 @@ async function resolveViaKoios(txHash, koiosUrl, fetchFn) {
4037
4298
  }
4038
4299
  const cborJson = parseJson(cborRes.bytes);
4039
4300
  if (!Array.isArray(cborJson) || cborJson.length === 0) {
4040
- throw new NotACip309RecordError("koios returned empty array for tx_cbor; tx may not exist");
4301
+ throw new NotALabel309RecordError("koios returned empty array for tx_cbor; tx may not exist");
4041
4302
  }
4042
4303
  const cborEntry = cborJson[0];
4043
4304
  if (typeof cborEntry.cbor !== "string") {
@@ -4058,7 +4319,7 @@ async function resolveViaKoios(txHash, koiosUrl, fetchFn) {
4058
4319
  }
4059
4320
  const infoJson = parseJson(infoRes.bytes);
4060
4321
  if (!Array.isArray(infoJson) || infoJson.length === 0) {
4061
- throw new NotACip309RecordError("koios returned empty array for tx_info");
4322
+ throw new NotALabel309RecordError("koios returned empty array for tx_info");
4062
4323
  }
4063
4324
  const infoEntry = infoJson[0];
4064
4325
  if (typeof infoEntry.tx_hash === "string" && infoEntry.tx_hash.toLowerCase() !== txHash.toLowerCase()) {
@@ -4170,7 +4431,7 @@ function hexToBytes(hex) {
4170
4431
  }
4171
4432
 
4172
4433
  // src/hex.ts
4173
- function bytesToHex(bytes) {
4434
+ function bytesToHex2(bytes) {
4174
4435
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
4175
4436
  }
4176
4437
 
@@ -4203,7 +4464,7 @@ async function verifyOneSig(index, entry, recordBodyCbor, input) {
4203
4464
  return { index, verdict: "unresolved", reason: "SIGNER_KEY_UNRESOLVED" };
4204
4465
  }
4205
4466
  const { pub, signerType } = resolved;
4206
- const verifyResult = coseSign1Cip309Verify({
4467
+ const verifyResult = coseSign1Label309Verify({
4207
4468
  message: coseBytes,
4208
4469
  detachedRecordBodyCbor: recordBodyCbor,
4209
4470
  expectedSignerKey: pub
@@ -4215,7 +4476,7 @@ async function verifyOneSig(index, entry, recordBodyCbor, input) {
4215
4476
  index,
4216
4477
  verdict: "unsupported",
4217
4478
  signer_type: signerType,
4218
- signer_pub: bytesToHex(pub),
4479
+ signer_pub: bytesToHex2(pub),
4219
4480
  reason
4220
4481
  };
4221
4482
  }
@@ -4223,7 +4484,7 @@ async function verifyOneSig(index, entry, recordBodyCbor, input) {
4223
4484
  index,
4224
4485
  verdict: "invalid",
4225
4486
  signer_type: signerType,
4226
- signer_pub: bytesToHex(pub),
4487
+ signer_pub: bytesToHex2(pub),
4227
4488
  reason
4228
4489
  };
4229
4490
  }
@@ -4234,7 +4495,7 @@ async function verifyOneSig(index, entry, recordBodyCbor, input) {
4234
4495
  index,
4235
4496
  verdict: "invalid",
4236
4497
  signer_type: signerType,
4237
- signer_pub: bytesToHex(pub),
4498
+ signer_pub: bytesToHex2(pub),
4238
4499
  reason: "WALLET_ADDRESS_MISMATCH"
4239
4500
  };
4240
4501
  }
@@ -4243,7 +4504,7 @@ async function verifyOneSig(index, entry, recordBodyCbor, input) {
4243
4504
  index,
4244
4505
  verdict: "valid",
4245
4506
  signer_type: signerType,
4246
- signer_pub: bytesToHex(pub)
4507
+ signer_pub: bytesToHex2(pub)
4247
4508
  };
4248
4509
  }
4249
4510
  function resolveSignerKey(cose, entry) {
@@ -4369,8 +4630,8 @@ function decodeTxWitnesses(witnessSetBytes, txBodyBytes) {
4369
4630
  if (vkey instanceof Uint8Array && vkey.length === ED25519_PUBLIC_KEY_LENGTH3) {
4370
4631
  out.push({
4371
4632
  type: "vkey",
4372
- vkey: bytesToHex(vkey),
4373
- key_hash: bytesToHex(blake2b2242(vkey)),
4633
+ vkey: bytesToHex2(vkey),
4634
+ key_hash: bytesToHex2(blake2b2242(vkey)),
4374
4635
  signature_valid: false
4375
4636
  });
4376
4637
  }
@@ -4384,8 +4645,8 @@ function decodeTxWitnesses(witnessSetBytes, txBodyBytes) {
4384
4645
  }
4385
4646
  out.push({
4386
4647
  type: "vkey",
4387
- vkey: bytesToHex(vkey),
4388
- key_hash: bytesToHex(blake2b2242(vkey)),
4648
+ vkey: bytesToHex2(vkey),
4649
+ key_hash: bytesToHex2(blake2b2242(vkey)),
4389
4650
  signature_valid: signatureValid
4390
4651
  });
4391
4652
  }
@@ -4418,7 +4679,7 @@ function decodeTxSummary(txBodyBytes, witnessSetBytes, network) {
4418
4679
  lovelace: lovelace.toString()
4419
4680
  });
4420
4681
  }
4421
- const requiredSigners = asArray(body.get(BODY_KEY_REQUIRED_SIGNERS)).filter((s) => s instanceof Uint8Array).map((s) => bytesToHex(s));
4682
+ const requiredSigners = asArray(body.get(BODY_KEY_REQUIRED_SIGNERS)).filter((s) => s instanceof Uint8Array).map((s) => bytesToHex2(s));
4422
4683
  const summary = {
4423
4684
  fee_lovelace: coinToString(body.get(BODY_KEY_FEE)),
4424
4685
  input_count: inputs.length,
@@ -4552,7 +4813,7 @@ async function verifyTx(input) {
4552
4813
  try {
4553
4814
  resolved = await resolveCardanoTx({ input, fetchFn });
4554
4815
  } catch (e) {
4555
- if (e instanceof NotACip309RecordError) {
4816
+ if (e instanceof NotALabel309RecordError) {
4556
4817
  return base({
4557
4818
  verdict: "failed",
4558
4819
  exit_code: 1,
@@ -4830,7 +5091,7 @@ function isPlainObject(v) {
4830
5091
  }
4831
5092
  function walk(value) {
4832
5093
  if (value === void 0 || value === null) return void 0;
4833
- if (value instanceof Uint8Array) return bytesToHex(value);
5094
+ if (value instanceof Uint8Array) return bytesToHex2(value);
4834
5095
  if (value instanceof Map) {
4835
5096
  throw new Error("unsupported Map in VerifyReport tree");
4836
5097
  }
@@ -4873,7 +5134,7 @@ exports.DEFAULT_PROFILE = DEFAULT_PROFILE;
4873
5134
  exports.DENY_HOSTS_DEFAULT = DENY_HOSTS_DEFAULT;
4874
5135
  exports.DenyHostError = DenyHostError;
4875
5136
  exports.KOIOS_MAINNET_URL = KOIOS_MAINNET_URL;
4876
- exports.NotACip309RecordError = NotACip309RecordError;
5137
+ exports.NotALabel309RecordError = NotALabel309RecordError;
4877
5138
  exports.OutboundExhaustedError = OutboundExhaustedError;
4878
5139
  exports.PROFILE_RANK = PROFILE_RANK;
4879
5140
  exports.UnsupportedMethodError = UnsupportedMethodError;