@monolythium/core-sdk 0.4.0 → 0.4.2

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.
@@ -501,82 +501,6 @@ function bincodeMlDsa65OpaqueInto2(w, raw) {
501
501
  w.u16(STANDARD_ALGO_NUMBER_ML_DSA_65);
502
502
  w.bytes(raw);
503
503
  }
504
-
505
- // src/crypto/submission.ts
506
- async function fetchEncryptionKey(client) {
507
- const result = await client.call(
508
- "lyth_getEncryptionKey",
509
- []
510
- );
511
- return {
512
- algo: result.algo ?? "ml-kem-768",
513
- epoch: typeof result.epoch === "string" ? BigInt(result.epoch) : BigInt(result.epoch),
514
- encapsulationKey: hexToBytes(result.encapsulationKey, "encapsulationKey")
515
- };
516
- }
517
- var ENCRYPTED_SUBMISSION_UNAVAILABLE_MESSAGE = "encrypted mempool submission unavailable until MB-3 threshold decryption is active";
518
- async function buildEncryptedSubmission(_args) {
519
- await Promise.resolve();
520
- throw new Error(ENCRYPTED_SUBMISSION_UNAVAILABLE_MESSAGE);
521
- }
522
- async function submitEncryptedEnvelope(client, envelopeWireHex) {
523
- return client.call("lyth_submitEncrypted", [envelopeWireHex]);
524
- }
525
- function buildPlaintextSubmission(args) {
526
- const signed = args.backend.signEvmTx(args.tx);
527
- return {
528
- signedTxWireHex: `0x${signed.wireHex}`,
529
- innerTxHashHex: bytesToHex(signed.txHash),
530
- innerSighashHex: bytesToHex(signed.sighash),
531
- innerWireBytes: signed.wireBytes.length
532
- };
533
- }
534
- async function submitPlaintextTransaction(client, signedTxWireHex, expectedTxHashHex) {
535
- const returned = await client.call("mesh_submitTx", [signedTxWireHex]);
536
- const returnedBytes = hexToBytes(returned, "mesh_submitTx tx hash");
537
- if (returnedBytes.length !== 32) {
538
- throw new Error(
539
- `mesh_submitTx tx hash must be 32 bytes, got ${returnedBytes.length}`
540
- );
541
- }
542
- const expectedBytes = hexToBytes(expectedTxHashHex, "expected tx hash");
543
- if (!bytesEqual(returnedBytes, expectedBytes)) {
544
- throw new Error(
545
- `mesh_submitTx returned tx hash ${bytesToHex(returnedBytes)} but the locally computed canonical hash is ${bytesToHex(expectedBytes)}`
546
- );
547
- }
548
- return bytesToHex(returnedBytes);
549
- }
550
- async function submitTransactionWithPrivacy(args) {
551
- if (args.private) {
552
- if (args.encryptionKey === void 0) {
553
- throw new Error(
554
- "private submission requires an encryptionKey; fetch it via fetchEncryptionKey()"
555
- );
556
- }
557
- const built = await buildEncryptedSubmission({
558
- backend: args.backend,
559
- tx: args.tx,
560
- encryptionKey: args.encryptionKey,
561
- class: args.class
562
- });
563
- await submitEncryptedEnvelope(args.client, built.envelopeWireHex);
564
- return built.innerTxHashHex;
565
- }
566
- const plaintext = buildPlaintextSubmission({ backend: args.backend, tx: args.tx });
567
- return submitPlaintextTransaction(
568
- args.client,
569
- plaintext.signedTxWireHex,
570
- plaintext.innerTxHashHex
571
- );
572
- }
573
- function bytesEqual(a, b) {
574
- if (a.length !== b.length) return false;
575
- for (let i = 0; i < a.length; i++) {
576
- if (a[i] !== b[i]) return false;
577
- }
578
- return true;
579
- }
580
504
  var SEAL_EK_LEN = 1184;
581
505
  var SEAL_DK_LEN = 2400;
582
506
  var SEAL_KEM_CT_LEN = 1088;
@@ -787,6 +711,8 @@ function sealToCluster(args) {
787
711
  recipients
788
712
  };
789
713
  }
714
+
715
+ // src/crypto/seal.ts
790
716
  var CLUSTER_MLKEM_SHAMIR_ALGO = "cluster-mlkem768-shamir";
791
717
  function parseClusterSealKeys(source) {
792
718
  const n = source.roster.length;
@@ -816,7 +742,7 @@ function parseClusterSealKeys(source) {
816
742
  const recomputed = sealRosterHash(keccak256, source.clusterId, source.t, n, hashInput);
817
743
  if (source.rosterHash !== void 0) {
818
744
  const supplied = expectBytes(hexToBytes(source.rosterHash, "rosterHash"), 32, "rosterHash");
819
- if (!bytesEqual2(supplied, recomputed)) {
745
+ if (!bytesEqual(supplied, recomputed)) {
820
746
  throw new Error(
821
747
  `cluster seal roster hash mismatch: source ${bytesToHex(supplied)} != recomputed ${bytesToHex(recomputed)} (the roster hash does not commit to this ek set)`
822
748
  );
@@ -885,6 +811,97 @@ function toBigInt(value) {
885
811
  if (typeof value === "bigint") return value;
886
812
  return BigInt(value);
887
813
  }
814
+ function bytesEqual(a, b) {
815
+ if (a.length !== b.length) return false;
816
+ for (let i = 0; i < a.length; i++) {
817
+ if (a[i] !== b[i]) return false;
818
+ }
819
+ return true;
820
+ }
821
+
822
+ // src/crypto/submission.ts
823
+ async function fetchEncryptionKey(client) {
824
+ const result = await client.call(
825
+ "lyth_getEncryptionKey",
826
+ []
827
+ );
828
+ return {
829
+ algo: result.algo ?? "ml-kem-768",
830
+ epoch: typeof result.epoch === "string" ? BigInt(result.epoch) : BigInt(result.epoch),
831
+ encapsulationKey: hexToBytes(result.encapsulationKey, "encapsulationKey")
832
+ };
833
+ }
834
+ var ENCRYPTED_SUBMISSION_UNAVAILABLE_MESSAGE = "private submission requires cluster seal keys; pass clusterSealKeysSource or enable lyth_getClusterSealKeys";
835
+ async function buildEncryptedSubmission(args) {
836
+ const signed = args.backend.signEvmTx(args.tx);
837
+ const clusterSealKeys = await resolveClusterSealKeys(args);
838
+ const aad = nonceAadForTx(args.tx, args.backend.addressBytes(), args.class);
839
+ const sealed = await sealTransaction({
840
+ signedTxBincode: signed.wireBytes,
841
+ clusterSealKeys,
842
+ aad,
843
+ senderAddress: args.backend.addressBytes(),
844
+ senderPubkey: args.backend.publicKey(),
845
+ signOuterDigest: (digest) => args.backend.signPrehash(digest)
846
+ });
847
+ return {
848
+ envelopeWireHex: sealed.envelopeWireHex,
849
+ innerSighashHex: bytesToHex(signed.sighash),
850
+ innerTxHashHex: bytesToHex(signed.txHash),
851
+ innerWireBytes: signed.wireBytes.length
852
+ };
853
+ }
854
+ async function submitEncryptedEnvelope(client, envelopeWireHex) {
855
+ return client.call("lyth_submitEncrypted", [envelopeWireHex]);
856
+ }
857
+ function buildPlaintextSubmission(args) {
858
+ const signed = args.backend.signEvmTx(args.tx);
859
+ return {
860
+ signedTxWireHex: `0x${signed.wireHex}`,
861
+ innerTxHashHex: bytesToHex(signed.txHash),
862
+ innerSighashHex: bytesToHex(signed.sighash),
863
+ innerWireBytes: signed.wireBytes.length
864
+ };
865
+ }
866
+ async function submitPlaintextTransaction(client, signedTxWireHex, expectedTxHashHex) {
867
+ const returned = await client.call("mesh_submitTx", [signedTxWireHex]);
868
+ const returnedBytes = hexToBytes(returned, "mesh_submitTx tx hash");
869
+ if (returnedBytes.length !== 32) {
870
+ throw new Error(
871
+ `mesh_submitTx tx hash must be 32 bytes, got ${returnedBytes.length}`
872
+ );
873
+ }
874
+ const expectedBytes = hexToBytes(expectedTxHashHex, "expected tx hash");
875
+ if (!bytesEqual2(returnedBytes, expectedBytes)) {
876
+ throw new Error(
877
+ `mesh_submitTx returned tx hash ${bytesToHex(returnedBytes)} but the locally computed canonical hash is ${bytesToHex(expectedBytes)}`
878
+ );
879
+ }
880
+ return bytesToHex(returnedBytes);
881
+ }
882
+ async function submitTransactionWithPrivacy(args) {
883
+ if (args.private) {
884
+ const built = await buildEncryptedSubmission({
885
+ client: args.client,
886
+ backend: args.backend,
887
+ tx: args.tx,
888
+ encryptionKey: args.encryptionKey,
889
+ clusterId: args.clusterId,
890
+ clusterSealKeys: args.clusterSealKeys,
891
+ clusterSealKeysSource: args.clusterSealKeysSource,
892
+ class: args.class
893
+ });
894
+ const returned = await submitEncryptedEnvelope(args.client, built.envelopeWireHex);
895
+ assertRpcHash(returned, "lyth_submitEncrypted tx hash");
896
+ return built.innerTxHashHex;
897
+ }
898
+ const plaintext = buildPlaintextSubmission({ backend: args.backend, tx: args.tx });
899
+ return submitPlaintextTransaction(
900
+ args.client,
901
+ plaintext.signedTxWireHex,
902
+ plaintext.innerTxHashHex
903
+ );
904
+ }
888
905
  function bytesEqual2(a, b) {
889
906
  if (a.length !== b.length) return false;
890
907
  for (let i = 0; i < a.length; i++) {
@@ -892,6 +909,50 @@ function bytesEqual2(a, b) {
892
909
  }
893
910
  return true;
894
911
  }
912
+ async function resolveClusterSealKeys(args) {
913
+ if (args.clusterSealKeys !== void 0) return args.clusterSealKeys;
914
+ if (args.clusterSealKeysSource !== void 0) {
915
+ return parseClusterSealKeys(args.clusterSealKeysSource);
916
+ }
917
+ if (args.client === void 0) {
918
+ throw new Error(ENCRYPTED_SUBMISSION_UNAVAILABLE_MESSAGE);
919
+ }
920
+ const clusterId = args.clusterId ?? 0;
921
+ const result = await args.client.call(
922
+ "lyth_getClusterSealKeys",
923
+ [clusterId]
924
+ );
925
+ return parseClusterSealKeys({ ...result, clusterId: result.clusterId ?? clusterId });
926
+ }
927
+ function nonceAadForTx(tx, sender, mempoolClass) {
928
+ return {
929
+ sender,
930
+ nonce: parseBigint(tx.nonce, "nonce"),
931
+ chainId: parseBigint(tx.chainId, "chainId"),
932
+ class: mempoolClass ?? inferMempoolClass(tx),
933
+ maxFeePerGas: parseBigint(tx.maxFeePerGas, "maxFeePerGas"),
934
+ maxPriorityFeePerGas: parseBigint(tx.maxPriorityFeePerGas, "maxPriorityFeePerGas"),
935
+ gasLimit: parseBigint(tx.gasLimit, "gasLimit")
936
+ };
937
+ }
938
+ function inferMempoolClass(tx) {
939
+ if (tx.to === null || hasInput(tx.input)) return MempoolClass.ContractCall;
940
+ return MempoolClass.Transfer;
941
+ }
942
+ function hasInput(input) {
943
+ if (input === void 0) return false;
944
+ if (typeof input === "string") {
945
+ const stripped = input.startsWith("0x") || input.startsWith("0X") ? input.slice(2) : input;
946
+ return stripped.length > 0;
947
+ }
948
+ return input.length > 0;
949
+ }
950
+ function assertRpcHash(value, label) {
951
+ const bytes = hexToBytes(value, label);
952
+ if (bytes.length !== 32) {
953
+ throw new Error(`${label} must be 32 bytes, got ${bytes.length}`);
954
+ }
955
+ }
895
956
 
896
957
  exports.ADDRESS_DERIVATION_DOMAIN = ADDRESS_DERIVATION_DOMAIN;
897
958
  exports.BincodeWriter = BincodeWriter;