1+ import assert from "node:assert" ;
12import { BIP32Interface } from "@bitgo/utxo-lib" ;
23import { getKey } from "@bitgo/utxo-lib/dist/src/testutil" ;
34
@@ -10,6 +11,10 @@ function toKeyWithPath(k: BIP32Interface, path = "*"): string {
1011 return k . toBase58 ( ) + "/" + path ;
1112}
1213
14+ function toKeyPlain ( k : Buffer ) : string {
15+ return k . toString ( "hex" ) ;
16+ }
17+
1318const external = getKey ( "external" ) ;
1419const a = getKey ( "a" ) ;
1520const b = getKey ( "b" ) ;
@@ -27,6 +32,7 @@ function describeSignDescriptor(
2732 signSeqs : BIP32Interface [ ] [ ] ,
2833) {
2934 describe ( `psbt with descriptor ${ name } ` , function ( ) {
35+ const isTaproot = Object . keys ( descriptor ) [ 0 ] === "tr" ;
3036 const psbt = mockPsbtDefault ( {
3137 descriptorSelf : Descriptor . fromString ( formatNode ( descriptor ) , "derivable" ) ,
3238 descriptorOther : Descriptor . fromString (
@@ -35,14 +41,39 @@ function describeSignDescriptor(
3541 ) ,
3642 } ) ;
3743
44+ function getSigResult ( keys : BIP32Interface [ ] ) {
45+ return {
46+ [ isTaproot ? "Schnorr" : "Ecdsa" ] : keys . map ( ( key ) =>
47+ key . publicKey . subarray ( isTaproot ? 1 : 0 ) . toString ( "hex" ) ,
48+ ) ,
49+ } ;
50+ }
51+
3852 signSeqs . forEach ( ( signSeq , i ) => {
39- it ( `should sign ${ signSeq . map ( ( k ) => getKeyName ( k ) ) } ` , function ( ) {
53+ it ( `should sign ${ signSeq . map ( ( k ) => getKeyName ( k ) ) } xprv ` , function ( ) {
4054 const wrappedPsbt = toWrappedPsbt ( psbt ) ;
4155 signSeq . forEach ( ( key ) => {
42- wrappedPsbt . signWithXprv ( key . toBase58 ( ) ) ;
56+ assert . deepStrictEqual ( wrappedPsbt . signWithXprv ( key . toBase58 ( ) ) , {
57+ 0 : getSigResult ( [ key . derive ( 0 ) ] ) ,
58+ 1 : getSigResult ( [ key . derive ( 1 ) ] ) ,
59+ } ) ;
4360 } ) ;
4461 wrappedPsbt . finalize ( ) ;
4562 } ) ;
63+
64+ it ( `should sign ${ signSeq . map ( ( k ) => getKeyName ( k ) ) } prv buffer` , function ( ) {
65+ if ( isTaproot ) {
66+ // signing with non-bip32 taproot keys is not supported apparently
67+ this . skip ( ) ;
68+ }
69+ const wrappedPsbt = toWrappedPsbt ( psbt ) ;
70+ signSeq . forEach ( ( key ) => {
71+ assert . deepStrictEqual ( wrappedPsbt . signWithPrv ( key . derive ( 0 ) . privateKey ) , {
72+ 0 : getSigResult ( [ key . derive ( 0 ) ] ) ,
73+ 1 : getSigResult ( [ ] ) ,
74+ } ) ;
75+ } ) ;
76+ } ) ;
4677 } ) ;
4778 } ) ;
4879}
@@ -65,3 +96,18 @@ describeSignDescriptor(
6596 } ,
6697 [ [ a ] , [ b ] , [ c ] ] ,
6798) ;
99+
100+ // while we cannot sign with a derived plain xonly key, we can sign with an xprv
101+ describeSignDescriptor (
102+ "TrWithExternalPlain" ,
103+ {
104+ tr : [
105+ toKeyPlain ( external . publicKey ) ,
106+ [
107+ { pk : toKeyPlain ( external . publicKey ) } ,
108+ { or_b : [ { pk : toKeyPlain ( external . publicKey ) } , { "s:pk" : toKeyWithPath ( a ) } ] } ,
109+ ] ,
110+ ] ,
111+ } ,
112+ [ [ a ] ] ,
113+ ) ;
0 commit comments