Skip to content

Commit 2a4e64b

Browse files
committed
tests: add bib341 tests by @sipa; plus refactoring
1 parent 2f55aad commit 2a4e64b

File tree

11 files changed

+236
-67
lines changed

11 files changed

+236
-67
lines changed

src/payments/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference types="node" />
22
import { Network } from '../networks';
3+
import { TaprootLeaf } from '../types';
34
import { p2data as embed } from './embed';
45
import { p2ms } from './p2ms';
56
import { p2pk } from './p2pk';
@@ -25,6 +26,7 @@ export interface Payment {
2526
hash?: Buffer;
2627
redeem?: Payment;
2728
scriptsTree?: any;
29+
scriptLeaf?: TaprootLeaf;
2830
witness?: Buffer[];
2931
}
3032
export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;

src/payments/p2tr.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ function p2tr(a, opts) {
3838
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
3939
),
4040
// scriptsTree: typef.maybe(typef.TaprootNode), // use merkel.isMast ?
41+
scriptLeaf: types_1.typeforce.maybe({
42+
version: types_1.typeforce.maybe(types_1.typeforce.Number),
43+
output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
44+
}),
4145
},
4246
a,
4347
);
@@ -87,6 +91,9 @@ function p2tr(a, opts) {
8791
if (!o.pubkey) return;
8892
return bscript.compile([OPS.OP_1, o.pubkey]);
8993
});
94+
lazy.prop(o, 'scriptLeaf', () => {
95+
if (!a.scriptLeaf) return a.scriptLeaf;
96+
});
9097
lazy.prop(o, 'pubkey', () => {
9198
if (a.pubkey) return a.pubkey;
9299
if (a.output) return a.output.slice(2);
@@ -107,7 +114,7 @@ function p2tr(a, opts) {
107114
return a.witness[0];
108115
});
109116
lazy.prop(o, 'input', () => {
110-
// todo: not sure
117+
// todo
111118
});
112119
lazy.prop(o, 'witness', () => {
113120
if (a.witness) return a.witness;
@@ -158,7 +165,6 @@ function p2tr(a, opts) {
158165
const hash = (0, taproot_1.rootHashFromTree)(a.scriptsTree);
159166
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
160167
}
161-
// todo: review cache
162168
const witness = _witness();
163169
if (witness && witness.length) {
164170
if (witness.length === 1) {

src/taproot.d.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
/// <reference types="node" />
2-
import { TweakedPublicKey } from './types';
2+
import { TweakedPublicKey, TaprootLeaf } from './types';
33
export declare function liftX(buffer: Buffer): Buffer | null;
44
export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
55
export declare function leafHash(script: Buffer, version: number): Buffer;
66
export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
7-
export declare function rootHashFromTree(scripts: any): Buffer;
7+
export interface HashTree {
8+
rootHash: Buffer;
9+
scritptPath?: Buffer;
10+
}
11+
export declare function rootHashFromTree(scripts: TaprootLeaf[]): Buffer;

src/taproot.js

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ function tweakKey(pubKey, h) {
5252
);
5353
if (tweakHash.compare(types_1.GROUP_ORDER) >= 0) {
5454
// todo: add test for this case
55-
throw new Error('Tweak value over the SECP256K1 Order');
55+
throw new TypeError('Tweak value over the SECP256K1 Order');
5656
}
5757
const P = liftX(pubKey);
5858
if (P === null) return null;
@@ -64,17 +64,19 @@ function tweakKey(pubKey, h) {
6464
}
6565
exports.tweakKey = tweakKey;
6666
function leafHash(script, version) {
67-
return buffer_1.Buffer.concat([
68-
buffer_1.Buffer.from([version]),
69-
serializeScript(script),
70-
]);
67+
return bcrypto.taggedHash(
68+
TAP_LEAF_TAG,
69+
buffer_1.Buffer.concat([
70+
buffer_1.Buffer.from([version]),
71+
serializeScript(script),
72+
]),
73+
);
7174
}
7275
exports.leafHash = leafHash;
7376
function rootHashFromPath(controlBlock, tapLeafMsg) {
74-
const k = [];
77+
const k = [tapLeafMsg];
7578
const e = [];
7679
const m = (controlBlock.length - 33) / 32;
77-
k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
7880
for (let j = 0; j < m; j++) {
7981
e[j] = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
8082
if (k[j].compare(e[j]) < 0) {
@@ -92,24 +94,16 @@ function rootHashFromPath(controlBlock, tapLeafMsg) {
9294
return k[m];
9395
}
9496
exports.rootHashFromPath = rootHashFromPath;
95-
// todo: solve any[]
9697
function rootHashFromTree(scripts) {
9798
if (scripts.length === 1) {
9899
const script = scripts[0];
99100
if (Array.isArray(script)) {
100101
return rootHashFromTree(script);
101102
}
102103
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
103-
if ((script.version & 1) !== 0) throw new Error('Invalid script version'); // todo typedef error
104-
// todo: if (script.output)scheck is bytes
105-
const scriptOutput = buffer_1.Buffer.from(script.output, 'hex');
106-
return bcrypto.taggedHash(
107-
TAP_LEAF_TAG,
108-
buffer_1.Buffer.concat([
109-
buffer_1.Buffer.from([script.version]),
110-
serializeScript(scriptOutput),
111-
]),
112-
);
104+
if ((script.version & 1) !== 0)
105+
throw new TypeError('Invalid script version');
106+
return leafHash(script.output, script.version);
113107
}
114108
// todo: this is a binary tree, use zero an one index
115109
const half = Math.trunc(scripts.length / 2);

src/types.d.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ export interface TweakedPublicKey {
1818
isOdd: boolean;
1919
x: Buffer;
2020
}
21-
export declare const TaprootLeaf: any;
22-
export declare const TaprootNode: any;
21+
export interface TaprootLeaf {
22+
output: Buffer;
23+
version?: number;
24+
}
2325
export declare const Buffer256bit: any;
2426
export declare const Hash160bit: any;
2527
export declare const Hash256bit: any;

src/types.js

Lines changed: 1 addition & 12 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.isPoint = exports.GROUP_ORDER = exports.EC_P = exports.ZERO32 = 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.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.GROUP_ORDER = exports.EC_P = exports.ZERO32 = exports.typeforce = void 0;
44
const buffer_1 = require('buffer');
55
exports.typeforce = require('typeforce');
66
exports.ZERO32 = buffer_1.Buffer.alloc(32, 0);
@@ -72,17 +72,6 @@ exports.Network = exports.typeforce.compile({
7272
scriptHash: exports.typeforce.UInt8,
7373
wif: exports.typeforce.UInt8,
7474
});
75-
exports.TaprootLeaf = exports.typeforce.compile({
76-
output: exports.typeforce.BufferN(34),
77-
version: exports.typeforce.maybe(exports.typeforce.UInt8), // todo: recheck
78-
});
79-
// / todo: revisit
80-
exports.TaprootNode = exports.typeforce.arrayOf(
81-
exports.typeforce.oneOf(
82-
exports.TaprootLeaf,
83-
exports.typeforce.arrayOf(exports.TaprootLeaf),
84-
),
85-
);
8675
exports.Buffer256bit = exports.typeforce.BufferN(32);
8776
exports.Hash160bit = exports.typeforce.BufferN(20);
8877
exports.Hash256bit = exports.typeforce.BufferN(32);

test/fixtures/p2tr.json

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,182 @@
354354
"input": null,
355355
"witness": null
356356
}
357+
},
358+
{
359+
"description": "BIP341 Test case 1",
360+
"arguments": {
361+
"internalPubkey": "d6889cb081036e0faefa3a35157ad71086b123b2b144b649798b494c300a961d"
362+
},
363+
"options": {},
364+
"expected": {
365+
"name": "p2tr",
366+
"output": "OP_1 53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
367+
"pubkey": "53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
368+
"address": "bc1p2wsldez5mud2yam29q22wgfh9439spgduvct83k3pm50fcxa5dps59h4z5",
369+
"signature": null,
370+
"input": null,
371+
"witness": null
372+
}
373+
},
374+
{
375+
"description": "BIP341 Test case 2",
376+
"arguments": {
377+
"internalPubkey": "187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27",
378+
"scriptsTree": [
379+
{
380+
"output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
381+
"version": 192
382+
}
383+
]
384+
},
385+
"options": {},
386+
"expected": {
387+
"name": "p2tr",
388+
"output": "OP_1 147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
389+
"pubkey": "147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
390+
"address": "bc1pz37fc4cn9ah8anwm4xqqhvxygjf9rjf2resrw8h8w4tmvcs0863sa2e586",
391+
"hash": "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21",
392+
"signature": null,
393+
"input": null
394+
}
395+
},
396+
{
397+
"description": "BIP341 Test case 3",
398+
"arguments": {
399+
"internalPubkey": "93478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820",
400+
"scriptsTree": [
401+
{
402+
"output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
403+
"version": 192
404+
}
405+
]
406+
},
407+
"options": {},
408+
"expected": {
409+
"name": "p2tr",
410+
"output": "OP_1 e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
411+
"pubkey": "e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
412+
"address": "bc1punvppl2stp38f7kwv2u2spltjuvuaayuqsthe34hd2dyy5w4g58qqfuag5",
413+
"hash": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
414+
"signature": null,
415+
"input": null
416+
}
417+
},
418+
{
419+
"description": "BIP341 Test case 4",
420+
"arguments": {
421+
"internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
422+
"scriptsTree": [
423+
{
424+
"output": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG",
425+
"version": 192
426+
},
427+
{
428+
"output": "424950333431",
429+
"version": 152
430+
}
431+
]
432+
},
433+
"options": {},
434+
"expected": {
435+
"name": "p2tr",
436+
"output": "OP_1 0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561",
437+
"pubkey": "0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561",
438+
"address": "bc1ppa3u5trk8xumkjlqgewvp237u79qwcd6ta0h6mlca2e5puya54ssw9zq0y",
439+
"hash": "f3004d6c183e038105d436db1424f321613366cbb7b05939bf05d763a9ebb962",
440+
"signature": null,
441+
"input": null
442+
}
443+
},
444+
{
445+
"description": "BIP341 Test case 5",
446+
"arguments": {
447+
"internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8",
448+
"scriptsTree": [
449+
{
450+
"output": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG",
451+
"version": 192
452+
},
453+
{
454+
"output": "546170726f6f74",
455+
"version": 82
456+
}
457+
]
458+
},
459+
"options": {},
460+
"expected": {
461+
"name": "p2tr",
462+
"output": "OP_1 053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587",
463+
"pubkey": "053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587",
464+
"address": "bc1pq5mfpw474wahs5xr9m4dpt8cm7vsemte7733udv040extz6tckrs29g04c",
465+
"hash": "d9c2c32808b41c0301d876d49c0af72e1d98e84b99ca9b4bb67fea1a7424b755",
466+
"signature": null,
467+
"input": null
468+
}
469+
},
470+
{
471+
"description": "BIP341 Test case 6",
472+
"arguments": {
473+
"internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
474+
"scriptsTree": [
475+
{
476+
"output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG",
477+
"version": 192
478+
},
479+
[
480+
{
481+
"output": "2352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8 OP_CHECKSIG",
482+
"version": 192
483+
},
484+
{
485+
"output": "7337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186a OP_CHECKSIG",
486+
"version": 192
487+
}
488+
]
489+
]
490+
},
491+
"options": {},
492+
"expected": {
493+
"name": "p2tr",
494+
"output": "OP_1 91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
495+
"pubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
496+
"address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e",
497+
"hash": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
498+
"signature": null,
499+
"input": null
500+
}
501+
},
502+
{
503+
"description": "BIP341 Test case 7",
504+
"arguments": {
505+
"internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
506+
"scriptsTree": [
507+
{
508+
"output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
509+
"version": 192
510+
},
511+
[
512+
{
513+
"output": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG",
514+
"version": 192
515+
},
516+
{
517+
"output": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG",
518+
"version": 192
519+
}
520+
]
521+
]
522+
},
523+
"options": {},
524+
"expected": {
525+
"name": "p2tr",
526+
"output": "OP_1 75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
527+
"pubkey": "75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
528+
"address": "bc1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcssyuewe",
529+
"hash": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
530+
"signature": null,
531+
"input": null
532+
}
357533
}
358534
],
359535
"invalid": [

ts_src/payments/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Network } from '../networks';
2+
import { TaprootLeaf } from '../types';
23
import { p2data as embed } from './embed';
34
import { p2ms } from './p2ms';
45
import { p2pk } from './p2pk';
@@ -23,8 +24,9 @@ export interface Payment {
2324
signature?: Buffer;
2425
address?: string; // taproot: betch32m
2526
hash?: Buffer; // taproot: MAST root
26-
redeem?: Payment; // taproot: when script path spending is used spending
27+
redeem?: Payment;
2728
scriptsTree?: any; // todo: solve
29+
scriptLeaf?: TaprootLeaf;
2830
witness?: Buffer[];
2931
}
3032

0 commit comments

Comments
 (0)