@dynamic-labs-wallet/forward-mpc-shared 0.2.0 → 0.4.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.cjs CHANGED
@@ -84,7 +84,7 @@ var Uint32ArrayCodec = new ioTs.Type(
84
84
  return utils_js.bytesToHex(uint8Array);
85
85
  }
86
86
  );
87
- var EncryptedKeyshareCodec = ioTs.type({
87
+ var EncryptedPayloadCodec = ioTs.type({
88
88
  salt: Uint8ArrayCodec,
89
89
  encryptedPayload: Uint8ArrayCodec
90
90
  });
@@ -191,7 +191,7 @@ function createSimpleMessage(config) {
191
191
  ...data
192
192
  }), "encodeData"),
193
193
  decodeData: /* @__PURE__ */ __name((decoded) => {
194
- const { type: type7, version, ...data } = decoded;
194
+ const { type: type8, version, ...data } = decoded;
195
195
  return data;
196
196
  }, "decodeData")
197
197
  });
@@ -470,7 +470,7 @@ var Uint8ArrayOrHexCodec = new ioTs.Type(
470
470
  // src/messages/SignMessageV1Request.ts
471
471
  var SignMessageRequestSchema = buildMessageSchema("signMessage", 1, {
472
472
  relayDomain: DomainCodec,
473
- keyshare: EncryptedKeyshareCodec,
473
+ keyshare: EncryptedPayloadCodec,
474
474
  message: Uint8ArrayOrHexCodec,
475
475
  roomUuid: ioTs.string,
476
476
  userId: OptionalStringCodec,
@@ -485,7 +485,7 @@ var SignMessageV1RequestMessage = createStandardMessage({
485
485
  signingAlgo: /* @__PURE__ */ __name((value) => fromDynamicSigningAlgorithm(value), "signingAlgo"),
486
486
  derivationPath: /* @__PURE__ */ __name((value) => Uint32ArrayCodec.encode(value), "derivationPath"),
487
487
  tweak: /* @__PURE__ */ __name((value) => Uint8ArrayCodec.encode(value), "tweak"),
488
- keyshare: /* @__PURE__ */ __name((value) => EncryptedKeyshareCodec.encode(value), "keyshare"),
488
+ keyshare: /* @__PURE__ */ __name((value) => EncryptedPayloadCodec.encode(value), "keyshare"),
489
489
  message: /* @__PURE__ */ __name((value) => Uint8ArrayOrHexCodec.encode(value), "message")
490
490
  }),
491
491
  decodeData: createStandardDecoder((decoded) => ({
@@ -555,6 +555,139 @@ var ConnectionAckV1ResponseMessage = createSimpleMessage({
555
555
  version: 1,
556
556
  schema: ConnectionAckResponseSchema
557
557
  });
558
+ var BaseKeygenParamsCodec = ioTs.type({
559
+ relayDomain: DomainCodec,
560
+ roomUuid: ioTs.string,
561
+ numParties: ioTs.number,
562
+ threshold: ioTs.number,
563
+ keygenInit: EncryptedPayloadCodec,
564
+ keygenIds: ioTs.array(ioTs.string),
565
+ userId: OptionalStringCodec,
566
+ environmentId: OptionalStringCodec,
567
+ traceContext: TraceContextCodec
568
+ });
569
+ var EcdsaKeygenParamsCodec = ioTs.type({
570
+ ...BaseKeygenParamsCodec.props,
571
+ signingAlgo: ioTs.literal("ecdsa")
572
+ });
573
+ var BIP340KeygenParamsCodec = ioTs.type({
574
+ ...BaseKeygenParamsCodec.props,
575
+ signingAlgo: ioTs.literal("bip340")
576
+ });
577
+ var KeygenAlgoParamsCodec = ioTs.union([
578
+ EcdsaKeygenParamsCodec,
579
+ BIP340KeygenParamsCodec
580
+ ]);
581
+ var KeygenRequestSchema = buildMessageSchema("keygen", 1, {
582
+ relayDomain: DomainCodec,
583
+ roomUuid: ioTs.string,
584
+ numParties: ioTs.number,
585
+ threshold: ioTs.number,
586
+ keygenInit: EncryptedPayloadCodec,
587
+ keygenIds: ioTs.array(ioTs.string),
588
+ userId: OptionalStringCodec,
589
+ environmentId: OptionalStringCodec,
590
+ traceContext: TraceContextCodec
591
+ }, KeygenAlgoParamsCodec);
592
+ var KeygenV1RequestMessage = createStandardMessage({
593
+ messageType: "keygen",
594
+ version: 1,
595
+ schema: KeygenRequestSchema,
596
+ encodeData: createComplexEncoder("keygen", 1, {
597
+ signingAlgo: /* @__PURE__ */ __name((value) => fromDynamicSigningAlgorithm(value), "signingAlgo"),
598
+ keygenInit: /* @__PURE__ */ __name((value) => EncryptedPayloadCodec.encode(value), "keygenInit")
599
+ }),
600
+ decodeData: createStandardDecoder((decoded) => ({
601
+ relayDomain: decoded.relayDomain,
602
+ signingAlgo: decoded.signingAlgo,
603
+ roomUuid: decoded.roomUuid,
604
+ numParties: decoded.numParties,
605
+ threshold: decoded.threshold,
606
+ keygenInit: decoded.keygenInit,
607
+ keygenIds: decoded.keygenIds,
608
+ userId: decoded.userId,
609
+ environmentId: decoded.environmentId,
610
+ traceContext: decoded.traceContext
611
+ }))
612
+ });
613
+ var KeygenResponseSchema = buildMessageSchema("keygen_response", 1, {
614
+ keygenResult: ioTs.union([
615
+ EncryptedPayloadCodec,
616
+ ioTs.undefined
617
+ ]),
618
+ error: ioTs.union([
619
+ WebSocketErrorCodec,
620
+ ioTs.undefined
621
+ ])
622
+ });
623
+ var KeygenV1ResponseMessage = createStandardMessage({
624
+ messageType: "keygen_response",
625
+ version: 1,
626
+ schema: KeygenResponseSchema,
627
+ encodeData: createComplexEncoder("keygen_response", 1, {
628
+ keygenResult: /* @__PURE__ */ __name((value) => EncryptedPayloadCodec.encode(value), "keygenResult")
629
+ }),
630
+ decodeData: createStandardDecoder((decoded) => ({
631
+ keygenResult: decoded.keygenResult,
632
+ error: decoded.error
633
+ }))
634
+ });
635
+ var ReceiveKeyRequestSchema = buildMessageSchema("receiveKey", 1, {
636
+ relayDomain: DomainCodec,
637
+ signingAlgo: ioTs.literal("ed25519"),
638
+ roomUuid: ioTs.string,
639
+ numParties: ioTs.number,
640
+ threshold: ioTs.number,
641
+ keygenInit: EncryptedPayloadCodec,
642
+ keygenIds: ioTs.array(ioTs.string),
643
+ userId: OptionalStringCodec,
644
+ environmentId: OptionalStringCodec,
645
+ traceContext: TraceContextCodec
646
+ });
647
+ var ReceiveKeyV1RequestMessage = createStandardMessage({
648
+ messageType: "receiveKey",
649
+ version: 1,
650
+ schema: ReceiveKeyRequestSchema,
651
+ encodeData: /* @__PURE__ */ __name((data) => ReceiveKeyRequestSchema.encode({
652
+ type: "receiveKey",
653
+ version: 1,
654
+ ...data
655
+ }), "encodeData"),
656
+ decodeData: createStandardDecoder((decoded) => ({
657
+ relayDomain: decoded.relayDomain,
658
+ signingAlgo: decoded.signingAlgo,
659
+ roomUuid: decoded.roomUuid,
660
+ numParties: decoded.numParties,
661
+ threshold: decoded.threshold,
662
+ keygenInit: decoded.keygenInit,
663
+ keygenIds: decoded.keygenIds,
664
+ userId: decoded.userId,
665
+ environmentId: decoded.environmentId,
666
+ traceContext: decoded.traceContext
667
+ }))
668
+ });
669
+ var ReceiveKeyResponseSchema = buildMessageSchema("receiveKey_response", 1, {
670
+ keygenResult: ioTs.union([
671
+ EncryptedPayloadCodec,
672
+ ioTs.undefined
673
+ ]),
674
+ error: ioTs.union([
675
+ WebSocketErrorCodec,
676
+ ioTs.undefined
677
+ ])
678
+ });
679
+ var ReceiveKeyV1ResponseMessage = createStandardMessage({
680
+ messageType: "receiveKey_response",
681
+ version: 1,
682
+ schema: ReceiveKeyResponseSchema,
683
+ encodeData: createComplexEncoder("receiveKey_response", 1, {
684
+ keygenResult: /* @__PURE__ */ __name((value) => EncryptedPayloadCodec.encode(value), "keygenResult")
685
+ }),
686
+ decodeData: createStandardDecoder((decoded) => ({
687
+ keygenResult: decoded.keygenResult,
688
+ error: decoded.error
689
+ }))
690
+ });
558
691
 
559
692
  // src/messages/allMessages.ts
560
693
  var ALL_MESSAGE_CLASSES = {
@@ -563,37 +696,41 @@ var ALL_MESSAGE_CLASSES = {
563
696
  "signMessage@1": SignMessageV1RequestMessage,
564
697
  "signMessage_response@1": SignMessageV1ResponseMessage,
565
698
  "connection_ack@1": ConnectionAckV1RequestMessage,
566
- "connection_ack_response@1": ConnectionAckV1ResponseMessage
699
+ "connection_ack_response@1": ConnectionAckV1ResponseMessage,
700
+ "keygen@1": KeygenV1RequestMessage,
701
+ "keygen_response@1": KeygenV1ResponseMessage,
702
+ "receiveKey@1": ReceiveKeyV1RequestMessage,
703
+ "receiveKey_response@1": ReceiveKeyV1ResponseMessage
567
704
  };
568
705
  var ALL_MESSAGE_KEYS = Object.keys(ALL_MESSAGE_CLASSES);
569
- function getMessageClass(type7, version) {
570
- const key = `${type7}@${version}`;
706
+ function getMessageClass(type8, version) {
707
+ const key = `${type8}@${version}`;
571
708
  const MessageClass = ALL_MESSAGE_CLASSES[key];
572
709
  if (!MessageClass) {
573
- throw new Error(`Unknown message type: ${type7} version ${version}`);
710
+ throw new Error(`Unknown message type: ${type8} version ${version}`);
574
711
  }
575
712
  return MessageClass;
576
713
  }
577
714
  __name(getMessageClass, "getMessageClass");
578
- function isValidMessageType(type7, version) {
579
- const key = `${type7}@${version}`;
715
+ function isValidMessageType(type8, version) {
716
+ const key = `${type8}@${version}`;
580
717
  return key in ALL_MESSAGE_CLASSES;
581
718
  }
582
719
  __name(isValidMessageType, "isValidMessageType");
583
720
  function getAllSupportedMessages() {
584
721
  return ALL_MESSAGE_KEYS.map((key) => {
585
- const [type7, versionStr] = key.split("@");
722
+ const [type8, versionStr] = key.split("@");
586
723
  return {
587
- type: type7,
724
+ type: type8,
588
725
  version: parseInt(versionStr, 10)
589
726
  };
590
727
  });
591
728
  }
592
729
  __name(getAllSupportedMessages, "getAllSupportedMessages");
593
730
  function parseMessageKey(key) {
594
- const [type7, versionStr] = key.split("@");
731
+ const [type8, versionStr] = key.split("@");
595
732
  return {
596
- type: type7,
733
+ type: type8,
597
734
  version: parseInt(versionStr, 10)
598
735
  };
599
736
  }
@@ -616,9 +753,9 @@ var MessageRegistry = class _MessageRegistry {
616
753
  /**
617
754
  * Get a message class by type and version (derived from single source)
618
755
  */
619
- getMessageClass(type7, version) {
756
+ getMessageClass(type8, version) {
620
757
  try {
621
- return getMessageClass(type7, version);
758
+ return getMessageClass(type8, version);
622
759
  } catch {
623
760
  return void 0;
624
761
  }
@@ -633,18 +770,18 @@ var MessageRegistry = class _MessageRegistry {
633
770
  left: "Invalid wire data: must be an object"
634
771
  };
635
772
  }
636
- const { type: type7, version } = wireData;
637
- if (!type7 || !version) {
773
+ const { type: type8, version } = wireData;
774
+ if (!type8 || !version) {
638
775
  return {
639
776
  _tag: "Left",
640
777
  left: "Invalid wire data: missing type or version"
641
778
  };
642
779
  }
643
- const MessageClass = this.getMessageClass(type7, version);
780
+ const MessageClass = this.getMessageClass(type8, version);
644
781
  if (!MessageClass) {
645
782
  return {
646
783
  _tag: "Left",
647
- left: `Unknown message type: ${type7}@${version}`
784
+ left: `Unknown message type: ${type8}@${version}`
648
785
  };
649
786
  }
650
787
  const result = MessageClass.decode(wireData);
@@ -669,7 +806,7 @@ var MessageRegistry = class _MessageRegistry {
669
806
  * Get all registered message types (derived from single source)
670
807
  */
671
808
  getRegisteredTypes() {
672
- return getAllSupportedMessages().map(({ type: type7, version }) => `${type7}@${version}`);
809
+ return getAllSupportedMessages().map(({ type: type8, version }) => `${type8}@${version}`);
673
810
  }
674
811
  };
675
812
  var messageRegistry = MessageRegistry.getInstance();
@@ -717,6 +854,13 @@ var AES_256_GCM_KEY_SIZE = 32;
717
854
  var AES_256_GCM_NONCE_SIZE = 12;
718
855
  var AES_256_GCM_TAG_SIZE = 16;
719
856
  var HKDF_SALT_SIZE = 32;
857
+ var EncryptionPurpose = /* @__PURE__ */ (function(EncryptionPurpose2) {
858
+ EncryptionPurpose2["KEYSHARE"] = "keyshare";
859
+ EncryptionPurpose2["KEYGEN_INIT"] = "keygen_init";
860
+ EncryptionPurpose2["KEYGEN_RESULT"] = "keygen_result";
861
+ EncryptionPurpose2["TEST"] = "test";
862
+ return EncryptionPurpose2;
863
+ })({});
720
864
  function deriveAESKey(sharedSecret, salt, info) {
721
865
  const infoBytes = new TextEncoder().encode(info);
722
866
  return hkdf_js.hkdf(sha2_js.sha256, sharedSecret, salt, infoBytes, AES_256_GCM_KEY_SIZE);
@@ -726,19 +870,23 @@ function createKeyDerivationInfo(purpose, connectionId, version = 1) {
726
870
  return `forward-mpc-${purpose}-v${version}-${connectionId}`;
727
871
  }
728
872
  __name(createKeyDerivationInfo, "createKeyDerivationInfo");
729
- async function encryptKeyshare(keyshare, sharedSecret, connectionId, signingAlgorithm) {
730
- const salt = utils_js.randomBytes(32);
731
- const keyshareInfo = createKeyDerivationInfo("keyshare", connectionId);
732
- const aesKey = deriveAESKey(sharedSecret, salt, keyshareInfo);
733
- const keyshareData = {
734
- keyshare,
735
- signingAlgorithm,
736
- timestamp: Date.now(),
737
- nonce: utils_js.bytesToHex(utils_js.randomBytes(16))
738
- };
739
- const nonce = utils_js.randomBytes(12);
873
+ var HKDF_SALT_SIZE2 = 32;
874
+ var AES_GCM_NONCE_SIZE = 12;
875
+ var MIN_SHARED_SECRET_SIZE = 32;
876
+ function encryptPayload(options) {
877
+ const { payload, sharedSecret, connectionId, purpose } = options;
878
+ if (!sharedSecret || sharedSecret.length < MIN_SHARED_SECRET_SIZE) {
879
+ throw new Error(`Invalid shared secret: must be at least ${MIN_SHARED_SECRET_SIZE} bytes`);
880
+ }
881
+ if (!connectionId || connectionId.trim().length === 0) {
882
+ throw new Error("Invalid connectionId: must be non-empty string");
883
+ }
884
+ const salt = utils_js.randomBytes(HKDF_SALT_SIZE2);
885
+ const info = createKeyDerivationInfo(purpose, connectionId);
886
+ const aesKey = deriveAESKey(sharedSecret, salt, info);
887
+ const nonce = utils_js.randomBytes(AES_GCM_NONCE_SIZE);
740
888
  const aes256Gcm = aes.gcm(aesKey, nonce);
741
- const plaintext = new TextEncoder().encode(JSON.stringify(keyshareData));
889
+ const plaintext = new TextEncoder().encode(JSON.stringify(payload));
742
890
  const ciphertext = aes256Gcm.encrypt(plaintext);
743
891
  const encryptedPayload = new Uint8Array(nonce.length + ciphertext.length);
744
892
  encryptedPayload.set(nonce, 0);
@@ -749,8 +897,82 @@ async function encryptKeyshare(keyshare, sharedSecret, connectionId, signingAlgo
749
897
  encryptedPayload
750
898
  };
751
899
  }
900
+ __name(encryptPayload, "encryptPayload");
901
+ function decryptPayload(options) {
902
+ const { encrypted, sharedSecret, connectionId, purpose } = options;
903
+ if (!sharedSecret || sharedSecret.length < MIN_SHARED_SECRET_SIZE) {
904
+ throw new Error(`Invalid shared secret: must be at least ${MIN_SHARED_SECRET_SIZE} bytes`);
905
+ }
906
+ if (!connectionId || connectionId.trim().length === 0) {
907
+ throw new Error("Invalid connectionId: must be non-empty string");
908
+ }
909
+ if (!encrypted.encryptedPayload || encrypted.encryptedPayload.length < AES_GCM_NONCE_SIZE) {
910
+ throw new Error(`Invalid encrypted payload: must be at least ${AES_GCM_NONCE_SIZE} bytes`);
911
+ }
912
+ const info = createKeyDerivationInfo(purpose, connectionId);
913
+ const aesKey = deriveAESKey(sharedSecret, encrypted.salt, info);
914
+ const nonce = encrypted.encryptedPayload.slice(0, AES_GCM_NONCE_SIZE);
915
+ const ciphertext = encrypted.encryptedPayload.slice(AES_GCM_NONCE_SIZE);
916
+ const aes256Gcm = aes.gcm(aesKey, nonce);
917
+ const plaintext = aes256Gcm.decrypt(ciphertext);
918
+ const decryptedText = new TextDecoder().decode(plaintext);
919
+ const data = JSON.parse(decryptedText);
920
+ aesKey.fill(0);
921
+ return data;
922
+ }
923
+ __name(decryptPayload, "decryptPayload");
924
+ function encryptKeyshare(keyshare, sharedSecret, connectionId, signingAlgorithm) {
925
+ const keyshareData = {
926
+ keyshare,
927
+ signingAlgorithm,
928
+ timestamp: Date.now(),
929
+ nonce: utils_js.bytesToHex(utils_js.randomBytes(16))
930
+ };
931
+ return encryptPayload({
932
+ payload: keyshareData,
933
+ sharedSecret,
934
+ connectionId,
935
+ purpose: EncryptionPurpose.KEYSHARE
936
+ });
937
+ }
752
938
  __name(encryptKeyshare, "encryptKeyshare");
753
939
 
940
+ // src/crypto/keygenEncryption.ts
941
+ function encryptKeygenInit(keygenInit, sharedSecret, connectionId) {
942
+ if (!keygenInit.keygenId || keygenInit.keygenId.trim().length === 0) {
943
+ throw new Error("Invalid keygenInit: keygenId must be non-empty string");
944
+ }
945
+ if (!keygenInit.keygenSecret || keygenInit.keygenSecret.trim().length === 0) {
946
+ throw new Error("Invalid keygenInit: keygenSecret must be non-empty string");
947
+ }
948
+ return encryptPayload({
949
+ payload: keygenInit,
950
+ sharedSecret,
951
+ connectionId,
952
+ purpose: EncryptionPurpose.KEYGEN_INIT
953
+ });
954
+ }
955
+ __name(encryptKeygenInit, "encryptKeygenInit");
956
+ function decryptKeygenResult(encrypted, sharedSecret, connectionId) {
957
+ const data = decryptPayload({
958
+ encrypted,
959
+ sharedSecret,
960
+ connectionId,
961
+ purpose: EncryptionPurpose.KEYGEN_RESULT
962
+ });
963
+ if (!data.pubkey || !Array.isArray(data.pubkey)) {
964
+ throw new Error("Invalid keygen result: pubkey must be an array");
965
+ }
966
+ if (!data.secretShare || typeof data.secretShare !== "string" || data.secretShare.trim().length === 0) {
967
+ throw new Error("Invalid keygen result: secretShare must be non-empty string");
968
+ }
969
+ return {
970
+ pubkey: new Uint8Array(data.pubkey),
971
+ secretShare: data.secretShare
972
+ };
973
+ }
974
+ __name(decryptKeygenResult, "decryptKeygenResult");
975
+
754
976
  // src/signing/registry.ts
755
977
  var SigningAlgorithmRegistry = class SigningAlgorithmRegistry2 {
756
978
  static {
@@ -804,14 +1026,23 @@ exports.ConnectionAckV1RequestMessage = ConnectionAckV1RequestMessage;
804
1026
  exports.ConnectionAckV1ResponseMessage = ConnectionAckV1ResponseMessage;
805
1027
  exports.EcdsaSigningAlgorithm = EcdsaSigningAlgorithm;
806
1028
  exports.Ed25519SigningAlgorithm = Ed25519SigningAlgorithm;
807
- exports.EncryptedKeyshareCodec = EncryptedKeyshareCodec;
1029
+ exports.EncryptedPayloadCodec = EncryptedPayloadCodec;
1030
+ exports.EncryptionPurpose = EncryptionPurpose;
808
1031
  exports.HKDF_SALT_SIZE = HKDF_SALT_SIZE;
809
1032
  exports.HandshakeRequestSchema = HandshakeRequestSchema;
810
1033
  exports.HandshakeResponseSchema = HandshakeResponseSchema;
811
1034
  exports.HandshakeV1RequestMessage = HandshakeV1RequestMessage;
812
1035
  exports.HandshakeV1ResponseMessage = HandshakeV1ResponseMessage;
1036
+ exports.KeygenRequestSchema = KeygenRequestSchema;
1037
+ exports.KeygenResponseSchema = KeygenResponseSchema;
1038
+ exports.KeygenV1RequestMessage = KeygenV1RequestMessage;
1039
+ exports.KeygenV1ResponseMessage = KeygenV1ResponseMessage;
813
1040
  exports.MessageRegistry = MessageRegistry;
814
1041
  exports.OptionalStringCodec = OptionalStringCodec;
1042
+ exports.ReceiveKeyRequestSchema = ReceiveKeyRequestSchema;
1043
+ exports.ReceiveKeyResponseSchema = ReceiveKeyResponseSchema;
1044
+ exports.ReceiveKeyV1RequestMessage = ReceiveKeyV1RequestMessage;
1045
+ exports.ReceiveKeyV1ResponseMessage = ReceiveKeyV1ResponseMessage;
815
1046
  exports.SIGNING_ALGORITHM_CLASSES = SIGNING_ALGORITHM_CLASSES;
816
1047
  exports.SIGNING_ALGORITHM_INSTANCES = SIGNING_ALGORITHM_INSTANCES;
817
1048
  exports.SignMessageRequestSchema = SignMessageRequestSchema;
@@ -828,9 +1059,13 @@ exports.assertNotNull = assertNotNull;
828
1059
  exports.createKeyDerivationInfo = createKeyDerivationInfo;
829
1060
  exports.createKeygenResultFromSecretShare = createKeygenResultFromSecretShare;
830
1061
  exports.decapsulateMlKem768 = decapsulateMlKem768;
1062
+ exports.decryptKeygenResult = decryptKeygenResult;
1063
+ exports.decryptPayload = decryptPayload;
831
1064
  exports.deriveAESKey = deriveAESKey;
832
1065
  exports.encapsulateMlKem768 = encapsulateMlKem768;
1066
+ exports.encryptKeygenInit = encryptKeygenInit;
833
1067
  exports.encryptKeyshare = encryptKeyshare;
1068
+ exports.encryptPayload = encryptPayload;
834
1069
  exports.fromDynamicSigningAlgorithm = fromDynamicSigningAlgorithm;
835
1070
  exports.generateMlKem768Keypair = generateMlKem768Keypair;
836
1071
  exports.getAllSupportedMessages = getAllSupportedMessages;