@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,62 @@
1
+ import { Assert } from '@vbyte/micro-lib'
2
+ import { parse_psbt } from './encoder.js'
3
+
4
+ import type {
5
+ PSBTData,
6
+ PSBTInput,
7
+ PSBTOutput,
8
+ PSBTPrevouts
9
+ } from '@/types/index.js'
10
+
11
+ export function collect_vins (
12
+ psbt : string | PSBTData
13
+ ) : PSBTInput[] {
14
+ const pdata = parse_psbt(psbt)
15
+ const count = pdata.inputsLength
16
+ const vins : PSBTInput[] = []
17
+ for (let i = 0; i < count; i++) {
18
+ const vin = pdata.getInput(i)
19
+ vins.push(vin)
20
+ }
21
+ return vins
22
+ }
23
+
24
+ export function collect_vouts (
25
+ psbt : string | PSBTData
26
+ ) : PSBTOutput[] {
27
+ const pdata = parse_psbt(psbt)
28
+ const count = pdata.outputsLength
29
+ const vouts : PSBTOutput[] = []
30
+ for (let i = 0; i < count; i++) {
31
+ const vout = pdata.getOutput(i)
32
+ vouts.push(vout)
33
+ }
34
+ return vouts
35
+ }
36
+
37
+ export function collect_prevouts (
38
+ psbt : PSBTData
39
+ ) : PSBTPrevouts {
40
+ const amounts : bigint[] = [],
41
+ scripts : Uint8Array[] = []
42
+ const pdata = parse_psbt(psbt)
43
+ for (let i = 0; i < pdata.inputsLength; i++) {
44
+ const txin = pdata.getInput(i)
45
+ Assert.exists(txin.witnessUtxo, `witness utxo does not exist for input ${i}`)
46
+ amounts.push(txin.witnessUtxo.amount)
47
+ scripts.push(txin.witnessUtxo.script)
48
+ }
49
+ return { amounts, scripts }
50
+ }
51
+
52
+ export function finalize_legacy_inputs (pdata : PSBTData) {
53
+ for (let i = 0; i < pdata.inputsLength; i++) {
54
+ const pvin = pdata.getInput(i)
55
+ const script = pvin.redeemScript
56
+ const psig = pvin.partialSig?.at(0)
57
+ if (script !== undefined && psig !== undefined) {
58
+ pdata.finalizeIdx(i)
59
+ }
60
+ }
61
+ return pdata
62
+ }
@@ -0,0 +1,18 @@
1
+ import { Assert } from '@vbyte/micro-lib'
2
+ import { parse_psbt } from './encoder.js'
3
+
4
+ import {
5
+ collect_vins,
6
+ collect_vouts
7
+ } from './util.js'
8
+
9
+ import type { PSBTData } from '@/types/index.js'
10
+
11
+ export function assert_psbt_is_funded (psbt : string | PSBTData) : void {
12
+ const pdata = parse_psbt(psbt)
13
+ const pvouts = collect_vins(pdata)
14
+ const txouts = collect_vouts(pdata)
15
+ const vin_amt = pvouts.reduce((p, n) => p + Number(n.witnessUtxo?.amount ?? 0), 0)
16
+ const out_amt = txouts.reduce((p, n) => p + Number(n.amount ?? 0), 0)
17
+ Assert.ok(vin_amt >= out_amt, `value in (${vin_amt}) < value out (${out_amt})`)
18
+ }
@@ -0,0 +1,75 @@
1
+ import { Stream } from '@vbyte/buff'
2
+
3
+ import {
4
+ get_op_code,
5
+ get_op_type,
6
+ is_valid_op
7
+ } from './words.js'
8
+
9
+ /**
10
+ * Decode a bitcoin script into asm instructions.
11
+ */
12
+ export function decode_script (
13
+ script : string | Uint8Array
14
+ ) : string[] {
15
+ const stream = new Stream(script)
16
+
17
+ const stack : string[] = []
18
+ const stack_size = stream.size
19
+
20
+ let word : number
21
+ let word_type : string
22
+ let word_size : number
23
+
24
+ let count = 0
25
+
26
+ while (count < stack_size) {
27
+ word = stream.read(1).num
28
+ word_type = get_op_type(word)
29
+ count++
30
+ switch (word_type) {
31
+ case 'varint':
32
+ stack.push(stream.read(word).hex)
33
+ count += word
34
+ break
35
+ case 'pushdata1':
36
+ word_size = stream.read(1).reverse().num
37
+ stack.push(stream.read(word_size).hex)
38
+ count += word_size + 1
39
+ break
40
+ case 'pushdata2':
41
+ word_size = stream.read(2).reverse().num
42
+ stack.push(stream.read(word_size).hex)
43
+ count += word_size + 2
44
+ break
45
+ case 'pushdata4':
46
+ word_size = stream.read(4).reverse().num
47
+ stack.push(stream.read(word_size).hex)
48
+ count += word_size + 4
49
+ break
50
+ case 'opcode':
51
+ if (!is_valid_op(word)) {
52
+ throw new Error(`Invalid OPCODE: ${word}`)
53
+ }
54
+ stack.push(get_op_code(word))
55
+ break
56
+ default:
57
+ throw new Error(`Word type undefined: ${word}`)
58
+ }
59
+ }
60
+ return stack
61
+ }
62
+
63
+ /**
64
+ * Check if a script is valid.
65
+ */
66
+ export function is_valid_script (
67
+ script : string | Uint8Array
68
+ ) : boolean {
69
+ try {
70
+ const stack = decode_script(script)
71
+ return stack.length > 0
72
+ } catch {
73
+ return false
74
+ }
75
+ }
@@ -0,0 +1,130 @@
1
+ import { Buff, Stream } from '@vbyte/buff'
2
+ import { get_asm_code, } from './words.js'
3
+
4
+ // The maximum size of a word in bytes.
5
+ const MAX_WORD_SIZE = 520
6
+
7
+ /**
8
+ * Encode script asm instructions into a hex string.
9
+ */
10
+ export function encode_script (
11
+ words : (string | number | Uint8Array)[],
12
+ varint = false
13
+ ) : string {
14
+ if (words.length === 0) return '00'
15
+
16
+ const bytes = []
17
+
18
+ for (const word of words) {
19
+
20
+ bytes.push(encode_script_word(word))
21
+ }
22
+
23
+ const buffer = Buff.join(bytes)
24
+
25
+ return (varint)
26
+ ? buffer.prepend(Buff.varint(buffer.length, 'le')).hex
27
+ : buffer.hex
28
+ }
29
+
30
+
31
+ /** Check if the word is a valid opcode,
32
+ * and return its integer value.
33
+ */
34
+ export function encode_script_word (word : string | number | Uint8Array) : Uint8Array {
35
+ let buff : Buff
36
+
37
+ // If word is a string:
38
+ if (typeof (word) === 'string') {
39
+ // If word is an opcode:
40
+ if (word.startsWith('OP_')) {
41
+ // Get the opcode number value.
42
+ const asm_code = get_asm_code(word)
43
+ // Return the opcode as a single byte.
44
+ return Buff.num(asm_code, 1)
45
+ // If word is valid hex:
46
+ } else if (Buff.is_hex(word)) {
47
+ // Encode as hex.
48
+ buff = Buff.hex(word)
49
+ } else {
50
+ // Encode as UTF8 string.
51
+ buff = Buff.str(word)
52
+ }
53
+ // If word is a number:
54
+ } else if (typeof (word) === 'number') {
55
+ // Encode the number value.
56
+ buff = Buff.num(word)
57
+ // If word is a Uint8Array:
58
+ } else if (word instanceof Uint8Array) {
59
+ // Encode as bytes.
60
+ buff = new Buff(word)
61
+ } else {
62
+ // If word is not a string, number, or Uint8Array, throw an error.
63
+ throw new Error('invalid word type:' + typeof (word))
64
+ }
65
+
66
+ // Format and return the word based on its size.
67
+ if (buff.length === 1 && buff[0] <= 16) {
68
+ // Number values 0-16 must be treated as opcodes.
69
+ if (buff[0] !== 0) buff[0] += 0x50
70
+ } else if (buff.length > MAX_WORD_SIZE) {
71
+ // Number values larger than max size must be split into chunks.
72
+ let words : Buff[]
73
+ // Split bytes into chunks, based on max word size.
74
+ words = split_script_word(buff)
75
+ // Prefix a varint length byte for each chunk.
76
+ words = words.map(e => prefix_word_size(e))
77
+ // Concatenate the chunks
78
+ buff = Buff.join(words)
79
+ } else {
80
+ // Else, return the word with a varint prefix.
81
+ buff = prefix_word_size(buff)
82
+ }
83
+ // Return the final result.
84
+ return buff
85
+ }
86
+
87
+ /**
88
+ * Split a word into smaller chunks.
89
+ */
90
+ export function split_script_word (
91
+ word : Uint8Array
92
+ ) : Buff[] {
93
+ const words = []
94
+ const buff = new Stream(word)
95
+ while (buff.size > MAX_WORD_SIZE) {
96
+ // Push a word chunk to the array.
97
+ words.push(buff.read(MAX_WORD_SIZE))
98
+ }
99
+ // Push the remainder to the array.
100
+ words.push(buff.read(buff.size))
101
+ return words
102
+ }
103
+
104
+ /**
105
+ * Prefix a word with its size, encoded as a varint.
106
+ */
107
+ export function prefix_word_size (
108
+ word : Uint8Array
109
+ ) : Buff {
110
+ const varint = get_size_varint(word.length)
111
+ return Buff.join([ varint, word ])
112
+ }
113
+
114
+ /**
115
+ * Return a varint that encodes a size value.
116
+ */
117
+ export function get_size_varint (size : number) : Buff {
118
+ const OP_PUSHDATA1 = Buff.num(0x4c, 1)
119
+ const OP_PUSHDATA2 = Buff.num(0x4d, 1)
120
+ switch (true) {
121
+ case (size <= 0x4b):
122
+ return Buff.num(size)
123
+ case (size > 0x4b && size < 0x100):
124
+ return Buff.join([ OP_PUSHDATA1, Buff.num(size, 1, 'le') ])
125
+ case (size >= 0x100 && size <= MAX_WORD_SIZE):
126
+ return Buff.join([ OP_PUSHDATA2, Buff.num(size, 2, 'le') ])
127
+ default:
128
+ throw new Error('Invalid word size:' + size.toString())
129
+ }
130
+ }
@@ -0,0 +1,26 @@
1
+ import { OPCODE_MAP } from './words.js'
2
+ import { encode_script } from './encode.js'
3
+
4
+ import {
5
+ decode_script,
6
+ is_valid_script
7
+ } from './decode.js'
8
+
9
+ import {
10
+ parse_script_pubkeys,
11
+ prefix_script_size
12
+ } from './util.js'
13
+
14
+ export * from './decode.js'
15
+ export * from './encode.js'
16
+ export * from './util.js'
17
+ export * from './words.js'
18
+
19
+ export namespace ScriptUtil {
20
+ export const prefix_size = prefix_script_size
21
+ export const decode = decode_script
22
+ export const encode = encode_script
23
+ export const is_valid = is_valid_script
24
+ export const get_pubkeys = parse_script_pubkeys
25
+ export const OPCODES = OPCODE_MAP
26
+ }
@@ -0,0 +1,78 @@
1
+ import { Buff } from '@vbyte/buff'
2
+
3
+ export function prefix_script_size (script: string | Uint8Array): string {
4
+ return Buff.bytes(script).prefix_varint('le').hex
5
+ }
6
+
7
+ export function parse_script_pubkeys (script: string | Uint8Array): string[] {
8
+ // Convert the script to a string if it's a Uint8Array
9
+ const scriptHex = typeof script === 'string' ? script : Buff.bytes(script).hex
10
+
11
+ // Define the regex pattern to match the specified pattern
12
+ // 20 = pushdata byte for 32 bytes (0x20)
13
+ // [0-9a-f]{64} = 32-byte hex string (64 hex characters)
14
+ // (ac|ad|ba) = OP_CHECKSIG (0xac), OP_CHECKSIGVERIFY (0xad), or OP_CHECKSIGADD (0xba)
15
+ const pubkeyPattern = /20([0-9a-f]{64})(ac|ad|ba)/gi
16
+
17
+ // Find all matches in the script
18
+ const matches = [...scriptHex.matchAll(pubkeyPattern)]
19
+
20
+ // Extract the public keys from the matches
21
+ return matches.map(match => match[1])
22
+ }
23
+
24
+ // export function parse_witness_pubkeys (
25
+ // witness : string[] | TxWitnessData
26
+ // ) : string[] {
27
+ // // Parse the witness data if it is an array.
28
+ // if (witness instanceof Array) {
29
+ // witness = parse_witness_data(witness)
30
+ // }
31
+ // // Define the set of pubkeys.
32
+ // const pubkeys = new Set<string>()
33
+ // // Get the witness type.
34
+ // const type = witness.type
35
+ // // If the witness type is a p2tr-ts:
36
+ // if (type === 'p2tr-ts') {
37
+ // // Parse the internal pubkey from the cblock.
38
+ // const int_pk = witness.cblock?.slice(2, 66)
39
+ // // If the internal pubkey is present, add it to the list.
40
+ // if (int_pk !== undefined) pubkeys.add(int_pk)
41
+ // // Parse any pubkeys witness parameters.
42
+ // witness.params
43
+ // .filter(p => p.length === 64)
44
+ // .forEach(p => pubkeys.add(p))
45
+ // // Parse any pubkeys from the script.
46
+ // parse_taproot_pubkeys(witness.script!)
47
+ // .forEach(p => pubkeys.add(p))
48
+ // // If the witness type is a p2w-pkh:
49
+ // } else if (type === 'p2w-pkh') {
50
+ // // Parse the witness parameter pubkey.
51
+ // const params_pk = witness.params.find(p => p.length === 66)
52
+ // // If the parameter pubkey is present, add it to the list.
53
+ // if (params_pk !== undefined) pubkeys.add(params_pk)
54
+ // // If the witness type is a p2w-sh:
55
+ // } else if (type === 'p2w-sh') {
56
+ // // Parse any witness parameter pubkeys.
57
+ // witness.params
58
+ // .filter(p => p.length === 66)
59
+ // .forEach(p => pubkeys.add(p))
60
+ // // Parse any script pubkeys.
61
+ // parse_segwit_pubkeys(witness.script!)
62
+ // .forEach(p => pubkeys.add(p))
63
+ // }
64
+ // // Return the list of pubkeys.
65
+ // return Array.from(pubkeys)
66
+ // }
67
+
68
+ // function parse_segwit_pubkeys (script : string) : string[] {
69
+ // const regex = /21([0-9a-f]{66})(ac|ad)/gi
70
+ // const matches = [...script.matchAll(regex)]
71
+ // return matches.map(match => match[1])
72
+ // }
73
+
74
+ // function parse_taproot_pubkeys (script : string) : string[] {
75
+ // const regex = /20([0-9a-f]{64})(ac|ad|ba)/gi
76
+ // const matches = [...script.matchAll(regex)]
77
+ // return matches.map(match => match[1])
78
+ // }
@@ -0,0 +1,182 @@
1
+ export const OPCODE_MAP = {
2
+ OP_0 : 0,
3
+ OP_PUSHDATA1 : 76,
4
+ OP_PUSHDATA2 : 77,
5
+ OP_PUSHDATA4 : 78,
6
+ OP_1NEGATE : 79,
7
+ OP_SUCCESS80 : 80,
8
+ OP_1 : 81,
9
+ OP_2 : 82,
10
+ OP_3 : 83,
11
+ OP_4 : 84,
12
+ OP_5 : 85,
13
+ OP_6 : 86,
14
+ OP_7 : 87,
15
+ OP_8 : 88,
16
+ OP_9 : 89,
17
+ OP_10 : 90,
18
+ OP_11 : 91,
19
+ OP_12 : 92,
20
+ OP_13 : 93,
21
+ OP_14 : 94,
22
+ OP_15 : 95,
23
+ OP_16 : 96,
24
+ OP_NOP : 97,
25
+ OP_SUCCESS98 : 98,
26
+ OP_IF : 99,
27
+ OP_NOTIF : 100,
28
+ OP_ELSE : 103,
29
+ OP_ENDIF : 104,
30
+ OP_VERIFY : 105,
31
+ OP_RETURN : 106,
32
+ OP_TOALTSTACK : 107,
33
+ OP_FROMALTSTACK : 108,
34
+ OP_2DROP : 109,
35
+ OP_2DUP : 110,
36
+ OP_3DUP : 111,
37
+ OP_2OVER : 112,
38
+ OP_2ROT : 113,
39
+ OP_2SWAP : 114,
40
+ OP_IFDUP : 115,
41
+ OP_DEPTH : 116,
42
+ OP_DROP : 117,
43
+ OP_DUP : 118,
44
+ OP_NIP : 119,
45
+ OP_OVER : 120,
46
+ OP_PICK : 121,
47
+ OP_ROLL : 122,
48
+ OP_ROT : 123,
49
+ OP_SWAP : 124,
50
+ OP_TUCK : 125,
51
+ OP_SUCCESS126 : 126,
52
+ OP_SUCCESS127 : 127,
53
+ OP_SUCCESS128 : 128,
54
+ OP_SUCCESS129 : 129,
55
+ OP_SIZE : 130,
56
+ OP_SUCCESS131 : 131,
57
+ OP_SUCCESS132 : 132,
58
+ OP_SUCCESS133 : 133,
59
+ OP_SUCCESS134 : 134,
60
+ OP_EQUAL : 135,
61
+ OP_EQUALVERIFY : 136,
62
+ OP_SUCCESS137 : 137,
63
+ OP_SUCCESS138 : 138,
64
+ OP_1ADD : 139,
65
+ OP_1SUB : 140,
66
+ OP_SUCCESS141 : 141,
67
+ OP_SUCCESS142 : 142,
68
+ OP_NEGATE : 143,
69
+ OP_ABS : 144,
70
+ OP_NOT : 145,
71
+ OP_0NOTEQUAL : 146,
72
+ OP_ADD : 147,
73
+ OP_SUB : 148,
74
+ OP_SUCCESS149 : 149,
75
+ OP_SUCCESS150 : 150,
76
+ OP_SUCCESS151 : 151,
77
+ OP_SUCCESS152 : 152,
78
+ OP_SUCCESS153 : 153,
79
+ OP_BOOLAND : 154,
80
+ OP_BOOLOR : 155,
81
+ OP_NUMEQUAL : 156,
82
+ OP_NUMEQUALVERIFY : 157,
83
+ OP_NUMNOTEQUAL : 158,
84
+ OP_LESSTHAN : 159,
85
+ OP_GREATERTHAN : 160,
86
+ OP_LESSTHANOREQUAL : 161,
87
+ OP_GREATERTHANOREQUAL : 162,
88
+ OP_MIN : 163,
89
+ OP_MAX : 164,
90
+ OP_WITHIN : 165,
91
+ OP_RIPEMD160 : 166,
92
+ OP_SHA1 : 167,
93
+ OP_SHA256 : 168,
94
+ OP_HASH160 : 169,
95
+ OP_HASH256 : 170,
96
+ OP_CODESEPARATOR : 171,
97
+ OP_CHECKSIG : 172,
98
+ OP_CHECKSIGVERIFY : 173,
99
+ OP_CHECKMULTISIG : 174,
100
+ OP_CHECKMULTISIGVERIFY : 175,
101
+ OP_NOP1 : 176,
102
+ OP_CHECKLOCKTIMEVERIFY : 177,
103
+ OP_CHECKSEQUENCEVERIFY : 178,
104
+ OP_NOP4 : 179,
105
+ OP_NOP5 : 180,
106
+ OP_NOP6 : 181,
107
+ OP_NOP7 : 182,
108
+ OP_NOP8 : 183,
109
+ OP_NOP9 : 184,
110
+ OP_NOP10 : 185,
111
+ OP_CHECKSIGADD : 186
112
+ }
113
+
114
+ /**
115
+ * Get the sting-representation of an opcode
116
+ * based on its number value.
117
+ */
118
+ export function get_op_code (num : number) : string {
119
+ if (num > 186 && num < 255) {
120
+ return 'OP_SUCCESS' + String(num)
121
+ }
122
+ for (const [ k, v ] of Object.entries(OPCODE_MAP)) {
123
+ if (v === num) return k
124
+ }
125
+ throw new Error('OPCODE not found:' + String(num))
126
+ }
127
+
128
+ /**
129
+ * Get the number-representation of an opcode
130
+ * based on its asm string value.
131
+ */
132
+ export function get_asm_code (string : string) : number {
133
+ for (const [ k, v ] of Object.entries(OPCODE_MAP)) {
134
+ if (k === string) return Number(v)
135
+ }
136
+ throw new Error('OPCODE not found:' + string)
137
+ }
138
+
139
+ /**
140
+ * Get the type of word based on its number value.
141
+ */
142
+ export function get_op_type (word : number) : string {
143
+ switch (true) {
144
+ case (word === 0):
145
+ return 'opcode'
146
+ case (word >= 1 && word <= 75):
147
+ return 'varint'
148
+ case (word === 76):
149
+ return 'pushdata1'
150
+ case (word === 77):
151
+ return 'pushdata2'
152
+ case (word === 78):
153
+ return 'pushdata4'
154
+ case (word <= 254):
155
+ return 'opcode'
156
+ default:
157
+ throw new Error(`Invalid word range: ${word}`)
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Check if the provided value is a valid script opcode.
163
+ */
164
+ export function is_valid_op (word : number) : boolean {
165
+ const MIN_RANGE = 75
166
+ const MAX_RANGE = 254
167
+
168
+ const DISABLED_OPCODES : number[] = []
169
+
170
+ switch (true) {
171
+ case (typeof (word) !== 'number'):
172
+ return false
173
+ case (word === 0):
174
+ return true
175
+ case (DISABLED_OPCODES.includes(word)):
176
+ return false
177
+ case (MIN_RANGE < word && word < MAX_RANGE):
178
+ return true
179
+ default:
180
+ return false
181
+ }
182
+ }
@@ -0,0 +1,5 @@
1
+ export * from './segwit.js'
2
+ export * from './sign.js'
3
+ export * from './taproot.js'
4
+ export * from './verify.js'
5
+ export * from './util.js'