bitcoinjs学习笔记4—p2pkh、p2sh、p2wpkh地址生成

BitcoinJS 学习笔记 4 --- P2PKH、P2SH、P2WPKH 地址生成大纲


1. 概述
  • 目标 : 学习如何使用 BitcoinJS 生成三种常见的比特币地址类型:
    1. P2PKH(Pay-to-Public-Key-Hash)
    2. P2SH(Pay-to-Script-Hash)
    3. P2WPKH(Pay-to-Witness-Public-Key-Hash)
  • 工具: BitcoinJS 库、比特币测试网(Testnet)或回归测试网络(Regtest)。

2. P2PKH 地址生成
  • 定义 : P2PKH 是最常见的比特币地址类型,以 1 开头。
  • 生成步骤 :
    1. 生成密钥对(私钥和公钥)。
    2. 对公钥进行哈希(SHA-256 + RIPEMD-160)生成公钥哈希。
    3. 使用 Base58Check 编码生成地址。
  • 代码示例:
javascript 复制代码
const bitcoin = require('bitcoinjs-lib');
const network = bitcoin.networks.regtest;
ECPairFactory = require('ecpair').default;
ecc = require('tiny-secp256k1');
ECPair = ECPairFactory(ecc);

const keyPair = bitcoin.ECPair.makeRandom({ network });
const { address } = bitcoin.payments.p2pkh({
  pubkey: keyPair.publicKey,
  network,
});

console.log('P2PKH Address:', address);

3. P2SH 地址生成
  • 定义 : P2SH 是一种支持多重签名和复杂脚本的地址类型,以 3 开头。
  • 生成步骤 :
    1. 创建赎回脚本(Redeem Script),例如多重签名脚本。
    2. 对赎回脚本进行哈希(SHA-256 + RIPEMD-160)生成脚本哈希。
    3. 使用 Base58Check 编码生成地址。
  • 代码示例:
javascript 复制代码
const bitcoin = require('bitcoinjs-lib');
const network = bitcoin.networks.regtest;
ECPairFactory = require('ecpair').default;
ecc = require('tiny-secp256k1');
ECPair = ECPairFactory(ecc);
const { signECDSA } = require('@scure/btc-signer/utils');
const hashtype = bitcoin.Transaction.SIGHASH_ALL;

// 3.p2sh地址生成
const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex',);
const keyPairAlice = ECPair.fromPrivateKey(ONE,  { network });
const TWO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000002', 'hex',);
const keyPairBob = ECPair.fromPrivateKey(TWO, { network });

// 3.1 Bob的交易信息
const previousTxHex_Bob = '02000000000101cecc606da73967ef24c219eb79422c8170aa1e8b2d7d8c4832d6d6e7bb3c1db00100000000fdffffff02f0412e1201000000160014862a1210923c5f90a1e4bd575f798f72e874fa7c00e1f5050000000016001406afd46bcdfd22ef94ac122aa11f241244a37ecc02473044022066f4cc42730accc40c8f69bb0144b676bef1d2b53c52df898d42b662154ab547022008856664818aaf3e8f87b7f48906559f097b53fa87634dc132bb9803aa6a1a1d01210251250ede05c16d0060b23bdce6585cda09fa0edddb77830266c0cf410a6096f3b8000000';
const utxo_Bob = bitcoin.Transaction.fromHex(previousTxHex_Bob);
const txid_Bob = utxo_Bob.getId();
txIndex_Bob = 1;
const amount_Bob = utxo_Bob.outs[txIndex_Bob].value;

// 3.2将Bob交易信息拼接成字符串,作为签名
x0=(Buffer.from(keyPairBob.publicKey)).toString('hex');
str= x0.concat(' ',  txid_Bob, txIndex_Bob.toString(), amount_Bob.toString(), hashtype.toString()) // Bob pays Alice
hashOut = bitcoin.crypto.hash160(str);
sig0 = signECDSA(hashOut, keyPairAlice.privateKey);
signature0Hash = bitcoin.crypto.hash160(sig0);

// 3.3构造p2sh锁定脚本
locking_script_Alice = bitcoin.script.compile([
   bitcoin.opcodes.OP_HASH160,
   signature0Hash,
   bitcoin.opcodes.OP_EQUALVERIFY,
   bitcoin.opcodes.OP_1,
]);
console.log('Locking_script_Alice: ' + Buffer.from(locking_script_Alice).toString('hex'));
//Complete the script of the previousTx, and deploy it
p2sh = bitcoin.payments.p2sh({redeem: {output: locking_script_Alice, network}, network})
console.log('p2sh.address  ', p2sh.address)

4. P2WPKH 地址生成
  • 定义 : P2WPKH 是 SegWit 地址类型,以 bc1 开头(主网)或 tb1 开头(测试网)。
  • 生成步骤 :
    1. 生成密钥对(私钥和公钥)。
    2. 对公钥进行哈希(SHA-256 + RIPEMD-160)生成公钥哈希。
    3. 使用 Bech32 编码生成地址。
  • 代码示例:
javascript 复制代码
const bitcoin = require('bitcoinjs-lib');
const network = bitcoin.networks.regtest;
ECPairFactory = require('ecpair').default;
ecc = require('tiny-secp256k1');
ECPair = ECPairFactory(ecc);

const keyPair = ECPair.makeRandom({ network });
const p2wpkh = bitcoin.payments.p2wpkh({
 pubkey: keyPair.publicKey,
 network,
});
console.log("p2wpkh address:", p2wpkh.address);

5.由私钥恢复公钥
javascript 复制代码
const bitcoin = require('bitcoinjs-lib');
const network = bitcoin.networks.regtest;
ECPairFactory = require('ecpair').default;
ecc = require('tiny-secp256k1');
ECPair = ECPairFactory(ecc);
// 4.两种记录私钥格式,hex形式以及WIF格式,还有memorica助记词格式的(bitcoinjs在GitHub上的示例中有使用助记词形式,但使用的是ts语法,感兴趣的可以看看官方代码)
// hex格式
const privateKey = '87e03af6877f730b54e082ddaf46d7dc2888c0d33ac6ff1307ab98ff1960ecfb';
// WIF格式
const WIF = 'cS8pu3rrhjmYeRjmCRjJdVpUfqv7nAgkPG7o7nqr9xyxcJVZJb5s';

// hex格式私钥恢复密钥对
const keyPairByHex = ECPair.fromPrivateKey(Buffer.from(privateKey,'hex'), { network });
console.log("Public Key By Hex:", Buffer.from(keyPairByHex.publicKey).toString('hex'));

const keyPairByWIF = ECPair.fromWIF(WIF, network);
console.log("Public Key By WIF:", Buffer.from(keyPairByWIF.publicKey).toString('hex'))
6. 地址生成的比较
特性 P2PKH P2SH P2WPKH
地址格式 Base58Check(1 开头) Base58Check(3 开头) Bech32(bc1tb1 开头)
脚本类型 简单脚本(公钥哈希) 复杂脚本(多重签名等) 简单脚本(公钥哈希)
签名存储 解锁脚本 解锁脚本 见证部分
交易大小 较大 较大 较小
手续费 较高 较高 较低
兼容性 所有钱包支持 所有钱包支持 需要 SegWit 支持

3种协议地址生成代码汇总
javascript 复制代码
const bitcoin = require('bitcoinjs-lib');
const network = bitcoin.networks.regtest;
ECPairFactory = require('ecpair').default;
ecc = require('tiny-secp256k1');
ECPair = ECPairFactory(ecc);
const { signECDSA } = require('@scure/btc-signer/utils');
const hashtype = bitcoin.Transaction.SIGHASH_ALL;

// 1.p2pkh地址生成
const keyPair = ECPair.makeRandom({ network });
const p2pkh = bitcoin.payments.p2pkh({
  pubkey: keyPair.publicKey,
  network,
});
// 2.p2wpkh地址生成
const p2wpkh = bitcoin.payments.p2wpkh({
  pubkey: keyPair.publicKey,
  network,
});
console.log('private key (HEX):', Buffer.from(keyPair.privateKey).toString('hex'));
console.log('Private Key (WIF):', keyPair.toWIF());
console.log("Public Key:", Buffer.from(keyPair.publicKey).toString('hex'));
console.log("p2pkh address:", p2pkh.address);
console.log("p2wpkh address:", p2wpkh.address);

// 3.p2sh地址生成
const ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex',);
const keyPairAlice = ECPair.fromPrivateKey(ONE,  { network });
const TWO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000002', 'hex',);
const keyPairBob = ECPair.fromPrivateKey(TWO, { network });

// 3.1 Bob的交易信息
const previousTxHex_Bob = '02000000000101cecc606da73967ef24c219eb79422c8170aa1e8b2d7d8c4832d6d6e7bb3c1db00100000000fdffffff02f0412e1201000000160014862a1210923c5f90a1e4bd575f798f72e874fa7c00e1f5050000000016001406afd46bcdfd22ef94ac122aa11f241244a37ecc02473044022066f4cc42730accc40c8f69bb0144b676bef1d2b53c52df898d42b662154ab547022008856664818aaf3e8f87b7f48906559f097b53fa87634dc132bb9803aa6a1a1d01210251250ede05c16d0060b23bdce6585cda09fa0edddb77830266c0cf410a6096f3b8000000';
const utxo_Bob = bitcoin.Transaction.fromHex(previousTxHex_Bob);
const txid_Bob = utxo_Bob.getId();
txIndex_Bob = 1;
const amount_Bob = utxo_Bob.outs[txIndex_Bob].value;

// 3.2将Bob交易信息拼接成字符串,作为签名
x0=(Buffer.from(keyPairBob.publicKey)).toString('hex');
str= x0.concat(' ',  txid_Bob, txIndex_Bob.toString(), amount_Bob.toString(), hashtype.toString()) // Bob pays Alice
hashOut = bitcoin.crypto.hash160(str);
sig0 = signECDSA(hashOut, keyPairAlice.privateKey);
signature0Hash = bitcoin.crypto.hash160(sig0);

// 3.3构造p2sh锁定脚本
locking_script_Alice = bitcoin.script.compile([
    bitcoin.opcodes.OP_HASH160,
    signature0Hash,
    bitcoin.opcodes.OP_EQUALVERIFY,
    bitcoin.opcodes.OP_1,
]);
console.log('Locking_script_Alice: ' + Buffer.from(locking_script_Alice).toString('hex'));
//Complete the script of the previousTx, and deploy it
p2sh = bitcoin.payments.p2sh({redeem: {output: locking_script_Alice, network}, network})
console.log('p2sh.address  ', p2sh.address)


// 4.两种记录私钥格式,hex形式以及WIF格式,还有memorica助记词格式的(bitcoinjs在GitHub上的示例中有使用助记词形式,但使用的是ts语法,感兴趣的可以看看官方代码)
// hex格式
const privateKey = '87e03af6877f730b54e082ddaf46d7dc2888c0d33ac6ff1307ab98ff1960ecfb';
// WIF格式
const WIF = 'cS8pu3rrhjmYeRjmCRjJdVpUfqv7nAgkPG7o7nqr9xyxcJVZJb5s';

// hex格式私钥恢复密钥对
const keyPairByHex = ECPair.fromPrivateKey(Buffer.from(privateKey,'hex'), { network });
console.log("Public Key By Hex:", Buffer.from(keyPairByHex.publicKey).toString('hex'));

const keyPairByWIF = ECPair.fromWIF(WIF, network);
console.log("Public Key By WIF:", Buffer.from(keyPairByWIF.publicKey).toString('hex'))
相关推荐
DKPT2 小时前
Java桥接模式实现方式与测试方法
java·笔记·学习·设计模式·桥接模式
巴伦是只猫4 小时前
【机器学习笔记Ⅰ】13 正则化代价函数
人工智能·笔记·机器学习
好好研究5 小时前
学习栈和队列的插入和删除操作
数据结构·学习
新中地GIS开发老师6 小时前
新发布:26考研院校和专业大纲
学习·考研·arcgis·大学生·遥感·gis开发·地理信息科学
SH11HF7 小时前
小菜狗的云计算之旅,学习了解rsync+sersync实现数据实时同步(详细操作步骤)
学习·云计算
Frank学习路上7 小时前
【IOS】XCode创建firstapp并运行(成为IOS开发者)
开发语言·学习·ios·cocoa·xcode
Chef_Chen8 小时前
从0开始学习计算机视觉--Day07--神经网络
神经网络·学习·计算机视觉
搞笑的秀儿9 小时前
信息新技术
大数据·人工智能·物联网·云计算·区块链
X_StarX10 小时前
【Unity笔记02】订阅事件-自动开门
笔记·学习·unity·游戏引擎·游戏开发·大学生
MingYue_SSS10 小时前
开关电源抄板学习
经验分享·笔记·嵌入式硬件·学习