@@ -247,161 +247,161 @@ describe("verifySignature", function () {
247247 txFormats
248248 . filter ( ( f ) => f !== "psbt" || networkName !== "zcash" )
249249 . forEach ( ( txFormat ) => {
250- describe ( `${ networkName } ${ txFormat } ` , function ( ) {
251- let rootWalletKeys : RootWalletKeys ;
252- let replayProtectionKey : ECPair ;
253- let xprivs : RootWalletXprivs ;
254- let unsignedFixture : Fixture ;
255- let halfsignedFixture : Fixture ;
256- let fullsignedFixture : Fixture ;
257-
258- before ( async function ( ) {
259- unsignedFixture = await loadPsbtFixture ( networkName , "unsigned" , txFormat ) ;
260- halfsignedFixture = await loadPsbtFixture ( networkName , "halfsigned" , txFormat ) ;
261- fullsignedFixture = await loadPsbtFixture ( networkName , "fullsigned" , txFormat ) ;
262- rootWalletKeys = loadWalletKeysFromFixture ( fullsignedFixture ) ;
263- replayProtectionKey = loadReplayProtectionKeyFromFixture ( fullsignedFixture ) ;
264- xprivs = loadXprivsFromFixture ( fullsignedFixture ) ;
265- } ) ;
266-
267- describe ( "unsigned PSBT" , function ( ) {
268- it ( "should return false for unsigned inputs, then sign and verify" , function ( ) {
269- runTestsForFixture (
270- unsignedFixture ,
271- networkName ,
272- rootWalletKeys ,
273- replayProtectionKey ,
274- xprivs ,
275- "unsigned" ,
276- ) ;
277- } ) ;
278- } ) ;
279-
280- describe ( "half-signed PSBT" , function ( ) {
281- it ( "should return true for signed xpubs and false for unsigned, then sign and verify" , function ( ) {
282- runTestsForFixture (
283- halfsignedFixture ,
284- networkName ,
285- rootWalletKeys ,
286- replayProtectionKey ,
287- xprivs ,
288- "halfsigned" ,
289- ) ;
290- } ) ;
291- } ) ;
292-
293- describe ( "fully signed PSBT" , function ( ) {
294- it ( "should have 2 signatures (2-of-3 multisig)" , function ( ) {
295- runTestsForFixture (
296- fullsignedFixture ,
297- networkName ,
298- rootWalletKeys ,
299- replayProtectionKey ,
300- xprivs ,
301- "fullsigned" ,
302- ) ;
303- } ) ;
304- } ) ;
305-
306- describe ( "error handling" , function ( ) {
307- it ( "should throw error for out of bounds input index" , function ( ) {
308- const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
309- assert . throws (
310- ( ) => {
311- psbt . verifySignature ( 999 , rootWalletKeys . userKey ( ) ) ;
312- } ,
313- ( error : Error ) => {
314- return error . message . includes ( "Input index 999 out of bounds" ) ;
315- } ,
316- "Should throw error for out of bounds input index" ,
317- ) ;
250+ describe ( `${ networkName } ${ txFormat } ` , function ( ) {
251+ let rootWalletKeys : RootWalletKeys ;
252+ let replayProtectionKey : ECPair ;
253+ let xprivs : RootWalletXprivs ;
254+ let unsignedFixture : Fixture ;
255+ let halfsignedFixture : Fixture ;
256+ let fullsignedFixture : Fixture ;
257+
258+ before ( async function ( ) {
259+ unsignedFixture = await loadPsbtFixture ( networkName , "unsigned" , txFormat ) ;
260+ halfsignedFixture = await loadPsbtFixture ( networkName , "halfsigned" , txFormat ) ;
261+ fullsignedFixture = await loadPsbtFixture ( networkName , "fullsigned" , txFormat ) ;
262+ rootWalletKeys = loadWalletKeysFromFixture ( fullsignedFixture ) ;
263+ replayProtectionKey = loadReplayProtectionKeyFromFixture ( fullsignedFixture ) ;
264+ xprivs = loadXprivsFromFixture ( fullsignedFixture ) ;
265+ } ) ;
266+
267+ describe ( "unsigned PSBT" , function ( ) {
268+ it ( "should return false for unsigned inputs, then sign and verify" , function ( ) {
269+ runTestsForFixture (
270+ unsignedFixture ,
271+ networkName ,
272+ rootWalletKeys ,
273+ replayProtectionKey ,
274+ xprivs ,
275+ "unsigned" ,
276+ ) ;
277+ } ) ;
278+ } ) ;
279+
280+ describe ( "half-signed PSBT" , function ( ) {
281+ it ( "should return true for signed xpubs and false for unsigned, then sign and verify" , function ( ) {
282+ runTestsForFixture (
283+ halfsignedFixture ,
284+ networkName ,
285+ rootWalletKeys ,
286+ replayProtectionKey ,
287+ xprivs ,
288+ "halfsigned" ,
289+ ) ;
290+ } ) ;
291+ } ) ;
292+
293+ describe ( "fully signed PSBT" , function ( ) {
294+ it ( "should have 2 signatures (2-of-3 multisig)" , function ( ) {
295+ runTestsForFixture (
296+ fullsignedFixture ,
297+ networkName ,
298+ rootWalletKeys ,
299+ replayProtectionKey ,
300+ xprivs ,
301+ "fullsigned" ,
302+ ) ;
303+ } ) ;
304+ } ) ;
305+
306+ describe ( "error handling" , function ( ) {
307+ it ( "should throw error for out of bounds input index" , function ( ) {
308+ const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
309+ assert . throws (
310+ ( ) => {
311+ psbt . verifySignature ( 999 , rootWalletKeys . userKey ( ) ) ;
312+ } ,
313+ ( error : Error ) => {
314+ return error . message . includes ( "Input index 999 out of bounds" ) ;
315+ } ,
316+ "Should throw error for out of bounds input index" ,
317+ ) ;
318+ } ) ;
319+
320+ it ( "should throw error for invalid xpub" , function ( ) {
321+ const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
322+ assert . throws (
323+ ( ) => {
324+ psbt . verifySignature ( 0 , "invalid-xpub" ) ;
325+ } ,
326+ ( error : Error ) => {
327+ return error . message . includes ( "Invalid" ) ;
328+ } ,
329+ "Should throw error for invalid xpub" ,
330+ ) ;
331+ } ) ;
332+
333+ it ( "should return false for xpub not in derivation path" , function ( ) {
334+ const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
335+ // Create a different xpub that's not in the wallet
336+ // Use a proper 32-byte seed (256 bits)
337+ const differentSeed = Buffer . alloc ( 32 , 0xaa ) ; // 32 bytes filled with 0xaa
338+ const differentKey = BIP32 . fromSeed ( differentSeed ) ;
339+ const differentXpub = differentKey . neutered ( ) ;
340+
341+ const result = psbt . verifySignature ( 0 , differentXpub ) ;
342+ assert . strictEqual (
343+ result ,
344+ false ,
345+ "Should return false for xpub not in PSBT derivation paths" ,
346+ ) ;
347+ } ) ;
348+
349+ it ( "should verify signature with raw public key (Uint8Array)" , function ( ) {
350+ const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
351+ // Find first wallet input (non-p2shP2pk) for xpub verification
352+ const walletInputIndex = fullsignedFixture . psbtInputs . findIndex (
353+ ( input ) => input . type !== "p2shP2pk" ,
354+ ) ;
355+ assert . ok ( walletInputIndex >= 0 , "Should have a wallet input" ) ;
356+
357+ // Verify that xpub-based verification works
358+ const userKey = rootWalletKeys . userKey ( ) ;
359+ const hasXpubSig = psbt . verifySignature ( walletInputIndex , userKey ) ;
360+
361+ // Use a random public key that's not in the PSBT to test the API works
362+ const randomSeed = Buffer . alloc ( 32 , 0xcc ) ;
363+ const randomKey = BIP32 . fromSeed ( randomSeed ) ;
364+ const randomPubkey = randomKey . publicKey ;
365+
366+ // This should return false (no signature for this key)
367+ const result = psbt . verifySignature ( walletInputIndex , randomPubkey ) ;
368+ assert . strictEqual ( result , false , "Should return false for public key not in PSBT" ) ;
369+
370+ // Verify the xpub check still works (regression test)
371+ assert . strictEqual ( hasXpubSig , true , "Should still verify with xpub" ) ;
372+ } ) ;
373+
374+ it ( "should return false for raw public key with no signature" , function ( ) {
375+ const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
376+ // Create a random public key that's not in the PSBT
377+ const randomSeed = Buffer . alloc ( 32 , 0xbb ) ;
378+ const randomKey = BIP32 . fromSeed ( randomSeed ) ;
379+ const randomPubkey = randomKey . publicKey ;
380+
381+ const result = psbt . verifySignature ( 0 , randomPubkey ) ;
382+ assert . strictEqual (
383+ result ,
384+ false ,
385+ "Should return false for public key not in PSBT signatures" ,
386+ ) ;
387+ } ) ;
388+
389+ it ( "should throw error for invalid key length" , function ( ) {
390+ const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
391+ const invalidKey = Buffer . alloc ( 31 ) ; // Invalid length (should be 32 for private key or 33 for public key)
392+
393+ assert . throws (
394+ ( ) => {
395+ psbt . verifySignature ( 0 , invalidKey ) ;
396+ } ,
397+ ( error : Error ) => {
398+ return error . message . includes ( "Invalid key length" ) ;
399+ } ,
400+ "Should throw error for invalid key length" ,
401+ ) ;
402+ } ) ;
403+ } ) ;
318404 } ) ;
319-
320- it ( "should throw error for invalid xpub" , function ( ) {
321- const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
322- assert . throws (
323- ( ) => {
324- psbt . verifySignature ( 0 , "invalid-xpub" ) ;
325- } ,
326- ( error : Error ) => {
327- return error . message . includes ( "Invalid" ) ;
328- } ,
329- "Should throw error for invalid xpub" ,
330- ) ;
331- } ) ;
332-
333- it ( "should return false for xpub not in derivation path" , function ( ) {
334- const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
335- // Create a different xpub that's not in the wallet
336- // Use a proper 32-byte seed (256 bits)
337- const differentSeed = Buffer . alloc ( 32 , 0xaa ) ; // 32 bytes filled with 0xaa
338- const differentKey = BIP32 . fromSeed ( differentSeed ) ;
339- const differentXpub = differentKey . neutered ( ) ;
340-
341- const result = psbt . verifySignature ( 0 , differentXpub ) ;
342- assert . strictEqual (
343- result ,
344- false ,
345- "Should return false for xpub not in PSBT derivation paths" ,
346- ) ;
347- } ) ;
348-
349- it ( "should verify signature with raw public key (Uint8Array)" , function ( ) {
350- const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
351- // Find first wallet input (non-p2shP2pk) for xpub verification
352- const walletInputIndex = fullsignedFixture . psbtInputs . findIndex (
353- ( input ) => input . type !== "p2shP2pk" ,
354- ) ;
355- assert . ok ( walletInputIndex >= 0 , "Should have a wallet input" ) ;
356-
357- // Verify that xpub-based verification works
358- const userKey = rootWalletKeys . userKey ( ) ;
359- const hasXpubSig = psbt . verifySignature ( walletInputIndex , userKey ) ;
360-
361- // Use a random public key that's not in the PSBT to test the API works
362- const randomSeed = Buffer . alloc ( 32 , 0xcc ) ;
363- const randomKey = BIP32 . fromSeed ( randomSeed ) ;
364- const randomPubkey = randomKey . publicKey ;
365-
366- // This should return false (no signature for this key)
367- const result = psbt . verifySignature ( walletInputIndex , randomPubkey ) ;
368- assert . strictEqual ( result , false , "Should return false for public key not in PSBT" ) ;
369-
370- // Verify the xpub check still works (regression test)
371- assert . strictEqual ( hasXpubSig , true , "Should still verify with xpub" ) ;
372- } ) ;
373-
374- it ( "should return false for raw public key with no signature" , function ( ) {
375- const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
376- // Create a random public key that's not in the PSBT
377- const randomSeed = Buffer . alloc ( 32 , 0xbb ) ;
378- const randomKey = BIP32 . fromSeed ( randomSeed ) ;
379- const randomPubkey = randomKey . publicKey ;
380-
381- const result = psbt . verifySignature ( 0 , randomPubkey ) ;
382- assert . strictEqual (
383- result ,
384- false ,
385- "Should return false for public key not in PSBT signatures" ,
386- ) ;
387- } ) ;
388-
389- it ( "should throw error for invalid key length" , function ( ) {
390- const psbt = getBitGoPsbt ( fullsignedFixture , networkName ) ;
391- const invalidKey = Buffer . alloc ( 31 ) ; // Invalid length (should be 32 for private key or 33 for public key)
392-
393- assert . throws (
394- ( ) => {
395- psbt . verifySignature ( 0 , invalidKey ) ;
396- } ,
397- ( error : Error ) => {
398- return error . message . includes ( "Invalid key length" ) ;
399- } ,
400- "Should throw error for invalid key length" ,
401- ) ;
402- } ) ;
403- } ) ;
404- } ) ;
405405 } ) ;
406406 } ) ;
407407} ) ;
0 commit comments