@@ -6,15 +6,13 @@ import {
66 BitGoBase ,
77 BuildNftTransferDataOptions ,
88 common ,
9- ECDSA ,
109 Ecdsa ,
1110 ECDSAMethodTypes ,
1211 EthereumLibraryUnavailableError ,
1312 FeeEstimateOptions ,
1413 FullySignedTransaction ,
1514 getIsUnsignedSweep ,
1615 HalfSignedTransaction ,
17- hexToBigInt ,
1816 InvalidAddressError ,
1917 InvalidAddressVerificationObjectPropertyError ,
2018 IWallet ,
@@ -36,7 +34,6 @@ import {
3634 Wallet ,
3735 ECDSAUtils ,
3836} from '@bitgo/sdk-core' ;
39- import { EcdsaPaillierProof , EcdsaRangeProof , EcdsaTypes } from '@bitgo/sdk-lib-mpc' ;
4037import {
4138 BaseCoin as StaticsBaseCoin ,
4239 CoinMap ,
@@ -1056,174 +1053,6 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
10561053 }
10571054 }
10581055
1059- /**
1060- * Method to sign tss recovery transaction
1061- * @param {ECDSA.KeyCombined } userKeyCombined
1062- * @param {ECDSA.KeyCombined } backupKeyCombined
1063- * @param {string } txHex
1064- * @param {Object } options
1065- * @param {EcdsaTypes.SerializedNtilde } options.rangeProofChallenge
1066- * @returns {Promise<ECDSAMethodTypes.Signature> }
1067- */
1068- private async signRecoveryTSS (
1069- userKeyCombined : ECDSA . KeyCombined ,
1070- backupKeyCombined : ECDSA . KeyCombined ,
1071- txHex : string ,
1072- openSSLBytes : Uint8Array ,
1073- {
1074- rangeProofChallenge,
1075- } : {
1076- rangeProofChallenge ?: EcdsaTypes . SerializedNtilde ;
1077- } = { }
1078- ) : Promise < ECDSAMethodTypes . Signature > {
1079- if ( ! userKeyCombined || ! backupKeyCombined ) {
1080- throw new Error ( 'Missing key combined shares for user or backup' ) ;
1081- }
1082-
1083- const MPC = new Ecdsa ( ) ;
1084- const signerOneIndex = userKeyCombined . xShare . i ;
1085- const signerTwoIndex = backupKeyCombined . xShare . i ;
1086-
1087- rangeProofChallenge =
1088- rangeProofChallenge ?? EcdsaTypes . serializeNtildeWithProofs ( await EcdsaRangeProof . generateNtilde ( openSSLBytes ) ) ;
1089-
1090- const userToBackupPaillierChallenge = await EcdsaPaillierProof . generateP (
1091- hexToBigInt ( userKeyCombined . yShares [ signerTwoIndex ] . n )
1092- ) ;
1093- const backupToUserPaillierChallenge = await EcdsaPaillierProof . generateP (
1094- hexToBigInt ( backupKeyCombined . yShares [ signerOneIndex ] . n )
1095- ) ;
1096-
1097- const userXShare = MPC . appendChallenge (
1098- userKeyCombined . xShare ,
1099- rangeProofChallenge ,
1100- EcdsaTypes . serializePaillierChallenge ( { p : userToBackupPaillierChallenge } )
1101- ) ;
1102- const userYShare = MPC . appendChallenge (
1103- userKeyCombined . yShares [ signerTwoIndex ] ,
1104- rangeProofChallenge ,
1105- EcdsaTypes . serializePaillierChallenge ( { p : backupToUserPaillierChallenge } )
1106- ) ;
1107- const backupXShare = MPC . appendChallenge (
1108- backupKeyCombined . xShare ,
1109- rangeProofChallenge ,
1110- EcdsaTypes . serializePaillierChallenge ( { p : backupToUserPaillierChallenge } )
1111- ) ;
1112- const backupYShare = MPC . appendChallenge (
1113- backupKeyCombined . yShares [ signerOneIndex ] ,
1114- rangeProofChallenge ,
1115- EcdsaTypes . serializePaillierChallenge ( { p : userToBackupPaillierChallenge } )
1116- ) ;
1117-
1118- const signShares : ECDSA . SignShareRT = await MPC . signShare ( userXShare , userYShare ) ;
1119-
1120- const signConvertS21 = await MPC . signConvertStep1 ( {
1121- xShare : backupXShare ,
1122- yShare : backupYShare , // YShare corresponding to the other participant signerOne
1123- kShare : signShares . kShare ,
1124- } ) ;
1125- const signConvertS12 = await MPC . signConvertStep2 ( {
1126- aShare : signConvertS21 . aShare ,
1127- wShare : signShares . wShare ,
1128- } ) ;
1129- const signConvertS21_2 = await MPC . signConvertStep3 ( {
1130- muShare : signConvertS12 . muShare ,
1131- bShare : signConvertS21 . bShare ,
1132- } ) ;
1133-
1134- const [ signCombineOne , signCombineTwo ] = [
1135- MPC . signCombine ( {
1136- gShare : signConvertS12 . gShare ,
1137- signIndex : {
1138- i : signConvertS12 . muShare . i ,
1139- j : signConvertS12 . muShare . j ,
1140- } ,
1141- } ) ,
1142- MPC . signCombine ( {
1143- gShare : signConvertS21_2 . gShare ,
1144- signIndex : {
1145- i : signConvertS21_2 . signIndex . i ,
1146- j : signConvertS21_2 . signIndex . j ,
1147- } ,
1148- } ) ,
1149- ] ;
1150-
1151- const MESSAGE = Buffer . from ( txHex , 'hex' ) ;
1152-
1153- const [ signA , signB ] = [
1154- MPC . sign ( MESSAGE , signCombineOne . oShare , signCombineTwo . dShare , Keccak ( 'keccak256' ) ) ,
1155- MPC . sign ( MESSAGE , signCombineTwo . oShare , signCombineOne . dShare , Keccak ( 'keccak256' ) ) ,
1156- ] ;
1157-
1158- return MPC . constructSignature ( [ signA , signB ] ) ;
1159- }
1160-
1161- /**
1162- * Helper which combines key shares of user and backup
1163- * @param {string } userPublicOrPrivateKeyShare
1164- * @param {string } backupPrivateOrPublicKeyShare
1165- * @param {string } walletPassphrase
1166- * @returns {[ECDSAMethodTypes.KeyCombined, ECDSAMethodTypes.KeyCombined] }
1167- */
1168- private getKeyCombinedFromTssKeyShares (
1169- userPublicOrPrivateKeyShare : string ,
1170- backupPrivateOrPublicKeyShare : string ,
1171- walletPassphrase ?: string
1172- ) : [ ECDSAMethodTypes . KeyCombined , ECDSAMethodTypes . KeyCombined ] {
1173- let backupPrv ;
1174- let userPrv ;
1175- try {
1176- backupPrv = this . bitgo . decrypt ( {
1177- input : backupPrivateOrPublicKeyShare ,
1178- password : walletPassphrase ,
1179- } ) ;
1180- userPrv = this . bitgo . decrypt ( {
1181- input : userPublicOrPrivateKeyShare ,
1182- password : walletPassphrase ,
1183- } ) ;
1184- } catch ( e ) {
1185- throw new Error ( `Error decrypting backup keychain: ${ e . message } ` ) ;
1186- }
1187-
1188- const userSigningMaterial = JSON . parse ( userPrv ) as ECDSAMethodTypes . SigningMaterial ;
1189- const backupSigningMaterial = JSON . parse ( backupPrv ) as ECDSAMethodTypes . SigningMaterial ;
1190-
1191- if ( ! userSigningMaterial . backupNShare ) {
1192- throw new Error ( 'Invalid user key - missing backupNShare' ) ;
1193- }
1194-
1195- if ( ! backupSigningMaterial . userNShare ) {
1196- throw new Error ( 'Invalid backup key - missing userNShare' ) ;
1197- }
1198-
1199- const MPC = new Ecdsa ( ) ;
1200-
1201- const userKeyCombined = MPC . keyCombine ( userSigningMaterial . pShare , [
1202- userSigningMaterial . bitgoNShare ,
1203- userSigningMaterial . backupNShare ,
1204- ] ) ;
1205- const userSigningKeyDerived = MPC . keyDerive (
1206- userSigningMaterial . pShare ,
1207- [ userSigningMaterial . bitgoNShare , userSigningMaterial . backupNShare ] ,
1208- 'm/0'
1209- ) ;
1210- const userKeyDerivedCombined = {
1211- xShare : userSigningKeyDerived . xShare ,
1212- yShares : userKeyCombined . yShares ,
1213- } ;
1214- const backupKeyCombined = MPC . keyCombine ( backupSigningMaterial . pShare , [
1215- userSigningKeyDerived . nShares [ 2 ] ,
1216- backupSigningMaterial . bitgoNShare ,
1217- ] ) ;
1218- if (
1219- userKeyDerivedCombined . xShare . y !== backupKeyCombined . xShare . y ||
1220- userKeyDerivedCombined . xShare . chaincode !== backupKeyCombined . xShare . chaincode
1221- ) {
1222- throw new Error ( 'Common keychains do not match' ) ;
1223- }
1224- return [ userKeyDerivedCombined , backupKeyCombined ] ;
1225- }
1226-
12271056 /**
12281057 * Helper which Adds signatures to tx object and re-serializes tx
12291058 * @param {EthLikeCommon.default } ethCommon
@@ -1289,7 +1118,7 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
12891118 */
12901119 async recover ( params : RecoverOptions ) : Promise < RecoveryInfo | OfflineVaultTxInfo > {
12911120 if ( params . isTss === true ) {
1292- return this . recoverTSS ( params , params . openSSLBytes ) ;
1121+ return this . recoverTSS ( params ) ;
12931122 }
12941123 return this . recoverEthLike ( params ) ;
12951124 }
@@ -1974,10 +1803,7 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
19741803 * Recovers a tx with TSS key shares
19751804 * same expected arguments as recover method, but with TSS key shares
19761805 */
1977- protected async recoverTSS (
1978- params : RecoverOptions ,
1979- openSSLBytes : Uint8Array
1980- ) : Promise < RecoveryInfo | OfflineVaultTxInfo > {
1806+ protected async recoverTSS ( params : RecoverOptions ) : Promise < RecoveryInfo | OfflineVaultTxInfo > {
19811807 this . validateRecoveryParams ( params ) ;
19821808 // Clean up whitespace from entered values
19831809 const userPublicOrPrivateKeyShare = params . userKey . replace ( / \s / g, '' ) ;
@@ -2010,48 +1836,19 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
20101836 params . replayProtectionOptions
20111837 ) ;
20121838 } else {
2013- const isGG18SigningMaterial = ECDSAUtils . isGG18SigningMaterial (
1839+ const { userKeyShare , backupKeyShare , commonKeyChain } = await ECDSAUtils . getMpcV2RecoveryKeyShares (
20141840 userPublicOrPrivateKeyShare ,
1841+ backupPrivateOrPublicKeyShare ,
20151842 params . walletPassphrase
20161843 ) ;
2017- let signature : ECDSAMethodTypes . Signature ;
2018- let unsignedTx : EthLikeTxLib . Transaction | EthLikeTxLib . FeeMarketEIP1559Transaction ;
2019- if ( isGG18SigningMaterial ) {
2020- const [ userKeyCombined , backupKeyCombined ] = this . getKeyCombinedFromTssKeyShares (
2021- userPublicOrPrivateKeyShare ,
2022- backupPrivateOrPublicKeyShare ,
2023- params . walletPassphrase
2024- ) ;
2025- const backupKeyPair = new KeyPairLib ( { pub : backupKeyCombined . xShare . y } ) ;
2026- const baseAddress = backupKeyPair . getAddress ( ) ;
2027-
2028- unsignedTx = ( await this . buildTssRecoveryTxn ( baseAddress , gasPrice , gasLimit , params ) ) . tx ;
2029-
2030- signature = await this . signRecoveryTSS (
2031- userKeyCombined ,
2032- backupKeyCombined ,
2033- unsignedTx . getMessageToSign ( false ) . toString ( 'hex' ) ,
2034- openSSLBytes
2035- ) ;
2036- } else {
2037- const { userKeyShare, backupKeyShare, commonKeyChain } = await ECDSAUtils . getMpcV2RecoveryKeyShares (
2038- userPublicOrPrivateKeyShare ,
2039- backupPrivateOrPublicKeyShare ,
2040- params . walletPassphrase
2041- ) ;
2042-
2043- const MPC = new Ecdsa ( ) ;
2044- const derivedCommonKeyChain = MPC . deriveUnhardened ( commonKeyChain , 'm' ) ;
2045- const backupKeyPair = new KeyPairLib ( { pub : derivedCommonKeyChain . slice ( 0 , 66 ) } ) ;
2046- const baseAddress = backupKeyPair . getAddress ( ) ;
2047-
2048- unsignedTx = ( await this . buildTssRecoveryTxn ( baseAddress , gasPrice , gasLimit , params ) ) . tx ;
2049-
2050- const messageHash = unsignedTx . getMessageToSign ( true ) ;
2051-
2052- signature = await ECDSAUtils . signRecoveryMpcV2 ( messageHash , userKeyShare , backupKeyShare , commonKeyChain ) ;
2053- }
20541844
1845+ const MPC = new Ecdsa ( ) ;
1846+ const derivedCommonKeyChain = MPC . deriveUnhardened ( commonKeyChain , 'm/0' ) ;
1847+ const backupKeyPair = new KeyPairLib ( { pub : derivedCommonKeyChain . slice ( 0 , 66 ) } ) ;
1848+ const baseAddress = backupKeyPair . getAddress ( ) ;
1849+ const unsignedTx = ( await this . buildTssRecoveryTxn ( baseAddress , gasPrice , gasLimit , params ) ) . tx ;
1850+ const messageHash = unsignedTx . getMessageToSign ( true ) ;
1851+ const signature = await ECDSAUtils . signRecoveryMpcV2 ( messageHash , userKeyShare , backupKeyShare , commonKeyChain ) ;
20551852 const ethCommmon = AbstractEthLikeNewCoins . getEthLikeCommon ( params . eip1559 , params . replayProtectionOptions ) ;
20561853 const signedTx = this . getSignedTxFromSignature ( ethCommmon , unsignedTx , signature ) ;
20571854
0 commit comments