Js生成btc地址

警告
本文最后更新于 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

0%