前言
后面毕设可能和区块链相关,这里学习一下,目前计划是先学习区块链概念,这里学习北京大学肖臻老师《区块链技术与应用》公开课
BTC-密码学原理
BTC 中加密主要是利用哈希和签名
哈希
在视频中提到哈希碰撞,也就是我有两个数 x 和 y,我利用哈希函数对两个分别加密,得到 H(x)和 H(y),因为哈希函数的特性,很难有H(x)==H(y)的情况出现。
注:难并不是不可能,学密码的都知道
那么用来干什么呢?这里举一个不太恰当的例子,a->b 发送信息,这个肯定是签名加密的,但里面数据快速校验是否被篡改,就是使用哈希加密。
并且哈希是不可逆的,这也就更加确保了加密的可靠性了。我把一个东西加密后,可以直接放出,不用担心被强行逆向。
同时要求H(block header) <= target ,这里的block header就是区块链的链头,我们要去找其中一个域里面nonce这个值,去满足这个大小要求,所以算力要求高。
数字签名
首先你知道的,需要有一对公私钥,合理吧。
一般情况下的,在数字签名中,我们使用私钥签名,公钥验证。
私钥签名的目的是验证发送者是本人,公钥验证是确定签名真实性和消息完整性。
区块链中常用的应该是 ECDSA
BTC-数据结构
hash 指针
这里主要用的是 hash 指针,存储地址+hash 值,方便查找位置和是否被篡改
因为结构的特殊性,前面的块会影响后面块的 hash 值,那么我们只需要关注最后块的 hash,就可以校验了。 同时如果我如果只存了后面几块,我找别人要前面的,直接对比 hash 值就行了
Merkle 树(哈希树)
这里是有 pdf 的,链接
Merkle 树一定是满的
树根那里就是root hash,下面修改任意一个子节点,root hash的值就会变。
最下面的块,其实是交易。
一个 block 分为两块
block header-> 存储 hash 值block body-> 交易相关内容
BTC 中节点分为全节点(保存整个区块内容)和轻节点(只存储 hash 值),那我只有轻节点的时候,如何查看交易内容呢?
可以查到交易的块,然后往上一直查到根,这个路径叫作Merkle proof。向上的过程其实是计算母节点 hash 值的过程,然后依次比较,直到 root 节点。
正常流程应该是:
- 交易广播与区块创建
- 发送交易: 交易发送者 将其交易 () 广播到比特币网络。
- 全节点打包: 网络中的 全节点 (Full Node) 接收 并将其打包进一个新的区块 中。
- 区块头接收
- 广播区块头: 全节点计算并向全网广播区块 的 区块头 (Block Header)。
- 轻节点保存: 轻节点 (SPV Client) 收到并保存该区块头,因为其中包含了关键的 Merkle Root (默克尔根)。
- 请求 Merkle Proof
- 发出请求: 轻节点 想要验证自己的交易 是否真的被包含在 中,它会向一个信任的/连接的 全节点 发出请求。
- 全节点提供证据
- 发送证明: 全节点 将以下两项信息发送给轻节点 :
- 交易本身 (): 需要验证的交易数据。
- Merkle Proof (兄弟哈希值路径): 计算 所需的兄弟节点的哈希值集合。
-
轻节点进行验证
轻节点 收到 和 后,开始执行本地校验:
-
计算交易哈希: 用 的数据计算出其哈希值:。
-
向上计算 Root Hash: 利用 和 中的兄弟哈希值,逐级向上计算 父节点的哈希值,直到最终得到一个 计算出的 Root Hash。
-
比对校验: 将 计算出的 Root Hash 与它在 区块头 中已保存的 Merkle Root 进行严格比对。
-
验证结果
- 如果两者相等 ,则 证明成功,交易 确实被包含在这个区块中,交易是有效的。
-
BTC-协议
BTC 协议主要对两个问题开展,谁有权发行货币,怎么验证交易的合法性,下面先从合法性开始
双花攻击
攻击者试图使用同一笔数字货币进行两次或多次支付的行为,在现实生活中是不可能出现的,你把一百块给别人了,你就没了,但是在数字世界中,可以无限复制的,因此需要一种机制来确保数字货币的稀缺性和唯一性。
BTC 网络就因此而生了。
核心原理与防御
- 每笔交易都广播到网络,记录到公开不可篡改的账本上
- 只有当交易被矿工打包进一个新的区块并添加到主链上时,这笔交易才被认为是确认的。
- 矿工通过解决复杂的数学难题(工作量证明)来竞争新区块的打包权。这使得创建新的、有效的区块成本高昂,从而保证了链的安全性。
逻辑: 一旦交易被打包进区块并在主链上获得了足够的确认(通常是 6 个确认),它就被认为是最终且不可逆转的。攻击者如果想要“双花”,就必须在交易被确认后,利用比主链更长的、包含另一笔花费的私有链来替代主链,这在算力上是极其困难的。
常见的双花攻击
- 51%attack
- 竞赛攻击
- Finney attack
- 扣块攻击
协议相关
主要分为交易层、数据层、网络层、共识层。
- 交易层
- 作用:定义了价值转移的基本单位和规则
- 核心机制:UTXO 模型。
- 数据层
- 作用:永久、不可篡改地记录所有经过验证的交易。
- 核心机制:区块(见数据结构)
- 网络层
- 作用:管理节点之间的通信和数据同步
- 核心机制:P2P
- 共识层
- 作用:确保所有节点对区块链的有效性达成一致,并防止恶意行为
- 核心机制:最长链原则,工作量证明(POW)
关于发表货币
结论:没有中心机构,发行权归属于比特币的底层算法协议。
主要机制是区块链的奖励与减半机制。
- 发行者:比特币的软件代码本身就是唯一的发行者。它预设了一套**通货紧缩(Deflationary)**的发行机制。
- 铸币行为: 新的比特币是通过挖矿(Mining)过程产生的。当一个矿工成功计算出满足难度要求的 工作量证明(PoW)并打包出一个新的有效区块时,协议会向该矿工发放一笔固定数量的比特币作为区块奖励。这笔奖励是新产生的,而非来自其他地址。
- 减半机制(Halving): 区块奖励的数额大约每 210,000 个区块(约 4 年)就会减半一次。
- 最初 50BTC/block
- 减半到 25BTC/block
- 以此类推…
交易的合法性
主要由验证节点执行,并在矿工打包区块时再次执行。
验证过程主要围绕以下四个核心要素展开:
- 结构与语法验证
- 资金来源验证(UTXO 模型)
- 所有权验证(数字签名)
- 价值和费用验证
- 最终合法化:区块确认
- 即使交易通过了上述所有验证,它仍处于“未确认”状态。只有当该交易被矿工打包进一个有效的区块,并且这个区块被网络接受,成为最长链的一部分后,这笔交易才获得了 1 个确认,被认为是最终的、不可逆的。随着后续区块的增加,确认数越多,交易的合法性和不可逆性就越高。
那么就不得不提如何在一个去中心化的无信任环境中建立权威和共识。
简单来说,工作量证明(PoW)机制通过将“权利”与“计算资源消耗”绑定,成功地将共识的基础从“身份数量”转移到了“经济成本”,从而防范了女巫攻击。
女巫攻击:网络中的单个攻击者创建和控制多个虚假身份或节点,以在网络中获得不成比例的影响力。在传统的 P2P 中,我们可以创建 100w 个身份账户,投票来占大头。
这明显是不合理的,在 BTC 中,我们把身份转换成了比较算力,也就是前面提到的nonce,所以你不管多少账户,算力不变,你爆破的速度不变,自然没用了。
BTC-实现
UTXO
所有的没有被花掉的集合,就是 UTXO,其实也就是你的余额,并不是在一个你自己的账户里面的,而是分散在网络中一系列未花费的交易输出上,如果不在,那就是假的。
在交易中,a->b 转账,之后 b->c 转账,如果 b 把 a 给的全转给 c 了,那么UTXO中就会删除掉 a->b 的记录,只添加 b->c 的。
每个交易可以有多个输入,也可以有多个输出,但输入之和要等于输出之和(total inputs = total outputs)。 存在一些交易的 total inputs 略大于 total outputs,这部分差额便作为交易费,给了获得记账权的节点,你知道的,白打工是不好的。
比特币系统安全性分析
BTC 本质上是一个概率性问题,比如挖到一个 BTC 的平均时间是 10min,如果没有人能在 10min 挖到,那么就继续 10min,不管算力大小,都会白干,那么算力低的用户,也有可能挖到。
- 可否”偷币”? 不能。因为转账交易需要签名,恶意节点无法伪造他人签名。加入其获得记账权并硬往区块中写入该交易,大多数用户会认为其是一个非法区块,大多数算力将不认可该区块,从而沿着其他路径挖矿,随着时间推移,拥有大多数算力的诚实的节点将会仍然沿着原来区块挖矿,从而形成一条“最长合法链”,该区块变成孤儿区块。对于攻击者来说,不仅不能偷到其他人的比特币,而且得不到出块奖励,还浪费了挖矿花费的电费等成本。
- 可否将已经花过的币再花一遍? 如果 a->b 了,现在 a->a 想这样干,如果在一个链上很明显是错误的,那他只能分支,分支采用那个那就取决于分支上面块的最大数了。一般都要等 6 个确认区块,所以一般善意节点会获胜
- 可否故意不包含合法交易? 可以,但是可以等待后续区块包含,所以问题不大。实际运行中,可能由于某段时间实际交易数太多,而一个区块包含交易数存在最大值,导致某些合法交易并未被写入区块链(等待后续区块写入)。
- selfish mining 提前挖到但不发布,继续挖下去,等到想要攻击的交易等了 6 次确认认为安全之后将整条链发布出去,试图回滚原来记录。这种情况,需要恶意节点掌握系统中半数以上算力才行,否则无法成为最长合法链。就像你挖到了 A,但是你不发表,你想继续往下挖,挖到 B 再发表,但是别人挖到了另一个分支的 C,你还没有挖到 B,那就需要快速发表去竞争了,这也是有风险的
BTC-网路
其实上面提到了,核心机制是P2P
比特币系统中所有节点完全平等,不像一些其他网络存在超级节点(super node)。要加入网络,至少需要知道一个种子节点,通过种子节点告知自己它所知道的节点。节点之间的通信采用了 TCP 协议,便于穿透防火墙。当节点离开时,只需要自行退出即可,其他节点在一定时间后仍然没有收到该节点消息,便会将其删掉。
设计原则
简单、鲁棒(最坏情况下能达到最优状况,即健壮性)而非高效。
每个节点维护一个邻居节点集合,消息传播在网络中采用洪泛法,某个节点在收到一条消息会将其发送给所有邻居节点并标记,下次再收到便不会再发送该消息。邻居节点选取随机,未考虑网络底层拓扑结构,也与现实世界物理地址无关。该网络具有极强鲁棒性,但牺牲了网络效率。
比特币系统中,每个节点要维护一个等待上链的交易集合。第一次听到交易,若是合法交易,则将其加入该交易集合并转发给邻居节点,以后再收到该交易就不再转发(避免网络上交易无线传输)。假如网络中存在两个冲突交易,如交易 1:A->B,交易 2:A->C(假设花费的同一笔钱)。具体接收哪个取决于节点先接收到哪个交易,之后收到另一个交易会将其放弃。
此外,比特币网络传播属于 Best effort(尽力而为),不能保证一定传输成功。以一个交易发布到网络上,未必所有节点都能收到,也未必所有节点收到交易顺序都一致。
BTC-挖矿难度
为什么要调整挖矿难度
挖矿就是 H(block header)<=target.(target 便是目标阈值,target 越小,目标难度就越大)对于挖矿难度的调整,可以视为调整目标空间在整个输出空间中所占比例大小。
那挖矿难度是
- 如果不调整挖矿难度会怎么样? 系统总算力越来越强,若挖矿难度保持不变,则出块时间会越来越短。
- 出块时间越来越短是好事吗? 出块时间缩短,那么交易可以很快便被写入区块链,并且提高了系统响应时间,增加了区块链系统效率。但是,出块时间并不是越短越好。出块时间太短,也会造成一定的问题。首先,区块在网络上传播具有时延,假如出块时间为 1 秒,但网络传播需要 10 秒,则会使得系统中节点经常性处于不一致的状态,增加了系统不稳定性,且系统经常性位于分叉状态(不仅二分叉,乃至多分叉)。分叉过多,则不利于系统达成共识,且会造成算力分散,使得黑客攻击成本大大降低(不再需要整个系统 51%的算力)。
- 10min 的出块间隔是最优吗? 当然不是,但可以确定的是,系统出块时间需要维持在一个定值附近。后续文章中会介绍以太坊,以太坊中平均出块时间仅为 15 秒左右,但同样在以太坊中也有相应难度调整算法维持其平均出块时间(后续会写文介绍),当然 15s 的时间明显会产生经常性的分叉,所以以太坊设计了新的共识协议 Ghost(后续文章中会介绍)。 当然,对于一个交易系统来说,10min 这样一个交易时间是比较长的。但对于跨国交易来说,这个时间反而大大缩短了交易时间,减少了相应成本。
BTC 系统如何调整挖矿难度
在 BTC 协议中规定,每隔 2016 个区块需要调整一次难度,根据 10min 产生一个新区块可以得到,大概需要 14 天的时间。具体调整公式如下:
如何让所有矿工都愿意调整这个挖矿难度呢? 这一调整算法在代码中已经写入,如果有恶意节点故意不调,其所产生的区块不会被大多数诚实的节点承认。 在 block header 中有一个 nbits 的域,它是对 target 的编码存储(target 为 256 位,nbits 为 32 位,也就是说 block header 并未直接存储 target),其他节点在进行合法性验证时候会验证 nbits 域是否合法,不合法则对该区块不予以承认。
BTC-挖矿
更像是总结课
全节点&&轻节点
| 特性 | 全节点(Full Node) | 轻节点(Light Node) |
|---|---|---|
| 在线状态 | 一直在线 | 不是一直在线(按需连接) |
| 区块链数据 | 在本地硬盘上维护完整区块链信息(包括所有交易) | 不保存整个区块链,只需要保存每个区块的块头(Block Header) |
| UTXO/交易数据 | 在内存中维护 UTXO 集合,以便于快速检验交易合法性 | 不保存全部交易,只保存和自己有关的交易 |
| 交易验证能力 | 监听比特币网络中交易内容,验证每个交易合法性 | 无法验证大多数交易合法性,只能检验和自己相关的交易合法性 |
| 出块决定权 | 决定哪些交易会打包到区块中 | 无法决定哪些交易会打包到区块中 |
| 区块验证能力 | 监听其他矿工挖出的区块,验证其合法性 | 无法检测网上发布的区块正确性 |
| 难度验证 | 可以验证挖矿难度 | 无法验证挖矿难度 |
| 链的选择 | 1. 决定沿着哪条链挖下去。2. 当出现等长分叉,选择哪一个分叉。 | 只能检测哪个是最长链(根据块头),不知道哪个是最长/合法链 |
挖矿演化
- 设备方面
普通 CPU -> GPU ->ASIC 芯片(挖矿专用矿机)
普通 CPU 的劣势是大多数部件都是闲置的,GPU 也与之类似,会有浪费。ASIC 芯片只能用于挖矿,一旦其过时,便完全作废。
- 矿池
你知道的,一个人挖矿很慢,就算是 ASIC 启动,算力依旧只能占一小部分,转账收入很不稳定,单个矿工除挖矿还要承担全节点其他责任,造成了算力的消耗。
因此,为了解决这些问题,便引入了矿池的概念。
可以认为有一个矿主,下面有一堆矿工,矿工只需要不停计算哈希值,而全节点其他职责由矿主来承担。ASIC 芯片只能计算哈希值,不能实现全节点其他功能。此外,矿池出现解决了单个矿工收益不稳定的问题。当获得收益后,所有矿工对收益进行分配,从而保证了收益的稳定性。
矿池一般具有两种组织形式。1.类似大型数据中心(同一机构),集中成千上万矿机进行哈希计算。2.分布式。矿工与矿主不认识(不同机构),矿工与矿主联系,自愿加入其矿池,矿主分配任务,矿工进行计算,获得收益后整个矿池中所有矿工进行利益分配。
- 矿池利益分配方法
如果像第二种情况,矿工和矿主不熟,利益分配绝对是问题.
分配一般两个方式:平均分配和降低挖矿难度(主要方案)
为什么后者是主要的方案呢? 假设原本挖矿难度要求,计算所得 126 位的哈希值前 70 位都必须为 0,现在降低要求,只需要前 60 位为 0,这样挖矿会更容易挖到。当然,这个哈希是不会被区块链所承认的,我们将其称为一个 share,或 almost valid share。矿工每挖到一个 share,将其提交给矿主,矿主对其进行记录,作为矿工工作量的证明。等到某个矿工真正挖到符合要求的的区块后,根据所有矿工提交的 share 数量进行分配。 因为每个矿工尝试的 nonce 越多,挖到矿的可能性越大,所能得到的 share 也会越多,所以这种方案作为工作量证明方案是可行的。
思考一:有没有可能,某个矿工平时正常提交 share,但真正挖到区块后不提交给矿主而是自己偷偷发布出去,从而避免他人分走挖矿所得到的出块奖励? 事实上,这种情况是不可能的。因为每个矿工挖矿任务是矿主分配的。矿主组装区块,交给矿工计算,而区块中铸币交易的收款人地址是矿主,如果矿工修改该地址,计算的 nonce 值也会作废。 思考二:如果矿工自己刚开始就自己偷偷组装一个区块,自己挖矿,这样就类似于其脱离了该矿池。因为其自己所组织的区块不会被矿主所认可,其提交的 share 也不会被认可,也就得不到分配的收益。 思考三:有没有可能矿工捣乱?平时提交 share,等挖到后扔掉区块,不提交? 这种可能是有的,如果矿工本身仅仅想捣乱,是可以这么做的。但扔掉区块后,对其本身来说,也没有相应的奖励获得,看似是损人不利己的情况。 但是,矿池之间存在竞争关系。有可能为了打击竞争对手,会派出矿机加入竞争对手矿池挖矿,从而起到搞破坏的作用。即只参与其他矿工挖矿分红,自己挖到的区块却丢掉不给他人分。
- 矿池出现的优劣
优点:解决了矿工收入不稳定的问题,减轻了矿工的负担。 缺点:威胁到了区块链系统的安全,使得 51%攻击变得容易起来(s)。
51%算力矿池攻击
51%攻击只是一个概率问题,并非达到 51%算力就能发动攻击,不能达到就无法发动攻击。此外,矿池本身算力也是在不断变化的。
- 分叉攻击 对已经经过 6 次确认的交易分叉,利用 51%算力将交易记录回滚。
- 封锁交易 假如攻击者不喜欢某个账户 A,不想让 A 的交易上区块链,在监听到有其他人将 A 的交易发布到区块链上时,立刻发动分叉攻击,使 A 所在链无法成为”最长合法链“。这样,便实现了对 A 账户的封锁。
- 盗币 这个是不可能的,因为其并没有他人账户私钥。如果依仗算力强,强行将没有签名的转账发布到区块链,正常节点不会认为其合法,这样,即使这条链再长,其他人也不会认为其是最长合法链。
BTC-比特币脚本
比特币系统中使用的脚本语言非常简单,唯一可以访问的内存空间只有栈,所以也被称为基于栈的语言
脚本结构
{ "txid": "[String] 交易的唯一哈希标识符(字节序翻转后的交易哈希)", "hash": "[String] 交易的哈希值(通常与 txid 相同,但字节序可能不同)", "version": "[Number] 交易的版本号,用于支持不同的交易类型或规则", "size": "[Number] 交易数据的原始字节大小", "vsize": "[Number] 交易的虚拟大小(用于隔离见证交易的费用计算)", "weight": "[Number] 交易权重(用于隔离见证交易的区块容量限制计算)", "locktime": "[Number] 交易的锁定时间或区块高度。0 表示立即生效",
"vin": [ { "txid": "[String] 被花费的 UTXO 所在的前一笔交易的哈希值", "vout": "[Number] 被花费的 UTXO 在前一笔交易输出列表中的索引位置", "scriptSig": { "asm": "[String] 解锁脚本(ScriptSig)的可读汇编表示,包含签名和公钥", "hex": "[String] 解锁脚本(ScriptSig)的原始十六进制字节码" }, "sequence": "[Number] 序列号,用于高级功能(如 RBF 或相对时间锁定)" } // ... 可能有多个输入 ],
"vout": [ { "value": "[Number] 该输出的金额,以 BTC 为单位", "n": "[Number] 该输出在当前交易输出列表中的索引位置(从 0 开始)", "scriptPubKey": { "asm": "[String] 锁定脚本(ScriptPubKey)的可读汇编表示,定义了花费条件", "hex": "[String] 锁定脚本(ScriptPubKey)的原始十六进制字节码", "reqSigs": "[Number] 锁定此 UTXO 所需的数字签名数量", "type": "[String] 锁定脚本的类型(例如:pubkeyhash, scripthash)", "addresses": ["[String] 锁定脚本解析出的人类可读的比特币地址"] } } // ... 可能有多个输出 ],
"blockhash": "[String] 交易所在区块的哈希值", "confirmations": "[Number] 交易已被确认的次数(即交易所在区块之后的区块数量)", "time": "[Number] 交易被节点接收的 Unix 时间戳", "blocktime": "[Number] 交易所在区块的 Unix 时间戳"}输入输出脚本的执行方法也很有意思。
A->B 转钱,会有一对输入输出脚本产生,这个时候 B->C 转钱,就会有另一对输入输出脚本产生,但是!如果 B->C 的资金来自 A,那就会有第二对的输入脚本(input script)拼接到第一对的输出脚本(output script)前,然后执行,来考虑到安全性问题,两个脚本改为分别执行:先执行 input script,若无出错,再执行 output script。
如果脚本可以顺利执行,最终栈顶结果为 true,则验证通过,交易合法;如果执行过程中出现任何错误,则交易非法。 如果一个交易有多个输入脚本,则每个输入脚本都要和对应的输出脚本匹配执行,全部验证通过才能说明该交易合法。
输入输出脚本的几种形式
| 形式 | P2PK (Pay to Public Key) | P2PKH (Pay to Public Key Hash) | P2SH (Pay to Script Hash) |
|---|---|---|---|
| 特点 | 输出脚本直接给出收款人公钥。 | 输出脚本给出收款人公钥的哈希。 | 输出脚本给出赎回脚本 (redeemScript) 的哈希。 |
| 安全性 | 较低/已弃用。 公钥永久暴露在链上。 | 常用且安全平衡。 未花费时隐藏公钥。 | 高效灵活。 复杂逻辑(如多签)的地址更短,节省发送方费用。 |
| 输出脚本 (ScriptPubKey) | [公钥] OP_CHECKSIG | OP_DUP OP_HASH160 [公钥哈希] OP_EQUALVERIFY OP_CHECKSIG | OP_HASH160 [赎回脚本哈希] OP_EQUAL |
| 输入脚本 (ScriptSig) | [签名] | [签名] [公钥] | [签名] [公钥] [赎回脚本] |
| 工作流程 | 使用脚本中的公钥和堆栈中的签名进行检查。 | 1. 对堆栈中的公钥哈希并与脚本中的公钥哈希比对。2. 验证签名。 | 1. 对堆栈中的赎回脚本哈希并与脚本中的哈希比对。2. 如果哈希匹配,执行赎回脚本。 |
补充形式:隔离见证 (SegWit) 脚本
隔离见证将签名等数据从交易主体中移出,放到一个独立的“见证(Witness)”字段,以降低交易费用和提高效率。
-
P2WPKH (Pay-to-Witness Public Key Hash)
- 特点: 隔离见证的 P2PKH 版本。
- 脚本:
ScriptPubKey更简单,签名数据在Witness字段。 - 优势: 交易的虚拟大小 (
vsize) 变小,费用更低。
-
P2WSH (Pay-to-Witness Script Hash)
- 特点: 隔离见证的 P2SH 版本。
- 脚本: 赎回脚本和签名数据都在
Witness字段。 - 优势: 对复杂的脚本结构(如多重签名)提供最大的费用优化。
多重签名
多重签名要求 个公钥中的至少 个提供有效签名才能花费资金。它主要通过 P2SH (Pay-to-Script-Hash) 实现。
- 锁定阶段:地址与输出脚本 (ScriptPubKey)
资金被锁定在一个 P2SH 地址(以 3 开头),其输出脚本只包含多签逻辑的哈希。
| 字段 | 脚本内容 | 作用 |
|---|---|---|
| 输出脚本 (ScriptPubKey) | OP_HASH160 [redeemScript 的哈希] OP_EQUAL | 锁定资金,要求花费者提供一个匹配该哈希的赎回脚本。 |
- 核心逻辑:赎回脚本 (redeemScript) 的构造
赎回脚本定义了 -of- 的多签规则。
| 字段 | 脚本内容 | 描述 |
|---|---|---|
| 赎回脚本 (redeemScript) | [M] [公钥1] [公钥2] ... [公钥N] [N] OP_CHECKMULTISIG | 定义了需要 M 个签名,并列出了所有 N 个参与的公钥。OP_CHECKMULTISIG 是执行多签检查的操作码。 |
示例: 2-of-3 多签的赎回脚本:
OP_2 [公钥1] [公钥2] [公钥3] OP_3 OP_CHECKMULTISIG
- 花费阶段:输入脚本 (ScriptSig)
花费资金时,必须在输入脚本中提供足够的签名和完整的赎回脚本。
| 字段 | 脚本内容 | 描述 |
|---|---|---|
| 输入脚本 (ScriptSig) | OP_0 [签名1] [签名2] ... [签名M] [redeemScript] | 提供了 个有效的数字签名和完整的赎回脚本内容。OP_0 是用于修复 OP_CHECKMULTISIG 错误的哑元(Dummy Element)。 |
- 脚本执行流程(验证过程)
| 阶段 | 脚本操作 | 验证目的 |
|---|---|---|
| 阶段 1 | 执行 OP_HASH160 [redeemScript] OP_EQUAL | 验证输入的赎回脚本内容与目标地址(输出脚本)的哈希是否匹配。 |
| 阶段 2 | 执行赎回脚本中的 [M] ... [N] OP_CHECKMULTISIG | 验证堆栈中提供的 个签名是否与赎回脚本中提供的 个公钥中的至少 个匹配。 |
补充:隔离见证 (SegWit) P2WSH
在现代交易中,多签通常使用 P2WSH (Pay-to-Witness Script Hash) 实现,以获得更低的费用。
- P2WSH: 签名、
OP_0和redeemScript都被移出ScriptSig,放在一个独立的 Witness 字段中。
BTC-分叉
分叉指的是,原来的系统中为一条链,但分成了两条链。分叉形成的原因可能有多种,例如:挖矿时两个节点差不多同时挖出矿,都会发布区块(对比特币系统当前状态产生分歧导致的分叉——state fork);分叉攻击,同样也会导致分叉(forking attack,人为故意造成);比特币协议改变,在分布式系统中不能保证所有节点同时升级软件,假设存在少数节点未升级,导致出现分叉(protocal fork);
根据对比特币协议修改的不同,可以将分叉分为硬分叉和软分叉。
硬分叉
对比特币协议增加新协议,扩展新功能,未升级软件的旧节点会不认可这些修改,会认为这些特性是非法的。这也就是对比特币协议内容产生分歧,从而导致分叉。硬分叉的一个典型例子,就是对比特币区块大小的修改(之前有提到过,BTC 区块大小限制 1MB,但是否合适存在争议)。
举一个简单的例子,有些人认为一个 block 最大 1MB 太小了,给他调大了,那假设挖到了一个 block,设定为 4MB,但是前面的 block 不认可,那他就是非法区块,并且会分叉继续挖 1Mb 的”正统”,这就会造成分裂,只要前面的不更新到 4MB,下面这个”正统”就不会消失
实际上,这个事情真正出现过。后续会介绍以太坊,以太坊历史上的一件大事就是硬分叉事件。以太坊称为 ETH,但目前看到的 ETH 已经不是最初的 ETH 了,以太坊在历史上发生过硬分叉,另一个链称为 ETC(和过高速公路那个 ETC 可半毛钱关系都没有呀)。实际上,ETC 才是以太坊设计原本的协议,而 ETH 是黑客攻击 ETH 上一个智能合约 THE DAO 后进行回滚的协议链(将黑客攻击偷取的以太币采用硬分叉方式回滚回到另一智能合约,然后退还给真正拥有者)。 但是这次硬分叉的后果,由于有人不愿意这么做,造成了以太坊社区的分裂。实际上,虽然 ETC 不如 ETH 又名,但实际它也是目前一种主流货币。 分叉之初,由于两个链分叉造成了互相影响,产生了很多麻烦。比如:在 ETH 链上有一笔转账 B->C,有人便在 ETC 链上回放,将 ETC 链上的货币页转给了 C(C 收到两笔钱)。后来,对两条链各添加了一个 chainID,将两个链区分开,才使得这两条链真正分开。
软分叉
如果对 BTC 协议添加限制,使得原本合法交易在新交易中不合法,便会形成软分叉。
同样,有人想将区块大小调大,也就会有人思考调小的好处。在这里,我们假设将区块大小从 1MB 减小至 0.5MB(实际中,1MB 已经足够小,不会调小了)。你从 1MB 后挖到一个 0.5MB 的,那你继续挖,但是新节点会认为该旧节点挖出区块超过 0.5MB 限制,为一个非法区块,不会认可该区块,会从其前一个小区块开始挖矿,那就是 0.5MB 的 block 分叉成了 1MB 的 block 和 0.5MB 的 block,然后以此类推。需要注意的是,旧节点如果不升级软件,挖出的区块可能就白挖了(大于 0.5MB),但对于系统来说,不会存在永久性分叉。
BTC-匿名性分析
BTC 系统中什么情况会破坏其匿名性?
一般来说,匿名性多与隐私保护相关。但实际上,比特币中的匿名并非真正的匿名,而是假的匿名。实际上,比特币与纸币相比,纸币的匿名性更好,因为其并没有对个人信息的标记。也正是因为其匿名性,很多非法交易采用现金交易(银行风控系统了解一下?)。但现金存在保管、运输等各个方面的不便,又因为数据完全公开,而网上的交易是要与实体世界进行交易的,所以大大破坏了其匿名性。假如银行允许用假名(以前的存折时代),由于银行数据并非公开,所以银行系统的匿名性是要比比特币更好的。
-
用户可以生成多个地址账户,但这些地址账户可以被关联起来 表面上看,每次交易可以更换公私钥对,从而每次都是新的账户,具有很强的匿名性。但实际上,这些账户在一定情况下,是可以被关联起来的。
-
地址账户与个人在真实社会中的身份也可能会产生关联。 任何使得 BTC 和实体世界中关联的操作都有可能泄露用户真实身份,其中最明显的就是资金的转入转出。要得到 BTC,如果用钱买,就会与实体世界进行交互。想要将 BTC 转为现实中的货币,也同样需要与实体世界交互。
-
BTC 支付时候 例如某些商家接受用 BTC 进行支付,例如可以用 BTC 购买咖啡、蛋糕等。(这种场景信用卡已经解决的很好了,用 BTC 交易延迟高,交易费贵,并非一个好的 idea) 在进行支付时候,便和个人账户建立了联系,从而会泄露掉个人信息。
也就是说,BTC 并不是具有很好的匿名信。实际中,很多人保持有较好的匿名性。保持最好的便是其开发者中本聪,其参与 BTC 时间最长,全世界都想知道他是谁。但实际上,中本聪的比特币并非有花出去,这也使得我们难以发现他具体是谁。
那么如何提高匿名性?
- 从应用层看,可以将各个不同用户的 BTC 混合在一起,使得追查变得混乱(Coin mixing);从网络层看,可以采用多路径转发的方法,数据不直接发送出去,而是经过很多跳(洋葱路由的基本思想)。
零知识证明
零知识证明:一方(证明者)向另一方(验证者)证明某一个陈述是正确的,但不需要透露除该陈述是正确的之外的任何信息。 例如:A 想要向 B 证明某一账户属于 A,这说明 A 知道该账户的私钥。但不可能通过 A 公布私钥的方法来证明,该账户确实属于 A。因此,A 可以产生一个账户签名,B 通过公钥对签名进行验证。(实际上该证明是否属于零知识证明存在争议,因为泄露了用私钥产生的签名)
同态隐藏
主要是三个特性
- xy 如果不同,那么 E(x)E(y)也不相同,反之也成立(md5 升级版的感觉)
- 给了 E(x)的值。很难推出 x 的值。
- 给定 E(x)E(y)的值,我们可以很简单的算出关于 xy 的加密值,比如 E(x+y),E(xy),拓展到多项式
缺点:如果我知道了 E(x+y)和 E(xy),那是不是就是二元爆破了?
盲签
签名是一种特殊的数字签名技术。盲签名因签名的人看不到所签署文件的具体内容而闻名,它有两个显著的特点:一是签名者对消息的内容是不可见的 ;二是签名被公开后,签名者不能追踪签名。
为什么要这么做呢? 例如电子交易中,我们的交易信息依赖于银行等第三方机构。第三方机构需要防范双花攻击等,就需要对电子货币进行签名。而签名的过程中,必然会导致其了解到交易内容。如果想要银行等第三方机构负责相应工作,但不知道交易具体内容,就可以采用盲签的方法。
举个例子:A->B 转钱,A 会提供编号给第三方,第三方会给一个 token,A 把编号和 token 给 B,B 拿这两个东西找第三方验证后增加存款。
既然了解到 BTC 提供了较好匿名性,但其无法完全消除关联性,那么如果想要这样一种货币怎么办?这就涉及了零币和零钞。
零币和零钞
当然可以!我已将上面的讲解内容重新整理为标准的 Markdown 格式,您可以直接复制粘贴到您的笔记中。
🔒 零币 (Zerocoin) 与 零钞 (Zerocash/Zcash) 详解
Zerocoin 和 Zerocash 是密码学货币中增强隐私保护的两大核心技术。
零币是比特币的一个协议扩展提案,旨在通过引入匿名性来增强隐私。
核心机制:铸币与兑换 (Mint and Redeem)
零币通过引入一个特殊的加密资产——零币 (Zerocoin)——来实现匿名性:
-
铸币 (Minting):
- 用户将普通币发送到零币池。
- 生成一个新的零币,并将其序列号的加密承诺 (Commitment) 发布到区块链上的累加器 (Accumulator) 中。
- 效果: 切断了货币的交易历史链条。
-
兑换 (Redeeming):
- 用户销毁零币,并使用非交互式零知识证明 (NIZK) 来证明以下两点:
- 该零币承诺在累加器中(即是有效的)。
- 用户知道零币的唯一序列号,但不泄露它(用于防止双重支付)。
- 效果: 证明只显示货币来自零币池,与原始铸币交易不关联,实现匿名。
- 用户销毁零币,并使用非交互式零知识证明 (NIZK) 来证明以下两点:
密码学要点
- 累加器 (Accumulator): 用于高效证明一个元素是集合的成员。
- 非交互式零知识证明 (NIZK): 用于证明知识(零币秘密信息)但不泄露知识本身。
局限性
- 固定面额: 零币通常需要固定面额(如 1 ZC, 10 ZC),交易不灵活,交易额(面额)公开。
- 交易量大: 证明和累加器更新导致交易数据量较大。
零钞是零币的升级和改进版,解决了零币的局限性,实现了交易金额和交易双方身份的完全匿名。
核心机制:全匿名交易
零钞的核心改进是使用强大的零知识证明系统,允许货币在“匿名池”内直接转账。
密码学要点:zk-SNARKs
零钞使用了 zk-SNARKs(Zero-Knowledge Succinct Non-Interactive Arguments of Knowledge,零知识简洁非交互式知识论证)技术。
zk-SNARKs 允许用户证明以下四点,而无需透露任何交易细节:
- 价值守恒 (Value): 输入值 = 输出值 (无通胀/通缩)。
- 拥有权限 (Authority): 发送方拥有私钥。
- 无双重支付 (Uniqueness): 通过揭示一个空值 (Nullifier) 来标记已花费的币。
- 有效来源 (Source): 该币曾被铸造到匿名池中。
优势 (对比零币)
- 交易金额匿名: zk-SNARKs 可以同时隐藏发送方、接收方和精确交易金额。
- 灵活度高: 无需固定面额,可发送任意金额。
- 验证高效: 证明本身简洁 (Succinct),验证速度极快。
关键挑战:初始设置 (Trusted Setup)
- 初始参数生成: zk-SNARKs 需要一个初始可信设置来生成公共参数。
- 信任风险: 如果生成参数的秘密信息(“毒性废物”)未被彻底销毁,则拥有秘密信息的人可以无限量地伪造货币。Zcash (ZEC) 通过多方计算仪式 (MPC) 来缓解此风险。
Some information may be outdated