@@ -1534,3 +1534,65 @@ function bytesToWord(bytes?: Uint8Array | number[]): number {
15341534
15351535 return bytes . reduce ( ( num , byte ) => num * 0x100 + byte , 0 ) ;
15361536}
1537+
1538+ describe ( 'EddsaMPCv2Utils.isEddsaMpcV1SigningMaterial' , ( ) => {
1539+ const PASSPHRASE = 'test-passphrase' ;
1540+
1541+ const MPCv1_MATERIAL_BACKUP = {
1542+ uShare : { i : 1 , t : 2 , n : 3 , y : 'aabbcc' , seed : 'deadbeef01234567' , chaincode : '00' } ,
1543+ bitgoYShare : { i : 3 , j : 1 , y : 'aabbcc' , u : 'bitgo-u-value' , chaincode : '00' } ,
1544+ backupYShare : { i : 2 , j : 1 , y : 'aabbcc' , u : 'backup-u-value' , chaincode : '00' } ,
1545+ } ;
1546+
1547+ const MPCv1_MATERIAL_USER = {
1548+ uShare : { i : 2 , t : 2 , n : 3 , y : 'aabbcc' , seed : 'deadbeef01234567' , chaincode : '00' } ,
1549+ bitgoYShare : { i : 3 , j : 2 , y : 'aabbcc' , u : 'bitgo-u-value' , chaincode : '00' } ,
1550+ userYShare : { i : 1 , j : 2 , y : 'aabbcc' , u : 'user-u-value' , chaincode : '00' } ,
1551+ } ;
1552+
1553+ const MPCv2_CBOR_BYTES = Buffer . from ( [ 0xd9 , 0x01 , 0x04 , 0xa3 , 0x61 , 0x78 , 0x18 , 0x00 ] ) . toString ( 'base64' ) ;
1554+
1555+ let eddsaUtils : EddsaMPCv2Utils ;
1556+ let mockBitgo : BitGoBase ;
1557+
1558+ beforeEach ( ( ) => {
1559+ mockBitgo = {
1560+ decryptAsync : sinon
1561+ . stub ( )
1562+ . callsFake ( async ( params : { input : string ; password : string } ) => sjcl . decrypt ( params . password , params . input ) ) ,
1563+ } as unknown as BitGoBase ;
1564+
1565+ eddsaUtils = new EddsaMPCv2Utils ( mockBitgo , { } as unknown as IBaseCoin ) ;
1566+ } ) ;
1567+
1568+ it ( 'returns true for MPCv1 SJCL-encrypted keycard with backupYShare + correct passphrase' , async ( ) => {
1569+ const encrypted = sjcl . encrypt ( PASSPHRASE , JSON . stringify ( MPCv1_MATERIAL_BACKUP ) ) ;
1570+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , true ) ;
1571+ } ) ;
1572+
1573+ it ( 'returns true for MPCv1 SJCL-encrypted keycard with userYShare + correct passphrase' , async ( ) => {
1574+ const encrypted = sjcl . encrypt ( PASSPHRASE , JSON . stringify ( MPCv1_MATERIAL_USER ) ) ;
1575+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , true ) ;
1576+ } ) ;
1577+
1578+ it ( 'returns false for MPCv2 CBOR content wrapped in SJCL envelope + correct passphrase' , async ( ) => {
1579+ const encrypted = sjcl . encrypt ( PASSPHRASE , MPCv2_CBOR_BYTES ) ;
1580+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , false ) ;
1581+ } ) ;
1582+
1583+ it ( 'returns false for MPCv2 Argon2id envelope (v2) + correct passphrase (forward-compat)' , async ( ) => {
1584+ const fakeV2Envelope = JSON . stringify ( { v : 2 , m : 65536 , t : 3 , p : 4 , salt : 'AAAA' , iv : 'AAAA' , ct : 'AAAA' } ) ;
1585+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( fakeV2Envelope , PASSPHRASE ) , false ) ;
1586+ } ) ;
1587+
1588+ it ( 'returns false for wrong passphrase — does not throw' , async ( ) => {
1589+ const encrypted = sjcl . encrypt ( PASSPHRASE , JSON . stringify ( MPCv1_MATERIAL_BACKUP ) ) ;
1590+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , 'wrong-passphrase' ) , false ) ;
1591+ } ) ;
1592+
1593+ it ( 'returns false when neither backupYShare.u nor userYShare.u is present' , async ( ) => {
1594+ const partial = { uShare : { seed : 'abc' } , bitgoYShare : { u : 'xyz' } } ;
1595+ const encrypted = sjcl . encrypt ( PASSPHRASE , JSON . stringify ( partial ) ) ;
1596+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , false ) ;
1597+ } ) ;
1598+ } ) ;
0 commit comments