@@ -765,3 +765,79 @@ describe('EddsaMPCv2Utils.signEddsaMPCv2TssUsingExternalSigner', () => {
765765 ) ;
766766 } ) ;
767767} ) ;
768+
769+ describe ( 'EddsaMPCv2Utils.isEddsaMpcV1SigningMaterial' , ( ) => {
770+ const PASSPHRASE = 'test-passphrase' ;
771+
772+ const MPCv1_MATERIAL_BACKUP = {
773+ uShare : { i : 1 , t : 2 , n : 3 , y : 'aabbcc' , seed : 'deadbeef01234567' , chaincode : '00' } ,
774+ bitgoYShare : { i : 3 , j : 1 , y : 'aabbcc' , u : 'bitgo-u-value' , chaincode : '00' } ,
775+ backupYShare : { i : 2 , j : 1 , y : 'aabbcc' , u : 'backup-u-value' , chaincode : '00' } ,
776+ } ;
777+
778+ const MPCv1_MATERIAL_USER = {
779+ uShare : { i : 2 , t : 2 , n : 3 , y : 'aabbcc' , seed : 'deadbeef01234567' , chaincode : '00' } ,
780+ bitgoYShare : { i : 3 , j : 2 , y : 'aabbcc' , u : 'bitgo-u-value' , chaincode : '00' } ,
781+ userYShare : { i : 1 , j : 2 , y : 'aabbcc' , u : 'user-u-value' , chaincode : '00' } ,
782+ } ;
783+
784+ const MPCv2_CBOR_BYTES = Buffer . from ( [ 0xd9 , 0x01 , 0x04 , 0xa3 , 0x61 , 0x78 , 0x18 , 0x00 ] ) . toString ( 'base64' ) ;
785+
786+ let eddsaUtils : EddsaMPCv2Utils ;
787+ let mockBitgo : BitGoBase ;
788+
789+ function encryptSjcl ( plaintext : string , password : string ) : string {
790+ const salt = randomBytes ( 8 ) ;
791+ const iv = randomBytes ( 16 ) ;
792+ return sjcl . encrypt ( password , plaintext , {
793+ salt : [ bytesToWord ( salt . subarray ( 0 , 4 ) ) , bytesToWord ( salt . subarray ( 4 , 8 ) ) ] ,
794+ iv : [
795+ bytesToWord ( iv . subarray ( 0 , 4 ) ) ,
796+ bytesToWord ( iv . subarray ( 4 , 8 ) ) ,
797+ bytesToWord ( iv . subarray ( 8 , 12 ) ) ,
798+ bytesToWord ( iv . subarray ( 12 , 16 ) ) ,
799+ ] ,
800+ } ) ;
801+ }
802+
803+ beforeEach ( ( ) => {
804+ mockBitgo = {
805+ decryptAsync : sinon
806+ . stub ( )
807+ . callsFake ( async ( params : { input : string ; password : string } ) => sjcl . decrypt ( params . password , params . input ) ) ,
808+ } as unknown as BitGoBase ;
809+
810+ eddsaUtils = new EddsaMPCv2Utils ( mockBitgo , { } as unknown as IBaseCoin ) ;
811+ } ) ;
812+
813+ it ( 'returns true for MPCv1 SJCL-encrypted keycard with backupYShare + correct passphrase' , async ( ) => {
814+ const encrypted = encryptSjcl ( JSON . stringify ( MPCv1_MATERIAL_BACKUP ) , PASSPHRASE ) ;
815+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , true ) ;
816+ } ) ;
817+
818+ it ( 'returns true for MPCv1 SJCL-encrypted keycard with userYShare + correct passphrase' , async ( ) => {
819+ const encrypted = encryptSjcl ( JSON . stringify ( MPCv1_MATERIAL_USER ) , PASSPHRASE ) ;
820+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , true ) ;
821+ } ) ;
822+
823+ it ( 'returns false for MPCv2 CBOR content wrapped in SJCL envelope + correct passphrase' , async ( ) => {
824+ const encrypted = encryptSjcl ( MPCv2_CBOR_BYTES , PASSPHRASE ) ;
825+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , false ) ;
826+ } ) ;
827+
828+ it ( 'returns false for MPCv2 Argon2id envelope (v2) + correct passphrase (forward-compat)' , async ( ) => {
829+ const fakeV2Envelope = JSON . stringify ( { v : 2 , m : 65536 , t : 3 , p : 4 , salt : 'AAAA' , iv : 'AAAA' , ct : 'AAAA' } ) ;
830+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( fakeV2Envelope , PASSPHRASE ) , false ) ;
831+ } ) ;
832+
833+ it ( 'returns false for wrong passphrase — does not throw' , async ( ) => {
834+ const encrypted = encryptSjcl ( JSON . stringify ( MPCv1_MATERIAL_BACKUP ) , PASSPHRASE ) ;
835+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , 'wrong-passphrase' ) , false ) ;
836+ } ) ;
837+
838+ it ( 'returns false when neither backupYShare.u nor userYShare.u is present' , async ( ) => {
839+ const partial = { uShare : { seed : 'abc' } , bitgoYShare : { u : 'xyz' } } ;
840+ const encrypted = encryptSjcl ( JSON . stringify ( partial ) , PASSPHRASE ) ;
841+ assert . strictEqual ( await eddsaUtils . isEddsaMpcV1SigningMaterial ( encrypted , PASSPHRASE ) , false ) ;
842+ } ) ;
843+ } ) ;
0 commit comments