@vbyte/btc-dev 1.1.8 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +260 -3
  3. package/dist/const.d.ts +3 -0
  4. package/dist/const.js +23 -22
  5. package/dist/index.d.ts +11 -11
  6. package/dist/index.js +10 -10
  7. package/dist/lib/address/api.d.ts +2 -2
  8. package/dist/lib/address/api.js +12 -12
  9. package/dist/lib/address/encode.d.ts +1 -1
  10. package/dist/lib/address/encode.js +24 -24
  11. package/dist/lib/address/index.d.ts +6 -6
  12. package/dist/lib/address/index.js +6 -6
  13. package/dist/lib/address/p2pkh.d.ts +2 -2
  14. package/dist/lib/address/p2pkh.js +14 -14
  15. package/dist/lib/address/p2sh.d.ts +2 -2
  16. package/dist/lib/address/p2sh.js +13 -13
  17. package/dist/lib/address/p2tr.d.ts +2 -2
  18. package/dist/lib/address/p2tr.js +13 -13
  19. package/dist/lib/address/p2wpkh.d.ts +2 -2
  20. package/dist/lib/address/p2wpkh.js +14 -14
  21. package/dist/lib/address/p2wsh.d.ts +2 -2
  22. package/dist/lib/address/p2wsh.js +13 -13
  23. package/dist/lib/address/script.d.ts +1 -1
  24. package/dist/lib/address/script.js +16 -16
  25. package/dist/lib/address/util.d.ts +1 -1
  26. package/dist/lib/address/util.js +22 -22
  27. package/dist/lib/meta/index.d.ts +4 -4
  28. package/dist/lib/meta/index.js +4 -4
  29. package/dist/lib/meta/locktime.d.ts +1 -1
  30. package/dist/lib/meta/locktime.js +12 -12
  31. package/dist/lib/meta/ref.js +9 -6
  32. package/dist/lib/meta/scribe.d.ts +2 -2
  33. package/dist/lib/meta/scribe.js +48 -53
  34. package/dist/lib/meta/sequence.d.ts +1 -1
  35. package/dist/lib/meta/sequence.js +16 -15
  36. package/dist/lib/script/decode.d.ts +2 -2
  37. package/dist/lib/script/decode.js +50 -15
  38. package/dist/lib/script/encode.d.ts +1 -1
  39. package/dist/lib/script/encode.js +20 -16
  40. package/dist/lib/script/index.d.ts +5 -13
  41. package/dist/lib/script/index.js +5 -14
  42. package/dist/lib/script/lock.d.ts +2 -2
  43. package/dist/lib/script/lock.js +15 -12
  44. package/dist/lib/script/util.js +4 -4
  45. package/dist/lib/script/words.js +129 -129
  46. package/dist/lib/sighash/index.d.ts +3 -3
  47. package/dist/lib/sighash/index.js +3 -3
  48. package/dist/lib/sighash/segwit.d.ts +2 -2
  49. package/dist/lib/sighash/segwit.js +15 -14
  50. package/dist/lib/sighash/taproot.d.ts +2 -2
  51. package/dist/lib/sighash/taproot.js +24 -23
  52. package/dist/lib/sighash/util.d.ts +2 -2
  53. package/dist/lib/sighash/util.js +7 -7
  54. package/dist/lib/signer/index.d.ts +2 -2
  55. package/dist/lib/signer/index.js +2 -2
  56. package/dist/lib/signer/sign.d.ts +1 -1
  57. package/dist/lib/signer/sign.js +42 -7
  58. package/dist/lib/signer/verify.d.ts +17 -3
  59. package/dist/lib/signer/verify.js +233 -3
  60. package/dist/lib/taproot/cblock.d.ts +1 -1
  61. package/dist/lib/taproot/cblock.js +14 -16
  62. package/dist/lib/taproot/encode.d.ts +1 -1
  63. package/dist/lib/taproot/encode.js +7 -7
  64. package/dist/lib/taproot/index.d.ts +4 -4
  65. package/dist/lib/taproot/index.js +4 -4
  66. package/dist/lib/taproot/parse.d.ts +1 -1
  67. package/dist/lib/taproot/parse.js +12 -14
  68. package/dist/lib/taproot/tree.d.ts +2 -2
  69. package/dist/lib/taproot/tree.js +11 -7
  70. package/dist/lib/tx/create.d.ts +1 -1
  71. package/dist/lib/tx/create.js +28 -12
  72. package/dist/lib/tx/decode.d.ts +2 -2
  73. package/dist/lib/tx/decode.js +50 -17
  74. package/dist/lib/tx/encode.d.ts +2 -2
  75. package/dist/lib/tx/encode.js +13 -16
  76. package/dist/lib/tx/index.d.ts +7 -7
  77. package/dist/lib/tx/index.js +7 -7
  78. package/dist/lib/tx/parse.d.ts +1 -1
  79. package/dist/lib/tx/parse.js +9 -9
  80. package/dist/lib/tx/size.d.ts +2 -2
  81. package/dist/lib/tx/size.js +9 -9
  82. package/dist/lib/tx/util.d.ts +2 -2
  83. package/dist/lib/tx/util.js +23 -20
  84. package/dist/lib/tx/validate.d.ts +1 -1
  85. package/dist/lib/tx/validate.js +3 -3
  86. package/dist/lib/witness/index.d.ts +2 -2
  87. package/dist/lib/witness/index.js +2 -2
  88. package/dist/lib/witness/parse.d.ts +2 -2
  89. package/dist/lib/witness/parse.js +24 -23
  90. package/dist/lib/witness/util.d.ts +2 -2
  91. package/dist/lib/witness/util.js +5 -5
  92. package/dist/main.cjs +2308 -1005
  93. package/dist/main.cjs.map +1 -1
  94. package/dist/module.mjs +2308 -1005
  95. package/dist/module.mjs.map +1 -1
  96. package/dist/package.json +20 -17
  97. package/dist/schema/base.d.ts +1 -1
  98. package/dist/schema/base.js +17 -13
  99. package/dist/schema/index.d.ts +2 -2
  100. package/dist/schema/index.js +2 -2
  101. package/dist/schema/taproot.d.ts +1 -1
  102. package/dist/schema/taproot.js +2 -2
  103. package/dist/schema/tx.d.ts +1 -1
  104. package/dist/schema/tx.js +4 -4
  105. package/dist/script.js +8 -8
  106. package/dist/script.js.map +1 -1
  107. package/dist/types/address.d.ts +4 -4
  108. package/dist/types/index.d.ts +8 -8
  109. package/dist/types/index.js +8 -8
  110. package/dist/types/meta.d.ts +4 -4
  111. package/dist/types/psbt.d.ts +2 -2
  112. package/dist/types/script.d.ts +2 -2
  113. package/dist/types/sighash.d.ts +2 -2
  114. package/dist/types/witness.d.ts +5 -5
  115. package/package.json +20 -17
  116. package/src/const.ts +0 -61
  117. package/src/index.ts +0 -13
  118. package/src/lib/address/api.ts +0 -50
  119. package/src/lib/address/encode.ts +0 -183
  120. package/src/lib/address/index.ts +0 -7
  121. package/src/lib/address/p2pkh.ts +0 -94
  122. package/src/lib/address/p2sh.ts +0 -96
  123. package/src/lib/address/p2tr.ts +0 -91
  124. package/src/lib/address/p2wpkh.ts +0 -94
  125. package/src/lib/address/p2wsh.ts +0 -92
  126. package/src/lib/address/script.ts +0 -63
  127. package/src/lib/address/util.ts +0 -87
  128. package/src/lib/meta/index.ts +0 -4
  129. package/src/lib/meta/locktime.ts +0 -57
  130. package/src/lib/meta/ref.ts +0 -107
  131. package/src/lib/meta/scribe.ts +0 -256
  132. package/src/lib/meta/sequence.ts +0 -146
  133. package/src/lib/script/decode.ts +0 -85
  134. package/src/lib/script/encode.ts +0 -129
  135. package/src/lib/script/index.ts +0 -20
  136. package/src/lib/script/lock.ts +0 -73
  137. package/src/lib/script/util.ts +0 -78
  138. package/src/lib/script/words.ts +0 -182
  139. package/src/lib/sighash/index.ts +0 -3
  140. package/src/lib/sighash/segwit.ts +0 -152
  141. package/src/lib/sighash/taproot.ts +0 -206
  142. package/src/lib/sighash/util.ts +0 -51
  143. package/src/lib/signer/index.ts +0 -2
  144. package/src/lib/signer/sign.ts +0 -39
  145. package/src/lib/signer/verify.ts +0 -88
  146. package/src/lib/taproot/cblock.ts +0 -96
  147. package/src/lib/taproot/encode.ts +0 -49
  148. package/src/lib/taproot/index.ts +0 -4
  149. package/src/lib/taproot/parse.ts +0 -65
  150. package/src/lib/taproot/tree.ts +0 -94
  151. package/src/lib/tx/create.ts +0 -90
  152. package/src/lib/tx/decode.ts +0 -123
  153. package/src/lib/tx/encode.ts +0 -155
  154. package/src/lib/tx/index.ts +0 -7
  155. package/src/lib/tx/parse.ts +0 -69
  156. package/src/lib/tx/size.ts +0 -68
  157. package/src/lib/tx/util.ts +0 -111
  158. package/src/lib/tx/validate.ts +0 -49
  159. package/src/lib/witness/index.ts +0 -2
  160. package/src/lib/witness/parse.ts +0 -127
  161. package/src/lib/witness/util.ts +0 -18
  162. package/src/schema/base.ts +0 -57
  163. package/src/schema/index.ts +0 -2
  164. package/src/schema/taproot.ts +0 -12
  165. package/src/schema/tx.ts +0 -48
  166. package/src/types/address.ts +0 -35
  167. package/src/types/index.ts +0 -8
  168. package/src/types/meta.ts +0 -48
  169. package/src/types/psbt.ts +0 -15
  170. package/src/types/script.ts +0 -18
  171. package/src/types/sighash.ts +0 -16
  172. package/src/types/taproot.ts +0 -41
  173. package/src/types/txdata.ts +0 -85
  174. package/src/types/witness.ts +0 -42
@@ -1,4 +1,234 @@
1
- export function verify_tx(_txdata, _config = {}) {
2
- console.warn('verify_segwit_tx is not implemented');
3
- return true;
1
+ import { Buff } from "@vbyte/buff";
2
+ import { ECC } from "@vbyte/micro-lib";
3
+ import { hash160 } from "@vbyte/micro-lib/hash";
4
+ import { get_lock_script_type } from "../../lib/script/lock.js";
5
+ import { hash_segwit_tx } from "../../lib/sighash/segwit.js";
6
+ import { hash_taproot_tx } from "../../lib/sighash/taproot.js";
7
+ import { verify_taproot } from "../../lib/taproot/cblock.js";
8
+ import { encode_tapscript } from "../../lib/taproot/encode.js";
9
+ import { parse_tx } from "../../lib/tx/index.js";
10
+ import { parse_witness } from "../../lib/witness/parse.js";
11
+ export function verify_tx(txdata, options = {}) {
12
+ const { throws = false } = options;
13
+ const tx = parse_tx(txdata);
14
+ const inputs = [];
15
+ let allValid = true;
16
+ for (let i = 0; i < tx.vin.length; i++) {
17
+ const vin = tx.vin[i];
18
+ if (vin.coinbase !== null) {
19
+ inputs.push({ index: i, valid: true, type: "coinbase" });
20
+ continue;
21
+ }
22
+ const result = verify_input(tx, vin, i, options);
23
+ inputs.push(result);
24
+ if (!result.valid) {
25
+ allValid = false;
26
+ if (throws) {
27
+ throw new Error(`Input ${i} verification failed: ${result.error}`);
28
+ }
29
+ }
30
+ }
31
+ return {
32
+ valid: allValid,
33
+ inputs,
34
+ error: allValid ? undefined : "One or more inputs failed verification",
35
+ };
36
+ }
37
+ function verify_input(tx, vin, index, options) {
38
+ try {
39
+ const { witness = [] } = vin;
40
+ if (witness.length === 0) {
41
+ return { index, valid: true, type: null };
42
+ }
43
+ const witnessData = parse_witness(witness.map((e) => Buff.hex(e)));
44
+ const { type, version } = witnessData;
45
+ if (type === null || version === null) {
46
+ return { index, valid: false, type, error: "Unknown witness type" };
47
+ }
48
+ const prevout = vin.prevout;
49
+ if (prevout === null || prevout === undefined) {
50
+ return { index, valid: false, type, error: "Missing prevout data" };
51
+ }
52
+ const scriptType = get_lock_script_type(prevout.script_pk);
53
+ if (version === 0) {
54
+ return verify_segwit_input(tx, vin, index, witnessData, options);
55
+ }
56
+ else if (version === 1) {
57
+ return verify_taproot_input(tx, vin, index, witnessData, scriptType, options);
58
+ }
59
+ return {
60
+ index,
61
+ valid: false,
62
+ type,
63
+ error: `Unsupported witness version: ${version}`,
64
+ };
65
+ }
66
+ catch (err) {
67
+ const error = err instanceof Error ? err.message : String(err);
68
+ return { index, valid: false, error };
69
+ }
70
+ }
71
+ function verify_segwit_input(tx, vin, index, witnessData, options) {
72
+ const { type, params, script } = witnessData;
73
+ if (params.length < 1) {
74
+ return { index, valid: false, type, error: "Missing signature in witness" };
75
+ }
76
+ const sigHex = params[0];
77
+ const { signature, sigflag } = parse_ecdsa_signature(sigHex);
78
+ let pubkey;
79
+ let hashScript;
80
+ if (type === "p2wpkh") {
81
+ if (params.length < 2) {
82
+ return {
83
+ index,
84
+ valid: false,
85
+ type,
86
+ error: "Missing pubkey in P2WPKH witness",
87
+ };
88
+ }
89
+ pubkey = params[1];
90
+ const pkh = hash160(pubkey).hex;
91
+ hashScript = `76a914${pkh}88ac`;
92
+ }
93
+ else if (type === "p2wsh") {
94
+ if (script === null) {
95
+ return {
96
+ index,
97
+ valid: false,
98
+ type,
99
+ error: "Missing script in P2WSH witness",
100
+ };
101
+ }
102
+ hashScript = script;
103
+ if (params.length >= 2) {
104
+ pubkey = params[1];
105
+ }
106
+ else {
107
+ return {
108
+ index,
109
+ valid: false,
110
+ type,
111
+ error: "Missing pubkey in P2WSH witness",
112
+ };
113
+ }
114
+ }
115
+ else {
116
+ return {
117
+ index,
118
+ valid: false,
119
+ type,
120
+ error: `Unexpected segwit type: ${type}`,
121
+ };
122
+ }
123
+ const sighashOptions = {
124
+ ...options,
125
+ txindex: index,
126
+ txinput: vin,
127
+ pubkey: type === "p2wpkh" ? pubkey : undefined,
128
+ script: type === "p2wsh" ? hashScript : undefined,
129
+ sigflag,
130
+ };
131
+ const hash = hash_segwit_tx(tx, sighashOptions);
132
+ const isValid = ECC.verify_ecdsa(signature, hash, pubkey);
133
+ return {
134
+ index,
135
+ valid: isValid,
136
+ type,
137
+ error: isValid ? undefined : "Invalid ECDSA signature",
138
+ };
139
+ }
140
+ function verify_taproot_input(tx, vin, index, witnessData, _scriptType, options) {
141
+ const { type, params, script, cblock } = witnessData;
142
+ if (vin.prevout == null) {
143
+ return {
144
+ index,
145
+ valid: false,
146
+ type,
147
+ error: "Missing prevout for taproot verification",
148
+ };
149
+ }
150
+ const prevout = vin.prevout;
151
+ if (params.length < 1) {
152
+ return { index, valid: false, type, error: "Missing signature in witness" };
153
+ }
154
+ const sigHex = params[0];
155
+ const { signature, sigflag } = parse_schnorr_signature(sigHex);
156
+ const tapkey = prevout.script_pk.slice(4);
157
+ let pubkey;
158
+ let extension;
159
+ if (type === "p2tr") {
160
+ pubkey = tapkey;
161
+ }
162
+ else if (type === "p2ts") {
163
+ if (cblock === null || script === null) {
164
+ return {
165
+ index,
166
+ valid: false,
167
+ type,
168
+ error: "Missing cblock or script in script-path spend",
169
+ };
170
+ }
171
+ const target = encode_tapscript(script).hex;
172
+ const pathValid = verify_taproot(tapkey, target, cblock);
173
+ if (!pathValid) {
174
+ return {
175
+ index,
176
+ valid: false,
177
+ type,
178
+ error: "Control block verification failed",
179
+ };
180
+ }
181
+ if (params.length >= 2 && params[1].length === 64) {
182
+ pubkey = params[1];
183
+ }
184
+ else {
185
+ pubkey = tapkey;
186
+ }
187
+ extension = target;
188
+ }
189
+ else {
190
+ return {
191
+ index,
192
+ valid: false,
193
+ type,
194
+ error: `Unexpected taproot type: ${type}`,
195
+ };
196
+ }
197
+ const sighashOptions = {
198
+ ...options,
199
+ txindex: index,
200
+ txinput: vin,
201
+ sigflag,
202
+ extension: extension,
203
+ script: type === "p2ts" ? (script ?? undefined) : undefined,
204
+ };
205
+ const hash = hash_taproot_tx(tx, sighashOptions);
206
+ const isValid = ECC.verify_bip340(signature, hash, pubkey);
207
+ return {
208
+ index,
209
+ valid: isValid,
210
+ type,
211
+ error: isValid ? undefined : "Invalid Schnorr signature",
212
+ };
213
+ }
214
+ function parse_ecdsa_signature(sigHex) {
215
+ const sigBytes = Buff.hex(sigHex);
216
+ const sigflag = sigBytes.at(-1) ?? 0x01;
217
+ const signature = sigBytes.slice(0, -1).hex;
218
+ return { signature, sigflag };
219
+ }
220
+ function parse_schnorr_signature(sigHex) {
221
+ const sigBytes = Buff.hex(sigHex);
222
+ if (sigBytes.length === 64) {
223
+ return { signature: sigHex, sigflag: 0x00 };
224
+ }
225
+ else if (sigBytes.length === 65) {
226
+ const sigflag = sigBytes.at(-1) ?? 0x00;
227
+ if (sigflag === 0x00) {
228
+ throw new Error("0x00 is not a valid appended sigflag");
229
+ }
230
+ const signature = sigBytes.slice(0, 64).hex;
231
+ return { signature, sigflag };
232
+ }
233
+ throw new Error(`Invalid Schnorr signature length: ${sigBytes.length}`);
4
234
  }
@@ -1,3 +1,3 @@
1
- import { TaprootConfig, TaprootContext } from '../../types/index.js';
1
+ import type { TaprootConfig, TaprootContext } from "../../types/index.js";
2
2
  export declare function create_taproot(config: TaprootConfig): TaprootContext;
3
3
  export declare function verify_taproot(tapkey: string, target: string, cblock: string): boolean;
@@ -1,18 +1,16 @@
1
- import { Buff } from '@vbyte/buff';
2
- import { Assert, ECC } from '@vbyte/micro-lib';
3
- import { merkleize } from './tree.js';
4
- import { TAPLEAF_DEFAULT_VERSION } from '../../const.js';
5
- import * as Schema from '../../schema/index.js';
6
- import { encode_tapbranch, encode_taptweak } from './encode.js';
7
- import { parse_pubkey_parity, parse_cblock } from './parse.js';
1
+ import { Buff } from "@vbyte/buff";
2
+ import { Assert, ECC } from "@vbyte/micro-lib";
3
+ import { TAPLEAF_DEFAULT_VERSION } from "../../const.js";
4
+ import * as Schema from "../../schema/index.js";
5
+ import { encode_tapbranch, encode_taptweak } from "./encode.js";
6
+ import { parse_cblock, parse_pubkey_parity } from "./parse.js";
7
+ import { merkleize } from "./tree.js";
8
8
  const DEFAULT_VERSION = TAPLEAF_DEFAULT_VERSION;
9
9
  export function create_taproot(config) {
10
10
  Schema.taproot.config.parse(config);
11
11
  const { pubkey, version = DEFAULT_VERSION } = config;
12
12
  const leaves = config.leaves ?? [];
13
- const target = (config.target !== undefined)
14
- ? Buff.bytes(config.target).hex
15
- : undefined;
13
+ const target = config.target !== undefined ? Buff.bytes(config.target).hex : undefined;
16
14
  let path = [], taproot;
17
15
  if (leaves.length > 0) {
18
16
  const [root, _, proofs] = merkleize(leaves, target);
@@ -23,13 +21,13 @@ export function create_taproot(config) {
23
21
  taproot = target;
24
22
  }
25
23
  const taptweak = encode_taptweak(pubkey, taproot);
26
- const twk_key = ECC.tweak_pubkey(pubkey, taptweak, 'ecdsa');
24
+ const twk_key = ECC.tweak_pubkey(pubkey, taptweak, "ecdsa");
27
25
  const parity = parse_pubkey_parity(twk_key);
28
- const tapkey = ECC.serialize_pubkey(twk_key, 'bip340');
26
+ const tapkey = ECC.serialize_pubkey(twk_key, "bip340");
29
27
  const cbit = Buff.num(version + parity);
30
28
  const block = [cbit, Buff.bytes(pubkey)];
31
29
  if (path.length > 0) {
32
- path.forEach(e => block.push(e));
30
+ block.push(...path);
33
31
  }
34
32
  const cblock = Buff.join(block);
35
33
  return {
@@ -39,7 +37,7 @@ export function create_taproot(config) {
39
37
  taproot: taproot ?? null,
40
38
  cblock: cblock.hex,
41
39
  tapkey: tapkey.hex,
42
- taptweak: taptweak.hex
40
+ taptweak: taptweak.hex,
43
41
  };
44
42
  }
45
43
  export function verify_taproot(tapkey, target, cblock) {
@@ -51,6 +49,6 @@ export function verify_taproot(tapkey, target, cblock) {
51
49
  branch = encode_tapbranch(branch, leaf).hex;
52
50
  }
53
51
  const tap_tweak = encode_taptweak(int_key, branch);
54
- const tweaked_key = ECC.tweak_pubkey(int_key, tap_tweak, 'ecdsa');
55
- return (ext_key.hex === tweaked_key.hex);
52
+ const tweaked_key = ECC.tweak_pubkey(int_key, tap_tweak, "ecdsa");
53
+ return ext_key.hex === tweaked_key.hex;
56
54
  }
@@ -1,4 +1,4 @@
1
- import { Buff } from '@vbyte/buff';
1
+ import type { Buff } from "@vbyte/buff";
2
2
  export declare function encode_tapscript(script: string | Uint8Array, version?: number): Buff;
3
3
  export declare function encode_tapleaf(data: string | Uint8Array, version?: number): Buff;
4
4
  export declare function encode_tapbranch(leaf_a: string, leaf_b: string): Buff;
@@ -1,7 +1,7 @@
1
- import { hash340 } from '@vbyte/micro-lib/hash';
2
- import { Assert } from '@vbyte/micro-lib';
3
- import { prefix_script_size } from '../../lib/script/index.js';
4
- import { TAPLEAF_DEFAULT_VERSION } from '../../const.js';
1
+ import { Assert } from "@vbyte/micro-lib";
2
+ import { hash340 } from "@vbyte/micro-lib/hash";
3
+ import { TAPLEAF_DEFAULT_VERSION } from "../../const.js";
4
+ import { prefix_script_size } from "../../lib/script/index.js";
5
5
  const DEFAULT_VERSION = TAPLEAF_DEFAULT_VERSION;
6
6
  export function encode_tapscript(script, version = DEFAULT_VERSION) {
7
7
  const preimg = prefix_script_size(script);
@@ -9,18 +9,18 @@ export function encode_tapscript(script, version = DEFAULT_VERSION) {
9
9
  }
10
10
  export function encode_tapleaf(data, version = DEFAULT_VERSION) {
11
11
  const vbyte = encode_leaf_version(version);
12
- return hash340('TapLeaf', vbyte, data);
12
+ return hash340("TapLeaf", vbyte, data);
13
13
  }
14
14
  export function encode_tapbranch(leaf_a, leaf_b) {
15
15
  if (leaf_b < leaf_a) {
16
16
  [leaf_a, leaf_b] = [leaf_b, leaf_a];
17
17
  }
18
- return hash340('TapBranch', leaf_a, leaf_b);
18
+ return hash340("TapBranch", leaf_a, leaf_b);
19
19
  }
20
20
  export function encode_leaf_version(version = 0xc0) {
21
21
  return version & 0xfe;
22
22
  }
23
23
  export function encode_taptweak(pubkey, data = new Uint8Array()) {
24
24
  Assert.size(pubkey, 32);
25
- return hash340('TapTweak', pubkey, data);
25
+ return hash340("TapTweak", pubkey, data);
26
26
  }
@@ -1,4 +1,4 @@
1
- export * from './cblock.js';
2
- export * from './encode.js';
3
- export * from './parse.js';
4
- export * from './tree.js';
1
+ export * from "./cblock.js";
2
+ export * from "./encode.js";
3
+ export * from "./parse.js";
4
+ export * from "./tree.js";
@@ -1,4 +1,4 @@
1
- export * from './cblock.js';
2
- export * from './encode.js';
3
- export * from './parse.js';
4
- export * from './tree.js';
1
+ export * from "./cblock.js";
2
+ export * from "./encode.js";
3
+ export * from "./parse.js";
4
+ export * from "./tree.js";
@@ -1,4 +1,4 @@
1
- import type { ControlBlock } from '../../types/index.js';
1
+ import type { ControlBlock } from "../../types/index.js";
2
2
  export declare function parse_taproot_witness(witness: string[]): {
3
3
  cblock: ControlBlock;
4
4
  params: string[];
@@ -1,11 +1,11 @@
1
- import { Buff, Stream } from '@vbyte/buff';
2
- import { Assert, ECC } from '@vbyte/micro-lib';
3
- import { parse_witness } from '../../lib/witness/parse.js';
4
- import { encode_tapbranch, encode_tapscript, encode_taptweak, } from './encode.js';
1
+ import { Buff, Stream } from "@vbyte/buff";
2
+ import { Assert, ECC } from "@vbyte/micro-lib";
3
+ import { parse_witness } from "../../lib/witness/parse.js";
4
+ import { encode_tapbranch, encode_tapscript, encode_taptweak, } from "./encode.js";
5
5
  export function parse_taproot_witness(witness) {
6
6
  const { cblock, params, script } = parse_witness(witness);
7
- Assert.exists(cblock, 'cblock is null');
8
- Assert.exists(script, 'script is null');
7
+ Assert.exists(cblock, "cblock is null");
8
+ Assert.exists(script, "script is null");
9
9
  const cblk = parse_cblock(cblock);
10
10
  const target = encode_tapscript(script, cblk.version);
11
11
  let branch = target.hex;
@@ -13,8 +13,8 @@ export function parse_taproot_witness(witness) {
13
13
  branch = encode_tapbranch(branch, leaf).hex;
14
14
  }
15
15
  const tweak = encode_taptweak(cblk.int_key, branch);
16
- const tapkey = ECC.tweak_pubkey(cblk.int_key, tweak, 'bip340');
17
- params.map(e => Buff.bytes(e).hex);
16
+ const tapkey = ECC.tweak_pubkey(cblk.int_key, tweak, "bip340");
17
+ params.map((e) => Buff.bytes(e).hex);
18
18
  return { cblock: cblk, params, script, tapkey: tapkey.hex, tweak: tweak.hex };
19
19
  }
20
20
  export function parse_cblock(cblock) {
@@ -27,21 +27,19 @@ export function parse_cblock(cblock) {
27
27
  path.push(buffer.read(32).hex);
28
28
  }
29
29
  if (buffer.size !== 0) {
30
- throw new Error('Non-empty buffer on control block: ' + String(buffer));
30
+ throw new Error(`Non-empty buffer on control block: ${String(buffer)}`);
31
31
  }
32
32
  return { int_key, path, parity, version };
33
33
  }
34
34
  export function parse_cblock_parity(cbits) {
35
- return (cbits % 2 === 0)
36
- ? [cbits - 0, 0x02]
37
- : [cbits - 1, 0x03];
35
+ return cbits % 2 === 0 ? [cbits - 0, 0x02] : [cbits - 1, 0x03];
38
36
  }
39
37
  export function parse_pubkey_parity(pubkey) {
40
- Assert.size(pubkey, 33, 'invalid pubkey size');
38
+ Assert.size(pubkey, 33, "invalid pubkey size");
41
39
  const [parity] = Buff.bytes(pubkey);
42
40
  if (parity === 0x02)
43
41
  return 0;
44
42
  if (parity === 0x03)
45
43
  return 1;
46
- throw new Error('Invalid parity bit: ' + String(parity));
44
+ throw new Error(`Invalid parity bit: ${String(parity)}`);
47
45
  }
@@ -1,3 +1,3 @@
1
- import type { TapTree, MerkleProof } from '../../types/index.js';
1
+ import type { MerkleProof, TapTree } from "../../types/index.js";
2
2
  export declare function get_merkle_root(leaves: TapTree): string;
3
- export declare function merkleize(taptree: TapTree, target?: string, path?: string[]): MerkleProof;
3
+ export declare function merkleize(taptree: TapTree, target?: string, path?: string[], depth?: number): MerkleProof;
@@ -1,18 +1,22 @@
1
- import { Buff } from '@vbyte/buff';
2
- import { encode_tapbranch } from './encode.js';
1
+ import { Buff } from "@vbyte/buff";
2
+ import { encode_tapbranch } from "./encode.js";
3
+ const MAX_TAPROOT_DEPTH = 128;
3
4
  export function get_merkle_root(leaves) {
4
5
  return merkleize(leaves)[0];
5
6
  }
6
- export function merkleize(taptree, target, path = []) {
7
+ export function merkleize(taptree, target, path = [], depth = 0) {
8
+ if (depth > MAX_TAPROOT_DEPTH) {
9
+ throw new Error(`Taproot tree depth ${depth} exceeds maximum ${MAX_TAPROOT_DEPTH}`);
10
+ }
7
11
  const leaves = [];
8
12
  const tree = [];
9
13
  if (taptree.length < 1) {
10
- throw new Error('Tree is empty!');
14
+ throw new Error("Tree is empty!");
11
15
  }
12
16
  for (let i = 0; i < taptree.length; i++) {
13
17
  const bytes = taptree[i];
14
18
  if (Array.isArray(bytes)) {
15
- let [tapleaf, new_target, branches] = merkleize(bytes, target);
19
+ const [tapleaf, new_target, branches] = merkleize(bytes, target, [], depth + 1);
16
20
  target = new_target;
17
21
  leaves.push(tapleaf);
18
22
  for (const branch of branches) {
@@ -34,7 +38,7 @@ export function merkleize(taptree, target, path = []) {
34
38
  for (let i = 0; i < leaves.length - 1; i += 2) {
35
39
  const branch = encode_tapbranch(leaves[i], leaves[i + 1]).hex;
36
40
  tree.push(branch);
37
- if (typeof target === 'string') {
41
+ if (typeof target === "string") {
38
42
  if (target === leaves[i]) {
39
43
  path.push(leaves[i + 1]);
40
44
  target = branch;
@@ -45,5 +49,5 @@ export function merkleize(taptree, target, path = []) {
45
49
  }
46
50
  }
47
51
  }
48
- return merkleize(tree, target, path);
52
+ return merkleize(tree, target, path, depth + 1);
49
53
  }
@@ -1,4 +1,4 @@
1
- import type { TxData, TxInput, TxOutput, TxTemplate, TxSpendInput, TxCoinbaseInput, TxOutputTemplate, TxVirtualInput, TxInputTemplate } from '../../types/index.js';
1
+ import type { TxCoinbaseInput, TxData, TxInput, TxInputTemplate, TxOutput, TxOutputTemplate, TxSpendInput, TxTemplate, TxVirtualInput } from "../../types/index.js";
2
2
  export declare function create_coinbase_input(config: TxInputTemplate): TxCoinbaseInput;
3
3
  export declare function create_virtual_input(config: TxInputTemplate): TxVirtualInput;
4
4
  export declare function create_spend_input(config: TxInputTemplate): TxSpendInput;
@@ -1,28 +1,44 @@
1
- import { Assert } from '@vbyte/micro-lib';
2
- import { COINBASE, DEFAULT } from '../../const.js';
3
- import { normalize_prevout, normalize_sequence, normalize_value } from './util.js';
4
- import { assert_tx_template, assert_vin_template, assert_vout_template } from './validate.js';
1
+ import { Assert } from "@vbyte/micro-lib";
2
+ import { COINBASE, DEFAULT } from "../../const.js";
3
+ import { normalize_prevout, normalize_sequence, normalize_value, } from "./util.js";
4
+ import { assert_tx_template, assert_vin_template, assert_vout_template, } from "./validate.js";
5
5
  export function create_coinbase_input(config) {
6
6
  assert_vin_template(config);
7
- Assert.exists(config.coinbase, 'coinbase is required');
7
+ Assert.exists(config.coinbase, "coinbase is required");
8
8
  const txid = COINBASE.TXID;
9
9
  const vout = COINBASE.VOUT;
10
10
  const coinbase = config.coinbase;
11
11
  const witness = config.witness ?? [];
12
12
  const sequence = normalize_sequence(config.sequence);
13
- return { coinbase, prevout: null, script_sig: null, sequence, witness, txid, vout };
13
+ return {
14
+ coinbase,
15
+ prevout: null,
16
+ script_sig: null,
17
+ sequence,
18
+ witness,
19
+ txid,
20
+ vout,
21
+ };
14
22
  }
15
23
  export function create_virtual_input(config) {
16
24
  assert_vin_template(config);
17
- Assert.is_empty(config.coinbase, 'coinbase is not allowed');
18
- Assert.is_empty(config.prevout, 'prevout is not allowed');
25
+ Assert.is_empty(config.coinbase, "coinbase is not allowed");
26
+ Assert.is_empty(config.prevout, "prevout is not allowed");
19
27
  const { txid, vout, script_sig = null, witness = [] } = config;
20
28
  const sequence = normalize_sequence(config.sequence);
21
- return { txid, vout, coinbase: null, prevout: null, script_sig, sequence, witness };
29
+ return {
30
+ txid,
31
+ vout,
32
+ coinbase: null,
33
+ prevout: null,
34
+ script_sig,
35
+ sequence,
36
+ witness,
37
+ };
22
38
  }
23
39
  export function create_spend_input(config) {
24
40
  assert_vin_template(config);
25
- Assert.exists(config.prevout, 'prevout is required');
41
+ Assert.exists(config.prevout, "prevout is required");
26
42
  const { txid, vout, script_sig = null, witness = [] } = config;
27
43
  const prevout = normalize_prevout(config.prevout);
28
44
  const sequence = normalize_sequence(config.sequence);
@@ -46,7 +62,7 @@ export function create_tx(config) {
46
62
  const { vin = [], vout = [] } = config ?? { vin: [], vout: [] };
47
63
  const locktime = config.locktime ?? DEFAULT.LOCKTIME;
48
64
  const version = config.version ?? DEFAULT.VERSION;
49
- const inputs = vin.map(txin => create_tx_input(txin));
50
- const outputs = vout.map(txout => create_tx_output(txout));
65
+ const inputs = vin.map((txin) => create_tx_input(txin));
66
+ const outputs = vout.map((txout) => create_tx_output(txout));
51
67
  return { locktime, vin: inputs, vout: outputs, version };
52
68
  }
@@ -1,4 +1,4 @@
1
- import { Stream } from '@vbyte/buff';
2
- import { TxDecodedData } from '../../types/index.js';
1
+ import { Stream } from "@vbyte/buff";
2
+ import type { TxDecodedData } from "../../types/index.js";
3
3
  export declare function decode_tx(txdata: string | Uint8Array, use_segwit?: boolean): TxDecodedData;
4
4
  export declare function read_payload(stream: Stream): string | null;