@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.
- package/CHANGELOG.md +94 -0
- package/README.md +260 -3
- package/dist/const.d.ts +3 -0
- package/dist/const.js +23 -22
- package/dist/index.d.ts +11 -11
- package/dist/index.js +10 -10
- package/dist/lib/address/api.d.ts +2 -2
- package/dist/lib/address/api.js +12 -12
- package/dist/lib/address/encode.d.ts +1 -1
- package/dist/lib/address/encode.js +24 -24
- package/dist/lib/address/index.d.ts +6 -6
- package/dist/lib/address/index.js +6 -6
- package/dist/lib/address/p2pkh.d.ts +2 -2
- package/dist/lib/address/p2pkh.js +14 -14
- package/dist/lib/address/p2sh.d.ts +2 -2
- package/dist/lib/address/p2sh.js +13 -13
- package/dist/lib/address/p2tr.d.ts +2 -2
- package/dist/lib/address/p2tr.js +13 -13
- package/dist/lib/address/p2wpkh.d.ts +2 -2
- package/dist/lib/address/p2wpkh.js +14 -14
- package/dist/lib/address/p2wsh.d.ts +2 -2
- package/dist/lib/address/p2wsh.js +13 -13
- package/dist/lib/address/script.d.ts +1 -1
- package/dist/lib/address/script.js +16 -16
- package/dist/lib/address/util.d.ts +1 -1
- package/dist/lib/address/util.js +22 -22
- package/dist/lib/meta/index.d.ts +4 -4
- package/dist/lib/meta/index.js +4 -4
- package/dist/lib/meta/locktime.d.ts +1 -1
- package/dist/lib/meta/locktime.js +12 -12
- package/dist/lib/meta/ref.js +9 -6
- package/dist/lib/meta/scribe.d.ts +2 -2
- package/dist/lib/meta/scribe.js +48 -53
- package/dist/lib/meta/sequence.d.ts +1 -1
- package/dist/lib/meta/sequence.js +16 -15
- package/dist/lib/script/decode.d.ts +2 -2
- package/dist/lib/script/decode.js +50 -15
- package/dist/lib/script/encode.d.ts +1 -1
- package/dist/lib/script/encode.js +20 -16
- package/dist/lib/script/index.d.ts +5 -13
- package/dist/lib/script/index.js +5 -14
- package/dist/lib/script/lock.d.ts +2 -2
- package/dist/lib/script/lock.js +15 -12
- package/dist/lib/script/util.js +4 -4
- package/dist/lib/script/words.js +129 -129
- package/dist/lib/sighash/index.d.ts +3 -3
- package/dist/lib/sighash/index.js +3 -3
- package/dist/lib/sighash/segwit.d.ts +2 -2
- package/dist/lib/sighash/segwit.js +15 -14
- package/dist/lib/sighash/taproot.d.ts +2 -2
- package/dist/lib/sighash/taproot.js +24 -23
- package/dist/lib/sighash/util.d.ts +2 -2
- package/dist/lib/sighash/util.js +7 -7
- package/dist/lib/signer/index.d.ts +2 -2
- package/dist/lib/signer/index.js +2 -2
- package/dist/lib/signer/sign.d.ts +1 -1
- package/dist/lib/signer/sign.js +42 -7
- package/dist/lib/signer/verify.d.ts +17 -3
- package/dist/lib/signer/verify.js +233 -3
- package/dist/lib/taproot/cblock.d.ts +1 -1
- package/dist/lib/taproot/cblock.js +14 -16
- package/dist/lib/taproot/encode.d.ts +1 -1
- package/dist/lib/taproot/encode.js +7 -7
- package/dist/lib/taproot/index.d.ts +4 -4
- package/dist/lib/taproot/index.js +4 -4
- package/dist/lib/taproot/parse.d.ts +1 -1
- package/dist/lib/taproot/parse.js +12 -14
- package/dist/lib/taproot/tree.d.ts +2 -2
- package/dist/lib/taproot/tree.js +11 -7
- package/dist/lib/tx/create.d.ts +1 -1
- package/dist/lib/tx/create.js +28 -12
- package/dist/lib/tx/decode.d.ts +2 -2
- package/dist/lib/tx/decode.js +50 -17
- package/dist/lib/tx/encode.d.ts +2 -2
- package/dist/lib/tx/encode.js +13 -16
- package/dist/lib/tx/index.d.ts +7 -7
- package/dist/lib/tx/index.js +7 -7
- package/dist/lib/tx/parse.d.ts +1 -1
- package/dist/lib/tx/parse.js +9 -9
- package/dist/lib/tx/size.d.ts +2 -2
- package/dist/lib/tx/size.js +9 -9
- package/dist/lib/tx/util.d.ts +2 -2
- package/dist/lib/tx/util.js +23 -20
- package/dist/lib/tx/validate.d.ts +1 -1
- package/dist/lib/tx/validate.js +3 -3
- package/dist/lib/witness/index.d.ts +2 -2
- package/dist/lib/witness/index.js +2 -2
- package/dist/lib/witness/parse.d.ts +2 -2
- package/dist/lib/witness/parse.js +24 -23
- package/dist/lib/witness/util.d.ts +2 -2
- package/dist/lib/witness/util.js +5 -5
- package/dist/main.cjs +2308 -1005
- package/dist/main.cjs.map +1 -1
- package/dist/module.mjs +2308 -1005
- package/dist/module.mjs.map +1 -1
- package/dist/package.json +20 -17
- package/dist/schema/base.d.ts +1 -1
- package/dist/schema/base.js +17 -13
- package/dist/schema/index.d.ts +2 -2
- package/dist/schema/index.js +2 -2
- package/dist/schema/taproot.d.ts +1 -1
- package/dist/schema/taproot.js +2 -2
- package/dist/schema/tx.d.ts +1 -1
- package/dist/schema/tx.js +4 -4
- package/dist/script.js +8 -8
- package/dist/script.js.map +1 -1
- package/dist/types/address.d.ts +4 -4
- package/dist/types/index.d.ts +8 -8
- package/dist/types/index.js +8 -8
- package/dist/types/meta.d.ts +4 -4
- package/dist/types/psbt.d.ts +2 -2
- package/dist/types/script.d.ts +2 -2
- package/dist/types/sighash.d.ts +2 -2
- package/dist/types/witness.d.ts +5 -5
- package/package.json +20 -17
- package/src/const.ts +0 -61
- package/src/index.ts +0 -13
- package/src/lib/address/api.ts +0 -50
- package/src/lib/address/encode.ts +0 -183
- package/src/lib/address/index.ts +0 -7
- package/src/lib/address/p2pkh.ts +0 -94
- package/src/lib/address/p2sh.ts +0 -96
- package/src/lib/address/p2tr.ts +0 -91
- package/src/lib/address/p2wpkh.ts +0 -94
- package/src/lib/address/p2wsh.ts +0 -92
- package/src/lib/address/script.ts +0 -63
- package/src/lib/address/util.ts +0 -87
- package/src/lib/meta/index.ts +0 -4
- package/src/lib/meta/locktime.ts +0 -57
- package/src/lib/meta/ref.ts +0 -107
- package/src/lib/meta/scribe.ts +0 -256
- package/src/lib/meta/sequence.ts +0 -146
- package/src/lib/script/decode.ts +0 -85
- package/src/lib/script/encode.ts +0 -129
- package/src/lib/script/index.ts +0 -20
- package/src/lib/script/lock.ts +0 -73
- package/src/lib/script/util.ts +0 -78
- package/src/lib/script/words.ts +0 -182
- package/src/lib/sighash/index.ts +0 -3
- package/src/lib/sighash/segwit.ts +0 -152
- package/src/lib/sighash/taproot.ts +0 -206
- package/src/lib/sighash/util.ts +0 -51
- package/src/lib/signer/index.ts +0 -2
- package/src/lib/signer/sign.ts +0 -39
- package/src/lib/signer/verify.ts +0 -88
- package/src/lib/taproot/cblock.ts +0 -96
- package/src/lib/taproot/encode.ts +0 -49
- package/src/lib/taproot/index.ts +0 -4
- package/src/lib/taproot/parse.ts +0 -65
- package/src/lib/taproot/tree.ts +0 -94
- package/src/lib/tx/create.ts +0 -90
- package/src/lib/tx/decode.ts +0 -123
- package/src/lib/tx/encode.ts +0 -155
- package/src/lib/tx/index.ts +0 -7
- package/src/lib/tx/parse.ts +0 -69
- package/src/lib/tx/size.ts +0 -68
- package/src/lib/tx/util.ts +0 -111
- package/src/lib/tx/validate.ts +0 -49
- package/src/lib/witness/index.ts +0 -2
- package/src/lib/witness/parse.ts +0 -127
- package/src/lib/witness/util.ts +0 -18
- package/src/schema/base.ts +0 -57
- package/src/schema/index.ts +0 -2
- package/src/schema/taproot.ts +0 -12
- package/src/schema/tx.ts +0 -48
- package/src/types/address.ts +0 -35
- package/src/types/index.ts +0 -8
- package/src/types/meta.ts +0 -48
- package/src/types/psbt.ts +0 -15
- package/src/types/script.ts +0 -18
- package/src/types/sighash.ts +0 -16
- package/src/types/taproot.ts +0 -41
- package/src/types/txdata.ts +0 -85
- package/src/types/witness.ts +0 -42
package/src/lib/signer/sign.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Buff } from '@vbyte/buff'
|
|
2
|
-
import { ECC } from '@vbyte/micro-lib'
|
|
3
|
-
import { parse_tx } from '@/lib/tx/parse.js'
|
|
4
|
-
import { SIGHASH_DEFAULT } from '@/const.js'
|
|
5
|
-
import { hash_segwit_tx } from '@/lib/sighash/segwit.js'
|
|
6
|
-
import { hash_taproot_tx } from '@/lib/sighash/taproot.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(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(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
|
-
}
|
|
36
|
-
|
|
37
|
-
function format_sigflag (flag : number) {
|
|
38
|
-
return (flag !== 0) ? Buff.num(flag, 1).hex : ''
|
|
39
|
-
}
|
package/src/lib/signer/verify.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { Bytes } from '@vbyte/buff'
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
SigHashOptions,
|
|
5
|
-
TxData
|
|
6
|
-
} from '@/types/index.js'
|
|
7
|
-
|
|
8
|
-
export function verify_tx (
|
|
9
|
-
_txdata : TxData | Bytes,
|
|
10
|
-
_config : SigHashOptions = {}
|
|
11
|
-
) : boolean {
|
|
12
|
-
console.warn('verify_segwit_tx is not implemented')
|
|
13
|
-
return true
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// export function verify_signature (
|
|
17
|
-
// txdata : TxData | Bytes,
|
|
18
|
-
// index : number,
|
|
19
|
-
// config : HashConfig = {}
|
|
20
|
-
// ) : boolean {
|
|
21
|
-
// const tx = Tx.fmt.toJson(txdata)
|
|
22
|
-
// const { throws = false } = config
|
|
23
|
-
// const { prevout, witness = [] } = tx.vin[index]
|
|
24
|
-
// const witnessData = Tx.util.readWitness(witness)
|
|
25
|
-
// const { cblock, script, params } = witnessData
|
|
26
|
-
|
|
27
|
-
// let pub : Buff
|
|
28
|
-
|
|
29
|
-
// if (params.length < 1) {
|
|
30
|
-
// return safeThrow('Invalid witness data: ' + String(witness), throws)
|
|
31
|
-
// }
|
|
32
|
-
|
|
33
|
-
// const { scriptPubKey } = prevout ?? {}
|
|
34
|
-
|
|
35
|
-
// if (scriptPubKey === undefined) {
|
|
36
|
-
// return safeThrow('Prevout scriptPubKey is empty!', throws)
|
|
37
|
-
// }
|
|
38
|
-
|
|
39
|
-
// const { type, data: tapkey } = Tx.util.readScriptPubKey(scriptPubKey)
|
|
40
|
-
|
|
41
|
-
// if (type !== 'p2tr') {
|
|
42
|
-
// return safeThrow('Prevout script is not a valid taproot output:' + tapkey.hex, throws)
|
|
43
|
-
// }
|
|
44
|
-
|
|
45
|
-
// if (tapkey.length !== 32) {
|
|
46
|
-
// return safeThrow('Invalid tapkey length: ' + String(tapkey.length), throws)
|
|
47
|
-
// }
|
|
48
|
-
|
|
49
|
-
// if (
|
|
50
|
-
// cblock !== null &&
|
|
51
|
-
// script !== null
|
|
52
|
-
// ) {
|
|
53
|
-
// const version = cblock[0] & 0xfe
|
|
54
|
-
// const target = getTapLeaf(script, version)
|
|
55
|
-
// config.extension = target
|
|
56
|
-
|
|
57
|
-
// if (!checkPath(tapkey, target, cblock, { throws })) {
|
|
58
|
-
// return safeThrow('cblock verification failed!', throws)
|
|
59
|
-
// }
|
|
60
|
-
// }
|
|
61
|
-
|
|
62
|
-
// if (config.pubkey !== undefined) {
|
|
63
|
-
// pub = Buff.bytes(config.pubkey)
|
|
64
|
-
// } else if (params.length > 1 && params[1].length === 32) {
|
|
65
|
-
// pub = Buff.bytes(params[1])
|
|
66
|
-
// } else {
|
|
67
|
-
// pub = Buff.bytes(tapkey)
|
|
68
|
-
// }
|
|
69
|
-
|
|
70
|
-
// const rawsig = Script.fmt.toParam(params[0])
|
|
71
|
-
// const stream = new Stream(rawsig)
|
|
72
|
-
// const signature = stream.read(64).raw
|
|
73
|
-
|
|
74
|
-
// if (stream.size === 1) {
|
|
75
|
-
// config.sigflag = stream.read(1).num
|
|
76
|
-
// if (config.sigflag === 0x00) {
|
|
77
|
-
// return safeThrow('0x00 is not a valid appended sigflag!', throws)
|
|
78
|
-
// }
|
|
79
|
-
// }
|
|
80
|
-
|
|
81
|
-
// const hash = hashTx(tx, index, config)
|
|
82
|
-
|
|
83
|
-
// if (!verify(signature, hash, pub, throws)) {
|
|
84
|
-
// return safeThrow('Invalid signature!', throws)
|
|
85
|
-
// }
|
|
86
|
-
|
|
87
|
-
// return true
|
|
88
|
-
// }
|
|
@@ -1,96 +0,0 @@
|
|
|
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
|
-
path,
|
|
68
|
-
parity,
|
|
69
|
-
taproot : taproot ?? null,
|
|
70
|
-
cblock : cblock.hex,
|
|
71
|
-
tapkey : tapkey.hex,
|
|
72
|
-
taptweak : taptweak.hex
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function verify_taproot (
|
|
77
|
-
tapkey : string,
|
|
78
|
-
target : string,
|
|
79
|
-
cblock : string
|
|
80
|
-
) : boolean {
|
|
81
|
-
Assert.size(tapkey, 32)
|
|
82
|
-
const { parity, path, int_key } = parse_cblock(cblock)
|
|
83
|
-
|
|
84
|
-
const ext_key = Buff.join([ parity, tapkey ])
|
|
85
|
-
|
|
86
|
-
let branch = Buff.bytes(target).hex
|
|
87
|
-
|
|
88
|
-
for (const leaf of path) {
|
|
89
|
-
branch = encode_tapbranch(branch, leaf).hex
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const tap_tweak = encode_taptweak(int_key, branch)
|
|
93
|
-
const tweaked_key = ECC.tweak_pubkey(int_key, tap_tweak, 'ecdsa')
|
|
94
|
-
|
|
95
|
-
return (ext_key.hex === tweaked_key.hex)
|
|
96
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
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
|
-
}
|
package/src/lib/taproot/index.ts
DELETED
package/src/lib/taproot/parse.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
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
|
-
|
|
5
|
-
import {
|
|
6
|
-
encode_tapbranch,
|
|
7
|
-
encode_tapscript,
|
|
8
|
-
encode_taptweak,
|
|
9
|
-
} from './encode.js'
|
|
10
|
-
|
|
11
|
-
import type { ControlBlock } from '@/types/index.js'
|
|
12
|
-
|
|
13
|
-
export function parse_taproot_witness (witness : string[]) {
|
|
14
|
-
const { cblock, params, script } = parse_witness(witness)
|
|
15
|
-
|
|
16
|
-
Assert.exists(cblock, 'cblock is null')
|
|
17
|
-
Assert.exists(script, 'script is null')
|
|
18
|
-
|
|
19
|
-
const cblk = parse_cblock(cblock)
|
|
20
|
-
const target = encode_tapscript(script, cblk.version)
|
|
21
|
-
|
|
22
|
-
let branch = target.hex
|
|
23
|
-
|
|
24
|
-
for (const leaf of cblk.path) {
|
|
25
|
-
branch = encode_tapbranch(branch, leaf).hex
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const tweak = encode_taptweak(cblk.int_key, branch)
|
|
29
|
-
const tapkey = ECC.tweak_pubkey(cblk.int_key, tweak, 'bip340')
|
|
30
|
-
|
|
31
|
-
params.map(e => Buff.bytes(e).hex)
|
|
32
|
-
|
|
33
|
-
return { cblock: cblk, params, script, tapkey: tapkey.hex, tweak: tweak.hex }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function parse_cblock (cblock : string | Uint8Array) : ControlBlock {
|
|
37
|
-
const buffer = new Stream(cblock)
|
|
38
|
-
const cbyte = buffer.read(1).num
|
|
39
|
-
const int_key = buffer.read(32).hex
|
|
40
|
-
const [ version, parity ] = parse_cblock_parity(cbyte)
|
|
41
|
-
const path = []
|
|
42
|
-
while (buffer.size >= 32) {
|
|
43
|
-
path.push(buffer.read(32).hex)
|
|
44
|
-
}
|
|
45
|
-
if (buffer.size !== 0) {
|
|
46
|
-
throw new Error('Non-empty buffer on control block: ' + String(buffer))
|
|
47
|
-
}
|
|
48
|
-
return { int_key, path, parity, version }
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function parse_cblock_parity (cbits : number) {
|
|
52
|
-
return (cbits % 2 === 0)
|
|
53
|
-
? [ cbits - 0, 0x02 ]
|
|
54
|
-
: [ cbits - 1, 0x03 ]
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function parse_pubkey_parity (
|
|
58
|
-
pubkey : string | Uint8Array
|
|
59
|
-
) : number {
|
|
60
|
-
Assert.size(pubkey, 33, 'invalid pubkey size')
|
|
61
|
-
const [ parity ] = Buff.bytes(pubkey)
|
|
62
|
-
if (parity === 0x02) return 0
|
|
63
|
-
if (parity === 0x03) return 1
|
|
64
|
-
throw new Error('Invalid parity bit: ' + String(parity))
|
|
65
|
-
}
|
package/src/lib/taproot/tree.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { Buff } from '@vbyte/buff'
|
|
2
|
-
import { encode_tapbranch } from './encode.js'
|
|
3
|
-
|
|
4
|
-
import type { TapTree, MerkleProof } from '@/types/index.js'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Get the root of a taproot tree.
|
|
8
|
-
* @param leaves - The leaves of the tree.
|
|
9
|
-
* @returns The root of the tree.
|
|
10
|
-
*/
|
|
11
|
-
export function get_merkle_root (leaves : TapTree) {
|
|
12
|
-
// Process the merkle tree, and return the root.
|
|
13
|
-
return merkleize(leaves)[0]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Process a taproot tree into a merkle proof.
|
|
18
|
-
* @param taptree - The leaves of the tree.
|
|
19
|
-
* @param target - The target leaf of the tree.
|
|
20
|
-
* @param path - The recursive path of the tree.
|
|
21
|
-
* @returns The root of the tree.
|
|
22
|
-
*/
|
|
23
|
-
export function merkleize (
|
|
24
|
-
taptree : TapTree,
|
|
25
|
-
target ?: string,
|
|
26
|
-
path : string[] = []
|
|
27
|
-
) : MerkleProof {
|
|
28
|
-
// Initialize the leaves and tree arrays.
|
|
29
|
-
const leaves : string[] = []
|
|
30
|
-
const tree : string[] = []
|
|
31
|
-
// If there are no leaves, throw an error.
|
|
32
|
-
if (taptree.length < 1) {
|
|
33
|
-
throw new Error('Tree is empty!')
|
|
34
|
-
}
|
|
35
|
-
// Crawl through the tree, and find each leaf.
|
|
36
|
-
for (let i = 0; i < taptree.length; i++) {
|
|
37
|
-
// Get the current leaf as bytes.
|
|
38
|
-
const bytes = taptree[i]
|
|
39
|
-
// If the leaf is an array,
|
|
40
|
-
if (Array.isArray(bytes)) {
|
|
41
|
-
// Recursively process the nested tree.
|
|
42
|
-
let [ tapleaf, new_target, branches ] = merkleize(bytes, target)
|
|
43
|
-
// Update the target leaf.
|
|
44
|
-
target = new_target
|
|
45
|
-
// Add the nested tapleaf to the leaves array.
|
|
46
|
-
leaves.push(tapleaf)
|
|
47
|
-
// For each branch node,
|
|
48
|
-
for (const branch of branches) {
|
|
49
|
-
// Add the branch to the path.
|
|
50
|
-
path.push(branch)
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
// Convert the leaf to a hex string.
|
|
54
|
-
const leaf = Buff.bytes(bytes).hex
|
|
55
|
-
// Add the leaf to the leaves array.
|
|
56
|
-
leaves.push(leaf)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// If there is only one leaf,
|
|
61
|
-
if (leaves.length === 1) {
|
|
62
|
-
// Return the leaf as the root.
|
|
63
|
-
return [ leaves[0], target, path ]
|
|
64
|
-
}
|
|
65
|
-
// Ensure the tree is sorted at this point.
|
|
66
|
-
leaves.sort()
|
|
67
|
-
// Ensure the tree is balanced evenly.
|
|
68
|
-
if (leaves.length % 2 !== 0) {
|
|
69
|
-
// If uneven, duplicate the last leaf.
|
|
70
|
-
leaves.push(leaves[leaves.length - 1])
|
|
71
|
-
}
|
|
72
|
-
// Sort through the leaves (two at a time).
|
|
73
|
-
for (let i = 0; i < leaves.length - 1; i += 2) {
|
|
74
|
-
// Compute two leaves into a branch.
|
|
75
|
-
const branch = encode_tapbranch(leaves[i], leaves[i + 1]).hex
|
|
76
|
-
// Push our branch to the tree.
|
|
77
|
-
tree.push(branch)
|
|
78
|
-
// Check if a proof target is specified.
|
|
79
|
-
if (typeof target === 'string') {
|
|
80
|
-
// Check if this branch is part of our proofs.
|
|
81
|
-
if (target === leaves[i]) {
|
|
82
|
-
// If so, include right-side of branch.
|
|
83
|
-
path.push(leaves[i + 1])
|
|
84
|
-
target = branch
|
|
85
|
-
} else if (target === leaves[i + 1]) {
|
|
86
|
-
// If so, include left-side of branch.
|
|
87
|
-
path.push(leaves[i])
|
|
88
|
-
target = branch
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
// Recursively process the tree.
|
|
93
|
-
return merkleize(tree, target, path)
|
|
94
|
-
}
|
package/src/lib/tx/create.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { Assert } from '@vbyte/micro-lib'
|
|
2
|
-
import { COINBASE, DEFAULT } from '@/const.js'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
normalize_prevout,
|
|
6
|
-
normalize_sequence,
|
|
7
|
-
normalize_value
|
|
8
|
-
} from './util.js'
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
assert_tx_template,
|
|
12
|
-
assert_vin_template,
|
|
13
|
-
assert_vout_template
|
|
14
|
-
} from './validate.js'
|
|
15
|
-
|
|
16
|
-
import type {
|
|
17
|
-
TxData,
|
|
18
|
-
TxInput,
|
|
19
|
-
TxOutput,
|
|
20
|
-
TxTemplate,
|
|
21
|
-
TxSpendInput,
|
|
22
|
-
TxCoinbaseInput,
|
|
23
|
-
TxOutputTemplate,
|
|
24
|
-
TxVirtualInput,
|
|
25
|
-
TxInputTemplate
|
|
26
|
-
} from '@/types/index.js'
|
|
27
|
-
|
|
28
|
-
export function create_coinbase_input (
|
|
29
|
-
config : TxInputTemplate
|
|
30
|
-
) : TxCoinbaseInput {
|
|
31
|
-
assert_vin_template(config)
|
|
32
|
-
Assert.exists(config.coinbase, 'coinbase is required')
|
|
33
|
-
const txid = COINBASE.TXID
|
|
34
|
-
const vout = COINBASE.VOUT
|
|
35
|
-
const coinbase = config.coinbase
|
|
36
|
-
const witness = config.witness ?? []
|
|
37
|
-
const sequence = normalize_sequence(config.sequence)
|
|
38
|
-
return { coinbase, prevout: null, script_sig: null, sequence, witness, txid, vout }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function create_virtual_input (
|
|
42
|
-
config : TxInputTemplate
|
|
43
|
-
) : TxVirtualInput {
|
|
44
|
-
assert_vin_template(config)
|
|
45
|
-
Assert.is_empty(config.coinbase, 'coinbase is not allowed')
|
|
46
|
-
Assert.is_empty(config.prevout, 'prevout is not allowed')
|
|
47
|
-
const { txid, vout, script_sig = null, witness = [] } = config
|
|
48
|
-
const sequence = normalize_sequence(config.sequence)
|
|
49
|
-
return { txid, vout, coinbase: null, prevout: null, script_sig, sequence, witness }
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function create_spend_input (
|
|
53
|
-
config : TxInputTemplate
|
|
54
|
-
) : TxSpendInput {
|
|
55
|
-
assert_vin_template(config)
|
|
56
|
-
Assert.exists(config.prevout, 'prevout is required')
|
|
57
|
-
const { txid, vout, script_sig = null, witness = [] } = config
|
|
58
|
-
const prevout = normalize_prevout(config.prevout)
|
|
59
|
-
const sequence = normalize_sequence(config.sequence)
|
|
60
|
-
return { txid, vout, coinbase: null, prevout, script_sig, sequence, witness }
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function create_tx_input (
|
|
64
|
-
config : TxInputTemplate
|
|
65
|
-
) : TxInput {
|
|
66
|
-
if (config.coinbase) return create_coinbase_input(config)
|
|
67
|
-
if (config.prevout) return create_spend_input(config)
|
|
68
|
-
return create_virtual_input(config)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function create_tx_output (
|
|
72
|
-
config : TxOutputTemplate
|
|
73
|
-
) : TxOutput {
|
|
74
|
-
assert_vout_template(config)
|
|
75
|
-
const script_pk = config.script_pk
|
|
76
|
-
const value = normalize_value(config.value)
|
|
77
|
-
return { script_pk, value }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function create_tx (
|
|
81
|
-
config? : Partial<TxTemplate>
|
|
82
|
-
) : TxData {
|
|
83
|
-
assert_tx_template(config)
|
|
84
|
-
const { vin = [], vout = [] } = config ?? { vin: [], vout: [] }
|
|
85
|
-
const locktime = config.locktime ?? DEFAULT.LOCKTIME
|
|
86
|
-
const version = config.version ?? DEFAULT.VERSION
|
|
87
|
-
const inputs = vin.map(txin => create_tx_input(txin))
|
|
88
|
-
const outputs = vout.map(txout => create_tx_output(txout))
|
|
89
|
-
return { locktime, vin : inputs, vout : outputs, version }
|
|
90
|
-
}
|
package/src/lib/tx/decode.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { Stream } from '@vbyte/buff'
|
|
2
|
-
import { Assert } from '@vbyte/micro-lib/assert'
|
|
3
|
-
import { parse_error } from '@vbyte/micro-lib/util'
|
|
4
|
-
import { COINBASE } from '@/const.js'
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
TxInput,
|
|
8
|
-
TxOutput,
|
|
9
|
-
TxCoinbaseInput,
|
|
10
|
-
TxVirtualInput,
|
|
11
|
-
TxDecodedData
|
|
12
|
-
} from '@/types/index.js'
|
|
13
|
-
|
|
14
|
-
export function decode_tx (
|
|
15
|
-
txdata : string | Uint8Array,
|
|
16
|
-
use_segwit = true
|
|
17
|
-
) : TxDecodedData {
|
|
18
|
-
// Assert the txdata is a bytes object.
|
|
19
|
-
Assert.is_bytes(txdata, 'txdata must be hex or bytes')
|
|
20
|
-
// Setup a byte-stream.
|
|
21
|
-
const stream = new Stream(txdata)
|
|
22
|
-
// Parse tx version.
|
|
23
|
-
const version = read_version(stream)
|
|
24
|
-
// Check and enable any flags that are set.
|
|
25
|
-
let has_witness = check_witness_flag(stream)
|
|
26
|
-
// If use_segwit is false, set has_witness to false.
|
|
27
|
-
has_witness = (use_segwit) ? has_witness : false
|
|
28
|
-
// Parse our inputs and outputs.
|
|
29
|
-
const vin = read_inputs(stream)
|
|
30
|
-
const vout = read_outputs(stream)
|
|
31
|
-
// If witness flag is set, parse witness data.
|
|
32
|
-
if (has_witness) {
|
|
33
|
-
for (const txin of vin) {
|
|
34
|
-
txin.witness = read_witness(stream)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
// Parse locktime.
|
|
38
|
-
const locktime = read_locktime(stream)
|
|
39
|
-
// Return transaction object with calculated fields.
|
|
40
|
-
return { version, vin, vout, locktime }
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function read_version (stream : Stream) : number {
|
|
44
|
-
return stream.read(4).reverse().to_num()
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function check_witness_flag (stream : Stream) : boolean {
|
|
48
|
-
const [ marker, flag ] : number[] = [ ...stream.peek(2) ]
|
|
49
|
-
if (marker === 0) {
|
|
50
|
-
stream.read(2)
|
|
51
|
-
if (flag === 1) {
|
|
52
|
-
return true
|
|
53
|
-
} else {
|
|
54
|
-
throw new Error(`Invalid witness flag: ${flag}`)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return false
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function read_inputs (stream : Stream) : TxInput[] {
|
|
61
|
-
const inputs = []
|
|
62
|
-
const vinCount = stream.varint()
|
|
63
|
-
for (let i = 0; i < vinCount; i++) {
|
|
64
|
-
const txinput = read_vin(stream)
|
|
65
|
-
inputs.push(txinput)
|
|
66
|
-
}
|
|
67
|
-
return inputs
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function read_vin (stream : Stream) : TxInput {
|
|
71
|
-
const txid = stream.read(32).reverse().hex
|
|
72
|
-
const vout = stream.read(4).reverse().num
|
|
73
|
-
const script_sig = read_payload(stream)
|
|
74
|
-
const sequence = stream.read(4).reverse().num
|
|
75
|
-
const witness : string[] = []
|
|
76
|
-
if (txid === COINBASE.TXID && vout === COINBASE.VOUT) {
|
|
77
|
-
return { coinbase : script_sig, prevout: null, script_sig : null, sequence, txid, vout, witness } as TxCoinbaseInput
|
|
78
|
-
} else {
|
|
79
|
-
return { coinbase : null, prevout: null, script_sig, sequence, txid, vout, witness } as TxVirtualInput
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function read_outputs (stream : Stream) : TxOutput[] {
|
|
84
|
-
const outputs = []
|
|
85
|
-
const vcount = stream.varint()
|
|
86
|
-
for (let i = 0; i < vcount; i++) {
|
|
87
|
-
try {
|
|
88
|
-
outputs.push(read_vout(stream))
|
|
89
|
-
} catch (error) {
|
|
90
|
-
throw new Error(`failed to decode output: ${i}: ${parse_error(error)}`)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return outputs
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function read_vout (stream : Stream) : TxOutput {
|
|
97
|
-
const value = stream.read(8).reverse().big
|
|
98
|
-
const script_pk = read_payload(stream)
|
|
99
|
-
Assert.exists(script_pk, 'failed to decode script_pk')
|
|
100
|
-
return { value, script_pk }
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function read_witness (stream : Stream) : string[] {
|
|
104
|
-
const stack = []
|
|
105
|
-
const count = stream.varint()
|
|
106
|
-
for (let i = 0; i < count; i++) {
|
|
107
|
-
const element = read_payload(stream)
|
|
108
|
-
if (element === null) {
|
|
109
|
-
throw new Error('failed to decode witness element: ' + i)
|
|
110
|
-
}
|
|
111
|
-
stack.push(element)
|
|
112
|
-
}
|
|
113
|
-
return stack
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function read_payload (stream : Stream) : string | null {
|
|
117
|
-
const size = stream.varint('le')
|
|
118
|
-
return (size > 0) ? stream.read(size).hex : null
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function read_locktime (stream : Stream) : number {
|
|
122
|
-
return stream.read(4).reverse().to_num()
|
|
123
|
-
}
|