@vbyte/btc-dev
Version:
Batteries-included toolset for plebian bitcoin development
48 lines (47 loc) • 1.81 kB
JavaScript
import { Buff, Stream } from '@vbyte/buff';
import { Assert, ECC } from '@vbyte/micro-lib';
import { parse_witness } from '../../lib/witness/parse.js';
import { encode_tapbranch, encode_tapscript, encode_taptweak, } from './encode.js';
export function parse_taproot_witness(witness) {
const { cblock, params, script } = parse_witness(witness);
Assert.exists(cblock, 'cblock is null');
Assert.exists(script, 'script is null');
const cblk = parse_cblock(cblock);
const target = encode_tapscript(script, cblk.version);
let branch = target.hex;
for (const leaf of cblk.path) {
branch = encode_tapbranch(branch, leaf).hex;
}
const tweak = encode_taptweak(cblk.int_key, branch);
const tapkey = ECC.tweak_pubkey(cblk.int_key, tweak, 'bip340');
params.map(e => Buff.bytes(e).hex);
return { cblock: cblk, params, script, tapkey: tapkey.hex, tweak: tweak.hex };
}
export function parse_cblock(cblock) {
const buffer = new Stream(cblock);
const cbyte = buffer.read(1).num;
const int_key = buffer.read(32).hex;
const [version, parity] = parse_cblock_parity(cbyte);
const path = [];
while (buffer.size >= 32) {
path.push(buffer.read(32).hex);
}
if (buffer.size !== 0) {
throw new Error('Non-empty buffer on control block: ' + String(buffer));
}
return { int_key, path, parity, version };
}
export function parse_cblock_parity(cbits) {
return (cbits % 2 === 0)
? [cbits - 0, 0x02]
: [cbits - 1, 0x03];
}
export function parse_pubkey_parity(pubkey) {
Assert.size(pubkey, 33, 'invalid pubkey size');
const [parity] = Buff.bytes(pubkey);
if (parity === 0x02)
return 0;
if (parity === 0x03)
return 1;
throw new Error('Invalid parity bit: ' + String(parity));
}