Skip to content

Commit 4fd164e

Browse files
committed
refactor: move tweakKey() to taproot utils
1 parent 6f70c88 commit 4fd164e

File tree

5 files changed

+74
-63
lines changed

5 files changed

+74
-63
lines changed

src/payments/p2tr.js

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function p2tr(a, opts) {
127127
if (a.output) return a.output.slice(2);
128128
if (a.address) return _address().data;
129129
if (o.internalPubkey) {
130-
const tweakedKey = tweakKey(o.internalPubkey, o.hash);
130+
const tweakedKey = (0, taprootutils_1.tweakKey)(o.internalPubkey, o.hash);
131131
if (tweakedKey) return tweakedKey.x;
132132
}
133133
});
@@ -152,7 +152,10 @@ function p2tr(a, opts) {
152152
});
153153
const path = (0, taprootutils_1.findScriptPath)(hashTree, leafHash);
154154
if (!path) return;
155-
const outputKey = tweakKey(a.internalPubkey, hashTree.hash);
155+
const outputKey = (0, taprootutils_1.tweakKey)(
156+
a.internalPubkey,
157+
hashTree.hash,
158+
);
156159
if (!outputKey) return;
157160
const controlBock = buffer_1.Buffer.concat(
158161
[
@@ -193,7 +196,7 @@ function p2tr(a, opts) {
193196
else pubkey = a.output.slice(2);
194197
}
195198
if (a.internalPubkey) {
196-
const tweakedKey = tweakKey(a.internalPubkey, o.hash);
199+
const tweakedKey = (0, taprootutils_1.tweakKey)(a.internalPubkey, o.hash);
197200
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
198201
throw new TypeError('Pubkey mismatch');
199202
else pubkey = tweakedKey.x;
@@ -274,7 +277,7 @@ function p2tr(a, opts) {
274277
controlBlock,
275278
leafHash,
276279
);
277-
const outputKey = tweakKey(internalPubkey, hash);
280+
const outputKey = (0, taprootutils_1.tweakKey)(internalPubkey, hash);
278281
if (!outputKey)
279282
// todo: needs test data
280283
throw new TypeError('Invalid outputKey for p2tr witness');
@@ -288,18 +291,6 @@ function p2tr(a, opts) {
288291
return Object.assign(o, a);
289292
}
290293
exports.p2tr = p2tr;
291-
function tweakKey(pubKey, h) {
292-
if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
293-
if (pubKey.length !== 32) return null;
294-
if (h && h.length !== 32) return null;
295-
const tweakHash = (0, taprootutils_1.tapTweakHash)(pubKey, h);
296-
const res = (0, ecc_lib_1.getEccLib)().xOnlyPointAddTweak(pubKey, tweakHash);
297-
if (!res || res.xOnlyPubkey === null) return null;
298-
return {
299-
parity: res.parity,
300-
x: buffer_1.Buffer.from(res.xOnlyPubkey),
301-
};
302-
}
303294
function stacksEqual(a, b) {
304295
if (a.length !== b.length) return false;
305296
return a.every((x, i) => {

src/payments/taprootutils.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/// <reference types="node" />
22
import { Tapleaf, Taptree } from '../types';
33
export declare const LEAF_VERSION_TAPSCRIPT = 192;
4-
export declare function rootHashFromPath(controlBlock: Buffer, leafHash: Buffer): Buffer;
54
interface HashLeaf {
65
hash: Buffer;
76
}
@@ -10,13 +9,18 @@ interface HashBranch {
109
left: HashTree;
1110
right: HashTree;
1211
}
12+
interface TweakedPublicKey {
13+
parity: number;
14+
x: Buffer;
15+
}
1316
/**
1417
* Binary tree representing leaf, branch, and root node hashes of a Taptree.
1518
* Each node contains a hash, and potentially left and right branch hashes.
1619
* This tree is used for 2 purposes: Providing the root hash for tweaking,
1720
* and calculating merkle inclusion proofs when constructing a control block.
1821
*/
1922
export declare type HashTree = HashLeaf | HashBranch;
23+
export declare function rootHashFromPath(controlBlock: Buffer, leafHash: Buffer): Buffer;
2024
/**
2125
* Build a hash tree of merkle nodes from the scripts binary tree.
2226
* @param scriptTree - the tree of scripts to pairwise hash.
@@ -33,4 +37,5 @@ export declare function toHashTree(scriptTree: Taptree): HashTree;
3337
export declare function findScriptPath(node: HashTree, hash: Buffer): Buffer[] | undefined;
3438
export declare function tapleafHash(leaf: Tapleaf): Buffer;
3539
export declare function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer;
40+
export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
3641
export {};

src/payments/taprootutils.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
'use strict';
22
Object.defineProperty(exports, '__esModule', { value: true });
3-
exports.tapTweakHash = exports.tapleafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = void 0;
3+
exports.tweakKey = exports.tapTweakHash = exports.tapleafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = void 0;
44
const buffer_1 = require('buffer');
5+
const ecc_lib_1 = require('../ecc_lib');
56
const bcrypto = require('../crypto');
67
const bufferutils_1 = require('../bufferutils');
78
const types_1 = require('../types');
89
exports.LEAF_VERSION_TAPSCRIPT = 0xc0;
10+
const isHashBranch = ht => 'left' in ht && 'right' in ht;
911
function rootHashFromPath(controlBlock, leafHash) {
1012
const m = (controlBlock.length - 33) / 32;
1113
let kj = leafHash;
@@ -20,7 +22,6 @@ function rootHashFromPath(controlBlock, leafHash) {
2022
return kj;
2123
}
2224
exports.rootHashFromPath = rootHashFromPath;
23-
const isHashBranch = ht => 'left' in ht && 'right' in ht;
2425
/**
2526
* Build a hash tree of merkle nodes from the scripts binary tree.
2627
* @param scriptTree - the tree of scripts to pairwise hash.
@@ -76,6 +77,19 @@ function tapTweakHash(pubKey, h) {
7677
);
7778
}
7879
exports.tapTweakHash = tapTweakHash;
80+
function tweakKey(pubKey, h) {
81+
if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
82+
if (pubKey.length !== 32) return null;
83+
if (h && h.length !== 32) return null;
84+
const tweakHash = tapTweakHash(pubKey, h);
85+
const res = (0, ecc_lib_1.getEccLib)().xOnlyPointAddTweak(pubKey, tweakHash);
86+
if (!res || res.xOnlyPubkey === null) return null;
87+
return {
88+
parity: res.parity,
89+
x: buffer_1.Buffer.from(res.xOnlyPubkey),
90+
};
91+
}
92+
exports.tweakKey = tweakKey;
7993
function tapBranchHash(a, b) {
8094
return bcrypto.taggedHash('TapBranch', buffer_1.Buffer.concat([a, b]));
8195
}

ts_src/payments/p2tr.ts

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
rootHashFromPath,
99
findScriptPath,
1010
tapleafHash,
11-
tapTweakHash,
11+
tweakKey,
1212
LEAF_VERSION_TAPSCRIPT,
1313
} from './taprootutils';
1414
import { Payment, PaymentOpts } from './index';
@@ -316,30 +316,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
316316
return Object.assign(o, a);
317317
}
318318

319-
interface TweakedPublicKey {
320-
parity: number;
321-
x: Buffer;
322-
}
323-
324-
function tweakKey(
325-
pubKey: Buffer,
326-
h: Buffer | undefined,
327-
): TweakedPublicKey | null {
328-
if (!NBuffer.isBuffer(pubKey)) return null;
329-
if (pubKey.length !== 32) return null;
330-
if (h && h.length !== 32) return null;
331-
332-
const tweakHash = tapTweakHash(pubKey, h);
333-
334-
const res = getEccLib().xOnlyPointAddTweak(pubKey, tweakHash);
335-
if (!res || res.xOnlyPubkey === null) return null;
336-
337-
return {
338-
parity: res.parity,
339-
x: NBuffer.from(res.xOnlyPubkey),
340-
};
341-
}
342-
343319
function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
344320
if (a.length !== b.length) return false;
345321

ts_src/payments/taprootutils.ts

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,12 @@
11
import { Buffer as NBuffer } from 'buffer';
2+
import { getEccLib } from '../ecc_lib';
23
import * as bcrypto from '../crypto';
34

45
import { varuint } from '../bufferutils';
56
import { Tapleaf, Taptree, isTapleaf } from '../types';
67

78
export const LEAF_VERSION_TAPSCRIPT = 0xc0;
89

9-
export function rootHashFromPath(
10-
controlBlock: Buffer,
11-
leafHash: Buffer,
12-
): Buffer {
13-
const m = (controlBlock.length - 33) / 32;
14-
15-
let kj = leafHash;
16-
for (let j = 0; j < m; j++) {
17-
const ej = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
18-
if (kj.compare(ej) < 0) {
19-
kj = tapBranchHash(kj, ej);
20-
} else {
21-
kj = tapBranchHash(ej, kj);
22-
}
23-
}
24-
25-
return kj;
26-
}
27-
2810
interface HashLeaf {
2911
hash: Buffer;
3012
}
@@ -35,6 +17,11 @@ interface HashBranch {
3517
right: HashTree;
3618
}
3719

20+
interface TweakedPublicKey {
21+
parity: number;
22+
x: Buffer;
23+
}
24+
3825
const isHashBranch = (ht: HashTree): ht is HashBranch =>
3926
'left' in ht && 'right' in ht;
4027

@@ -46,6 +33,25 @@ const isHashBranch = (ht: HashTree): ht is HashBranch =>
4633
*/
4734
export type HashTree = HashLeaf | HashBranch;
4835

36+
export function rootHashFromPath(
37+
controlBlock: Buffer,
38+
leafHash: Buffer,
39+
): Buffer {
40+
const m = (controlBlock.length - 33) / 32;
41+
42+
let kj = leafHash;
43+
for (let j = 0; j < m; j++) {
44+
const ej = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
45+
if (kj.compare(ej) < 0) {
46+
kj = tapBranchHash(kj, ej);
47+
} else {
48+
kj = tapBranchHash(ej, kj);
49+
}
50+
}
51+
52+
return kj;
53+
}
54+
4955
/**
5056
* Build a hash tree of merkle nodes from the scripts binary tree.
5157
* @param scriptTree - the tree of scripts to pairwise hash.
@@ -104,6 +110,25 @@ export function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer {
104110
);
105111
}
106112

113+
export function tweakKey(
114+
pubKey: Buffer,
115+
h: Buffer | undefined,
116+
): TweakedPublicKey | null {
117+
if (!NBuffer.isBuffer(pubKey)) return null;
118+
if (pubKey.length !== 32) return null;
119+
if (h && h.length !== 32) return null;
120+
121+
const tweakHash = tapTweakHash(pubKey, h);
122+
123+
const res = getEccLib().xOnlyPointAddTweak(pubKey, tweakHash);
124+
if (!res || res.xOnlyPubkey === null) return null;
125+
126+
return {
127+
parity: res.parity,
128+
x: NBuffer.from(res.xOnlyPubkey),
129+
};
130+
}
131+
107132
function tapBranchHash(a: Buffer, b: Buffer): Buffer {
108133
return bcrypto.taggedHash('TapBranch', NBuffer.concat([a, b]));
109134
}

0 commit comments

Comments
 (0)