@vbyte/btc-dev 1.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 (205) hide show
  1. package/LICENSE +121 -0
  2. package/README.md +5 -0
  3. package/dist/class/index.d.ts +5 -0
  4. package/dist/class/index.js +5 -0
  5. package/dist/class/signer.d.ts +18 -0
  6. package/dist/class/signer.js +32 -0
  7. package/dist/class/tx.d.ts +38 -0
  8. package/dist/class/tx.js +73 -0
  9. package/dist/class/txin.d.ts +29 -0
  10. package/dist/class/txin.js +68 -0
  11. package/dist/class/txout.d.ts +18 -0
  12. package/dist/class/txout.js +38 -0
  13. package/dist/class/witness.d.ts +20 -0
  14. package/dist/class/witness.js +57 -0
  15. package/dist/const.d.ts +22 -0
  16. package/dist/const.js +36 -0
  17. package/dist/index.d.ts +11 -0
  18. package/dist/index.js +10 -0
  19. package/dist/lib/address/encode.d.ts +3 -0
  20. package/dist/lib/address/encode.js +79 -0
  21. package/dist/lib/address/index.d.ts +20 -0
  22. package/dist/lib/address/index.js +21 -0
  23. package/dist/lib/address/p2pkh.d.ts +10 -0
  24. package/dist/lib/address/p2pkh.js +33 -0
  25. package/dist/lib/address/p2sh.d.ts +10 -0
  26. package/dist/lib/address/p2sh.js +33 -0
  27. package/dist/lib/address/p2tr.d.ts +8 -0
  28. package/dist/lib/address/p2tr.js +26 -0
  29. package/dist/lib/address/p2wpkh.d.ts +10 -0
  30. package/dist/lib/address/p2wpkh.js +34 -0
  31. package/dist/lib/address/p2wsh.d.ts +10 -0
  32. package/dist/lib/address/p2wsh.js +33 -0
  33. package/dist/lib/address/script.d.ts +5 -0
  34. package/dist/lib/address/script.js +46 -0
  35. package/dist/lib/address/util.d.ts +4 -0
  36. package/dist/lib/address/util.js +57 -0
  37. package/dist/lib/meta/index.d.ts +2 -0
  38. package/dist/lib/meta/index.js +2 -0
  39. package/dist/lib/meta/pointer.d.ts +42 -0
  40. package/dist/lib/meta/pointer.js +69 -0
  41. package/dist/lib/meta/scribe.d.ts +7 -0
  42. package/dist/lib/meta/scribe.js +192 -0
  43. package/dist/lib/psbt/encoder.d.ts +5 -0
  44. package/dist/lib/psbt/encoder.js +21 -0
  45. package/dist/lib/psbt/index.d.ts +4 -0
  46. package/dist/lib/psbt/index.js +4 -0
  47. package/dist/lib/psbt/meta.d.ts +3 -0
  48. package/dist/lib/psbt/meta.js +11 -0
  49. package/dist/lib/psbt/util.d.ts +5 -0
  50. package/dist/lib/psbt/util.js +44 -0
  51. package/dist/lib/psbt/validate.d.ts +2 -0
  52. package/dist/lib/psbt/validate.js +11 -0
  53. package/dist/lib/script/decode.d.ts +2 -0
  54. package/dist/lib/script/decode.js +55 -0
  55. package/dist/lib/script/encode.d.ts +6 -0
  56. package/dist/lib/script/encode.js +80 -0
  57. package/dist/lib/script/index.d.ts +126 -0
  58. package/dist/lib/script/index.js +17 -0
  59. package/dist/lib/script/util.d.ts +2 -0
  60. package/dist/lib/script/util.js +10 -0
  61. package/dist/lib/script/words.d.ts +116 -0
  62. package/dist/lib/script/words.js +164 -0
  63. package/dist/lib/sighash/index.d.ts +5 -0
  64. package/dist/lib/sighash/index.js +5 -0
  65. package/dist/lib/sighash/segwit.d.ts +3 -0
  66. package/dist/lib/sighash/segwit.js +89 -0
  67. package/dist/lib/sighash/sign.d.ts +3 -0
  68. package/dist/lib/sighash/sign.js +20 -0
  69. package/dist/lib/sighash/taproot.d.ts +9 -0
  70. package/dist/lib/sighash/taproot.js +124 -0
  71. package/dist/lib/sighash/util.d.ts +3 -0
  72. package/dist/lib/sighash/util.js +16 -0
  73. package/dist/lib/sighash/verify.d.ts +1 -0
  74. package/dist/lib/sighash/verify.js +1 -0
  75. package/dist/lib/taproot/cblock.d.ts +3 -0
  76. package/dist/lib/taproot/cblock.js +55 -0
  77. package/dist/lib/taproot/encode.d.ts +6 -0
  78. package/dist/lib/taproot/encode.js +26 -0
  79. package/dist/lib/taproot/index.d.ts +4 -0
  80. package/dist/lib/taproot/index.js +4 -0
  81. package/dist/lib/taproot/parse.d.ts +11 -0
  82. package/dist/lib/taproot/parse.js +47 -0
  83. package/dist/lib/taproot/tree.d.ts +3 -0
  84. package/dist/lib/taproot/tree.js +49 -0
  85. package/dist/lib/tx/create.d.ts +6 -0
  86. package/dist/lib/tx/create.js +54 -0
  87. package/dist/lib/tx/decode.d.ts +9 -0
  88. package/dist/lib/tx/decode.js +109 -0
  89. package/dist/lib/tx/encode.d.ts +15 -0
  90. package/dist/lib/tx/encode.js +94 -0
  91. package/dist/lib/tx/index.d.ts +10 -0
  92. package/dist/lib/tx/index.js +10 -0
  93. package/dist/lib/tx/locktime.d.ts +7 -0
  94. package/dist/lib/tx/locktime.js +37 -0
  95. package/dist/lib/tx/meta.d.ts +8 -0
  96. package/dist/lib/tx/meta.js +48 -0
  97. package/dist/lib/tx/parse.d.ts +2 -0
  98. package/dist/lib/tx/parse.js +12 -0
  99. package/dist/lib/tx/sequence.d.ts +7 -0
  100. package/dist/lib/tx/sequence.js +65 -0
  101. package/dist/lib/tx/size.d.ts +10 -0
  102. package/dist/lib/tx/size.js +48 -0
  103. package/dist/lib/tx/validate.d.ts +7 -0
  104. package/dist/lib/tx/validate.js +21 -0
  105. package/dist/lib/tx/witness.d.ts +3 -0
  106. package/dist/lib/tx/witness.js +85 -0
  107. package/dist/main.cjs +14625 -0
  108. package/dist/main.cjs.map +1 -0
  109. package/dist/module.mjs +14610 -0
  110. package/dist/module.mjs.map +1 -0
  111. package/dist/package.json +106 -0
  112. package/dist/schema/index.d.ts +2 -0
  113. package/dist/schema/index.js +2 -0
  114. package/dist/schema/taproot.d.ts +18 -0
  115. package/dist/schema/taproot.js +9 -0
  116. package/dist/schema/tx.d.ts +278 -0
  117. package/dist/schema/tx.js +35 -0
  118. package/dist/script.js +15 -0
  119. package/dist/script.js.map +1 -0
  120. package/dist/types/address.d.ts +34 -0
  121. package/dist/types/address.js +1 -0
  122. package/dist/types/index.d.ts +9 -0
  123. package/dist/types/index.js +9 -0
  124. package/dist/types/meta.d.ts +10 -0
  125. package/dist/types/meta.js +1 -0
  126. package/dist/types/psbt.d.ts +9 -0
  127. package/dist/types/psbt.js +1 -0
  128. package/dist/types/sighash.d.ts +14 -0
  129. package/dist/types/sighash.js +1 -0
  130. package/dist/types/taproot.d.ts +35 -0
  131. package/dist/types/taproot.js +1 -0
  132. package/dist/types/transaction.d.ts +81 -0
  133. package/dist/types/transaction.js +1 -0
  134. package/dist/types/txdata.d.ts +45 -0
  135. package/dist/types/txdata.js +1 -0
  136. package/dist/types/txmeta.d.ts +19 -0
  137. package/dist/types/txmeta.js +1 -0
  138. package/dist/types/witness.d.ts +30 -0
  139. package/dist/types/witness.js +1 -0
  140. package/package.json +106 -0
  141. package/src/class/index.ts +5 -0
  142. package/src/class/signer.ts +47 -0
  143. package/src/class/tx.ts +118 -0
  144. package/src/class/txin.ts +95 -0
  145. package/src/class/txout.ts +57 -0
  146. package/src/class/witness.ts +85 -0
  147. package/src/const.ts +43 -0
  148. package/src/index.ts +14 -0
  149. package/src/lib/address/encode.ts +183 -0
  150. package/src/lib/address/index.ts +24 -0
  151. package/src/lib/address/p2pkh.ts +65 -0
  152. package/src/lib/address/p2sh.ts +65 -0
  153. package/src/lib/address/p2tr.ts +51 -0
  154. package/src/lib/address/p2wpkh.ts +67 -0
  155. package/src/lib/address/p2wsh.ts +65 -0
  156. package/src/lib/address/script.ts +63 -0
  157. package/src/lib/address/util.ts +102 -0
  158. package/src/lib/meta/index.ts +2 -0
  159. package/src/lib/meta/pointer.ts +107 -0
  160. package/src/lib/meta/scribe.ts +251 -0
  161. package/src/lib/psbt/encoder.ts +24 -0
  162. package/src/lib/psbt/index.ts +4 -0
  163. package/src/lib/psbt/meta.ts +15 -0
  164. package/src/lib/psbt/util.ts +62 -0
  165. package/src/lib/psbt/validate.ts +18 -0
  166. package/src/lib/script/decode.ts +75 -0
  167. package/src/lib/script/encode.ts +130 -0
  168. package/src/lib/script/index.ts +26 -0
  169. package/src/lib/script/util.ts +78 -0
  170. package/src/lib/script/words.ts +182 -0
  171. package/src/lib/sighash/index.ts +5 -0
  172. package/src/lib/sighash/segwit.ts +152 -0
  173. package/src/lib/sighash/sign.ts +35 -0
  174. package/src/lib/sighash/taproot.ts +236 -0
  175. package/src/lib/sighash/util.ts +29 -0
  176. package/src/lib/sighash/verify.ts +83 -0
  177. package/src/lib/taproot/cblock.ts +95 -0
  178. package/src/lib/taproot/encode.ts +49 -0
  179. package/src/lib/taproot/index.ts +4 -0
  180. package/src/lib/taproot/parse.ts +65 -0
  181. package/src/lib/taproot/tree.ts +94 -0
  182. package/src/lib/tx/create.ts +82 -0
  183. package/src/lib/tx/decode.ts +145 -0
  184. package/src/lib/tx/encode.ts +154 -0
  185. package/src/lib/tx/index.ts +10 -0
  186. package/src/lib/tx/locktime.ts +57 -0
  187. package/src/lib/tx/meta.ts +73 -0
  188. package/src/lib/tx/parse.ts +16 -0
  189. package/src/lib/tx/sequence.ts +146 -0
  190. package/src/lib/tx/size.ts +77 -0
  191. package/src/lib/tx/validate.ts +36 -0
  192. package/src/lib/tx/witness.ts +122 -0
  193. package/src/schema/index.ts +2 -0
  194. package/src/schema/taproot.ts +12 -0
  195. package/src/schema/tx.ts +42 -0
  196. package/src/types/address.ts +39 -0
  197. package/src/types/index.ts +9 -0
  198. package/src/types/meta.ts +10 -0
  199. package/src/types/psbt.ts +15 -0
  200. package/src/types/sighash.ts +16 -0
  201. package/src/types/taproot.ts +40 -0
  202. package/src/types/transaction.ts +98 -0
  203. package/src/types/txdata.ts +53 -0
  204. package/src/types/txmeta.ts +25 -0
  205. package/src/types/witness.ts +36 -0
@@ -0,0 +1,152 @@
1
+ import { Buff } from '@vbyte/buff'
2
+ import { hash160, hash256 } from '@vbyte/micro-lib/hash'
3
+ import { Assert } from '@vbyte/micro-lib'
4
+ import { parse_txinput } from './util.js'
5
+
6
+ import {
7
+ prefix_script_size,
8
+ decode_script
9
+ } from '@/lib/script/index.js'
10
+
11
+ import {
12
+ encode_txin_vout,
13
+ encode_tx_locktime,
14
+ encode_txin_sequence,
15
+ encode_txin_txid,
16
+ encode_vout_value,
17
+ encode_tx_version,
18
+ parse_tx_data
19
+ } from '@/lib/tx/index.js'
20
+
21
+ import {
22
+ SigHashOptions,
23
+ TxData,
24
+ TxInput,
25
+ TxOutput
26
+ } from '@/types/index.js'
27
+
28
+ import * as CONST from '@/const.js'
29
+
30
+ export function hash_segwit_tx (
31
+ txdata : TxData,
32
+ options : SigHashOptions = {}
33
+ ) : Buff {
34
+ // Unpack the sigflag from our config object.
35
+ const { sigflag = 0x01, txindex } = options
36
+ // Normalize the tx into JSON format.
37
+ const tx = parse_tx_data(txdata)
38
+ // Check if the ANYONECANPAY flag is set.
39
+ const is_anypay = (sigflag & 0x80) === 0x80
40
+ // Save a normalized version of the sigflag.
41
+ const flag = sigflag % 0x80
42
+ // Check if the sigflag exists as a valid type.
43
+ if (!CONST.SIGHASH_SEGWIT.includes(flag)) {
44
+ throw new Error('Invalid hash type: ' + String(sigflag))
45
+ }
46
+ // Unpack the tx object.
47
+ const { version, vin, vout, locktime } = tx
48
+ // Parse the input we are signing from the config.
49
+ const txinput = parse_txinput(tx, options)
50
+ // Unpack the chosen input for signing.
51
+ const { txid, vout: prevIdx, prevout, sequence } = txinput
52
+ // Unpack the prevout for the chosen input.
53
+ const { value } = prevout ?? {}
54
+ // Check if a prevout value is provided.
55
+ if (value === undefined) {
56
+ throw new Error('Prevout value is empty!')
57
+ }
58
+ // Initialize our script variable from the config.
59
+ let { pubkey, script } = options
60
+ // Check if a pubkey is provided (instead of a script).
61
+ if (script === undefined && pubkey !== undefined) {
62
+ const pkhash = hash160(pubkey).hex
63
+ script = `76a914${String(pkhash)}88ac`
64
+ }
65
+ // Make sure that some form of script has been provided.
66
+ if (script === undefined) {
67
+ throw new Error('No pubkey / script has been set!')
68
+ }
69
+ // Throw if OP_CODESEPARATOR is used in a script.
70
+ if (decode_script(script).includes('OP_CODESEPARATOR')) {
71
+ throw new Error('This library does not currently support the use of OP_CODESEPARATOR in segwit scripts.')
72
+ }
73
+
74
+ const sighash = [
75
+ encode_tx_version(version),
76
+ hash_prevouts(vin, is_anypay),
77
+ hash_sequence(vin, flag, is_anypay),
78
+ encode_txin_txid(txid),
79
+ encode_txin_vout(prevIdx),
80
+ prefix_script_size(script),
81
+ encode_vout_value(value),
82
+ encode_txin_sequence(sequence),
83
+ hash_outputs(vout, flag, txindex),
84
+ encode_tx_locktime(locktime),
85
+ Buff.num(sigflag, 4).reverse()
86
+ ]
87
+
88
+ return hash256(Buff.join(sighash))
89
+ }
90
+
91
+ function hash_prevouts (
92
+ vin : TxInput[],
93
+ isAnypay ?: boolean
94
+ ) : Uint8Array {
95
+ if (isAnypay === true) {
96
+ return Buff.num(0, 32)
97
+ }
98
+
99
+ const stack = []
100
+
101
+ for (const { txid, vout } of vin) {
102
+ stack.push(encode_txin_txid(txid))
103
+ stack.push(encode_txin_vout(vout))
104
+ }
105
+
106
+ return hash256(Buff.join(stack))
107
+ }
108
+
109
+ function hash_sequence (
110
+ vin : TxInput[],
111
+ sigflag : number,
112
+ isAnyPay : boolean
113
+ ) : Uint8Array {
114
+ if (isAnyPay || sigflag !== 0x01) {
115
+ return Buff.num(0, 32)
116
+ }
117
+
118
+ const stack = []
119
+
120
+ for (const { sequence } of vin) {
121
+ stack.push(encode_txin_sequence(sequence))
122
+ }
123
+ return hash256(Buff.join(stack))
124
+ }
125
+
126
+ function hash_outputs (
127
+ vout : TxOutput[],
128
+ sigflag : number,
129
+ idx ?: number
130
+ ) : Uint8Array {
131
+ const stack = []
132
+
133
+ if (sigflag === 0x01) {
134
+ for (const { value, script_pk } of vout) {
135
+ stack.push(encode_vout_value(value))
136
+ stack.push(prefix_script_size(script_pk))
137
+ }
138
+ return hash256(Buff.join(stack))
139
+ }
140
+
141
+ if (sigflag === 0x03) {
142
+ Assert.ok(idx !== undefined)
143
+ if (idx < vout.length) {
144
+ const { value, script_pk } = vout[idx]
145
+ stack.push(encode_vout_value(value))
146
+ stack.push(prefix_script_size(script_pk))
147
+ return hash256(Buff.join(stack))
148
+ }
149
+ }
150
+
151
+ return Buff.num(0, 32)
152
+ }
@@ -0,0 +1,35 @@
1
+ import { ECC } from '@vbyte/micro-lib'
2
+ import { parse_tx_data } from '@/lib/tx/parse.js'
3
+ import { SIGHASH_DEFAULT } from '@/const.js'
4
+ import { hash_segwit_tx } from './segwit.js'
5
+ import { hash_taproot_tx } from './taproot.js'
6
+ import { format_sigflag } from './util.js'
7
+
8
+ import type {
9
+ SigHashOptions,
10
+ TxData
11
+ } from '@/types/index.js'
12
+
13
+ export function sign_segwit_tx (
14
+ seckey : string,
15
+ txdata : TxData,
16
+ options : SigHashOptions,
17
+ ) {
18
+ const tx = parse_tx_data(txdata)
19
+ const msg = hash_segwit_tx(tx, options)
20
+ const sig = ECC.sign_ecdsa(seckey, msg).hex
21
+ const flag = format_sigflag(options.sigflag ?? SIGHASH_DEFAULT)
22
+ return sig + flag
23
+ }
24
+
25
+ export function sign_taproot_tx (
26
+ seckey : string,
27
+ txdata : TxData,
28
+ options : SigHashOptions,
29
+ ) {
30
+ const tx = parse_tx_data(txdata)
31
+ const msg = hash_taproot_tx(tx, options)
32
+ const sig = ECC.sign_bip340(seckey, msg).hex
33
+ const flag = format_sigflag(options.sigflag ?? 0)
34
+ return sig + flag
35
+ }
@@ -0,0 +1,236 @@
1
+ import { Buff } from '@vbyte/buff'
2
+ import { Assert } from '@vbyte/micro-lib'
3
+ import { hash340, sha256 } from '@vbyte/micro-lib/hash'
4
+ import { prefix_script_size } from '@/lib/script/util.js'
5
+ import { encode_tapscript } from '@/lib/taproot/encode.js'
6
+ import { parse_tx_data } from '@/lib/tx/parse.js'
7
+ import * as CONST from '@/const.js'
8
+ import { parse_txinput } from './util.js'
9
+
10
+ import {
11
+ encode_txin_vout,
12
+ encode_tx_locktime,
13
+ encode_txin_sequence,
14
+ encode_txin_txid,
15
+ encode_vout_value,
16
+ encode_tx_version
17
+ } from '@/lib/tx/encode.js'
18
+
19
+ import type {
20
+ SigHashOptions,
21
+ TxData,
22
+ TxInput,
23
+ TxOutput
24
+ } from '@/types/index.js'
25
+
26
+ export function hash_taproot_tx (
27
+ template : TxData | string,
28
+ config : SigHashOptions = {}
29
+ ) : Buff {
30
+ // Unpack configuration.
31
+ const {
32
+ script,
33
+ txindex,
34
+ sigflag = 0x00,
35
+ extflag = 0x00,
36
+ key_version = 0x00,
37
+ separator_pos = 0xFFFFFFFF
38
+ } = config
39
+ // Normalize the txdata object.
40
+ const tx = parse_tx_data(template)
41
+ // Unpack the txdata object.
42
+ const { version, vin: input, vout: output, locktime } = tx
43
+ // Parse the input we are signing from the config.
44
+ const txinput = parse_txinput(tx, config)
45
+ // Unpack the txinput object.
46
+ const { txid, vout, sequence, witness = [] } = txinput
47
+ // Check if we are using a valid hash type.
48
+ if (!CONST.SIGHASH_TAPROOT.includes(sigflag)) {
49
+ // If the sigflag is an invalid type, throw error.
50
+ throw new Error('Invalid hash type: ' + String(sigflag))
51
+ }
52
+ if (extflag < 0 || extflag > 127) {
53
+ // If the extflag is out of range, throw error.
54
+ throw new Error('Extention flag out of range: ' + String(extflag))
55
+ }
56
+
57
+ let { extension } = config
58
+
59
+ if (script !== undefined) {
60
+ extension = encode_tapscript(script).hex
61
+ }
62
+
63
+ // Define the parameters of the transaction.
64
+ const is_anypay = (sigflag & 0x80) === 0x80
65
+ const annex = get_annex_data(witness)
66
+ const annexBit = (annex !== undefined) ? 1 : 0
67
+ const extendBit = (extension !== undefined) ? 1 : 0
68
+ const spendType = ((extflag + extendBit) * 2) + annexBit
69
+ const hashtag = hash340('TapSighash')
70
+
71
+ // Begin building our preimage.
72
+ const preimage : (string | Uint8Array)[] = [
73
+ hashtag, // Buffer input with TapSighash.
74
+ Buff.num(0x00, 1), // Add zero-byte.
75
+ Buff.num(sigflag, 1), // Commit to signature flag.
76
+ encode_tx_version(version), // Commit to tx version.
77
+ encode_tx_locktime(locktime) // Commit to tx locktime.
78
+ ]
79
+
80
+ if (!is_anypay) {
81
+ // If flag ANYONE_CAN_PAY is not set,
82
+ // then commit to all inputs.
83
+ const prevouts = input.map(e => get_prevout(e))
84
+ preimage.push(
85
+ hash_outpoints(input), // Commit to txid/vout for each input.
86
+ hash_amounts(prevouts), // Commit to prevout amount for each input.
87
+ hash_scripts(prevouts), // Commit to prevout script for each input.
88
+ hash_sequence(input) // Commit to sequence value for each input.
89
+ )
90
+ }
91
+
92
+ if ((sigflag & 0x03) < 2 || (sigflag & 0x03) > 3) {
93
+ // If neither SINGLE or NONE flags are set,
94
+ // include a commitment to all outputs.
95
+ preimage.push(hash_outputs(output))
96
+ }
97
+
98
+ // At this step, we include the spend type.
99
+ preimage.push(Buff.num(spendType, 1))
100
+
101
+ if (is_anypay) {
102
+ // If ANYONE_CAN_PAY flag is set, then we will
103
+ // provide a commitment to the input being signed.
104
+ const { value, script_pk } = get_prevout(txinput)
105
+ preimage.push(
106
+ encode_txin_txid(txid), // Commit to the input txid.
107
+ encode_txin_vout(vout), // Commit to the input vout index.
108
+ encode_vout_value(value), // Commit to the input's prevout value.
109
+ prefix_script_size(script_pk), // Commit to the input's prevout script.
110
+ encode_txin_sequence(sequence) // Commit to the input's sequence value.
111
+ )
112
+ } else {
113
+ // Otherwise, we must have already included a commitment
114
+ // to all inputs in the tx, so simply add a commitment to
115
+ // the index of the input we are signing for.
116
+ Assert.ok(typeof txindex === 'number')
117
+ preimage.push(Buff.num(txindex, 4).reverse())
118
+ }
119
+
120
+ if (annex !== undefined) {
121
+ // If an annex has been set, include it here.
122
+ preimage.push(annex)
123
+ }
124
+
125
+ if ((sigflag & 0x03) === 0x03) {
126
+ // If the SINGLE flag is set, then include a
127
+ // commitment to the output which is adjacent
128
+ // to the input that we are signing for.
129
+ Assert.ok(typeof txindex === 'number')
130
+ preimage.push(hash_output(output[txindex]))
131
+ }
132
+
133
+ if (extension !== undefined) {
134
+ // If we are extending this signature to include
135
+ // other commitments (such as a tapleaf), then we
136
+ // will add it to the preimage here.
137
+ preimage.push(
138
+ Buff.bytes(extension), // Extention data (in bytes).
139
+ Buff.num(key_version), // Key version (reserved for future upgrades).
140
+ Buff.num(separator_pos, 4) // If OP_CODESEPARATOR is used, this must be set.
141
+ )
142
+ }
143
+
144
+ // Useful for debugging the preimage stack.
145
+ // console.log(preimage.map(e => Buff.raw(e).hex))
146
+
147
+ return sha256(Buff.join(preimage))
148
+ }
149
+
150
+ export function hash_outpoints (
151
+ vin : TxInput[]
152
+ ) : Buff {
153
+ const stack = []
154
+ for (const { txid, vout } of vin) {
155
+ stack.push(encode_txin_txid(txid))
156
+ stack.push(encode_txin_vout(vout))
157
+ }
158
+ return sha256(Buff.join(stack))
159
+ }
160
+
161
+ export function hash_sequence (
162
+ vin : TxInput[]
163
+ ) : Buff {
164
+ const stack = []
165
+ for (const { sequence } of vin) {
166
+ stack.push(encode_txin_sequence(sequence))
167
+ }
168
+ return sha256(Buff.join(stack))
169
+ }
170
+
171
+ export function hash_amounts (
172
+ prevouts : TxOutput[]
173
+ ) : Buff {
174
+ const stack = []
175
+ for (const { value } of prevouts) {
176
+ stack.push(encode_vout_value(value))
177
+ }
178
+ return sha256(Buff.join(stack))
179
+ }
180
+
181
+ export function hash_scripts (
182
+ prevouts : TxOutput[]
183
+ ) : Buff {
184
+ const stack = []
185
+ for (const { script_pk } of prevouts) {
186
+ stack.push(prefix_script_size(script_pk))
187
+ }
188
+ return sha256(Buff.join(stack))
189
+ }
190
+
191
+ export function hash_outputs (
192
+ vout : TxOutput[]
193
+ ) : Buff {
194
+ const stack = []
195
+ for (const { value, script_pk } of vout) {
196
+ stack.push(encode_vout_value(value))
197
+ stack.push(prefix_script_size(script_pk))
198
+ }
199
+ return sha256(Buff.join(stack))
200
+ }
201
+
202
+ export function hash_output (
203
+ vout : TxOutput
204
+ ) : Buff {
205
+ return sha256(
206
+ encode_vout_value(vout.value),
207
+ prefix_script_size(vout.script_pk)
208
+ )
209
+ }
210
+
211
+ function get_annex_data (
212
+ witness ?: string[]
213
+ ) : Buff | undefined {
214
+ // If no witness exists, return undefined.
215
+ if (witness === undefined) return
216
+ // If there are less than two elements, return undefined.
217
+ if (witness.length < 2) return
218
+ // Define the last element as the annex.
219
+ const annex = witness.at(-1)
220
+ // If the annex is a string and starts with '50',
221
+ if (typeof annex === 'string' && annex.startsWith('50')) {
222
+ // Convert the annex to a buffer with a varint prefix.
223
+ const bytes = Buff.hex(annex).prefix_varint('be')
224
+ // Return the sha256 of the annex.
225
+ return sha256(bytes)
226
+ }
227
+ // Else, return undefined.
228
+ return undefined
229
+ }
230
+
231
+ function get_prevout (vin : TxInput) : TxOutput {
232
+ if (vin.prevout === null) {
233
+ throw new Error('Prevout data missing for input: ' + String(vin.txid))
234
+ }
235
+ return vin.prevout
236
+ }
@@ -0,0 +1,29 @@
1
+ import { Buff } from '@vbyte/buff'
2
+ import { Assert } from '@vbyte/micro-lib'
3
+
4
+ import type {
5
+ SigHashOptions,
6
+ TxInput,
7
+ TxData,
8
+ } from '@/types/index.js'
9
+
10
+ export function parse_txinput (
11
+ txdata : TxData,
12
+ config ?: SigHashOptions
13
+ ) : TxInput {
14
+ let { txindex, txinput } = config ?? {}
15
+ if (txindex !== undefined) {
16
+ if (txindex >= txdata.vin.length) {
17
+ // If index is out of bounds, throw error.
18
+ throw new Error('Input index out of bounds: ' + String(txindex))
19
+ }
20
+ txinput = txdata.vin.at(txindex)
21
+ }
22
+ Assert.ok(txinput !== undefined)
23
+ return txinput
24
+ }
25
+
26
+ export function format_sigflag (flag : number) {
27
+ return (flag !== 0) ? Buff.num(flag, 1).hex : ''
28
+ }
29
+
@@ -0,0 +1,83 @@
1
+ // import { Buff, Bytes, Stream } from '@vbyte/buff'
2
+ // import { safeThrow } from '@/lib/utils.js'
3
+ // import { checkPath } from '@/lib/tap/key.js'
4
+ // import { getTapLeaf } from '@/lib/tap/tree.js'
5
+ // import { Tx } from '@/lib/tx/index.js'
6
+ // import { Script } from '@/lib/script/index.js'
7
+ // import { HashConfig, TxData } from '@/types/index.js'
8
+ // import { TxTemplate } from '@/schema/types.js'
9
+ // import { hashTx } from './segwit.js'
10
+
11
+ // export function verify_signature (
12
+ // txdata : TxData | Bytes,
13
+ // index : number,
14
+ // config : HashConfig = {}
15
+ // ) : boolean {
16
+ // const tx = Tx.fmt.toJson(txdata)
17
+ // const { throws = false } = config
18
+ // const { prevout, witness = [] } = tx.vin[index]
19
+ // const witnessData = Tx.util.readWitness(witness)
20
+ // const { cblock, script, params } = witnessData
21
+
22
+ // let pub : Buff
23
+
24
+ // if (params.length < 1) {
25
+ // return safeThrow('Invalid witness data: ' + String(witness), throws)
26
+ // }
27
+
28
+ // const { scriptPubKey } = prevout ?? {}
29
+
30
+ // if (scriptPubKey === undefined) {
31
+ // return safeThrow('Prevout scriptPubKey is empty!', throws)
32
+ // }
33
+
34
+ // const { type, data: tapkey } = Tx.util.readScriptPubKey(scriptPubKey)
35
+
36
+ // if (type !== 'p2tr') {
37
+ // return safeThrow('Prevout script is not a valid taproot output:' + tapkey.hex, throws)
38
+ // }
39
+
40
+ // if (tapkey.length !== 32) {
41
+ // return safeThrow('Invalid tapkey length: ' + String(tapkey.length), throws)
42
+ // }
43
+
44
+ // if (
45
+ // cblock !== null &&
46
+ // script !== null
47
+ // ) {
48
+ // const version = cblock[0] & 0xfe
49
+ // const target = getTapLeaf(script, version)
50
+ // config.extension = target
51
+
52
+ // if (!checkPath(tapkey, target, cblock, { throws })) {
53
+ // return safeThrow('cblock verification failed!', throws)
54
+ // }
55
+ // }
56
+
57
+ // if (config.pubkey !== undefined) {
58
+ // pub = Buff.bytes(config.pubkey)
59
+ // } else if (params.length > 1 && params[1].length === 32) {
60
+ // pub = Buff.bytes(params[1])
61
+ // } else {
62
+ // pub = Buff.bytes(tapkey)
63
+ // }
64
+
65
+ // const rawsig = Script.fmt.toParam(params[0])
66
+ // const stream = new Stream(rawsig)
67
+ // const signature = stream.read(64).raw
68
+
69
+ // if (stream.size === 1) {
70
+ // config.sigflag = stream.read(1).num
71
+ // if (config.sigflag === 0x00) {
72
+ // return safeThrow('0x00 is not a valid appended sigflag!', throws)
73
+ // }
74
+ // }
75
+
76
+ // const hash = hashTx(tx, index, config)
77
+
78
+ // if (!verify(signature, hash, pub, throws)) {
79
+ // return safeThrow('Invalid signature!', throws)
80
+ // }
81
+
82
+ // return true
83
+ // }
@@ -0,0 +1,95 @@
1
+ import { Buff, Bytes } 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
+
7
+ import {
8
+ encode_tapbranch,
9
+ encode_taptweak
10
+ } from './encode.js'
11
+
12
+ import {
13
+ parse_pubkey_parity,
14
+ parse_cblock
15
+ } from './parse.js'
16
+
17
+ import {
18
+ TaprootConfig,
19
+ TaprootContext
20
+ } from '@/types/index.js'
21
+
22
+ const DEFAULT_VERSION = TAPLEAF_DEFAULT_VERSION
23
+
24
+ export function create_taproot (config : TaprootConfig) : TaprootContext {
25
+ Schema.taproot.config.parse(config)
26
+
27
+ const { pubkey, version = DEFAULT_VERSION } = config
28
+
29
+ const leaves = config.leaves ?? []
30
+
31
+ const target = (config.target !== undefined)
32
+ ? Buff.bytes(config.target).hex
33
+ : undefined
34
+
35
+ let path : string[] = [],
36
+ taproot : string | undefined
37
+
38
+ if (leaves.length > 0) {
39
+ // Merkelize the leaves into a root hash (with proof).
40
+ const [ root, _, proofs ] = merkleize(leaves, target)
41
+ // Get the control path from the merkelized output.
42
+ path = proofs
43
+ // Get the tapped key from the internal key.
44
+ taproot = root
45
+ } else {
46
+ // Get the tapped key from the single tapleaf.
47
+ taproot = target
48
+ }
49
+
50
+ const taptweak = encode_taptweak(pubkey, taproot)
51
+ const twk_key = ECC.tweak_pubkey(pubkey, taptweak, 'ecdsa')
52
+ const parity = parse_pubkey_parity(twk_key)
53
+ const tapkey = ECC.serialize_pubkey(twk_key, 'bip340')
54
+ // Get the block version / parity bit.
55
+ const cbit = Buff.num(version + parity)
56
+ // Stack the initial control block data.
57
+ const block : Bytes[] = [ cbit, Buff.bytes(pubkey) ]
58
+ // If there is more than one path, add to block.
59
+ if (path.length > 0) {
60
+ path.forEach(e => block.push(e))
61
+ }
62
+ // Merge the data together into one array.
63
+ const cblock = Buff.join(block)
64
+
65
+ return {
66
+ int_key : Buff.bytes(pubkey).hex,
67
+ parity,
68
+ taproot : taproot ?? null,
69
+ cblock : cblock.hex,
70
+ tapkey : tapkey.hex,
71
+ taptweak : taptweak.hex
72
+ }
73
+ }
74
+
75
+ export function verify_taproot (
76
+ tapkey : string,
77
+ target : string,
78
+ cblock : string
79
+ ) : boolean {
80
+ Assert.size(tapkey, 32)
81
+ const { parity, path, int_key } = parse_cblock(cblock)
82
+
83
+ const ext_key = Buff.join([ parity, tapkey ])
84
+
85
+ let branch = Buff.bytes(target).hex
86
+
87
+ for (const leaf of path) {
88
+ branch = encode_tapbranch(branch, leaf).hex
89
+ }
90
+
91
+ const tap_tweak = encode_taptweak(int_key, branch)
92
+ const tweaked_key = ECC.tweak_pubkey(int_key, tap_tweak, 'ecdsa')
93
+
94
+ return (ext_key.hex === tweaked_key.hex)
95
+ }
@@ -0,0 +1,49 @@
1
+ import { Buff } from '@vbyte/buff'
2
+ import { hash340 } from '@vbyte/micro-lib/hash'
3
+ import { Assert } from '@vbyte/micro-lib'
4
+ import { prefix_script_size } from '@/lib/script/index.js'
5
+
6
+ import { TAPLEAF_DEFAULT_VERSION } from '@/const.js'
7
+
8
+ const DEFAULT_VERSION = TAPLEAF_DEFAULT_VERSION
9
+
10
+ export function encode_tapscript (
11
+ script : string | Uint8Array,
12
+ version = DEFAULT_VERSION
13
+ ) : Buff {
14
+ const preimg = prefix_script_size(script)
15
+ return encode_tapleaf(preimg, version)
16
+ }
17
+
18
+ export function encode_tapleaf (
19
+ data : string | Uint8Array,
20
+ version = DEFAULT_VERSION
21
+ ) : Buff {
22
+ const vbyte = encode_leaf_version(version)
23
+ return hash340('TapLeaf', vbyte, data)
24
+ }
25
+
26
+ export function encode_tapbranch (
27
+ leaf_a : string,
28
+ leaf_b : string
29
+ ) : Buff {
30
+ // Compare leaves in lexical order.
31
+ if (leaf_b < leaf_a) {
32
+ // Swap leaves if needed.
33
+ [ leaf_a, leaf_b ] = [ leaf_b, leaf_a ]
34
+ }
35
+ // Return digest of leaves as a branch hash.
36
+ return hash340('TapBranch', leaf_a, leaf_b)
37
+ }
38
+
39
+ export function encode_leaf_version (version = 0xc0) : number {
40
+ return version & 0xfe
41
+ }
42
+
43
+ export function encode_taptweak (
44
+ pubkey : string | Uint8Array,
45
+ data : string | Uint8Array = new Uint8Array()
46
+ ) : Buff {
47
+ Assert.size(pubkey, 32)
48
+ return hash340('TapTweak', pubkey, data)
49
+ }
@@ -0,0 +1,4 @@
1
+ export * from './cblock.js'
2
+ export * from './encode.js'
3
+ export * from './parse.js'
4
+ export * from './tree.js'