@@ -22,7 +22,6 @@ import {
2222 EDDSAUtils ,
2323 EddsaMPCv2KeyGenCallbacks ,
2424 EddsaMPCv2Utils ,
25- EddsaRetrofitData ,
2625 IBaseCoin ,
2726 IWallet ,
2827 RequestTracer ,
@@ -2181,135 +2180,87 @@ describe('EddsaMPCv2Utils.createKeychainsWithExternalSigner', function () {
21812180} ) ;
21822181
21832182describe ( 'EddsaMPCv2Utils.getMpcV2RetrofitDataFromMpcV1Keys' , ( ) => {
2184- // 32-byte seed and chaincode values used across all tests
2185- const userSeed = randomBytes ( 32 ) . toString ( 'hex' ) ;
2186- const backupSeed = randomBytes ( 32 ) . toString ( 'hex' ) ;
2187- const userChaincode = randomBytes ( 32 ) . toString ( 'hex' ) ;
2188- const backupChaincode = randomBytes ( 32 ) . toString ( 'hex' ) ;
2189- const aggregatePk = randomBytes ( 32 ) . toString ( 'hex' ) ;
2190-
2191- const userMpcV1Key = JSON . stringify ( {
2192- uShare : { i : 1 , seed : userSeed , chaincode : userChaincode , y : randomBytes ( 32 ) . toString ( 'hex' ) } ,
2193- pShare : { y : aggregatePk } ,
2194- bitgoYShare : { u : randomBytes ( 32 ) . toString ( 'hex' ) } ,
2195- backupYShare : { u : randomBytes ( 32 ) . toString ( 'hex' ) } ,
2196- } ) ;
2183+ let utils : EddsaMPCv2Utils ;
2184+ // Real 3-party MPCv1 EdDSA key shares: 1 = user, 2 = backup, 3 = bitgo.
2185+ let userSigningMaterial : Record < string , unknown > ;
2186+ let backupSigningMaterial : Record < string , unknown > ;
2187+ let expectedUserPShare : { y : string ; u : string ; chaincode : string } ;
2188+ let expectedBackupPShare : { y : string ; u : string ; chaincode : string } ;
21972189
2198- const backupMpcV1Key = JSON . stringify ( {
2199- uShare : { i : 2 , seed : backupSeed , chaincode : backupChaincode , y : randomBytes ( 32 ) . toString ( 'hex' ) } ,
2200- bitgoYShare : { u : randomBytes ( 32 ) . toString ( 'hex' ) } ,
2201- userYShare : { u : randomBytes ( 32 ) . toString ( 'hex' ) } ,
2190+ before ( async ( ) => {
2191+ const MPC = await getInitializedMpcInstance ( ) ;
2192+ const user = MPC . keyShare ( 1 , 2 , 3 ) ;
2193+ const backup = MPC . keyShare ( 2 , 2 , 3 ) ;
2194+ const bitgo = MPC . keyShare ( 3 , 2 , 3 ) ;
2195+
2196+ expectedUserPShare = MPC . keyCombine ( user . uShare , [ backup . yShares [ 1 ] , bitgo . yShares [ 1 ] ] ) . pShare ;
2197+ expectedBackupPShare = MPC . keyCombine ( backup . uShare , [ user . yShares [ 2 ] , bitgo . yShares [ 2 ] ] ) . pShare ;
2198+
2199+ userSigningMaterial = {
2200+ uShare : user . uShare ,
2201+ bitgoYShare : bitgo . yShares [ 1 ] ,
2202+ backupYShare : backup . yShares [ 1 ] ,
2203+ } ;
2204+ backupSigningMaterial = {
2205+ uShare : backup . uShare ,
2206+ bitgoYShare : bitgo . yShares [ 2 ] ,
2207+ userYShare : user . yShares [ 2 ] ,
2208+ } ;
22022209 } ) ;
22032210
2204- let utils : EddsaMPCv2Utils ;
2205-
22062211 beforeEach ( ( ) => {
22072212 const mockBitGo = { } as unknown as BitGoBase ;
22082213 const mockCoin = { } as unknown as IBaseCoin ;
22092214 utils = new EddsaMPCv2Utils ( mockBitGo , mockCoin ) ;
22102215 } ) ;
22112216
2212- function deriveScalar ( seedHex : string ) : string {
2213- const { createHash } = require ( 'crypto' ) ;
2214- const seedBytes = Buffer . from ( seedHex , 'hex' ) ;
2215- const hash = createHash ( 'sha512' ) . update ( seedBytes ) . digest ( ) ;
2216- const scalar = Buffer . from ( hash . subarray ( 0 , 32 ) ) ;
2217- scalar [ 0 ] &= 248 ;
2218- scalar [ 31 ] &= 127 ;
2219- scalar [ 31 ] |= 64 ;
2220- return scalar . toString ( 'hex' ) ;
2221- }
2222-
2223- it ( 'returns EddsaRetrofitData for user and backup with matching expectedPk' , ( ) => {
2224- const result = utils . getMpcV2RetrofitDataFromMpcV1Keys ( {
2225- mpcv1UserKeyShare : userMpcV1Key ,
2226- mpcv1BackupKeyShare : backupMpcV1Key ,
2217+ it ( 'derives matching expectedPk and chainCode for user and backup from real MPCv1 key combine' , async ( ) => {
2218+ const { userRetrofitData, backupRetrofitData } = await utils . getMpcV2RetrofitDataFromMpcV1Keys ( {
2219+ mpcv1UserKeyShare : JSON . stringify ( userSigningMaterial ) ,
2220+ mpcv1BackupKeyShare : JSON . stringify ( backupSigningMaterial ) ,
22272221 } ) ;
22282222
2229- const { userRetrofitData, backupRetrofitData } = result as {
2230- userRetrofitData : EddsaRetrofitData ;
2231- backupRetrofitData : EddsaRetrofitData ;
2232- } ;
2233-
2234- assert . strictEqual ( userRetrofitData . expectedPk , aggregatePk ) ;
2235- assert . strictEqual ( backupRetrofitData . expectedPk , aggregatePk ) ;
2236- } ) ;
2237-
2238- it ( 'returns correct chainCode per party' , ( ) => {
2239- const { userRetrofitData, backupRetrofitData } = utils . getMpcV2RetrofitDataFromMpcV1Keys ( {
2240- mpcv1UserKeyShare : userMpcV1Key ,
2241- mpcv1BackupKeyShare : backupMpcV1Key ,
2242- } ) ;
2223+ assert . strictEqual ( userRetrofitData . expectedPk , expectedUserPShare . y ) ;
2224+ assert . strictEqual ( backupRetrofitData . expectedPk , expectedBackupPShare . y ) ;
2225+ assert . strictEqual ( userRetrofitData . expectedPk , backupRetrofitData . expectedPk ) ;
22432226
2244- assert . strictEqual ( userRetrofitData . chainCode , userChaincode ) ;
2245- assert . strictEqual ( backupRetrofitData . chainCode , backupChaincode ) ;
2227+ assert . strictEqual ( userRetrofitData . chainCode , expectedUserPShare . chaincode ) ;
2228+ assert . strictEqual ( backupRetrofitData . chainCode , expectedBackupPShare . chaincode ) ;
2229+ assert . strictEqual ( userRetrofitData . chainCode , backupRetrofitData . chainCode ) ;
22462230 } ) ;
22472231
2248- it ( 'returns correctly clamped s_i_0 scalars' , ( ) => {
2249- const { userRetrofitData, backupRetrofitData } = utils . getMpcV2RetrofitDataFromMpcV1Keys ( {
2250- mpcv1UserKeyShare : userMpcV1Key ,
2251- mpcv1BackupKeyShare : backupMpcV1Key ,
2232+ it ( 'derives s_i_0 as the combined pShare.u ( clamped scalar) for each party' , async ( ) => {
2233+ const { userRetrofitData, backupRetrofitData } = await utils . getMpcV2RetrofitDataFromMpcV1Keys ( {
2234+ mpcv1UserKeyShare : JSON . stringify ( userSigningMaterial ) ,
2235+ mpcv1BackupKeyShare : JSON . stringify ( backupSigningMaterial ) ,
22522236 } ) ;
22532237
2254- assert . strictEqual ( userRetrofitData . s_i_0 , deriveScalar ( userSeed ) ) ;
2255- assert . strictEqual ( backupRetrofitData . s_i_0 , deriveScalar ( backupSeed ) ) ;
2238+ assert . strictEqual ( userRetrofitData . s_i_0 , expectedUserPShare . u ) ;
2239+ assert . strictEqual ( backupRetrofitData . s_i_0 , expectedBackupPShare . u ) ;
2240+ assert . notStrictEqual ( userRetrofitData . s_i_0 , backupRetrofitData . s_i_0 ) ;
22562241 } ) ;
22572242
2258- it ( 'scalar byte[0] has low 3 bits cleared, byte[31] has bit7 cleared and bit6 set' , ( ) => {
2259- const { userRetrofitData } = utils . getMpcV2RetrofitDataFromMpcV1Keys ( {
2260- mpcv1UserKeyShare : userMpcV1Key ,
2261- mpcv1BackupKeyShare : backupMpcV1Key ,
2262- } ) ;
2263-
2264- const scalarBytes = Buffer . from ( userRetrofitData . s_i_0 , 'hex' ) ;
2265- assert . strictEqual ( scalarBytes [ 0 ] & 0b111 , 0 , 'byte[0] low 3 bits should be cleared' ) ;
2266- assert . strictEqual ( scalarBytes [ 31 ] & 0b10000000 , 0 , 'byte[31] bit7 should be cleared' ) ;
2267- assert . strictEqual ( scalarBytes [ 31 ] & 0b01000000 , 0b01000000 , 'byte[31] bit6 should be set' ) ;
2268- } ) ;
2269-
2270- it ( 'throws if user key is missing pShare.y' , ( ) => {
2271- const keyNoPShare = JSON . stringify ( {
2272- uShare : { i : 1 , seed : userSeed , chaincode : userChaincode } ,
2273- bitgoYShare : { u : 'x' } ,
2274- } ) ;
2275- assert . throws (
2276- ( ) =>
2277- utils . getMpcV2RetrofitDataFromMpcV1Keys ( {
2278- mpcv1UserKeyShare : keyNoPShare ,
2279- mpcv1BackupKeyShare : backupMpcV1Key ,
2280- } ) ,
2281- / M P C v 1 u s e r k e y m i s s i n g p S h a r e \. y /
2282- ) ;
2283- } ) ;
2284-
2285- it ( 'throws if user key is missing uShare.seed' , ( ) => {
2286- const keyNoSeed = JSON . stringify ( {
2287- uShare : { i : 1 , chaincode : userChaincode } ,
2288- pShare : { y : aggregatePk } ,
2289- bitgoYShare : { u : 'x' } ,
2290- } ) ;
2291- assert . throws (
2243+ it ( 'throws if user key is missing backupYShare' , async ( ) => {
2244+ const keyNoBackupYShare = JSON . stringify ( { uShare : userSigningMaterial . uShare } ) ;
2245+ await assert . rejects (
22922246 ( ) =>
22932247 utils . getMpcV2RetrofitDataFromMpcV1Keys ( {
2294- mpcv1UserKeyShare : keyNoSeed ,
2295- mpcv1BackupKeyShare : backupMpcV1Key ,
2248+ mpcv1UserKeyShare : keyNoBackupYShare ,
2249+ mpcv1BackupKeyShare : JSON . stringify ( backupSigningMaterial ) ,
22962250 } ) ,
2297- / M P C v 1 k e y m i s s i n g u S h a r e \. s e e d /
2251+ / M P C v 1 u s e r k e y m i s s i n g b a c k u p Y S h a r e /
22982252 ) ;
22992253 } ) ;
23002254
2301- it ( 'throws if backup key is missing uShare.seed' , ( ) => {
2302- const backupNoSeed = JSON . stringify ( {
2303- uShare : { i : 2 , chaincode : backupChaincode } ,
2304- bitgoYShare : { u : 'x' } ,
2305- } ) ;
2306- assert . throws (
2255+ it ( 'throws if backup key is missing userYShare' , async ( ) => {
2256+ const keyNoUserYShare = JSON . stringify ( { uShare : backupSigningMaterial . uShare } ) ;
2257+ await assert . rejects (
23072258 ( ) =>
23082259 utils . getMpcV2RetrofitDataFromMpcV1Keys ( {
2309- mpcv1UserKeyShare : userMpcV1Key ,
2310- mpcv1BackupKeyShare : backupNoSeed ,
2260+ mpcv1UserKeyShare : JSON . stringify ( userSigningMaterial ) ,
2261+ mpcv1BackupKeyShare : keyNoUserYShare ,
23112262 } ) ,
2312- / M P C v 1 k e y m i s s i n g u S h a r e \. s e e d /
2263+ / M P C v 1 b a c k u p k e y m i s s i n g u s e r Y S h a r e /
23132264 ) ;
23142265 } ) ;
23152266} ) ;
0 commit comments