关键词:比特币私钥、比特币公钥、比特币地址、隔离见证、多重签名、主网、测试网、bitcoin-utils
一、为什么用 Python 生成比特币密钥
很多人在比特币突破 7 万美元时,既没入场资金,又担心高位接盘,于是把好奇心转向了“底层技术”。出于对安全与学习的双重需求,用本地代码亲手生成一套 比特币私钥→比特币公钥→比特币地址,不仅能避免把私密信息暴露给网页工具,还能深入理解 P2PKH、P2SH、P2WPKH 的区别。
二、3 行代码就能跑的极简版本
如果你只想得到最普通的 1 开头地址(主网 P2PKH),可以直接用 bitcoin 原生库:
from bitcoin import *
my_private_key = random_key() # 生成 256 位随机私钥
my_public_key = privtopub(my_private_key)
my_bitcoin_address = pubtoaddr(my_public_key)
print("Private Key:", my_private_key)
print("Public Key :", my_public_key)
print("Address :", my_bitcoin_address)这段代码默认压缩公钥,生成的地址均以 1 开头。
三、升级到以 3 开头的 P2SH 地址
想让地址以 3 开头?本质上需要 P2SH(Pay-to-Script-Hash),脚本内部封装了一个隔离见证公钥脚本即可:导入 bit 库即可一行搞定:
from bit import Key
key = Key() # 随机私钥
print("Private Key :", key.to_wif())
print("P2SH 3 开头 :", key.segwit_address)四、更进一步:bc1 开头的原生隔离见证地址
隔离见证(SegWit)可显著缩减 交易字节大小,手续费更低。切换到 bitcoin-utils(目前最新维护的纯 Python 方案)如下所示:
from bitcoinutils.setup import setup
from bitcoinutils.keys import PrivateKey
setup('mainnet')
priv = PrivateKey() # 随机私钥
pub = priv.get_public_key()
segwit_addr = pub.get_segwit_address()
print("Private Key WIF :", priv.to_wif())
print("Public Key :", pub.to_hex())
print("Bech32 bc1 地址 :", segwit_addr.to_string())常见报错排查
AttributeError: 'P2wpkhAddress' object has no attribute 'to_hash160'
解决:.to_hash160()仅适用于 P2PKHAddress。对 P2wpkhAddress 改用.to_hash()。- 签名验证不通过:
segwit_addr的验证需显式指定 witness version。参考库示例代码修复顺序即可。
五、实战案例:一次生成 4 种地址格式
下面把私钥固定为字符串,便于大家跑同样结果做对比:
from bitcoinutils.setup import setup
from bitcoinutils.keys import PrivateKey
from bitcoinutils.script import Script
setup('mainnet')
secret = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
priv = PrivateKey(secret_exponent=secret)
pub = priv.get_public_key()
# 1. P2PKH 1 开头
addr_p2pkh = pub.get_address()
print("P2PKH Address :", addr_p2pkh.to_string())
# 2. P2SH-P2WPKH 3 开头
redeem_script = Script(['OP_0', pub.to_hash160()])
addr_p2sh_p2wpkh = redeem_script.to_p2sh_address()
print("P2SH-P2WPKH Address :", addr_p2sh_p2wpkh.to_string())
# 3. P2WPKH bc1 开头
addr_p2wpkh = pub.get_segwit_address()
print("P2WPKH Address :", addr_p2wpkh.to_string())
# 4. P2TR bc1p 开头(Taproot)
addr_p2tr = pub.taproot_address()
print("P2TR Address :", addr_p2tr.to_string())六、区分 Mainnet、Testnet 与 Regtest
| 网络 | 前缀规律 | 用途 |
|---|---|---|
| Mainnet | 1/3/bc1 | 存放真币,务必保管好私钥 |
| Testnet | m/n/2 | 供开发者免费测试,无需挖矿机 |
| Regtest | m/n/2 | 本地完全私链,可“秒挖”区块,无外部 peer |
快速切网只需修改 setup('regtest') 网,即可全链路本地测试。
FAQ
- 问:生成的私钥与助记词如何备份?
答:私钥可用 WIF 格式(priv.to_wif())抄写到 金属助记板,切勿拍照存网盘。若想与助记词互通,请引入mnemonic模块转 12/24 词组。 - 问:为何我生成的 3 开头地址在部分交易所无法充值?
答:某些早期平台仅支持 P2PKH(1 开头)。该限制已急剧减少,若碰到问题,可直接使用 bc1 原生隔离见证地址。 - 问:P2TR(bc1p)让所有旧地址作废了吗?
答:不会,Taproot 只是新格式,资产互通,但钱包需支持 Bech32m 解码即可识别。 问:如何验证地址属于哪种类型?
答:首字符 + 长度速查- 以 1,长 26–35 位:P2PKH
- 以 3,长 26–35 位:P2SH
- 以 bc1q,长 42:P2WPKH / P2WSH
- 以 bc1p,长 62:P2TR
- 问:主网地址能直接当测试网地址用吗?
答:不能,二者前缀不同。混淆将造成资产“永久黑洞”。