跳到主要内容

比特币地址生成与验证 - 完整指南

· 阅读需 3 分钟
iamnivekx
Blockchain Developer

比特币地址是比特币网络中的关键组件,它们代表公钥的哈希值,用于接收比特币。本文将详细介绍比特币地址的生成过程,包括传统的 Base58 地址和现代的 Bech32 地址。

比特币地址类型

比特币支持多种地址格式:

  1. Legacy 地址 (P2PKH) - 以 "1" 开头的 Base58 地址
  2. P2SH 地址 - 以 "3" 开头的 Base58 地址
  3. Native SegWit 地址 (P2WPKH) - 以 "bc1" 开头的 Bech32 地址
  4. 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)

详细步骤说明:

  1. 版本字节: 添加网络标识符(主网为 0x00,测试网为 0x6f)
  2. 公钥哈希: 将 RIPEMD160(SHA256(公钥)) 添加到版本字节后
  3. 校验和: 计算双重 SHA256 哈希的前 4 字节作为校验和
  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);

网络标识符

不同网络使用不同的版本字节:

网络LegacyP2SHBech32
主网0x000x05bc1
测试网0x6f0xc4tb1
回归测试0x6f0xc4bcrt1

安全考虑

  1. 私钥安全: 永远不要暴露私钥
  2. 地址重用: 避免重复使用地址以保护隐私
  3. 网络验证: 确保在正确的网络上生成地址
  4. 校验和验证: 始终验证地址的校验和

总结

比特币地址生成是一个多步骤的过程,涉及密码学哈希函数、校验和计算和编码转换。理解这个过程对于:

  • 开发比特币钱包应用
  • 验证交易地址的有效性
  • 实现安全的密钥管理
  • 支持多种地址格式

在下一篇文章中,我们将探讨比特币交易类型的分类和识别。