Bitcoin 钱包离线地址生成和签名实战
一. Bitcoin 概览
1. Bitcoin 简介
比特币(Bitcoin)是由一个或一群化名为中本聪(Satoshi Nakamoto)的人在 2008 年提出,并于 2009 年开始发布的去中心化数字货币。它的出现标志着一种新型金融体系的诞生,具有以下主要特点:
去中心化
💡💡比特币网络没有中央管理机构或中介机构,它通过一个称为区块链的分布式账本来记录所有交易。
💡💡区块链技术确保了所有参与者都可以查看和验证交易,提高了透明度和安全性。
有限供应
💡💡比特币的总供应量被固定在2100万枚,这通过代码内的机制控制。
💡💡这一机制使比特币具备了抗通胀的特点。
点对点交易
💡💡比特币允许用户之间直接进行交易,不需要通过银行或支付处理机构。
💡💡这种点对点交易减少了交易成本和处理时间。
安全性
💡💡比特币使用加密技术确保交易的安全性和隐私性。
💡💡每一笔交易都需要通过复杂的数学算法进行验证,从而确保系统的完整性。
不可逆交易
💡💡一旦比特币交易被确认,它就无法被撤销。这减少了欺诈的风险,但也意味着用户需要谨慎操作。
挖矿机制
💡💡新的比特币通过一个称为挖矿的过程产生。矿工们使用计算能力来解决复杂的数学问题,成功解决问题的矿工将获得比特币奖励。
💡💡挖矿不仅生成新币,还维护和保护比特币网络的安全。
全球流通
💡💡比特币可以在全球范围内进行交易,不受地域和国界的限制。
💡💡它为跨国支付提供了一种高效、低成本的替代方案。
隐私和匿名性
💡💡虽然比特币交易是公开记录的,但用户身份是匿名的。交易是通过地址(类似于账号)进行的,而不是通过真实身份。
2.Bitcoin 的升级次数介绍
比特币自 2009 年发布以来,经历了多次重要升级。这些升级旨在提高比特币网络的安全性、效率和功能性。
并且比特币的 Taproot 升级给比特币带来更多的可能性,Taproot 升级带动了 BRC20 和 Bitcoin-Layer2 的发展,这里我们不在做过多的介绍,在未来的 Layer2. 的课程中我们会深入讲解这部分的内容
P2SH(Pay-to-Script-Hash)
💡💡时间:2012年
💡💡BIP(Bitcoin Improvement Proposal):BIP-0016
💡💡内容:允许更复杂的交易脚本,支持多重签名地址。这种升级使得比特币交易更加灵活和安全
比特币改进提案 BIP 66
💡💡时间:2015年
💡💡BIP:BIP-0066
💡💡内容:规范了交易中DER格式的签名,解决了交易签名的一致性问题,增强了网络的安全性。
CheckSequenceVerify(CSV)
💡💡时间:2016年
💡💡BIP:BIP-0112
💡💡内容:增加了相对时间锁功能,使得交易可以在指定的时间或块高度之后才生效,这为更复杂的支付通道铺平了道路。
Segregated Witness(SegWit)
💡💡时间:2017年
💡💡BIP:BIP-0141, BIP-0143, BIP-0144
💡💡内容:分离交易签名数据,提高了区块的有效容量,减小了交易体积,降低了交易费用。还解决了交易的可塑性问题,使得闪电网络等侧链解决方案成为可能。
隔离见证2x(SegWit2x)
💡💡时间:2017年
💡💡内容:这次升级是对 SegWit 的后续提案,旨在进一步增加区块大小。然而,由于社区共识未达成,这次升级最终未能实现。
Taproot
💡💡时间:2021年
💡💡BIP:BIP-0340, BIP-0341, BIP-0342
💡💡内容:引入了 Schnorr 签名和默克尔化抽象语法树(MAST),增强了隐私性和执行脚本验证的功能,进一步提高了交易的灵活性和效率。这是自2017年 SegWit 以来最重要的一次升级。
💡💡💡💡MAST(Merkelized Abstract Syntax Trees)
💡💡💡💡💡💡时间:2021年
💡💡💡💡💡💡BIP:作为 Taproot 的一部分
💡💡💡💡💡💡内容:允许将多种条件的智能合约合并为一个,使得只有满足条件的部分才被公开,提高了隐私性和效率。
💡💡💡💡Schnorr Signatures
💡💡💡💡💡💡时间:2021年
💡💡💡💡💡💡BIP:作为 Taproot 的一部分
💡💡💡💡💡💡内容:提供了一种更高效和安全的签名算法,允许多重签名聚合,提高了交易的隐私性和可扩展性。
3.UTXO 介绍
UTXO(Unspent Transaction Output,未花费交易输出)模型是比特币及其他一些加密货币使用的一种记账方法。它与账户模型不同,通过追踪未花费的交易输出来记录每个地址的余额。以下是UTXO模型的详细介绍:
模型解说
在解说 UTXO 模型之前,我想先说说一个名词,叫做 Transaction,即交易,Transaction 和 UTXO 是相辅相成的,下面先来举个例子:
张三:通过挖矿得到了120个比特币,现在张三饿了,想要花费2个比特币去购买一个面包。这是只是举例而已,以现在比特币的价格,1个比特币就可以买到一大堆面包了。
现在我们假设,李四是面包店营业主
这样的话,在比特币中,张三付给李四将一次性付给李四 120 块,李四给张三找零 118 块,这里其实产生了两笔交易,咱们可以这样理解,张三的钱被分成了两份,其中 118 打给了自己,剩下的 2 块打给了李四。
交易与交易之间组成了网状关系,1 个交易的输出,成为了下 1 个交易的输入;下 1 个交易的输出,又成了下下 1 个交易的输入。所有的钱,在这个网络中流动,每 1 笔钱的去向、来源,都是可追溯的,而这也是区块链网络的一个重要特点。
上面的讲解可能大多数人都比较懵逼,接下来咱们用比较通俗的方式来说明 UTXO 和 Transaction 到底是什么
在现实生活中,一笔转账对应的事一个付款人和一个收款人,而在比特币种,一笔转账对应的事多个转账人和多个收款人。
现在咱们仔细分析一下上面的这个例子,对于张三买面包这个案列
- 付款人:张三 120块
- 收款人:张三 118块,李四 2块
张三的120,转118块给自己,转2块给李四,对应到交易里面,就是这笔交易有1个输入,2个输出!
下面来一个多输入,多输出的案例
考虑如下场景:用户A和用户B之间发生了一个交易T3,A 向 B 转 100 元。 A的100元,来自T1:C向A转的80元 + T2:D向A转的30元(共110元,但A只转了100元给B,10元找零返回给A的账号)。 同理,C向A转的这80元,来自用户E、F的某次交易...... D向A转的这30元,来自用户E的某次交易......
这个交易就有2个输入,2个输出: 2个输入(也就是2个UTXO): T1: C向A转的80元 T2:D向A转的30元
2个输出: B:100元 A:10元(找零)
当你理解上面的例子时,我们再来说一下UTXO,理解上面的例子对你理解UTXO会特别有帮助。
-
比特币的交易中不是通过账户的增减来实现的,而是一笔笔关联的输入/输出交易事务。
-
每一笔的交易都要花费“输入”,然后产生“输出”,这个产生的“输出”就是所谓的“未花费过的交易输出”,也就是UTXO。每一笔交易事务都有一个唯一的编号,称为交易事务ID,这是通过哈希算法计算而来的,当需要引用某一笔交易事务中的“输出”时,主要提供交易事务ID和所处“输出”列表中的序号就可以了。
-
由于没有账户的概念,因此当“输入”部分的金额大于所需的“输出”时,必须给自己找零,这个找零也是作为交易的一部分包含在“输出”中。
-
旧的 UTXO不断消亡,新的UTXO不断产生。所有的UTXO,组成了UTXO Set 的数据库,存在于每个节点
-
任何1笔 UTXO,有且仅可能被1个交易花费1次
-
1 个 UTXO,具有如下的表达形式: 1 个 UTXO = 1个Transaction ID + Output Index
2. UTXO模型的区块链钱包余额形式
深刻理解了UTXO的概念,钱包就很容易理解了,某个人的钱包的余额 = 属于他的UTXO的总和;在这里,你会发现一个不同于现实世界的“银行”里的一个概念,在银行里,会存储每个账号剩余多少钱。但这里,我们存储的并不是每个账号的余额,而存的是1笔笔的交易,也就是1 笔笔的UTXO,每个账户的余额是通过UTXO计算出来的,而不是直接存储余额。
二. Bitcoin 钱包地址类型
Bitcoin 钱包地址有几种不同的类型,每种类型都有其特定的用途和特点。主要的几种类型包括:
P2PKH(Pay-to-PubKeyHash)地址
💡💡格式:以1开头,例如,1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa。
💡💡特点:这是最传统和最常见的地址类型,广泛用于比特币的早期交易。
💡💡优点:兼容性好,几乎所有钱包和交易所都支持。
💡💡缺点:随着时间的推移,这种地址类型的使用效率较低,交易费用可能会较高。
P2SH(Pay-to-Script-Hash)地址
💡💡格式:以3开头,例如,3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy。
💡💡特点:这种地址允许更复杂的交易脚本,例如多重签名地址。
💡💡优点:支持更复杂的交易和脚本,安全性更高。
💡💡缺点:创建和管理比P2PKH地址更复杂。
Bech32(SegWit)地址
💡💡格式:以 bc1 开头,例如,bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwfvenl。
💡💡特点:这是比特币改进提案BIP-0173中引入的新地址格式,旨在提高交易效率和减少费用。
💡💡优点:交易费用更低,处理速度更快,且有助于减少交易体积。
💡💡缺点:并非所有的钱包和交易所都支持这种地址类型,尽管支持率在逐步增加。
每种地址类型都有其特定的应用场景和优缺点,用户可以根据自己的需求选择合适的地址类型来存储和交易比特币
三. Bitcoin 离线地址生成代码
NodeJs 代码
export function createAddress (params: any): any {
const {seedHex, receiveOrChange, addressIndex, network, method } = params
const root = bip32.fromSeed(Buffer.from(seedHex, 'hex'));
let path = "m/44'/0'/0'/0/" + addressIndex + '';
if (receiveOrChange === '1') {
path = "m/44'/0'/0'/1/" + addressIndex + '';
}
const child = root.derivePath(path);
let address: string
switch(method) {
case "p2pkh":
const p2pkhAddress = bitcoin.payments.p2pkh({
pubkey: child.publicKey,
network: bitcoin.networks[network]
});
address = p2pkhAddress.address
break
case "p2wpkh":
const p2wpkhAddress = bitcoin.payments.p2wpkh({
pubkey: child.publicKey,
network: bitcoin.networks[network]
});
address = p2wpkhAddress.address
break
case "p2sh":
const p2shAddress = bitcoin.payments.p2sh({
redeem: bitcoin.payments.p2wpkh({
pubkey: child.publicKey,
network: bitcoin.networks[network]
}),
});
address = p2shAddress.address
break
default:
console.log("This way can not support")
}
return {
privateKey: Buffer.from(child.privateKey).toString('hex'),
publicKey: Buffer.from(child.publicKey).toString('hex'),
address
};
}
代码中通过 method 来控制生成的地址类别
四. Bitcoin 离线签名代码
export function buildAndSignTx (params: { privateKey: string; signObj: any; network: string; }): string {
const { privateKey, signObj, network } = params;
const net = bitcore.Networks[network];
const inputs = signObj.inputs.map(input => {
return {
address: input.address,
txId: input.txid,
outputIndex: input.vout,
script: new bitcore.Script.fromAddress(input.address).toHex(),
satoshis: input.amount
}
});
const outputs = signObj.outputs.map(output => {
return {
address: output.address,
satoshis: output.amount
};
});
const transaction = new bitcore.Transaction(net).from(inputs).to(outputs);
transaction.version = 2;
transaction.sign(privateKey);
return transaction.toString();
}