@@ -8,7 +8,6 @@ const types_1 = require('../types');
8
8
const taprootutils_1 = require ( './taprootutils' ) ;
9
9
const lazy = require ( './lazy' ) ;
10
10
const bech32_1 = require ( 'bech32' ) ;
11
- const verifyecc_1 = require ( './verifyecc' ) ;
12
11
const OPS = bscript . OPS ;
13
12
const TAPROOT_WITNESS_VERSION = 0x01 ;
14
13
const ANNEX_PREFIX = 0x50 ;
@@ -22,10 +21,10 @@ function p2tr(a, opts) {
22
21
)
23
22
throw new TypeError ( 'Not enough data' ) ;
24
23
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 ;
29
28
} ) ;
30
29
( 0 , types_1 . typeforce ) (
31
30
{
@@ -132,7 +131,7 @@ function p2tr(a, opts) {
132
131
if ( a . output ) return a . output . slice ( 2 ) ;
133
132
if ( a . address ) return _address ( ) . data ;
134
133
if ( o . internalPubkey ) {
135
- const tweakedKey = tweakKey ( o . internalPubkey , o . hash , _ecc ( ) ) ;
134
+ const tweakedKey = tweakKey ( o . internalPubkey , o . hash , _tweakFn ( ) ) ;
136
135
if ( tweakedKey ) return tweakedKey . x ;
137
136
}
138
137
} ) ;
@@ -157,7 +156,7 @@ function p2tr(a, opts) {
157
156
} ) ;
158
157
const path = ( 0 , taprootutils_1 . findScriptPath ) ( hashTree , leafHash ) ;
159
158
if ( ! path ) return ;
160
- const outputKey = tweakKey ( a . internalPubkey , hashTree . hash , _ecc ( ) ) ;
159
+ const outputKey = tweakKey ( a . internalPubkey , hashTree . hash , _tweakFn ( ) ) ;
161
160
if ( ! outputKey ) return ;
162
161
const controlBock = buffer_1 . Buffer . concat (
163
162
[
@@ -198,13 +197,13 @@ function p2tr(a, opts) {
198
197
else pubkey = a . output . slice ( 2 ) ;
199
198
}
200
199
if ( a . internalPubkey ) {
201
- const tweakedKey = tweakKey ( a . internalPubkey , o . hash , _ecc ( ) ) ;
200
+ const tweakedKey = tweakKey ( a . internalPubkey , o . hash , _tweakFn ( ) ) ;
202
201
if ( pubkey . length > 0 && ! pubkey . equals ( tweakedKey . x ) )
203
202
throw new TypeError ( 'Pubkey mismatch' ) ;
204
203
else pubkey = tweakedKey . x ;
205
204
}
206
205
if ( pubkey && pubkey . length ) {
207
- if ( ! _ecc ( ) . isXOnlyPoint ( pubkey ) )
206
+ if ( ! ( 0 , types_1 . isXOnlyPoint ) ( pubkey ) )
208
207
throw new TypeError ( 'Invalid pubkey for p2tr' ) ;
209
208
}
210
209
const hashTree = _hashTree ( ) ;
@@ -267,7 +266,7 @@ function p2tr(a, opts) {
267
266
const internalPubkey = controlBlock . slice ( 1 , 33 ) ;
268
267
if ( a . internalPubkey && ! a . internalPubkey . equals ( internalPubkey ) )
269
268
throw new TypeError ( 'Internal pubkey mismatch' ) ;
270
- if ( ! _ecc ( ) . isXOnlyPoint ( internalPubkey ) )
269
+ if ( ! ( 0 , types_1 . isXOnlyPoint ) ( internalPubkey ) )
271
270
throw new TypeError ( 'Invalid internalPubkey for p2tr witness' ) ;
272
271
const leafVersion = controlBlock [ 0 ] & types_1 . TAPLEAF_VERSION_MASK ;
273
272
const script = witness [ witness . length - 2 ] ;
@@ -279,7 +278,7 @@ function p2tr(a, opts) {
279
278
controlBlock ,
280
279
leafHash ,
281
280
) ;
282
- const outputKey = tweakKey ( internalPubkey , hash , _ecc ( ) ) ;
281
+ const outputKey = tweakKey ( internalPubkey , hash , _tweakFn ( ) ) ;
283
282
if ( ! outputKey )
284
283
// todo: needs test data
285
284
throw new TypeError ( 'Invalid outputKey for p2tr witness' ) ;
@@ -293,12 +292,12 @@ function p2tr(a, opts) {
293
292
return Object . assign ( o , a ) ;
294
293
}
295
294
exports . p2tr = p2tr ;
296
- function tweakKey ( pubKey , h , eccLib ) {
295
+ function tweakKey ( pubKey , h , tweakFn ) {
297
296
if ( ! buffer_1 . Buffer . isBuffer ( pubKey ) ) return null ;
298
297
if ( pubKey . length !== 32 ) return null ;
299
298
if ( h && h . length !== 32 ) return null ;
300
299
const tweakHash = ( 0 , taprootutils_1 . tapTweakHash ) ( pubKey , h ) ;
301
- const res = eccLib . xOnlyPointAddTweak ( pubKey , tweakHash ) ;
300
+ const res = tweakFn ( pubKey , tweakHash ) ;
302
301
if ( ! res || res . xOnlyPubkey === null ) return null ;
303
302
return {
304
303
parity : res . parity ,
@@ -311,3 +310,43 @@ function stacksEqual(a, b) {
311
310
return x . equals ( b [ i ] ) ;
312
311
} ) ;
313
312
}
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