Skip to content

Commit 9947571

Browse files
committed
refactor: split computeTweakFromScriptPath() into rootHash() and leafHash()`
1 parent af639f9 commit 9947571

File tree

5 files changed

+38
-51
lines changed

5 files changed

+38
-51
lines changed

src/payments/p2tr.js

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ function p2tr(a, opts) {
8585
if (a.output) return a.output.slice(2);
8686
if (a.address) return _address().data;
8787
if (o.internalPubkey) {
88-
const tweakedKey = (0, types_1.tweakPublicKey)(o.internalPubkey, o.hash);
88+
const tweakedKey = (0, types_1.tweakKey)(o.internalPubkey, o.hash);
8989
if (tweakedKey) return tweakedKey.x;
9090
}
9191
});
@@ -136,7 +136,7 @@ function p2tr(a, opts) {
136136
else pubkey = a.output.slice(2);
137137
}
138138
if (a.internalPubkey) {
139-
const tweakedKey = (0, types_1.tweakPublicKey)(a.internalPubkey, o.hash);
139+
const tweakedKey = (0, types_1.tweakKey)(a.internalPubkey, o.hash);
140140
if (tweakedKey === null)
141141
throw new TypeError('Invalid internalPubkey for p2tr');
142142
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
@@ -187,14 +187,9 @@ function p2tr(a, opts) {
187187
throw new TypeError('Invalid internalPubkey for p2tr witness');
188188
const leafVersion = controlBlock[0] & 0b11111110;
189189
const script = witness[witness.length - 2];
190-
const tweak = (0, types_1.computeTweakFromScriptPath)(
191-
controlBlock,
192-
script,
193-
internalPubkey,
194-
m,
195-
leafVersion,
196-
);
197-
const outputKey = (0, types_1.tweakPublicKey)(internalPubkey, tweak);
190+
const tapLeafHash = (0, types_1.leafHash)(script, leafVersion);
191+
const hash = (0, types_1.rootHash)(controlBlock, tapLeafHash);
192+
const outputKey = (0, types_1.tweakKey)(internalPubkey, hash);
198193
if (!outputKey)
199194
// todo: needs test data
200195
throw new TypeError('Invalid outputKey for p2tr witness');

src/types.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/// <reference types="node" />
2-
import { Buffer as NBuffer } from 'buffer';
32
export declare const typeforce: any;
43
export declare function isPoint(p: Buffer | number | undefined | null): boolean;
54
export declare function liftX(buffer: Buffer): Buffer | null;
6-
export declare function tweakPublicKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
7-
export declare function computeTweakFromScriptPath(controlBlock: Buffer, script: Buffer, internalPubkey: Buffer, m: number, v: number): NBuffer;
5+
export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
6+
export declare function leafHash(script: Buffer, version: number): Buffer;
7+
export declare function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
88
export declare function UInt31(value: number): boolean;
99
export declare function BIP32Path(value: string): boolean;
1010
export declare namespace BIP32Path {

src/types.js

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22
Object.defineProperty(exports, '__esModule', { value: true });
3-
exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.computeTweakFromScriptPath = exports.tweakPublicKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
3+
exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.rootHash = exports.leafHash = exports.tweakKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
44
const buffer_1 = require('buffer');
55
const bcrypto = require('./crypto');
66
const varuint = require('bip174/src/lib/converter/varint');
@@ -69,7 +69,7 @@ const GROUP_ORDER = buffer_1.Buffer.from(
6969
);
7070
// todo: compare buffers dirrectly
7171
const GROUP_ORDER_BN = new BN(GROUP_ORDER);
72-
function tweakPublicKey(pubKey, h) {
72+
function tweakKey(pubKey, h) {
7373
if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
7474
if (pubKey.length !== 32) return null;
7575
if (h && h.length !== 32) return null;
@@ -90,22 +90,20 @@ function tweakPublicKey(pubKey, h) {
9090
x: Q.slice(1, 33),
9191
};
9292
}
93-
exports.tweakPublicKey = tweakPublicKey;
93+
exports.tweakKey = tweakKey;
9494
const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
9595
const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
96-
function computeTweakFromScriptPath(
97-
controlBlock,
98-
script,
99-
internalPubkey,
100-
m,
101-
v,
102-
) {
103-
const k = [];
104-
const e = [];
105-
const tapLeafMsg = buffer_1.Buffer.concat([
106-
buffer_1.Buffer.from([v]),
96+
function leafHash(script, version) {
97+
return buffer_1.Buffer.concat([
98+
buffer_1.Buffer.from([version]),
10799
serializeScript(script),
108100
]);
101+
}
102+
exports.leafHash = leafHash;
103+
function rootHash(controlBlock, tapLeafMsg) {
104+
const k = [];
105+
const e = [];
106+
const m = (controlBlock.length - 33) / 32;
109107
k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
110108
for (let j = 0; j < m; j++) {
111109
e[j] = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
@@ -121,16 +119,9 @@ function computeTweakFromScriptPath(
121119
);
122120
}
123121
}
124-
const t = bcrypto.taggedHash(
125-
TAP_TWEAK_TAG,
126-
buffer_1.Buffer.concat([internalPubkey, k[m]]),
127-
);
128-
if (t.compare(GROUP_ORDER) >= 0) {
129-
throw new Error('Over the order of secp256k1');
130-
}
131-
return t;
122+
return k[m];
132123
}
133-
exports.computeTweakFromScriptPath = computeTweakFromScriptPath;
124+
exports.rootHash = rootHash;
134125
// todo: move out
135126
function serializeScript(s) {
136127
const varintLen = varuint.encodingLength(s.length);

ts_src/payments/p2tr.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { bitcoin as BITCOIN_NETWORK } from '../networks';
22
import * as bscript from '../script';
3-
import { liftX, tweakPublicKey, computeTweakFromScriptPath, typeforce as typef } from '../types';
3+
import { liftX, leafHash, rootHash, tweakKey, typeforce as typef } from '../types';
44
import { computeMastRoot } from '../merkle';
55
import { Payment, PaymentOpts } from './index';
66
import * as lazy from './lazy';
@@ -81,7 +81,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
8181
if (a.output) return a.output.slice(2)
8282
if (a.address) return _address().data;
8383
if (o.internalPubkey) {
84-
const tweakedKey = tweakPublicKey(o.internalPubkey, o.hash)
84+
const tweakedKey = tweakKey(o.internalPubkey, o.hash)
8585
if (tweakedKey) return tweakedKey.x
8686
}
8787
});
@@ -136,7 +136,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
136136
}
137137

138138
if (a.internalPubkey) {
139-
const tweakedKey = tweakPublicKey(a.internalPubkey, o.hash)
139+
const tweakedKey = tweakKey(a.internalPubkey, o.hash)
140140
if (tweakedKey === null) throw new TypeError('Invalid internalPubkey for p2tr');
141141
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
142142
throw new TypeError('Pubkey mismatch');
@@ -189,9 +189,11 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
189189

190190
const leafVersion = controlBlock[0] & 0b11111110;
191191
const script = witness[witness.length - 2];
192-
const tweak = computeTweakFromScriptPath(controlBlock, script, internalPubkey, m, leafVersion)
192+
193+
const tapLeafHash = leafHash(script, leafVersion)
194+
const hash = rootHash(controlBlock, tapLeafHash)
193195

194-
const outputKey = tweakPublicKey(internalPubkey, tweak)
196+
const outputKey = tweakKey(internalPubkey, hash)
195197
if (!outputKey)
196198
// todo: needs test data
197199
throw new TypeError('Invalid outputKey for p2tr witness');

ts_src/types.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ const GROUP_ORDER = NBuffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a0
7878
// todo: compare buffers dirrectly
7979
const GROUP_ORDER_BN = new BN(GROUP_ORDER);
8080

81-
export function tweakPublicKey(
81+
export function tweakKey(
8282
pubKey: Buffer,
8383
h: Buffer | undefined,
8484
): TweakedPublicKey | null {
@@ -109,14 +109,18 @@ export function tweakPublicKey(
109109
const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
110110
const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
111111

112-
export function computeTweakFromScriptPath(controlBlock: Buffer, script: Buffer, internalPubkey: Buffer, m: number, v: number) {
112+
113+
export function leafHash(script: Buffer, version: number): Buffer {
114+
return NBuffer.concat([NBuffer.from([version]), serializeScript(script)]);
115+
}
116+
117+
export function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
113118
const k = [];
114119
const e = [];
115120

116-
const tapLeafMsg = NBuffer.concat([NBuffer.from([v]), serializeScript(script)]);
121+
const m = (controlBlock.length - 33) / 32;
117122
k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
118123

119-
120124
for (let j = 0; j < m; j++) {
121125
e[j] = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
122126
if (k[j].compare(e[j]) < 0) {
@@ -126,12 +130,7 @@ export function computeTweakFromScriptPath(controlBlock: Buffer, script: Buffer,
126130
}
127131
}
128132

129-
const t = bcrypto.taggedHash(TAP_TWEAK_TAG, NBuffer.concat([internalPubkey, k[m]]));
130-
if (t.compare(GROUP_ORDER) >= 0) {
131-
throw new Error('Over the order of secp256k1')
132-
}
133-
134-
return t
133+
return k[m]
135134
}
136135

137136
// todo: move out

0 commit comments

Comments
 (0)