区块链(02):哈希之前,先说清究竟签了哪些字节
把订单标识与收款人直接拼接再哈希,看起来已经“承诺”了一笔支付:b"ab" + b"c" == b"a" + b"bc"。左右两组输入完全不同,却产生相同的字节串;再强的哈希也无法替调用者找回字段边界。00 篇的重试指纹和 01 篇的签名意图都依赖这一层编码。
先修:区块链(00):从中心化订单基线开始 的字节自测,以及 区块链(01):两份签名都正确,账本仍会冲突 的签名意图。这里使用 Python 标准库 SHA-256 与自行定义的教学编码;不宣称编码兼容 Bitcoin 或 Ethereum。
把类型、边界与用途放进预映像
有限模型只接受 bytes,每个字段先写 4 字节大端长度,再写字段本身。于是:
1 | |
固定消息的向量:SHA256(b"abc") = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad。这个值在标准库测试中实测;将 Unicode 文本传给编码器会直接报错,调用者必须自己选 UTF-8 或其他字节编码。真实协议还要规定整数符号、字段出现次数、序列化顺序、版本号、链身份及未知字段的处理;本例只证明两种分组在这个编码下不冲突,不声称定义了全球唯一编码。
flowchart LR
M[字段数组与协议版本] --> E[确定性编码: 长度 + 字节]
E --> D[用途标签: leaf / node]
D --> H[SHA-256]
H --> C[摘要: 仅相对这些规则承诺字节]
“域分离”是另一道门槛:同样的业务字段作为叶子、内部节点、登录挑战或订单授权,不能默认可以互换。模型计算 SHA256(encode(tag, payload)),leaf 与 node 是不同标签。审计时不仅要核对摘要,还要问标签、字段顺序和应用上下文是否由双方一致解释。哈希的抗碰撞性是算法性质;“两种输入不混用”则还需要正确编码和调用点不漏传域。
SHA-256 属于 SHA-2 家族,标准 SHA3-256 属于 FIPS 202 规范的 SHA-3;Ethereum 常见的 keccak256 不等于 hashlib.sha3_256,两者不能凭“256 位”互换。本地代码只运行 SHA-256,没有生成 Ethereum Keccak 向量,也没有调用 Ethereum 执行客户端;涉及 Ethereum 的位置要待 18 篇冻结规范与客户端后再核对。
编码修复的前提是解析器也同意规则。4 字节长度意味着单个字段最大长度小于 2^32;模型遇到过长字段直接拒绝。即使字节可拆回字段,协议仍需另行约束“哪些字段可以省略”“同一字段能否重复”“未知版本如何处理”。若签名端允许未知字段而执行端忽略它,双方可能对相同签名字节赋予不同权限;这不属于 SHA-256 的碰撞攻击,而是语义不一致。
另一个容易混淆的边界是编码和可用性。只保存摘要与字段说明,后来拿不到原字节时可以判断有人承诺过某个值,却不能恢复订单或完成重新执行。04 篇将用这个摘要构造 Merkle 包含,仍然需要检查根从哪里来。
错误情况不是“哈希函数算错”:如果订单 API 把 {order:"ab", recipient:"c"} 与 {order:"a", recipient:"bc"} 当同一待发送记录,重复处理会混淆意图;若把十进制字符串 "70" 与整数 70 静默混用,签名者和执行者可能理解不同金额。将已定义的字段逐一编码,再绑定业务版本/动作,才能谈验签或承诺。
两道练习
- 构造反例:只用字符串拼接,为
("12", "3")找到另一组字段,令字节相等;换成长度前缀后呢?答案:("1", "23")得到相同的b"123";前缀编码分别是00000002 3132 00000001 33与00000001 31 00000002 3233,不相等。 - 修改域:同样的
b"order",改用leaf与node标签时,摘要预映像如何变化?答案:第一字段的内容字节分别为b"leaf"和b"node",其余长度/负载仍相同;digest测试断言不同。这个断言不是密码学碰撞不可得的数学证明。
可迁移原则:任何“哈希已保护数据”都要补上“保护的是何种编码、在何用途域、由谁信任哪个摘要”。软件制品、幂等键和透明日志有同样的问题。
参考资料与核验边界
- NIST FIPS 180-4,SHA-256(原文待核验)。本地
abc向量已通过;官方页面当前未能取得。 - NIST FIPS 202,SHA-3(原文待核验);Ethereum Yellow Paper(当前网络语义须另核对)。不可把 Ethereum 早期论文当当前 fork 激活证据。
系列导航:区块链(01):两份签名都正确,账本仍会冲突 · 02 编码与承诺 · 区块链(03):签名证明授权了哪条消息;00、04–05 见系列入口 区块链(00):从中心化订单基线开始。


