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'))
相关推荐
Max_uuc1 小时前
【C++ 硬核】利用链接器魔法 (Linker Sections) 实现“去中心化”的自动初始化与插件系统
去中心化·区块链
devmoon1 小时前
在 Polkadot 上部署独立区块链Paseo 测试网实战部署指南
开发语言·安全·区块链·polkadot·erc-20·测试网·独立链
傻小胖1 小时前
22.ETH-智能合约-北大肖臻老师客堂笔记
笔记·区块链·智能合约
1024小神1 小时前
SVG标签中path路径参数学习
学习
浅念-1 小时前
C++入门(2)
开发语言·c++·经验分享·笔记·学习
ZH15455891311 小时前
Flutter for OpenHarmony Python学习助手实战:面向对象编程实战的实现
python·学习·flutter
简佐义的博客1 小时前
生信入门进阶指南:学习顶级实验室多组学整合方案,构建肾脏细胞空间分子图谱
人工智能·学习
近津薪荼2 小时前
dfs专题4——二叉树的深搜(验证二叉搜索树)
c++·学习·算法·深度优先
rannn_1112 小时前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
张人玉2 小时前
VisionPro 定位与卡尺测量学习笔记
笔记·学习·计算机视觉·vsionprp