警告
本文最后更新于 2024-07-23,文中内容可能已过时。
bitcoin TapRoot 地址生成
好久没有更新区块链的东西了,最近看brc20,用的都是btc的TapRoot地址。这次我们看看js如何生成TapRoot地址吧。
依赖库
1
2
3
4
|
const bitcoin = require('bitcoinjs-lib')
const bip39 = require('bip39');
const ecc = require('tiny-secp256k1');
const { BIP32Factory } = require('bip32');
|
初始化&部分参数
1
2
3
|
const network = bitcoin.networks.bitcoin // 主网
const bip32 = BIP32Factory(ecc)
bitcoin.initEccLib(ecc);
|
大家玩这个好像都是用的BIP86,这里暂不研究,后续需要深入了解的时候再来看。
回来了,强烈建议为P2TR公钥使用一个新的推导路径(例如由BIP86定义的),如果你在ECDSA和schnorr签名中使用相同的密钥,可能会被攻击。
所以重点在于换一个推导路径。
1
2
3
|
const rootKey = bip32.fromSeed(bip39.mnemonicToSeedSync('mnemonic'))
const path = "m/86'/0'/0'/0/0";
const child = rootKey.derivePath(path);
|
记录一下,之前的各种地址输出
1
2
3
4
5
6
|
// address: 1......
console.log(bitcoin.payments.p2pkh({ pubkey: child.publicKey, network }).address);
// address: bc1q....
console.log(bitcoin.payments.p2wpkh({ pubkey: child.publicKey }).address);
// address: 3........
console.log(bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: child.publicKey }), }).address);
|
生成TapRoot地址
方式一:直接使用bitcoin.payments.p2tr生成地址
1
|
const address = bitcoin.payments.p2tr({ internalPubkey: child.publicKey.slice(1, 33), network }).address
|
方式二:使用bitcoin.address.fromOutputScript生成地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function createKeySpendOutput(publicKey) {
// x-only pubkey (remove 1 byte y parity)
const myXOnlyPubkey = publicKey.slice(1, 33);
const commitHash = bitcoin.crypto.taggedHash('TapTweak', myXOnlyPubkey);
const tweakResult = ecc.xOnlyPointAddTweak(myXOnlyPubkey, commitHash);
if (tweakResult === null) throw new Error('Invalid Tweak');
const { xOnlyPubkey: tweaked } = tweakResult;
// scriptPubkey
return Buffer.concat([
// witness v1, PUSH_DATA 32 bytes
Buffer.from([0x51, 0x20]),
// x-only tweaked pubkey
tweaked,
]);
}
|
http://blog.shengchao.top/article/32
1
2
3
|
const output = createKeySpendOutput(child.publicKey);
const address = bitcoin.address.fromOutputScript(output, network);
console.log({address});
|
OK,这样你就得到了一个TapRoot地址,地址是以bc1p开头。
目前网上很多生成区块链私钥、公钥等的代码都是基于bitcoinjs-lib@3版本实现的,现在bitcoinjs-lib已经更新到了@6.0.1版本。原先的代码已经不可用了。下面是基于bitcoinjs-lib@6.0.1的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
const bitcoin=require('bitcoinjs-lib');
const TestNet=bitcoin.networks.testnet;
const ecpair=require('ecpair');
const ecc=require('tiny-secp256k1');
const ECPair=ecpair.ECPairFactory(ecc);
let keyPair=ECPair.makeRandom({network:TestNet});
//16进制表示的私钥和公钥
var private_key=keyPair.privateKey.toString('hex');
var public_key=keyPair.publicKey.toString('hex');
console.log('pri_key = '+private_key);
console.log('pub_key = '+public_key);
//WIF编码
const wif=require('wif');
var encoded=wif.encode(0x80,Buffer.from(private_key,'hex'),false);
console.log('WIF编码 = '+encoded);
//利用公钥生成地址
const { address }=bitcoin.payments.p2pkh({pubkey:keyPair.publicKey});
console.log('address = '+address);
|
运行结果如下(这里是使用随机数生成的私钥,所以代码每次运行的结果都不一样):
1
2
3
4
|
pri_key = 2b80a47ed30802b733a5573201f26a6c5285bd78fa1f9978706e7f8f00971f51
pub_key = 02b7f35b0d82a37fa0dfff7139a4b3fab2a9e870ab1409a076529cfcc342aa6049
WIF编码 = 5J9So3m6eMZqgWKLjHe2AKUjc4sf4Mtum2ZYW83mo2vPcfcN8KA
address = 1GmHrm4BFQCEG834aohqweeb8zvfuN8iMx
|
https://blog.csdn.net/yeshang_lady/article/details/123330595