@@ -1534,3 +1534,79 @@ 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+ function encryptSjcl ( plaintext : string , password : string ) : string {
1559+ const salt = randomBytes ( 8 ) ;
1560+ const iv = randomBytes ( 16 ) ;
1561+ return sjcl . encrypt ( password , plaintext , {
1562+ salt : [ bytesToWord ( salt . subarray ( 0 , 4 ) ) , bytesToWord ( salt . subarray ( 4 , 8 ) ) ] ,
1563+ iv : [
1564+ bytesToWord ( iv . subarray ( 0 , 4 ) ) ,
1565+ bytesToWord ( iv . subarray ( 4 , 8 ) ) ,
1566+ bytesToWord ( iv . subarray ( 8 , 12 ) ) ,
1567+ bytesToWord ( iv . subarray ( 12 , 16 ) ) ,
1568+ ] ,
1569+ } ) ;
1570+ }
1571+
1572+ beforeEach ( ( ) => {
1573+ mockBitgo = {
1574+ decryptAsync : sinon
1575+ . stub ( )
1576+ . callsFake ( async ( params : { input : string ; password : string } ) => sjcl . decrypt ( params . password , params . input ) ) ,
1577+ } as unknown as BitGoBase ;
1578+
1579+ eddsaUtils = new EddsaMPCv2Utils ( mockBitgo , { } as unknown as IBaseCoin ) ;
1580+ } ) ;
1581+
1582+ it ( 'returns true for MPCv1 SJCL-encrypted keycard with backupYShare + correct passphrase' , async ( ) => {
1583+ const encrypted = encryptSjcl ( JSON . stringify ( MPCv1_MATERIAL_BACKUP ) , PASSPHRASE ) ;
1584+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , true ) ;
1585+ } ) ;
1586+
1587+ it ( 'returns true for MPCv1 SJCL-encrypted keycard with userYShare + correct passphrase' , async ( ) => {
1588+ const encrypted = encryptSjcl ( JSON . stringify ( MPCv1_MATERIAL_USER ) , PASSPHRASE ) ;
1589+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , true ) ;
1590+ } ) ;
1591+
1592+ it ( 'returns false for MPCv2 CBOR content wrapped in SJCL envelope + correct passphrase' , async ( ) => {
1593+ const encrypted = encryptSjcl ( MPCv2_CBOR_BYTES , PASSPHRASE ) ;
1594+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , false ) ;
1595+ } ) ;
1596+
1597+ it ( 'returns false for MPCv2 Argon2id envelope (v2) + correct passphrase (forward-compat)' , async ( ) => {
1598+ const fakeV2Envelope = JSON . stringify ( { v : 2 , m : 65536 , t : 3 , p : 4 , salt : 'AAAA' , iv : 'AAAA' , ct : 'AAAA' } ) ;
1599+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( fakeV2Envelope , PASSPHRASE ) , false ) ;
1600+ } ) ;
1601+
1602+ it ( 'returns false for wrong passphrase — does not throw' , async ( ) => {
1603+ const encrypted = encryptSjcl ( JSON . stringify ( MPCv1_MATERIAL_BACKUP ) , PASSPHRASE ) ;
1604+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , 'wrong-passphrase' ) , false ) ;
1605+ } ) ;
1606+
1607+ it ( 'returns false when neither backupYShare.u nor userYShare.u is present' , async ( ) => {
1608+ const partial = { uShare : { seed : 'abc' } , bitgoYShare : { u : 'xyz' } } ;
1609+ const encrypted = encryptSjcl ( JSON . stringify ( partial ) , PASSPHRASE ) ;
1610+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , false ) ;
1611+ } ) ;
1612+ } ) ;
0 commit comments