比特币地址生成与验证 - 完整指南
· 阅读需 3 分钟
比特币地址是比特币网络中的关键组件,它们代表公钥的哈希值,用于接收比特币。本文将详细介绍比特币地址的生成过程,包括传统的 Base58 地址和现代的 Bech32 地址。
比特币地址类型
比特币支持多种地址格式:
- Legacy 地址 (P2PKH) - 以 "1" 开头的 Base58 地址
- P2SH 地址 - 以 "3" 开头的 Base58 地址
- Native SegWit 地址 (P2WPKH) - 以 "bc1" 开头的 Bech32 地址
- Taproot 地址 (P2TR) - 以 "bc1p" 开头的 Bech32m 地址
地址生成核心算法
1. 公钥哈希计算
所有比特币地址都基于公钥的哈希值生成:
const { sha256x2, sha256, ripemd160 } = require('../utils/crypto');
// 计算公钥哈希的标准流程
function calculatePubKeyHash(pubkey) {
const hash256 = sha256(pubkey); // SHA256
const hash160 = ripemd160(hash256); // RIPEMD160
return hash160;
}
2. Base58 地址生成
传统的 Base58 地址生成过程:
// https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04_keys.adoc
// pubKeyHash: Version byte. 0x00 for Mainnet P2PKH, 0x6f for Testnet, etc.
export function toBase58Address(pubkey: Buffer, pubKeyHash = 0x00): string {
const hash256 = sha256(pubkey);
const hash160 = ripemd160(hash256);
// version + payload
const payload = Buffer.allocUnsafe(21);
payload.writeUInt8(pubKeyHash, 0);
hash160.copy(payload, 1);
// checksum, first 4 buffer
const checksum = sha256x2(payload).slice(0, 4);
// Buffer.concat([payload, checksum], payload.length + 4);
const buffer = Buffer.allocUnsafe(25);
payload.copy(buffer);
checksum.copy(buffer, 21);
// version + payload + checksum(first 4 bytes)
详细步骤说明:
- 版本字节: 添加网络标识符(主网为 0x00,测试网为 0x6f)
- 公钥哈希: 将 RIPEMD160(SHA256(公钥)) 添加到版本字节后
- 校验和: 计算双重 SHA256 哈希的前 4 字节作为校验和
- Base58 编码: 将整个 25 字节数据编码为 Base58 字符串
3. Bech32 地址生成
现代的 Bech32 地址(SegWit)生成过程:
export function toBech32Address(pubkey: Buffer, pubKeyHash = 0x00): string {
// pubKeyHash: Witness version. 0x00 for P2WPKH
const hash256 = sha256(pubkey);
const hash160 = ripemd160(hash256);
const words = bech32.toWords(hash160);
words.unshift(pubKeyHash);
return bech32.encode('bc', words);
地址验证
function validateBase58Address(address) {
try {
const decoded = base58.decode(address);
if (decoded.length !== 25) return false;
const version = decoded[0];
const payload = decoded.slice(0, 21);
const checksum = decoded.slice(21);
const calculatedChecksum = sha256x2(payload).slice(0, 4);
return checksum.equals(calculatedChecksum);
} catch (error) {
return false;
}
}
function validateBech32Address(address) {
try {
const decoded = bech32.decode(address);
return decoded.prefix === 'bc' && decoded.words.length > 0;
} catch (error) {
return false;
}
}
多签名地址
多签名地址允许多个私钥共同控制资金:
import bitgoV1 from '@bitgo/utxo-lib';
import { payments } from 'bitcoinjs-lib';
const pubKeys = [
'02f4147da97162a214dbe25828ee4c4acc4dc721cd0c15b2761b43ed0292ed82b5', // 2 -3
'0377155e520059d3b85c6afc5c617b7eb519afadd0360f1ef03aff3f7e3f5438dd',
'02f44bce3eecd274e7aa24ec975388d12905dfc670a99b16e1d968e6ab5f69b266',
].map(function (hex) {
return Buffer.from(hex, 'hex');
});
const threshold = 2;
const network = bitgoV1.networks.testnet
var redeemScript = bitgoV1.script.multisig.output.encode(threshold, pubKeys); // 2 of 3
var scriptPubKey = bitgoV1.script.scriptHash.output.encode(bitgoV1.crypto.hash160(redeemScript));
var address = bitgoV1.address.fromOutputScript(scriptPubKey, network);
console.log('bitgo address : ', address);
//
var { address } = payments.p2sh({
redeem: payments.p2ms({ m: threshold, pubkeys: pubKeys, network }),
network,
});
console.log('bitcoin address: ', address);
网络标识符
不同网络使用不同的版本字节:
网络 | Legacy | P2SH | Bech32 |
---|---|---|---|
主网 | 0x00 | 0x05 | bc1 |
测试网 | 0x6f | 0xc4 | tb1 |
回归测试 | 0x6f | 0xc4 | bcrt1 |
安全考虑
- 私钥安全: 永远不要暴露私钥
- 地址重用: 避免重复使用地址以保护隐私
- 网络验证: 确保在正确的网络上生成地址
- 校验和验证: 始终验证地址的校验和
总结
比特币地址生成是一个多步骤的过程,涉及密码学哈希函数、校验和计算和编码转换。理解这个过程对于:
- 开发比特币钱包应用
- 验证交易地址的有效性
- 实现安全的密钥管理
- 支持多种地址格式
在下一篇文章中,我们将探讨比特币交易类型的分类和识别。