@@ -8,7 +8,6 @@ const types_1 = require('../types');
88const taprootutils_1 = require ( './taprootutils' ) ;
99const lazy = require ( './lazy' ) ;
1010const bech32_1 = require ( 'bech32' ) ;
11- const verifyecc_1 = require ( './verifyecc' ) ;
1211const OPS = bscript . OPS ;
1312const TAPROOT_WITNESS_VERSION = 0x01 ;
1413const ANNEX_PREFIX = 0x50 ;
@@ -22,10 +21,10 @@ function p2tr(a, opts) {
2221 )
2322 throw new TypeError ( 'Not enough data' ) ;
2423 opts = Object . assign ( { validate : true } , opts || { } ) ;
25- const _ecc = lazy . value ( ( ) => {
26- if ( ! opts . eccLib ) throw new Error ( 'ECC Library is missing for p2tr.' ) ;
27- ( 0 , verifyecc_1 . verifyEcc ) ( opts . eccLib ) ;
28- return opts . eccLib ;
24+ const _tweakFn = lazy . value ( ( ) => {
25+ if ( ! opts . tweakFn ) throw new Error ( 'Tweak function is missing for p2tr.' ) ;
26+ verifyTweakFn ( opts . tweakFn ) ;
27+ return opts . tweakFn ;
2928 } ) ;
3029 ( 0 , types_1 . typeforce ) (
3130 {
@@ -132,7 +131,7 @@ function p2tr(a, opts) {
132131 if ( a . output ) return a . output . slice ( 2 ) ;
133132 if ( a . address ) return _address ( ) . data ;
134133 if ( o . internalPubkey ) {
135- const tweakedKey = tweakKey ( o . internalPubkey , o . hash , _ecc ( ) ) ;
134+ const tweakedKey = tweakKey ( o . internalPubkey , o . hash , _tweakFn ( ) ) ;
136135 if ( tweakedKey ) return tweakedKey . x ;
137136 }
138137 } ) ;
@@ -157,7 +156,7 @@ function p2tr(a, opts) {
157156 } ) ;
158157 const path = ( 0 , taprootutils_1 . findScriptPath ) ( hashTree , leafHash ) ;
159158 if ( ! path ) return ;
160- const outputKey = tweakKey ( a . internalPubkey , hashTree . hash , _ecc ( ) ) ;
159+ const outputKey = tweakKey ( a . internalPubkey , hashTree . hash , _tweakFn ( ) ) ;
161160 if ( ! outputKey ) return ;
162161 const controlBock = buffer_1 . Buffer . concat (
163162 [
@@ -198,13 +197,13 @@ function p2tr(a, opts) {
198197 else pubkey = a . output . slice ( 2 ) ;
199198 }
200199 if ( a . internalPubkey ) {
201- const tweakedKey = tweakKey ( a . internalPubkey , o . hash , _ecc ( ) ) ;
200+ const tweakedKey = tweakKey ( a . internalPubkey , o . hash , _tweakFn ( ) ) ;
202201 if ( pubkey . length > 0 && ! pubkey . equals ( tweakedKey . x ) )
203202 throw new TypeError ( 'Pubkey mismatch' ) ;
204203 else pubkey = tweakedKey . x ;
205204 }
206205 if ( pubkey && pubkey . length ) {
207- if ( ! _ecc ( ) . isXOnlyPoint ( pubkey ) )
206+ if ( ! ( 0 , types_1 . isXOnlyPoint ) ( pubkey ) )
208207 throw new TypeError ( 'Invalid pubkey for p2tr' ) ;
209208 }
210209 const hashTree = _hashTree ( ) ;
@@ -267,7 +266,7 @@ function p2tr(a, opts) {
267266 const internalPubkey = controlBlock . slice ( 1 , 33 ) ;
268267 if ( a . internalPubkey && ! a . internalPubkey . equals ( internalPubkey ) )
269268 throw new TypeError ( 'Internal pubkey mismatch' ) ;
270- if ( ! _ecc ( ) . isXOnlyPoint ( internalPubkey ) )
269+ if ( ! ( 0 , types_1 . isXOnlyPoint ) ( internalPubkey ) )
271270 throw new TypeError ( 'Invalid internalPubkey for p2tr witness' ) ;
272271 const leafVersion = controlBlock [ 0 ] & types_1 . TAPLEAF_VERSION_MASK ;
273272 const script = witness [ witness . length - 2 ] ;
@@ -279,7 +278,7 @@ function p2tr(a, opts) {
279278 controlBlock ,
280279 leafHash ,
281280 ) ;
282- const outputKey = tweakKey ( internalPubkey , hash , _ecc ( ) ) ;
281+ const outputKey = tweakKey ( internalPubkey , hash , _tweakFn ( ) ) ;
283282 if ( ! outputKey )
284283 // todo: needs test data
285284 throw new TypeError ( 'Invalid outputKey for p2tr witness' ) ;
@@ -293,12 +292,12 @@ function p2tr(a, opts) {
293292 return Object . assign ( o , a ) ;
294293}
295294exports . p2tr = p2tr ;
296- function tweakKey ( pubKey , h , eccLib ) {
295+ function tweakKey ( pubKey , h , tweakFn ) {
297296 if ( ! buffer_1 . Buffer . isBuffer ( pubKey ) ) return null ;
298297 if ( pubKey . length !== 32 ) return null ;
299298 if ( h && h . length !== 32 ) return null ;
300299 const tweakHash = ( 0 , taprootutils_1 . tapTweakHash ) ( pubKey , h ) ;
301- const res = eccLib . xOnlyPointAddTweak ( pubKey , tweakHash ) ;
300+ const res = tweakFn ( pubKey , tweakHash ) ;
302301 if ( ! res || res . xOnlyPubkey === null ) return null ;
303302 return {
304303 parity : res . parity ,
@@ -311,3 +310,43 @@ function stacksEqual(a, b) {
311310 return x . equals ( b [ i ] ) ;
312311 } ) ;
313312}
313+ function verifyTweakFn ( tweakFn ) {
314+ [
315+ {
316+ pubkey :
317+ '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' ,
318+ tweak : 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140' ,
319+ parity : - 1 ,
320+ result : null ,
321+ } ,
322+ {
323+ pubkey :
324+ '1617d38ed8d8657da4d4761e8057bc396ea9e4b9d29776d4be096016dbd2509b' ,
325+ tweak : 'a8397a935f0dfceba6ba9618f6451ef4d80637abf4e6af2669fbc9de6a8fd2ac' ,
326+ parity : 1 ,
327+ result :
328+ 'e478f99dab91052ab39a33ea35fd5e6e4933f4d28023cd597c9a1f6760346adf' ,
329+ } ,
330+ {
331+ pubkey :
332+ '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991' ,
333+ tweak : '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47' ,
334+ parity : 0 ,
335+ result :
336+ '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c' ,
337+ } ,
338+ ] . forEach ( t => {
339+ const r = tweakFn (
340+ Buffer . from ( t . pubkey , 'hex' ) ,
341+ Buffer . from ( t . tweak , 'hex' ) ,
342+ ) ;
343+ if ( t . result === null ) {
344+ if ( r !== null ) throw new Error ( 'Expected failed tweak' ) ;
345+ } else {
346+ if ( r === null ) throw new Error ( 'Expected successful tweak' ) ;
347+ if ( r . parity !== t . parity ) throw new Error ( 'Tweaked key parity mismatch' ) ;
348+ if ( ! Buffer . from ( r . xOnlyPubkey ) . equals ( Buffer . from ( t . result , 'hex' ) ) )
349+ throw new Error ( 'Tweaked key mismatch' ) ;
350+ }
351+ } ) ;
352+ }
0 commit comments