@cardanowall/crypto-core 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -4,9 +4,10 @@ export { GetPublicKeyEd25519Opts, SignEd25519Opts, VerifyEd25519Opts, getPublicK
4
4
  export { MLKEM768X25519_ENC_LENGTH, MLKEM768X25519_ESEED_LENGTH, MLKEM768X25519_PUBLIC_KEY_LENGTH, MLKEM768X25519_SEED_LENGTH, MLKEM768X25519_SHARED_SECRET_LENGTH, Mlkem768X25519DecapsulateOpts, Mlkem768X25519EncapsulateOpts, Mlkem768X25519Encapsulation, Mlkem768X25519KeyPair, X25519EcdhOpts, X25519KeyPair, X25519LowOrderPointError, X25519PublicKeyOpts, mlkem768x25519Decapsulate, mlkem768x25519Encapsulate, mlkem768x25519Keygen, x25519Ecdh, x25519Keygen, x25519PublicKey } from './kem.cjs';
5
5
  export { AeadVerificationError, ChaCha20Poly1305DecryptOpts, ChaCha20Poly1305EncryptOpts, XChaCha20Poly1305DecryptOpts, XChaCha20Poly1305EncryptOpts, chacha20Poly1305Decrypt, chacha20Poly1305Encrypt, xchacha20Poly1305Decrypt, xchacha20Poly1305Encrypt } from './aead.cjs';
6
6
  export { compareCt, hexToBytes } from './util.cjs';
7
- export { CanonicalCborError, CanonicalCborErrorCode, CanonicalCborValue, decodeCanonicalCbor, decodeCbor, encodeCanonicalCbor } from './cbor.cjs';
7
+ export { C as CanonicalCborValue, d as decodeCanonicalCbor, e as encodeCanonicalCbor } from './canonical-DHeJLYDR.cjs';
8
+ export { CanonicalCborError, CanonicalCborErrorCode, decodeCbor } from './cbor.cjs';
8
9
  export { BuildLabel309SigStructureArgs, BuildSigStructureArgs, CARDANO_POE_SIG_DOMAIN_PREFIX, CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES, CoseHeader, CoseSign1BuildError, CoseSign1BuildErrorCode, CoseSign1Decoded, CoseSign1Label309BuildArgs, CoseSign1Label309VerifyArgs, CoseVerifyError, CoseVerifyErrorCode, CoseVerifyResult, EncodeCoseSign1Args, buildLabel309SigStructure, buildSigStructure, coseSign1Label309Build, coseSign1Label309Verify, decodeCoseSign1, encodeCoseSign1, parseCoseKeyEd25519 } from './cose.cjs';
9
10
  export { DerivedEd25519KeyPair, DerivedMlKem768X25519KeyPair, DerivedX25519KeyPair, INFO_ED25519, INFO_MLKEM768X25519, INFO_X25519, SeedDeriveError, SeedDeriveErrorCode, deriveEd25519KeypairFromSeed, deriveMlKem768X25519KeypairFromSeed, deriveX25519KeypairFromSeed } from './seed-derive.cjs';
10
- export { CARDANO_POE_HKDF_INFO_KEK, CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519, CARDANO_POE_HKDF_INFO_SLOTS_MAC, EciesSealedPoeError, EciesSealedPoeErrorCode, Mlkem768X25519Slot, ParsedEnvelopeShape, ParsedSlotShape, RecipientKeyBundle, SealedEnvelope, SealedKem, SealedPoeOutput, TrialDecryptOnlyArgs, TrialDecryptOnlyResult, UnwrapArgs, UnwrapArgsBundle, UnwrapArgsMultiPriv, UnwrapArgsSinglePriv, UnwrapFailureReason, UnwrapResult, WrapArgs, X25519Slot, chunkKemCt, eciesSealedPoeTrialDecrypt, eciesSealedPoeUnwrap, eciesSealedPoeWrap, joinKemCt, sealedEnvelopeFromParsed, slotsToMacCbor, uniformIndexBelow } from './sealed-poe.cjs';
11
+ export { CARDANO_POE_HKDF_INFO_KEK, CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519, CARDANO_POE_HKDF_INFO_PAYLOAD, CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE, CARDANO_POE_HKDF_INFO_SLOTS_MAC, CARDANO_POE_PW_NORM_PROFILE, CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX, CARDANO_POE_XWING_KEK_SALT_PREFIX, EciesSealedPoeError, EciesSealedPoeErrorCode, MAX_DECODED_ENVELOPE_BYTES, MAX_SEALED_CIPHERTEXT, MAX_SEALED_PLAINTEXT, MAX_SLOTS, Mlkem768X25519Slot, ParsedEnvelopeShape, ParsedSlotShape, RecipientKeyBundle, SealedEnvelope, SealedKem, SealedPayloadTooLargeError, SealedPoeOutput, TrialDecryptOnlyArgs, TrialDecryptOnlyResult, UnwrapArgs, UnwrapArgsBundle, UnwrapArgsMultiPriv, UnwrapArgsSinglePriv, UnwrapFailureReason, UnwrapResult, WrapArgs, X25519Slot, adContentPassphrase, adContentSlots, assertCiphertextWithinBound, assertPlaintextWithinBound, canonicalizeSlots, chunkKemCt, computeSlotsHash, eciesSealedPoeTrialDecrypt, eciesSealedPoeUnwrap, eciesSealedPoeWrap, joinKemCt, passphrasePayloadKey, sealedEnvelopeFromParsed, slotsPayloadKey, uniformIndexBelow, xwingKekSalt } from './sealed-poe.cjs';
11
12
  export { DecodedLeavesList, EncodeLeavesListArgs, LEAVES_LIST_FORMAT_V1, MerkleLeavesListError, MerkleLeavesListErrorCode, decodeLeavesList, encodeLeavesList } from './merkle.cjs';
12
13
  export { ParsedAgeRecipient, RecipientKem, bech32DecodeNoLimit, bech32EncodeNoLimit, encodeAgeX25519Recipient, encodeAgeXWingRecipient, parseAgeRecipient } from './recipient.cjs';
package/dist/index.d.ts CHANGED
@@ -4,9 +4,10 @@ export { GetPublicKeyEd25519Opts, SignEd25519Opts, VerifyEd25519Opts, getPublicK
4
4
  export { MLKEM768X25519_ENC_LENGTH, MLKEM768X25519_ESEED_LENGTH, MLKEM768X25519_PUBLIC_KEY_LENGTH, MLKEM768X25519_SEED_LENGTH, MLKEM768X25519_SHARED_SECRET_LENGTH, Mlkem768X25519DecapsulateOpts, Mlkem768X25519EncapsulateOpts, Mlkem768X25519Encapsulation, Mlkem768X25519KeyPair, X25519EcdhOpts, X25519KeyPair, X25519LowOrderPointError, X25519PublicKeyOpts, mlkem768x25519Decapsulate, mlkem768x25519Encapsulate, mlkem768x25519Keygen, x25519Ecdh, x25519Keygen, x25519PublicKey } from './kem.js';
5
5
  export { AeadVerificationError, ChaCha20Poly1305DecryptOpts, ChaCha20Poly1305EncryptOpts, XChaCha20Poly1305DecryptOpts, XChaCha20Poly1305EncryptOpts, chacha20Poly1305Decrypt, chacha20Poly1305Encrypt, xchacha20Poly1305Decrypt, xchacha20Poly1305Encrypt } from './aead.js';
6
6
  export { compareCt, hexToBytes } from './util.js';
7
- export { CanonicalCborError, CanonicalCborErrorCode, CanonicalCborValue, decodeCanonicalCbor, decodeCbor, encodeCanonicalCbor } from './cbor.js';
7
+ export { C as CanonicalCborValue, d as decodeCanonicalCbor, e as encodeCanonicalCbor } from './canonical-DHeJLYDR.js';
8
+ export { CanonicalCborError, CanonicalCborErrorCode, decodeCbor } from './cbor.js';
8
9
  export { BuildLabel309SigStructureArgs, BuildSigStructureArgs, CARDANO_POE_SIG_DOMAIN_PREFIX, CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES, CoseHeader, CoseSign1BuildError, CoseSign1BuildErrorCode, CoseSign1Decoded, CoseSign1Label309BuildArgs, CoseSign1Label309VerifyArgs, CoseVerifyError, CoseVerifyErrorCode, CoseVerifyResult, EncodeCoseSign1Args, buildLabel309SigStructure, buildSigStructure, coseSign1Label309Build, coseSign1Label309Verify, decodeCoseSign1, encodeCoseSign1, parseCoseKeyEd25519 } from './cose.js';
9
10
  export { DerivedEd25519KeyPair, DerivedMlKem768X25519KeyPair, DerivedX25519KeyPair, INFO_ED25519, INFO_MLKEM768X25519, INFO_X25519, SeedDeriveError, SeedDeriveErrorCode, deriveEd25519KeypairFromSeed, deriveMlKem768X25519KeypairFromSeed, deriveX25519KeypairFromSeed } from './seed-derive.js';
10
- export { CARDANO_POE_HKDF_INFO_KEK, CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519, CARDANO_POE_HKDF_INFO_SLOTS_MAC, EciesSealedPoeError, EciesSealedPoeErrorCode, Mlkem768X25519Slot, ParsedEnvelopeShape, ParsedSlotShape, RecipientKeyBundle, SealedEnvelope, SealedKem, SealedPoeOutput, TrialDecryptOnlyArgs, TrialDecryptOnlyResult, UnwrapArgs, UnwrapArgsBundle, UnwrapArgsMultiPriv, UnwrapArgsSinglePriv, UnwrapFailureReason, UnwrapResult, WrapArgs, X25519Slot, chunkKemCt, eciesSealedPoeTrialDecrypt, eciesSealedPoeUnwrap, eciesSealedPoeWrap, joinKemCt, sealedEnvelopeFromParsed, slotsToMacCbor, uniformIndexBelow } from './sealed-poe.js';
11
+ export { CARDANO_POE_HKDF_INFO_KEK, CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519, CARDANO_POE_HKDF_INFO_PAYLOAD, CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE, CARDANO_POE_HKDF_INFO_SLOTS_MAC, CARDANO_POE_PW_NORM_PROFILE, CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX, CARDANO_POE_XWING_KEK_SALT_PREFIX, EciesSealedPoeError, EciesSealedPoeErrorCode, MAX_DECODED_ENVELOPE_BYTES, MAX_SEALED_CIPHERTEXT, MAX_SEALED_PLAINTEXT, MAX_SLOTS, Mlkem768X25519Slot, ParsedEnvelopeShape, ParsedSlotShape, RecipientKeyBundle, SealedEnvelope, SealedKem, SealedPayloadTooLargeError, SealedPoeOutput, TrialDecryptOnlyArgs, TrialDecryptOnlyResult, UnwrapArgs, UnwrapArgsBundle, UnwrapArgsMultiPriv, UnwrapArgsSinglePriv, UnwrapFailureReason, UnwrapResult, WrapArgs, X25519Slot, adContentPassphrase, adContentSlots, assertCiphertextWithinBound, assertPlaintextWithinBound, canonicalizeSlots, chunkKemCt, computeSlotsHash, eciesSealedPoeTrialDecrypt, eciesSealedPoeUnwrap, eciesSealedPoeWrap, joinKemCt, passphrasePayloadKey, sealedEnvelopeFromParsed, slotsPayloadKey, uniformIndexBelow, xwingKekSalt } from './sealed-poe.js';
11
12
  export { DecodedLeavesList, EncodeLeavesListArgs, LEAVES_LIST_FORMAT_V1, MerkleLeavesListError, MerkleLeavesListErrorCode, decodeLeavesList, encodeLeavesList } from './merkle.js';
12
13
  export { ParsedAgeRecipient, RecipientKem, bech32DecodeNoLimit, bech32EncodeNoLimit, encodeAgeX25519Recipient, encodeAgeXWingRecipient, parseAgeRecipient } from './recipient.js';
package/dist/index.js CHANGED
@@ -775,27 +775,141 @@ function joinKemCt(chunks) {
775
775
  }
776
776
  return out;
777
777
  }
778
- function slotsToMacCbor(slots, kem) {
779
- let value;
778
+ function canonicalizeSlots(slots, kem) {
780
779
  if (kem === "x25519") {
781
- value = slots.map((s) => ({ epk: s.epk, wrap: s.wrap }));
782
- } else {
783
- value = slots.map((s) => ({
784
- // Canonicalize the chunk boundaries before the MAC commits to them:
785
- // reassemble the logical ciphertext and re-split into canonical ≤ 64-byte
786
- // chunks. The on-wire `kem_ct` array is a transport detail (the Cardano
787
- // ledger's 64-byte metadatum cap), and a hostile or non-canonical chunking
788
- // ([1, 63, …] instead of [64, …]) reassembles to the SAME bytes — so the
789
- // MAC must be invariant to it. Committing to the verbatim wire chunks would
790
- // let an attacker re-chunk an honest envelope and break the slots_mac match
791
- // for an honest recipient. Honest (already-64B-chunked) records are
792
- // unchanged; a real byte flip still changes the reassembled bytes and is
793
- // still rejected.
794
- kem_ct: chunkKemCt(joinKemCt(s.kem_ct)),
795
- wrap: s.wrap
796
- }));
797
- }
798
- return encodeCanonicalCbor(value);
780
+ return slots.map((s) => ({ epk: s.epk, wrap: s.wrap }));
781
+ }
782
+ return slots.map((s) => ({
783
+ kem_ct: chunkKemCt(joinKemCt(s.kem_ct)),
784
+ wrap: s.wrap
785
+ }));
786
+ }
787
+ var CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX = new TextEncoder().encode(
788
+ "cardano-poe-slots-transcript-v1"
789
+ );
790
+ var CARDANO_POE_HKDF_INFO_PAYLOAD = new TextEncoder().encode(
791
+ "cardano-poe-payload-v1"
792
+ );
793
+ var CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE = new TextEncoder().encode(
794
+ "cardano-poe-payload-passphrase-v1"
795
+ );
796
+ var CARDANO_POE_XWING_KEK_SALT_PREFIX = new TextEncoder().encode(
797
+ "cardano-poe-xwing-kek-salt-v1"
798
+ );
799
+ if (CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length !== 31) {
800
+ throw new Error(
801
+ "CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX byte-length invariant violated (expected 31)"
802
+ );
803
+ }
804
+ if (CARDANO_POE_HKDF_INFO_PAYLOAD.length !== 22) {
805
+ throw new Error("CARDANO_POE_HKDF_INFO_PAYLOAD byte-length invariant violated (expected 22)");
806
+ }
807
+ if (CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE.length !== 33) {
808
+ throw new Error(
809
+ "CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE byte-length invariant violated (expected 33)"
810
+ );
811
+ }
812
+ if (CARDANO_POE_XWING_KEK_SALT_PREFIX.length !== 29) {
813
+ throw new Error("CARDANO_POE_XWING_KEK_SALT_PREFIX byte-length invariant violated (expected 29)");
814
+ }
815
+ var CARDANO_POE_PW_NORM_PROFILE = "cardano-poe-pw-norm-v1";
816
+ var MAX_SLOTS = 1024;
817
+ var MAX_DECODED_ENVELOPE_BYTES = 65536;
818
+ var MAX_SEALED_PLAINTEXT = 274877906880;
819
+ var MAX_SEALED_CIPHERTEXT = MAX_SEALED_PLAINTEXT + 16;
820
+ function assertPlaintextWithinBound(plaintextLength) {
821
+ if (plaintextLength >= MAX_SEALED_PLAINTEXT) {
822
+ throw new SealedPayloadTooLargeError(
823
+ `plaintext length ${plaintextLength} is at or above the maximum sealed payload size ${MAX_SEALED_PLAINTEXT}`
824
+ );
825
+ }
826
+ }
827
+ function assertCiphertextWithinBound(ciphertextLength) {
828
+ if (ciphertextLength >= MAX_SEALED_CIPHERTEXT) {
829
+ throw new SealedPayloadTooLargeError(
830
+ `ciphertext length ${ciphertextLength} is at or above the maximum sealed ciphertext size ${MAX_SEALED_CIPHERTEXT}`
831
+ );
832
+ }
833
+ }
834
+ var SealedPayloadTooLargeError = class extends Error {
835
+ constructor(message) {
836
+ super(message);
837
+ this.name = "SealedPayloadTooLargeError";
838
+ }
839
+ };
840
+ function computeSlotsHash(args) {
841
+ const transcript = {
842
+ scheme: 1,
843
+ path: "slots",
844
+ aead: "xchacha20-poly1305",
845
+ kem: args.kem,
846
+ nonce: args.nonce,
847
+ slots: canonicalizeSlots(args.slots, args.kem)
848
+ };
849
+ const encoded = encodeCanonicalCbor(transcript);
850
+ const message = new Uint8Array(CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length + encoded.length);
851
+ message.set(CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX, 0);
852
+ message.set(encoded, CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length);
853
+ return sha256$1(message);
854
+ }
855
+ function adContentSlots(args) {
856
+ const ad = {
857
+ scheme: 1,
858
+ path: "slots",
859
+ aead: "xchacha20-poly1305",
860
+ kem: args.kem,
861
+ nonce: args.nonce,
862
+ slots_hash: args.slotsHash,
863
+ slots_mac: args.slotsMac
864
+ };
865
+ return encodeCanonicalCbor(ad);
866
+ }
867
+ function adContentPassphrase(args) {
868
+ const ad = {
869
+ scheme: 1,
870
+ path: "passphrase",
871
+ aead: "xchacha20-poly1305",
872
+ nonce: args.nonce,
873
+ passphrase: {
874
+ alg: args.passphrase.alg,
875
+ salt: args.passphrase.salt,
876
+ params: {
877
+ m: args.passphrase.params.m,
878
+ t: args.passphrase.params.t,
879
+ p: args.passphrase.params.p
880
+ },
881
+ normalization: CARDANO_POE_PW_NORM_PROFILE
882
+ }
883
+ };
884
+ return encodeCanonicalCbor(ad);
885
+ }
886
+ function slotsPayloadKey(args) {
887
+ return hkdfSha256({
888
+ ikm: args.cek,
889
+ salt: args.nonce,
890
+ info: CARDANO_POE_HKDF_INFO_PAYLOAD,
891
+ length: 32
892
+ });
893
+ }
894
+ function passphrasePayloadKey(args) {
895
+ return hkdfSha256({
896
+ ikm: args.cek,
897
+ salt: args.nonce,
898
+ info: CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE,
899
+ length: 32
900
+ });
901
+ }
902
+ function xwingKekSalt(args) {
903
+ const message = new Uint8Array(
904
+ CARDANO_POE_XWING_KEK_SALT_PREFIX.length + args.kemCt.length + args.pubR.length
905
+ );
906
+ let offset = 0;
907
+ message.set(CARDANO_POE_XWING_KEK_SALT_PREFIX, offset);
908
+ offset += CARDANO_POE_XWING_KEK_SALT_PREFIX.length;
909
+ message.set(args.kemCt, offset);
910
+ offset += args.kemCt.length;
911
+ message.set(args.pubR, offset);
912
+ return sha256$1(message);
799
913
  }
800
914
 
801
915
  // src/sealed-poe/wrap.ts
@@ -889,7 +1003,7 @@ function wrapSlotMlkem768X25519(args) {
889
1003
  }
890
1004
  const kek = hkdfSha256({
891
1005
  ikm: ss,
892
- salt: EMPTY_SALT2,
1006
+ salt: xwingKekSalt({ kemCt: enc, pubR: args.pubR }),
893
1007
  info: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
894
1008
  length: 32
895
1009
  });
@@ -908,6 +1022,7 @@ function eciesSealedPoeWrap(args) {
908
1022
  const { plaintext, recipientPublicKeys } = args;
909
1023
  const kem = args.kem ?? "x25519";
910
1024
  const n = recipientPublicKeys.length;
1025
+ assertPlaintextWithinBound(plaintext.length);
911
1026
  if (n < 1) {
912
1027
  throw new EciesSealedPoeError(
913
1028
  "ENC_SLOTS_EMPTY",
@@ -977,6 +1092,7 @@ function eciesSealedPoeWrap(args) {
977
1092
  );
978
1093
  }
979
1094
  let envelope;
1095
+ let slotsHash;
980
1096
  if (kem === "x25519") {
981
1097
  const slots = [];
982
1098
  for (let i = 0; i < n; i++) {
@@ -992,14 +1108,14 @@ function eciesSealedPoeWrap(args) {
992
1108
  if (args.skipShuffle !== true) {
993
1109
  csprngShuffle(slots);
994
1110
  }
995
- const slotsMac = computeSlotsMac(cek, slots, "x25519");
1111
+ slotsHash = computeSlotsHash({ kem: "x25519", nonce, slots });
996
1112
  envelope = {
997
1113
  scheme: 1,
998
1114
  aead: "xchacha20-poly1305",
999
1115
  kem: "x25519",
1000
1116
  nonce,
1001
1117
  slots,
1002
- slots_mac: slotsMac
1118
+ slots_mac: computeSlotsMac(cek, slotsHash)
1003
1119
  };
1004
1120
  } else {
1005
1121
  const slots = [];
@@ -1015,34 +1131,39 @@ function eciesSealedPoeWrap(args) {
1015
1131
  if (args.skipShuffle !== true) {
1016
1132
  csprngShuffle(slots);
1017
1133
  }
1018
- const slotsMac = computeSlotsMac(cek, slots, "mlkem768x25519");
1134
+ slotsHash = computeSlotsHash({ kem: "mlkem768x25519", nonce, slots });
1019
1135
  envelope = {
1020
1136
  scheme: 1,
1021
1137
  aead: "xchacha20-poly1305",
1022
1138
  kem: "mlkem768x25519",
1023
1139
  nonce,
1024
1140
  slots,
1025
- slots_mac: slotsMac
1141
+ slots_mac: computeSlotsMac(cek, slotsHash)
1026
1142
  };
1027
1143
  }
1028
- const adContent = concat(nonce, envelope.slots_mac);
1144
+ const payloadKey = slotsPayloadKey({ cek, nonce });
1145
+ const adContent = adContentSlots({
1146
+ kem: envelope.kem,
1147
+ nonce,
1148
+ slotsHash,
1149
+ slotsMac: envelope.slots_mac
1150
+ });
1029
1151
  const ciphertext = xchacha20Poly1305Encrypt({
1030
- key: cek,
1152
+ key: payloadKey,
1031
1153
  nonce,
1032
1154
  aad: adContent,
1033
1155
  plaintext
1034
1156
  });
1035
1157
  return { envelope, ciphertext };
1036
1158
  }
1037
- function computeSlotsMac(cek, slots, kem) {
1159
+ function computeSlotsMac(cek, slotsHash) {
1038
1160
  const hmacKey = hkdfSha256({
1039
1161
  ikm: cek,
1040
1162
  salt: EMPTY_SALT2,
1041
1163
  info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
1042
1164
  length: 32
1043
1165
  });
1044
- const slotsCbor = slotsToMacCbor(slots, kem);
1045
- const slotsMac = hmac(sha256$1, hmacKey, slotsCbor);
1166
+ const slotsMac = hmac(sha256$1, hmacKey, slotsHash);
1046
1167
  if (slotsMac.length !== SLOTS_MAC_LENGTH) {
1047
1168
  throw new Error(`internal: slots_mac.length=${slotsMac.length}, expected ${SLOTS_MAC_LENGTH}`);
1048
1169
  }
@@ -1064,6 +1185,13 @@ function concat2(a, b) {
1064
1185
  out.set(b, a.length);
1065
1186
  return out;
1066
1187
  }
1188
+ function bytesKey(bytes) {
1189
+ let s = "";
1190
+ for (let i = 0; i < bytes.length; i++) {
1191
+ s += String.fromCharCode(bytes[i]);
1192
+ }
1193
+ return s;
1194
+ }
1067
1195
  function assertEnvelopeStructure(envelope, multiPrivKeys, singlePrivKey) {
1068
1196
  if (envelope.scheme !== 1) {
1069
1197
  throw new EciesSealedPoeError(
@@ -1087,6 +1215,12 @@ function assertEnvelopeStructure(envelope, multiPrivKeys, singlePrivKey) {
1087
1215
  if (n < 1) {
1088
1216
  throw new EciesSealedPoeError("ENC_SLOTS_EMPTY", `envelope.slots.length=${n} must be >= 1`);
1089
1217
  }
1218
+ if (n > MAX_SLOTS) {
1219
+ throw new EciesSealedPoeError(
1220
+ "ENC_SLOTS_TOO_MANY",
1221
+ `envelope.slots.length=${n} exceeds MAX_SLOTS=${MAX_SLOTS}`
1222
+ );
1223
+ }
1090
1224
  if (envelope.nonce.length !== NONCE_LENGTH2) {
1091
1225
  throw new EciesSealedPoeError(
1092
1226
  "NONCE_LENGTH_MISMATCH",
@@ -1099,6 +1233,7 @@ function assertEnvelopeStructure(envelope, multiPrivKeys, singlePrivKey) {
1099
1233
  `envelope.slots_mac MUST be exactly ${SLOTS_MAC_LENGTH2} bytes, got ${envelope.slots_mac.length}`
1100
1234
  );
1101
1235
  }
1236
+ const seenKemMaterial = /* @__PURE__ */ new Set();
1102
1237
  if (envelope.kem === "x25519") {
1103
1238
  for (let i = 0; i < n; i++) {
1104
1239
  const slot = envelope.slots[i];
@@ -1114,6 +1249,14 @@ function assertEnvelopeStructure(envelope, multiPrivKeys, singlePrivKey) {
1114
1249
  `envelope.slots[${i}].wrap MUST be exactly ${WRAP_LENGTH2} bytes, got ${slot.wrap.length}`
1115
1250
  );
1116
1251
  }
1252
+ const key = bytesKey(slot.epk);
1253
+ if (seenKemMaterial.has(key)) {
1254
+ throw new EciesSealedPoeError(
1255
+ "ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
1256
+ `envelope.slots[${i}].epk duplicates an earlier slot \u2014 per-slot KEK uniqueness is violated`
1257
+ );
1258
+ }
1259
+ seenKemMaterial.add(key);
1117
1260
  }
1118
1261
  } else {
1119
1262
  for (let i = 0; i < n; i++) {
@@ -1131,8 +1274,24 @@ function assertEnvelopeStructure(envelope, multiPrivKeys, singlePrivKey) {
1131
1274
  `envelope.slots[${i}].wrap MUST be exactly ${WRAP_LENGTH2} bytes, got ${slot.wrap.length}`
1132
1275
  );
1133
1276
  }
1277
+ const key = bytesKey(enc);
1278
+ if (seenKemMaterial.has(key)) {
1279
+ throw new EciesSealedPoeError(
1280
+ "ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
1281
+ `envelope.slots[${i}].kem_ct duplicates an earlier slot \u2014 per-slot KEK uniqueness is violated`
1282
+ );
1283
+ }
1284
+ seenKemMaterial.add(key);
1134
1285
  }
1135
1286
  }
1287
+ const perSlotBytes = envelope.kem === "x25519" ? X25519_PUBLIC_KEY_LENGTH2 + WRAP_LENGTH2 : MLKEM768X25519_ENC_LENGTH + WRAP_LENGTH2;
1288
+ const decodedEnvelopeBytes = NONCE_LENGTH2 + SLOTS_MAC_LENGTH2 + n * perSlotBytes;
1289
+ if (decodedEnvelopeBytes > MAX_DECODED_ENVELOPE_BYTES) {
1290
+ throw new EciesSealedPoeError(
1291
+ "ENC_ENVELOPE_TOO_LARGE",
1292
+ `decoded envelope size ${decodedEnvelopeBytes} exceeds MAX_DECODED_ENVELOPE_BYTES=${MAX_DECODED_ENVELOPE_BYTES}`
1293
+ );
1294
+ }
1136
1295
  if (multiPrivKeys !== void 0) {
1137
1296
  for (let i = 0; i < multiPrivKeys.length; i++) {
1138
1297
  if (multiPrivKeys[i].length !== X25519_SECRET_KEY_LENGTH2) {
@@ -1151,60 +1310,42 @@ function assertEnvelopeStructure(envelope, multiPrivKeys, singlePrivKey) {
1151
1310
  }
1152
1311
  }
1153
1312
  }
1313
+ var ZERO_IKM_32 = new Uint8Array(32);
1154
1314
  function tryX25519Slot(args) {
1155
- if (args.liveSlot) {
1156
- try {
1157
- const shared = x25519Ecdh({
1158
- secretKey: args.recipientSecretKey,
1159
- theirPublicKey: args.slot.epk
1160
- });
1161
- const kek = hkdfSha256({
1162
- ikm: shared,
1163
- salt: concat2(args.slot.epk, args.pubRLocal),
1164
- info: CARDANO_POE_HKDF_INFO_KEK,
1165
- length: 32
1166
- });
1167
- return chacha20Poly1305Decrypt({
1168
- key: kek,
1169
- nonce: ZERO_NONCE_122,
1170
- aad: CARDANO_POE_HKDF_INFO_KEK,
1171
- ciphertext: args.slot.wrap
1172
- });
1173
- } catch (e) {
1174
- if (!(e instanceof AeadVerificationError) && !(e instanceof X25519LowOrderPointError)) {
1175
- throw e;
1176
- }
1177
- return null;
1178
- }
1179
- }
1315
+ const salt = concat2(args.slot.epk, args.pubRLocal);
1316
+ let shared;
1180
1317
  try {
1181
- const shared = x25519Ecdh({
1318
+ shared = x25519Ecdh({
1182
1319
  secretKey: args.recipientSecretKey,
1183
1320
  theirPublicKey: args.slot.epk
1184
1321
  });
1185
- hkdfSha256({
1186
- ikm: shared,
1187
- salt: concat2(args.slot.epk, args.pubRLocal),
1188
- info: CARDANO_POE_HKDF_INFO_KEK,
1189
- length: 32
1190
- });
1191
1322
  } catch (e) {
1192
1323
  if (!(e instanceof X25519LowOrderPointError)) throw e;
1324
+ hkdfSha256({ ikm: ZERO_IKM_32, salt, info: CARDANO_POE_HKDF_INFO_KEK, length: 32 });
1325
+ return null;
1326
+ }
1327
+ const kek = hkdfSha256({ ikm: shared, salt, info: CARDANO_POE_HKDF_INFO_KEK, length: 32 });
1328
+ try {
1329
+ return chacha20Poly1305Decrypt({
1330
+ key: kek,
1331
+ nonce: ZERO_NONCE_122,
1332
+ aad: CARDANO_POE_HKDF_INFO_KEK,
1333
+ ciphertext: args.slot.wrap
1334
+ });
1335
+ } catch (e) {
1336
+ if (!(e instanceof AeadVerificationError)) throw e;
1337
+ return null;
1193
1338
  }
1194
- return null;
1195
1339
  }
1196
1340
  function tryMlkem768X25519Slot(args) {
1197
1341
  const enc = joinKemCt(args.slot.kem_ct);
1198
1342
  const ss = mlkem768x25519Decapsulate({ secretSeed: args.recipientSecretKey, enc });
1199
1343
  const kek = hkdfSha256({
1200
1344
  ikm: ss,
1201
- salt: EMPTY_SALT3,
1345
+ salt: xwingKekSalt({ kemCt: enc, pubR: args.pubR }),
1202
1346
  info: CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519,
1203
1347
  length: 32
1204
1348
  });
1205
- if (!args.liveSlot) {
1206
- return null;
1207
- }
1208
1349
  try {
1209
1350
  return chacha20Poly1305Decrypt({
1210
1351
  key: kek,
@@ -1221,51 +1362,43 @@ function tryRecipientUnwrapWithIdx(envelope, recipientSecretKey, constantTimeN,
1221
1362
  const n = envelope.slots.length;
1222
1363
  let cek = null;
1223
1364
  let matchedSlotIdx = -1;
1365
+ let cekConflict = false;
1366
+ const recordMatch = (candidate, i) => {
1367
+ if (candidate === null) return;
1368
+ if (cek === null) {
1369
+ cek = candidate;
1370
+ matchedSlotIdx = i;
1371
+ } else if (!compareCt(candidate, cek)) {
1372
+ cekConflict = true;
1373
+ }
1374
+ };
1224
1375
  if (envelope.kem === "x25519") {
1225
1376
  const pubRLocal = x25519PublicKey({ secretKey: recipientSecretKey });
1226
1377
  for (let i = 0; i < n; i++) {
1227
1378
  if (slotsAttemptedOut !== void 0) {
1228
1379
  slotsAttemptedOut.count = i + 1;
1229
1380
  }
1230
- const candidate = tryX25519Slot({
1231
- slot: envelope.slots[i],
1232
- recipientSecretKey,
1233
- pubRLocal,
1234
- liveSlot: cek === null
1235
- });
1236
- if (cek === null && candidate !== null) {
1237
- cek = candidate;
1238
- matchedSlotIdx = i;
1239
- }
1381
+ recordMatch(tryX25519Slot({ slot: envelope.slots[i], recipientSecretKey, pubRLocal }), i);
1240
1382
  if (cek !== null && !constantTimeN) break;
1241
1383
  }
1242
1384
  } else {
1385
+ const pubR = mlkem768x25519Keygen(recipientSecretKey).publicKey;
1243
1386
  for (let i = 0; i < n; i++) {
1244
1387
  if (slotsAttemptedOut !== void 0) {
1245
1388
  slotsAttemptedOut.count = i + 1;
1246
1389
  }
1247
- const candidate = tryMlkem768X25519Slot({
1248
- slot: envelope.slots[i],
1249
- recipientSecretKey,
1250
- liveSlot: cek === null
1251
- });
1252
- if (cek === null && candidate !== null) {
1253
- cek = candidate;
1254
- matchedSlotIdx = i;
1255
- }
1390
+ recordMatch(tryMlkem768X25519Slot({ slot: envelope.slots[i], recipientSecretKey, pubR }), i);
1256
1391
  if (cek !== null && !constantTimeN) break;
1257
1392
  }
1258
1393
  }
1259
- return cek === null ? null : { cek, slotIdx: matchedSlotIdx };
1260
- }
1261
- function tryRecipientUnwrap(envelope, recipientSecretKey, constantTimeN, slotsAttemptedOut) {
1262
- return tryRecipientUnwrapWithIdx(envelope, recipientSecretKey, constantTimeN, slotsAttemptedOut)?.cek ?? null;
1394
+ return cek === null ? null : { cek, slotIdx: matchedSlotIdx, cekConflict };
1263
1395
  }
1264
- function slotsMacCborBytes(envelope) {
1265
- return slotsToMacCbor(
1266
- envelope.slots,
1267
- envelope.kem
1268
- );
1396
+ function slotsHashBytes(envelope) {
1397
+ return computeSlotsHash({
1398
+ kem: envelope.kem,
1399
+ nonce: envelope.nonce,
1400
+ slots: envelope.slots
1401
+ });
1269
1402
  }
1270
1403
  function eciesSealedPoeUnwrap(args) {
1271
1404
  const { envelope, ciphertext } = args;
@@ -1294,34 +1427,38 @@ function eciesSealedPoeUnwrap(args) {
1294
1427
  } else {
1295
1428
  assertEnvelopeStructure(envelope, void 0, args.recipientSecretKey);
1296
1429
  }
1430
+ assertCiphertextWithinBound(ciphertext.length);
1431
+ const slotsHash = slotsHashBytes(envelope);
1297
1432
  let matchedCek = null;
1298
1433
  let anyCandidateRecovered = false;
1299
1434
  if (hasSingle) {
1300
1435
  const recipientSecretKey = args.recipientSecretKey;
1301
- const cek = tryRecipientUnwrap(
1436
+ const candidate = tryRecipientUnwrapWithIdx(
1302
1437
  envelope,
1303
1438
  recipientSecretKey,
1304
1439
  constantTimeN,
1305
1440
  args._slotsAttemptedOut
1306
1441
  );
1307
- if (cek === null) {
1442
+ if (candidate === null) {
1308
1443
  return { matched: false, reason: "WRONG_RECIPIENT_KEY" };
1309
1444
  }
1310
- const slotsCbor = slotsMacCborBytes(envelope);
1445
+ if (candidate.cekConflict) {
1446
+ return { matched: false, reason: "TAMPERED_HEADER" };
1447
+ }
1311
1448
  const hmacKey = hkdfSha256({
1312
- ikm: cek,
1449
+ ikm: candidate.cek,
1313
1450
  salt: EMPTY_SALT3,
1314
1451
  info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
1315
1452
  length: 32
1316
1453
  });
1317
- const slotsMacCalc = hmac(sha256$1, hmacKey, slotsCbor);
1454
+ const slotsMacCalc = hmac(sha256$1, hmacKey, slotsHash);
1318
1455
  if (!compareCt(slotsMacCalc, envelope.slots_mac)) {
1319
1456
  return { matched: false, reason: "TAMPERED_HEADER" };
1320
1457
  }
1321
- matchedCek = cek;
1458
+ matchedCek = candidate.cek;
1322
1459
  } else {
1323
- const slotsCbor = slotsMacCborBytes(envelope);
1324
1460
  const recipientSecretKeys = multiPrivKeys;
1461
+ let cekConflict = false;
1325
1462
  for (let k = 0; k < recipientSecretKeys.length; k++) {
1326
1463
  if (args._privsAttemptedOut !== void 0) {
1327
1464
  args._privsAttemptedOut.count = k + 1;
@@ -1329,7 +1466,7 @@ function eciesSealedPoeUnwrap(args) {
1329
1466
  if (args._slotsAttemptedOut !== void 0) {
1330
1467
  args._slotsAttemptedOut.count = 0;
1331
1468
  }
1332
- const cek = tryRecipientUnwrap(
1469
+ const candidate = tryRecipientUnwrapWithIdx(
1333
1470
  envelope,
1334
1471
  recipientSecretKeys[k],
1335
1472
  constantTimeN,
@@ -1338,20 +1475,25 @@ function eciesSealedPoeUnwrap(args) {
1338
1475
  if (args._slotsAttemptedOut?.perPrivCounts !== void 0) {
1339
1476
  args._slotsAttemptedOut.perPrivCounts.push(args._slotsAttemptedOut.count);
1340
1477
  }
1341
- if (cek === null) continue;
1478
+ if (candidate === null) continue;
1479
+ if (candidate.cekConflict) cekConflict = true;
1480
+ const cek = candidate.cek;
1342
1481
  const hmacKey = hkdfSha256({
1343
1482
  ikm: cek,
1344
1483
  salt: EMPTY_SALT3,
1345
1484
  info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
1346
1485
  length: 32
1347
1486
  });
1348
- const slotsMacCalc = hmac(sha256$1, hmacKey, slotsCbor);
1487
+ const slotsMacCalc = hmac(sha256$1, hmacKey, slotsHash);
1349
1488
  if (compareCt(slotsMacCalc, envelope.slots_mac)) {
1350
1489
  matchedCek = cek;
1351
1490
  break;
1352
1491
  }
1353
1492
  anyCandidateRecovered = true;
1354
1493
  }
1494
+ if (matchedCek !== null && cekConflict) {
1495
+ return { matched: false, reason: "TAMPERED_HEADER" };
1496
+ }
1355
1497
  if (matchedCek === null) {
1356
1498
  return {
1357
1499
  matched: false,
@@ -1359,10 +1501,16 @@ function eciesSealedPoeUnwrap(args) {
1359
1501
  };
1360
1502
  }
1361
1503
  }
1362
- const adContent = concat2(envelope.nonce, envelope.slots_mac);
1504
+ const payloadKey = slotsPayloadKey({ cek: matchedCek, nonce: envelope.nonce });
1505
+ const adContent = adContentSlots({
1506
+ kem: envelope.kem,
1507
+ nonce: envelope.nonce,
1508
+ slotsHash,
1509
+ slotsMac: envelope.slots_mac
1510
+ });
1363
1511
  try {
1364
1512
  const plaintext = xchacha20Poly1305Decrypt({
1365
- key: matchedCek,
1513
+ key: payloadKey,
1366
1514
  nonce: envelope.nonce,
1367
1515
  aad: adContent,
1368
1516
  ciphertext
@@ -1388,7 +1536,7 @@ function eciesSealedPoeTrialDecrypt(args) {
1388
1536
  );
1389
1537
  }
1390
1538
  assertEnvelopeStructure(envelope, recipientSecretKeys, void 0);
1391
- const slotsCbor = slotsMacCborBytes(envelope);
1539
+ const slotsHash = slotsHashBytes(envelope);
1392
1540
  let anyCandidateRecovered = false;
1393
1541
  for (let k = 0; k < recipientSecretKeys.length; k++) {
1394
1542
  if (args._privsAttemptedOut !== void 0) {
@@ -1407,13 +1555,17 @@ function eciesSealedPoeTrialDecrypt(args) {
1407
1555
  args._slotsAttemptedOut.perPrivCounts.push(args._slotsAttemptedOut.count);
1408
1556
  }
1409
1557
  if (candidate === null) continue;
1558
+ if (candidate.cekConflict) {
1559
+ anyCandidateRecovered = true;
1560
+ continue;
1561
+ }
1410
1562
  const hmacKey = hkdfSha256({
1411
1563
  ikm: candidate.cek,
1412
1564
  salt: EMPTY_SALT3,
1413
1565
  info: CARDANO_POE_HKDF_INFO_SLOTS_MAC,
1414
1566
  length: 32
1415
1567
  });
1416
- const slotsMacCalc = hmac(sha256$1, hmacKey, slotsCbor);
1568
+ const slotsMacCalc = hmac(sha256$1, hmacKey, slotsHash);
1417
1569
  if (compareCt(slotsMacCalc, envelope.slots_mac)) {
1418
1570
  return { kind: "match", slotIdx: candidate.slotIdx, cek: candidate.cek };
1419
1571
  }
@@ -1754,6 +1906,6 @@ function parseAgeRecipient(recipient) {
1754
1906
  throw new Error(`parseAgeRecipient: unrecognized recipient prefix "${hrp}"`);
1755
1907
  }
1756
1908
 
1757
- export { AeadVerificationError, CARDANO_POE_HKDF_INFO_KEK, CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519, CARDANO_POE_HKDF_INFO_SLOTS_MAC, CARDANO_POE_SIG_DOMAIN_PREFIX, CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES, CanonicalCborError, CoseSign1BuildError, CoseVerifyError, EciesSealedPoeError, INFO_ED25519, INFO_MLKEM768X25519, INFO_X25519, LEAVES_LIST_FORMAT_V1, MERKLE_ALG_ID, MLKEM768X25519_ENC_LENGTH, MLKEM768X25519_ESEED_LENGTH, MLKEM768X25519_PUBLIC_KEY_LENGTH, MLKEM768X25519_SEED_LENGTH, MLKEM768X25519_SHARED_SECRET_LENGTH, MerkleLeavesListError, SeedDeriveError, X25519LowOrderPointError, argon2idV13, bech32DecodeNoLimit, bech32EncodeNoLimit, blake2b224, blake2b256, buildLabel309SigStructure, buildSigStructure, chacha20Poly1305Decrypt, chacha20Poly1305Encrypt, chunkKemCt, compareCt, coseSign1Label309Build, coseSign1Label309Verify, decodeCanonicalCbor, decodeCbor, decodeCoseSign1, decodeLeavesList, deriveEd25519KeypairFromSeed, deriveMlKem768X25519KeypairFromSeed, deriveX25519KeypairFromSeed, dualHash, dualHashStream, eciesSealedPoeTrialDecrypt, eciesSealedPoeUnwrap, eciesSealedPoeWrap, encodeAgeX25519Recipient, encodeAgeXWingRecipient, encodeCanonicalCbor, encodeCoseSign1, encodeLeavesList, getPublicKeyEd25519, hexToBytes, hkdfSha256, joinKemCt, merkleSha2256InclusionProof, merkleSha2256Root, merkleSha2256VerifyInclusion, mlkem768x25519Decapsulate, mlkem768x25519Encapsulate, mlkem768x25519Keygen, parseAgeRecipient, parseCoseKeyEd25519, sealedEnvelopeFromParsed, sha256, signEd25519, slotsToMacCbor, uniformIndexBelow, verifyEd25519, x25519Ecdh, x25519Keygen, x25519PublicKey, xchacha20Poly1305Decrypt, xchacha20Poly1305Encrypt };
1909
+ export { AeadVerificationError, CARDANO_POE_HKDF_INFO_KEK, CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519, CARDANO_POE_HKDF_INFO_PAYLOAD, CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE, CARDANO_POE_HKDF_INFO_SLOTS_MAC, CARDANO_POE_PW_NORM_PROFILE, CARDANO_POE_SIG_DOMAIN_PREFIX, CARDANO_POE_SIG_DOMAIN_PREFIX_BYTES, CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX, CARDANO_POE_XWING_KEK_SALT_PREFIX, CanonicalCborError, CoseSign1BuildError, CoseVerifyError, EciesSealedPoeError, INFO_ED25519, INFO_MLKEM768X25519, INFO_X25519, LEAVES_LIST_FORMAT_V1, MAX_DECODED_ENVELOPE_BYTES, MAX_SEALED_CIPHERTEXT, MAX_SEALED_PLAINTEXT, MAX_SLOTS, MERKLE_ALG_ID, MLKEM768X25519_ENC_LENGTH, MLKEM768X25519_ESEED_LENGTH, MLKEM768X25519_PUBLIC_KEY_LENGTH, MLKEM768X25519_SEED_LENGTH, MLKEM768X25519_SHARED_SECRET_LENGTH, MerkleLeavesListError, SealedPayloadTooLargeError, SeedDeriveError, X25519LowOrderPointError, adContentPassphrase, adContentSlots, argon2idV13, assertCiphertextWithinBound, assertPlaintextWithinBound, bech32DecodeNoLimit, bech32EncodeNoLimit, blake2b224, blake2b256, buildLabel309SigStructure, buildSigStructure, canonicalizeSlots, chacha20Poly1305Decrypt, chacha20Poly1305Encrypt, chunkKemCt, compareCt, computeSlotsHash, coseSign1Label309Build, coseSign1Label309Verify, decodeCanonicalCbor, decodeCbor, decodeCoseSign1, decodeLeavesList, deriveEd25519KeypairFromSeed, deriveMlKem768X25519KeypairFromSeed, deriveX25519KeypairFromSeed, dualHash, dualHashStream, eciesSealedPoeTrialDecrypt, eciesSealedPoeUnwrap, eciesSealedPoeWrap, encodeAgeX25519Recipient, encodeAgeXWingRecipient, encodeCanonicalCbor, encodeCoseSign1, encodeLeavesList, getPublicKeyEd25519, hexToBytes, hkdfSha256, joinKemCt, merkleSha2256InclusionProof, merkleSha2256Root, merkleSha2256VerifyInclusion, mlkem768x25519Decapsulate, mlkem768x25519Encapsulate, mlkem768x25519Keygen, parseAgeRecipient, parseCoseKeyEd25519, passphrasePayloadKey, sealedEnvelopeFromParsed, sha256, signEd25519, slotsPayloadKey, uniformIndexBelow, verifyEd25519, x25519Ecdh, x25519Keygen, x25519PublicKey, xchacha20Poly1305Decrypt, xchacha20Poly1305Encrypt, xwingKekSalt };
1758
1910
  //# sourceMappingURL=index.js.map
1759
1911
  //# sourceMappingURL=index.js.map