为什么要有比特币?
1933年,因为美国的通货膨胀非常严重,联邦财政正在崩溃,经济形势也很困难,罗斯福签署法案,禁止私人使用直接形式的货币和间接形式的货币,政府没收了所有公民的黄金。
1971年,因为越南战争和普遍的衰退,美国联邦政府需要钱,尼克松决定暂停美元和黄金的兑换。各国货币进入浮动汇率时代,需要灵活调整货币政策应对经济问题。但是美元从依赖黄金标定转换为依赖美国信用背书的货币。而自此之后
- 货币的价值变得不稳定:因为失去锚定物,货币发行失去限制,可能导致货币超发,引发通货膨胀。
- 经济失衡加剧:由于美元需求旺盛,美国长期维持贸易逆差,其他国家被迫储备美元以稳定自身经济
- 金融危机频发:黄金挂钩的终结导致全球货币系统进入更加依赖信用和市场信心的时代,一旦信心受损,可能引发危机。1970 年代的石油危机与滞胀、1997 年亚洲金融危机,以及 2008 年全球金融危机,都与美元体系的波动性和失衡相关。
- 贫富差距扩大:浮动汇率和信用货币的普及加剧了资本市场的波动性,富裕国家和大资本拥有更多工具获利,而经济弱势国家和普通劳动者受到较大冲击。
从上面的历史可以看出,失去价值锚定的货币带来了一系列问题,包括通货膨胀、信用危机和金融体系的不透明性。那么是否存在一种锚定物来绕过权利机构(政府,银行…)从而诞生一种新的货币体系呢。
1936 年,图灵发表了一篇名为 “论可计算的数字以及可判定性的运用”,为信息革命奠定了理论基础。这不但支撑了比特币产生的技术体系,还给我们带来了新的锚定物。是否可以使用计算机处理能力、带宽和数据存储这样的稀缺资源作为锚定物,通过互联网点对点交换…
在比特币之前
其实计算机行业对去中心的电子货币的尝试一直都在进行,而这一切的基础则是基于密码学的发展。
非对称加密
在1976年之前,所有的密码系统都是对称的,可以理解为用密钥将明文加密为密文和用密钥将密文解码为明文的过程是难度相同的。
对称加密的例子:
- Alice 写出了她想发送给 Bob 的明文,现在她想对这份明文加密;
- Alice 将信件中的每一个字母都换成其在字母表上前 7 个位置的字母,使得文字变成没有逻辑含义的字母块;
- Alice 把密文发送给 Bob;
- 为了恢复出原文,Bob 必须把每一个字母都换成其在字母表上后 7 个位置的字母,这样就能找回 Alice 的明文。
而1976年,迪费和赫尔曼发表了论文“密码学的新方向”中创造了一种非对称密码学,即用密钥将明文加密为密文这个过程是非常简单的,而用密钥将密文解码为明文的过程却近于不可能。
非对称加密的例子:
- 参与密码学交换的双方各有两个密钥,一个是公开的,一个是私密的;
- Alice 生成一个私钥;
- Alice 运用数学,确定性地计算出跟这个私钥相关联的公钥;
- Alice 可以把公钥发给任何人;
- Bob 想要加密跟 Alice 的通信,他可以使用 Alice 的公钥,让文本变得没法阅读(即加密);
- 而密文只能用 Alice 的私钥来解密。
1978 年, “一种获得数字签名和公钥密码系统的方法” 的文章被发表,发明了一种基于质数的非对成加密方法,让非对称加密成为可能。
1985 年,《椭圆曲线密码学》出版,提出了一种基于有限域椭圆曲线、替代上面加密方法的公钥签名算法。
数字签名技术
1981年,大卫·乔姆提出了一种使用数字签名、无法追踪的电子邮件协议,并出版了《不可追踪的电子邮件、返回地址以及电子假名》。他标志着使用非对称密码学来签名消息(而非加密文本)的用法的开端。
数字签名的例子:
- Alice 发送一条消息给 Bob,并希望证明她是这条消息的发起人
- Alice 使用自己的私钥签名这条消息
- Alice 把明文和使用自己的私钥 “加密” 过的密文(签名)都发送给 Bob
- Bob 知道 Alice 的公钥,所以他可以使用 Alice 的公钥 “解密” Alice 给他的密文(签名)
- 如果 Alice 真的使用她的私钥签名了这条消息,那么明文将与密文具有一致性
DigiCash
1983年,大卫·乔姆出版了《用于不可追踪的支付的盲签名》,第一次提出了使用密码学签名系统来构造不可追踪的电子支付的想法。
1989年,他基于非对称密码学和盲签名开发了一个电子支付系统 DigiCash,为支付提供安全、匿名和保证用户隐私的电子工具。
为了实现这个目标,乔姆使用了密码学来保护交易,并保证只有发送者和接收者能知晓交易的细节,而且所有的东西都和一套 “数字签名” 系统绑定在一起,以验证交易的合法性及防止伪造。
DigiCash 系统基于电子货币 ecash,ecash 可以在网络中传输、用于完成在线支付。但是其实现依然依赖 DigiCash 公司作为清算机构,其早于时代的理念难以被人们理解。另外没有找到合适的盈利方式导致 DigiCash 最终破产。
HashCash
1997年,亚当贝克用匿名的电子邮件和其他人交流,这些电子邮件是一次性的。这就产生了滥发消息的问题,为了避免被消息轰炸,亚当使用了一种工作量证明的方式:
- Alice 创建了一条电子邮件消息
哈喽,你好吗?,带上的当天的日期后,就开始对消息运行哈希函数;
- Alice 给 Bob 发送文本和对应的哈希值;
- Bob 检查消息的哈希值是否以
0开头,如果是,他会打开邮件,如果不是,就直接丢掉;
- 如果 Alice 注意到她的邮件的哈希值以
1开头,她直接就不发送这条消息了,她会稍微修改文字,以产生一个新的哈希值:如果新的哈希值以0开头,就发出去(然后 Bob 也会打开、阅读),不然她就继续修改;
另外 HashCash 开创了一种思想,即可以通过算力作为发送邮件的成本来进行支付,这也是其名字中 Cash 的来源,似乎和我们开头提到的想法不谋而合。
B-Money
1998年,Wei Dai 发表了一篇论文,提出了一种去中心化的数字货币以及通过一个智能合约系统来管理交易并保证系统安全性的想法。
提出了一种基于分布式账本的经济系统,所有交易记录在分布式网络中共享,确保系统的透明性和抗审查性。系统通过协议在节点间实现一致性,确保账本记录的唯一性和准确性。
B-Money 借用 HashCash 思想,提出了一种基于工作量证明的货币生成机制。
另外 Wei Dai 还提出了一种参与者通过质押存款来记录交易,解决了工作量证明中的资源浪费问题,类似于权益证明。
虽然 B-Money 没有被正式实现,但是其思想已经包含很多比特币的影子,但是它有一个巨大的问题,就是资金可能被重复花费(双花问题)。
Wei Dai 为解决这个问题想出的办法是为交易建立排序,为此,参与者需要对交易的先后进行投票,但这样会导致一些节点作恶投出假票,或创建一些节点操纵投票结果,即女巫攻击。
Wei Dai 为解决女巫攻击提出了让提供更多电子货币担保的节点获得更高的投票权重,将无成本创建的投票视为无效。但是这样会导致一个循环问题,在这个系统中,决定交易排序的投票权重是由在押的资金存量决定的,但在押的资金存量又取决于上一轮的交易排序,这个排序又依赖于上一轮的在押资金存量,又依赖于上上轮的交易排序。这样的逻辑会产生一个更弱的系统,很容易导致资金被集中化。
所以双花问题并没有被真正解决,而比特币的创新性就是解决了这个问题。
RPOW 可复用的工作量证明
2004年,哈尼芬尔创建了 RPOW ,和 B-Money 的 PoW 相比。PoW 只是在货币生成使用,是一次性的。而 RPOW 生成的工作量证明可以“包装”为一个代币,并通过网络进行多次转移。而 RPOW 解决双花问题的办法是通过可信硬件来验证工作量证明的真实性和代币的唯一性,确保代币不能被伪造或重复使用。但是硬件本身还是需要信任,双花问题仍然没有被很好地解决。
比特币——解决双花问题
其实 Wei Dai 的思想已经告诉了我们,解决双花问题的核心在于为交易建立排序,从而确保交易是不可篡改和唯一的,接下来我们将通过比特币白皮书的内容理解比特币的创新性:解决双花问题。
比特币的时间戳机制
比特币通过一种去中心化的时间戳机制为每笔交易打上时间标记。具体来说:
- 交易的哈希时间戳:每笔交易被记录到一个区块中,区块通过包含交易数据计算出一个哈希值,这个哈希值就是该区块的时间戳。
- 链式结构:每个区块的哈希值不仅取决于该区块的交易,还包含了前一个区块的哈希值。这种设计形成了一条不可篡改的链条,称为区块链。
- 增强不可篡改性:后续区块的生成依赖前一个区块的哈希值,因此每增加一个新区块,前面区块中的交易记录就越难被篡改。这种链式结构使得时间戳具有累积的防篡改能力。
这种设计使得所有交易都可以按照时间顺序排列,从而为双花问题提供了解决方案——即当交易被链条中的一个区块确认后,其排序就被锁定,无法修改。
解决投票问题:工作量证明(PoW)
然而,Wei Dai 提出的通过节点投票来为交易排序的机制在实践中会面临严重的女巫攻击问题:恶意节点可以伪造大量虚假身份,从而操控投票结果。比特币的创新之处在于使用POW机制来取代传统的投票方式,从根本上解决了这一问题。
- 什么是工作量证明(PoW)?
- 防止女巫攻击:每个节点只有通过消耗真实资源才能竞争出块权,伪造多个虚假节点无法带来优势。
- 公平性:出块概率与节点所投入的计算资源(算力)成正比。
工作量证明要求节点为生成一个有效区块执行大量复杂计算任务,这些计算任务通常是寻找一个满足特定条件的哈希值。这种计算非常耗费资源(如电力和硬件),从而限制了恶意节点操控网络的能力:
- PoW 的双重作用:
- 生成货币:完成工作量证明的节点会获得比特币奖励,这成为新比特币的发行机制。
- 排序交易:在节点成功生成区块后,区块内的所有交易记录就被按照时间顺序确认,并与区块链其他部分连接起来,形成一致的全网交易历史。
- 竞争记账权:通过 PoW,每个节点都需要通过竞争算力来争夺下一个区块的记账权。这种竞争不仅确保了去中心化,还防止了单一节点或恶意节点垄断网络。
比特币的产生
前面提到,PoW 不仅解决了交易排序问题,同时也实现了货币的生产机制。在比特币网络中,每个新区块都包含一笔特殊的交易——Coinbase 交易,它是比特币生成的来源。Coinbase 交易是由获得出块权的矿工构造的,其作用是奖励矿工成功创建一个新区块并将其添加到区块链。
比特币的设计使得其总供应量为 2100 万枚。为了逐渐接近这一上限,每隔 210,000 个区块,Coinbase 交易的区块补贴会减半:
- 第一阶段:最初的区块补贴是 50 BTC/区块。
- 第二阶段:在第 210,001 个区块开始,区块补贴减半为 25 BTC/区块。
- 第三阶段:进一步减半为 12.5 BTC/区块,依此类推。
矿工在创建一个新区块时,不但可以获得创建Coinbase 交易的权利,还可以获得区块内包含的交易的手续费,这两部分一起构成了比特币的激励机制。
长链原则:全网共识的核心
然而比特币这样的链式结构有可能会分叉,想象一下,如果有节点恶意将之前的区块作为前一个区块进行计算, 或者两个节点同时计算出了下一个区块。

为了解决这个问题,比特币节点通过最长链原则达成共识:
- 每个节点都会选择包含最多工作量证明的链作为主链。
- 当出现分叉时,网络会优先认可最长链作为合法的区块链。
这种设计确保了网络中的分歧会随着时间推移而自动解决,所有节点最终会就唯一的区块链达成共识。
比特币交易如何进入区块
现在我们已经知道为什么要有比特币,以及比特币在加密货币方向上所作的开创性创新,让他成为一个真正的点对点电子货币系统。那么点对点这一过程如何实现呢,交易是如何从一方直接发送到另一方的呢?
假设Alice已经拥有了 2 个 BTC,要向 Bob 发送 1 个 BTC。我们通过这个过程来理解比特币的交易。
创建钱包
假设 Bob 是一个从未接触过比特币的人,他要接收 Alice 向他发送的 BTC,他首先需要创建一个比特币钱包。比特币钱包并不是存储币的地方,而是管理私钥、公钥和地址的工具。这些组件是比特币交易的核心,它们通过 椭圆曲线加密算法(ECC) 提供安全性。
- 生成私钥:私钥是一个随机生成的 256 位数字,代表了 Bob 对钱包的完全控制权。也就是你可以选择从0到1.158*10^77之间的任意一个数作为你的私钥,但是为了足够的安全,我们需要有一个足够随机的来源来生成私钥。如(十六进制表示):
E9873D79C6D87DC0FB6A5778633389E499F78A77FBCBF62BF5A6CFFF2337AAAA
- 计算公钥:比特币使用的椭圆曲线算法在前文中提到过,是一种非对称加密方法,通过椭圆曲线算法可以从私钥计算得到公钥,这是不可逆转的过程,
P = k * G。其中k是私钥,G是被称为生成点的常数点,而P是所得公钥。其反向运算,被称为“寻找离散对数”——已知公钥P来求出私钥k——是非常困难的,就像去试验所有可能的k值,即暴力搜索。 如(压缩形式,33 字节):0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
- 生成比特币地址(公钥哈希):比特币地址是通过对公钥进行哈希处理得到的
- 对公钥执行 SHA-256 哈希:
H[sha256](P) - 对结果执行 RIPEMD-160 哈希:
H[RIPEMD160](H[sha256](P)) - 添加网络前缀和校验码:
- 主网前缀:
0x00。 - 校验码:对上述结果(含前缀)执行两次 SHA-256 哈希,取前 4 字节作为校验和。
- Base58Check 编码:最终生成一个可读的比特币地址。如:
1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs创建交易
Alice 通过钱包软件生成了一笔交易,包含以下关键信息:
- 交易输入(Inputs):
指向 Alice 之前获得的一笔未花费交易输出(UTXO),这里则是 Alice 所拥有的 2 BTC。
- 交易输出(Outputs):
- 发送给 Bob 的金额: 1 BTC,输出的目标是 Bob 的地址。
- 找零: 0.999 BTC,找零金额会返回到 Alice 的钱包地址。
- 矿工费:实际上矿工费并没有包含在交易输出中,它是输入和输出金额之间的差值。
- 解锁脚本(Unlocking Script,ScriptSig):
Alice 使用自己的私钥为交易进行签名,证明她对这笔 UTXO 的控制权。
类似如下结构:
这里的 inputs 就是 Alice 之前接受到的 2 BTC,这个 UTXO 包含一个锁定脚本 scriptPubKey,当 Alice 要花费这个 UTXO 时,需要提供一个对应的解锁脚本 scriptSig 以证明有花费该 UTXO 的权利。
上面的交易中 inputs 中的
pkscript 对应锁定脚本,sigscript 对应解锁脚本。而 outputs 中包含两个 UTXO,第一个是转账给 Bob 的 1 BTC,第二个是给 Alice 的找零 0.999 BTC,剩下的差值则是给节点的交易费。这里我们使用的是 P2PKH 标准来进行转账,其具体的验证过程将会在下一节介绍。这里的
pkscript 和 sigscript 都是16进制表示的比特币脚本操作码另外,前面我们提到比特币的总量是有上限的,但是在实际使用中,类似于实物黄金的使用,比特币是可以拆分的,目前最小支持拆分为 1 聪(1比特币等于 1 亿聪),拆分可以让比特币更加灵活和支持小额支付。
比特币的脚本语言
比特币的交易脚本语言,是一种非常简单的基于栈的语言,因为他使用的数据结构为栈,可以把他想象为一个堆卡片,栈只允许两类操作:入栈和出栈。入栈是在栈顶部增加一个项目,出栈则是从栈顶部移除一个项目。
脚本语言通过从左至右地处理每个项目的方式执行脚本。常数被推送至堆栈,操作码向堆栈推送(或移除)一个或多个参数,对它们进行处理,甚至可能会向堆栈推送一个结果。
如脚本
2 3 OP_ADD 5 OP_EQUAL 的执行过程为:- 将 2 和 3 依次推入栈中。
OP_ADD操作符将 2 和 3 出栈,将两个值相加并推入栈中。
- 再将 5 推入栈中,
OP_EQUAL将栈内的两个值(即 5 和 5)推出并验证这两个值是否相等。
上一节中提到,比特币的交易验证引擎依赖于两类脚本来验证比特币交易:一个锁定脚本和一个解锁脚本。假设我们使用这个例子
2 3 OP_ADD 5 OP_EQUAL ,这部分将会被用作锁定脚本:3 OP_ADD 5 OP_EQUAL,而它的解锁脚本则是:2 。比特币验证交易时会将解锁脚本和锁定脚本拼接起来,成为:
2 3 OP_ADD 5 OP_EQUAL ,当拼接后的脚本运行结果为 OP_TRUE 时,该交易就为一个有效交易。但是这样并不能保证比特币被指定的人拥有,任何知道这个运算规则的人都能使用这笔 UTXO,所以比特币的转账交易有几个标准的脚本:- P2PKH(Pay-to-Public-Key-Hash)向公钥哈希转账
- 将 Bob 的签名和公钥依次推入栈内
OP_DUP复制栈顶的 Bob 的公钥OP_HASH160将 Bob 的公钥推出并进行两次哈希处理得到 Bob 的公钥哈希 并推入栈- 将Bob 的公钥哈希推入栈
OP_EQUAL推出栈顶两个公钥哈希并进行比较OP_CHECKSIG推出栈顶的 Bob 的签名和 Bob 的公钥,检查签名有效性
比特币网络上的大多数交易都是P2PKH交易,即转账给公钥哈希(比特币地址)。这种交易的解锁脚本由公钥哈希实现阻碍输出的功能。而解锁则需要通过键入对应公钥和由其私钥创建的数字签名得以解锁。假设 Alice 通过 P2PKH 的方式向 Bob 转账,那么其锁定脚本应该是:
OP_DUP OP_HASH160 <Bob's Public Key Hash> OP_EQUAL OP_CHECKSIG当 Bob 需要使用这笔转账时,应该提供的解锁脚本为:
<Bob's Signature> <Bob's Public Key>拼接后的脚本为
<Bob's Signature> <Bob's Public Key> OP_DUP OP_HASH160 <Bob's Public Key Hash> OP_EQUAL OP_CHECKSIG 执行过程为:- P2PK(Pay-to-Public-Key)向公钥转账
- 将 Bob 的签名 和 Bob 的公钥依次推入栈内
OP_CHECKSIG将栈内两个元素弹出 检查签名有效性
与P2PKH相比,P2PK模式更为简单。在P2PK脚本模式中,公钥本身已经存储在锁定脚本中,而且代码长度也更短。P2PKH是由Satoshi创建的,主要目的一方面为使比特币地址更简短,另一方面也使之更方便使用。P2PK目前在Coinbase交易中最为常见。假设 Alice 通过 P2PK 的方式向 Bob 转账,那么其锁定脚本应该是:
<Bob's Public Key> OP_CHECKSIG当 Bob 需要使用这笔转账时,应该提供的解锁脚本为:
<Bob's Signature>拼接后的脚本为
<Bob's Signature> <Bob's Public Key> OP_CHECKSIG 执行过程为:- 多重签名
- 将
OP_0和两个签名依次推入栈 - 将 3 推入栈
- 三个公钥推入栈
- 将 2 推入栈
OP_CHECKMULTISIG检查是否含有与3个公钥中的任意2个相一致的私钥的有效签名。
多重签名脚本设置了这样一个条件,假如记录在脚本中的公钥个数为N,则至少需提供其中的M个公钥才可以解锁。这也被称为M-N组合,其中,N是记录在脚本中的公钥总个数,M是使得多重签名生效的公钥数阀值(最少数目)。假设 Alice 商议和 Bob 共同管理一笔资金,约定一个律师为见证,只有当三个人中的两个批准时,这笔资金才能被花费。
那么其锁定脚本应该为:
3 <Alice's Public Key> <Bob's Public Key > <lawyer's Key> 2 OP_CHECKMULTISIG对应的解锁脚本为:
OP_0 <Signature B> <Signature C>之所以要加上前缀OP_0,是因为最早的CHECKMULTISIG在处理含有多个项目的过程中有个小漏洞,CHECKMULTISIG会自动忽略这个前缀,它只是占位符而已。
这里至少需要 Alice,Bob 或 律师三个人中的两个签名才能解锁这笔资金,拼接后的脚本为:
OP_0 <Signature B> <Signature C> 3 <Alice's Public Key> <Bob's Public Key > <lawyer's Key> 2 OP_CHECKMULTISIG执行过程为:
- P2SH(Pay-to-Script-Hash)向赎回脚本转账
- 将
OP_0和两个签名依次推入栈 - 将
RedeemScript推入栈 OP_HASH160弹出RedeemScript并计算其哈希值,然后将其哈希值推入栈- 将
RedeemScript_Hash推入栈 OP_EQUAL将计算过后的哈希 和RedeemScript_Hash弹出,进行比较- 如果哈希验证通过,会执行 赎回脚本(RedeemScript )部分
- 此时栈内为
OP_0和两个签名,剩余步骤和上面的多签执行相同
P2SH 是比特币中用于支持复杂脚本(如多签、时间锁等)的交易类型,其核心思想是将资金锁定到脚本的哈希值,而非直接锁定到公钥哈希。发送者只需知道脚本的哈希值即可转账,而花费时需要提供匹配哈希的脚本及其参数。假设 Alice 和 Bob 通过 P2SH 进行多签,那么其锁定脚本应该是:
OP_HASH160 <RedeemScript_Hash> OP_EQUAL当 Bob 需要使用这笔转账时,应该提供的解锁脚本为:
OP_0 <Signature B> <Signature C> <RedeemScript> RedeemScript 对应的脚本为:3 <Alice's Public Key> <Bob's Public Key > <lawyer's Key> 2 OP_CHECKMULTISI拼接后的脚本为:
OP_0 <Signature B> <Signature C> <RedeemScript> OP_HASH160 <RedeemScript_Hash> OP_EQUAL执行过程为:
由于比特币的交易 ID 和输入中提供的签名相关,所以在多签内提供不同数量或不同账户的签名,会导致同一笔交易有不同的交易ID,导致交易ID在签名后可能被篡改。2017年通过的 SegWit 升级将签名数据从交易主体分离,间接扩大了区块的有效容量(如 一个 20 of 30 的多签,这样就减少了 20 个签名数据),签名数据也不影响交易ID的唯一性。
广播交易并进入内存池
交易完成签名后,Alice 的钱包将其广播到比特币网络中。接收到交易的节点会执行初步验证:
- 检查交易结构: 确保交易的格式符合比特币协议的规则。
- 检查 UTXO 是否未被使用: 确保输入引用的 UTXO 尚未被其他交易花费。
- 验证解锁脚本:将解锁脚本和锁定脚本拼接执行。
- 验证数字签名: 使用 Alice 提供的公钥验证其签名,以及签名覆盖的内容是否被篡改。
一旦一笔比特币交易被发送到任意一个连接至比特币网络的节点,这笔交易将会被该节点验证。将
pkscript 与 signscript 对应的比特币操作码以及其中添加的相关数据排列在一起,然后用栈式虚拟机进行执行,最后 OP_CHECKSIG 的结果如果是 OP_TRUE(整个脚本执行完成后,堆栈顶端留下的结果必须是 True,表示交易验证通过。),那就说明该解密脚本是合法的。
如果通过验证,交易会被存入节点的内存池(Mempool),内存池就是未确认交易的缓存。并且该节点将会将这笔交易传播到这个节点所连接的其他节点。
矿工打包交易和工作量证明
矿工从内存池中选择交易进行打包,通常优先选择手续费较高的交易。
矿工会将被选中的交易和特殊 Coinbase 交易一起构建成一个候选区块,并进行默克尔树运算。这是为了压缩包含在区块内的交易数据,如果所有的交易都包含在区块内,那将是非常庞大的数据,而默克尔树将每笔交易的哈希值作为叶子节点,相邻交易的哈希值两两组合后再次哈希,生成父节点。重复上述过程,直至生成唯一的根哈希值,即默克尔根。如果其中一笔交易被篡改,那么默克尔根的值就会发生改变,也就是说,只要默克尔根就可以保证交易一定存在于区块中。

之后矿工会对区块头的信息进行哈希计算,区块头包含如下信息:
比特币的难度目标 target 是一个 256 位的数值,公式为:
target = coefficient * 256^(exponent – 3)难度目标的计算参数存储在 Bits字段中:
Bits = [Exponent (1 byte)][Coefficient (3 bytes)]其中
Exponent 表示目标值的长度,Coefficient 表示目标值的有效位数字段。计算出 target 值之后,矿工通过不断调整
Nonce 的值,将区块头进行双重 SHA-256 哈希计算:Hash=SHA256(SHA256(Block Header))直到 Hash ≤ target,在实际操作中,比特币的目标难度过大时,可能找完所有有可能的
Nonce 值都无法满足条件,这时候矿工会调整 Coinbase 交易,从而调整默克尔根,来增加出块的可能性。比特币每 2016 个区块(两周)调整一次难度,以确保平均出块时间保持在 10 分钟。难度调整公式为:
新的难度 = 旧的难度 × 1/4 >= 旧的难度 × 2016个区块出块预期时间 / 2016个区块总出块时间 <= 旧的难度 × 4一旦矿工找到有效的哈希值,就会将新区块广播到网络中。
节点验证新区块及交易
收到新区块的节点会进行全面验证,其中包括对每笔交易的锁定脚本与解锁脚本的执行:
- 验证工作量证明: 确保区块头的哈希值满足难度目标。
- 验证交易的合法性: 对区块中的每笔交易,节点会运行锁定脚本与解锁脚本,确保交易符合以下规则:
- 输入中的解锁脚本(ScriptSig)必须提供解锁 UTXO 所需的条件。
- 锁定脚本(ScriptPubKey)和解锁脚本的组合执行后,必须在脚本堆栈中留下一个
True值。
- 验证默克尔根:节点通过区块中的所有交易重新计算默克尔根,并检查它是否与区块头中记录的默克尔根一致。
一旦节点验证通过,就会将这个区块作为上一个区块,并沿着他计算下一个区块的哈希值。Alice 的交易就进入了区块,Bob 得到了 Alice 发送给他的值为 1 BTC 的 UTXO,每生成一个新的后续区块,交易的确认数会增加,交易被篡改的可能性逐渐降低。
比特币的安全性
前面我们通过从密码学到加密货币发展了解了比特币的创新,又从 Alice 向 Bob 转账这一过程了解了比特币交易是如何进入区块的。但是对于资金来说,安全是第一原则,那么比特币是如何保护网络内的资金安全的呢。
密码学基础
比特币发展在密码学之上,如果没有非对称加密和数字签名技术来确保交易身份认证和不可伪造,加密货币就无法保证可用性。比特币中使用数字签名主要是在解锁脚本阶段参与的,但是数字签名需要对相应的内容进行签名,那么比特币解锁脚本中的签名是对什么信息进行签名的呢?
实际上比特币并非对整个交易签名,而是对交易数据的特定部分进行签名,比特币中包含四种签名方式:
SIGHASH_ALL:几乎所有钱包的默认签名方式,它签名的对象包含所有的输入和输出,所以交易的数据有一丝一毫的改变,都会使签名无效。它本质上就是说:“我只同意以这些输入和这些输出的组合转移我的比特币”。
SIGHASH_NONE: 该方式下,签名的对象仅包括所有的输入,但不包含任何输出。所以,它的授权含义是:“我同意(使用这些资金)参与这样一笔交易,结果怎么样我不是特别在乎”。
SIGHASH_SINGLE: 这种签名的对象包含所有的输入,以及一个相应的输出。所以,它的授权含义是:“我同意使用所有这些输入参与这笔交易,只要这么多钱是打到这个地址的”。
SIGHASH_ANYONECANPAY: 表示任何人都可以花,但是需要和上面的三种使用按位运算符结合起来使用。SIGHASH_ALL | SIGHASH_ANYONECANPAY:类似于SIGHASH_ALL,也是签名所有的输出。不过,它只签名其中的一个输入。相当于是说:“我同意参与这笔交易,只要这些受益人能收到这些款项。至于谁愿意给这笔交易提供赞助(额外的输入),我没所谓”。SIGHASH_NONE | SIGHASH_ANYONECANPAY(0x82)—— 类似于SIGHASH_NONE,但只为一个输入(这个签名所在的输入)提供许可。它本质上是说:“我愿意发送这笔比特币,不问缘由。实际上我甚至不在乎这笔钱是不是通过这笔交易来发送。这里是一个签名,表示任何包含了这个签名的交易都可以花费这笔资金”。SIGHASH_SINGLE | SIGHASH_ANYONECANPAY(0x83)—— 类似于SIGHASH_SINGLE,签名只针对会包含这个签名的输入,以及对应的输出。意思是:“我就是想移动这么多比特币到这个输出中,我不介意有没有人愿意跟我参与同一笔交易,也不介意交易有没有别的输出”。
比特币在检查签名有效性时,不止会验证签名是否为公钥对应的私钥生成,还会验证签名所覆盖的内容是否被篡改,保证了交易内容的正确性。
而签名通过私钥生成,私钥的安全就显得至关重要了。比特币使用的 secp256k1 椭圆曲线的安全性核心在于 离散对数问题在椭圆曲线上极难求解,即使公钥公开的,也只能通过暴力破解的方式来推导私钥,但需要2^128次操作,远超现有的算力。只要保证私钥足够随机,比特币就能保证资产的安全。
脚本语言设计
比特币脚本语言包含许多操作,但都故意限定为一种重要的方式——没有循环或者复杂流控制功能以外的其他条件的流控制。这样就保证了脚本语言的图灵非完备性,这意味着脚本的复杂性有限,交易可执行的次数也可预见。脚本并不是一种通用语言,施加的这些限制确保该语言不被用于创造无限循环或其它类型的逻辑炸弹,这样的炸弹可以植入在一笔交易中,通过引起拒绝服务的方式攻击比特币网络。受限制的语言能防止交易激活机制被人当作薄弱环节而加以利用。
另外比特币的脚本语言也严格验证输入,依赖于上面提到的数字签名技术,节点在对交易进行验证时,会验证签名与公钥哈希和其覆盖数据的匹配性。
另外脚本语言或者说比特币的 UTXO 解锁设计,都符合 Len 强调的 解析是防止恶意输入的最后防线 。整个脚本的执行过程都可以说是在验证用户的输入的合法性(用户签名的合法性和其覆盖数据未被篡改,脚本最终执行结果必须为真)。
另外也符合 Len 所强调的要限制语法的复杂性,避免协议需要上下文相关或更高级语法,限制图灵完备的输入内容。
另外比特币的分布式设计,交易的验证结果作为全网共识,避免了不同节点对同一脚本的解析结果不同这一问题,解决了协议实现上的方言问题可能导致的漏洞。
50% 算力攻击
比特币基于工作量证明共识机制,矿工通过算力竞争来验证交易和生产区块,如果某一实体掌握了全网超过50%的算力,理论上可以对比特币网络进行如下攻击:
- 双花:将同一笔比特币重复花费,例如在交易所充值后撤销交易。
- 阻止交易确认:选择性屏蔽某些交易,使其无法被打包到区块中。
- 重组区块链:通过生成更长的私有链覆盖主链,逆转已确认的交易。
但是因为比特币非对成加密和脚本保护,这种攻击无法直接窃取他人的比特币。
分布式和激励影响
比特币通过设计一套巧妙的激励机制和协议规则,确保了网络中所有节点(包括矿工和验证节点)有动力正确执行比特币协议,从而实现了 Alice 和 Bob 之间交易意图的准确传递。这种设计不仅解决了去中心化环境中的信任问题,还保证了系统的稳定性和安全性。
在比特币网络中,矿工通过参与工作量证明竞争来争取生成新区块的权利。为了获得区块奖励和交易手续费,矿工有动力确保生成的区块被网络中的其他节点接受。
矿工的经济动机:如果矿工生成的区块不符合比特币协议规定的交易验证规则(例如接受了无效的交易),其他节点会拒绝该区块。一旦区块被拒绝,矿工将无法获得奖励,且浪费了大量的计算资源。
正是这样的激励机制将矿工的计算成本和安全直接挂钩,参与到网络中的节点为了获得利益,必须保持和绝大多数节点相同的验证规则,在比特币白皮书的绝大多数诚实节点的前提下,参与进来的节点也只能保持诚实,从而促进了整体的安全性和容错度。
