密码学 29:Merkle 包含证明究竟证明什么——叶、路径、根与可信区块头
钱包经 HTTPS RPC 发了一笔测试交易,RPC 返回一条交易哈希和一串“Merkle proof”。有人由此断言“交易已经写入不能修改的历史,订单一定交付”。要使“包含”有意义,最先问的不是路径有多少个哈希,而是:根是谁给的,它被谁认可,它承诺的到底是哪一组字节? 先用四份合成订单把证明画出来 以下是教学二叉树,不是 Bitcoin 真实交易树,更不是 Ethereum 的十六进制 Patricia Trie。四个合成订单先各自编码为确定字节;叶哈希加 00 前缀,父节点加 01 前缀以区分不同位置的拼接: 12345678910order-a order-b order-c order-d │ │ │ │ Ha=h(00|a) Hb=h(00|b) Hc=h(00|c) Hd=h(00|d) \ / \ / left = h(01|Ha|Hb) ...
密码学 25:WebAuthn 与 passkey——网站验证什么,用户验证在哪里
一个站点希望用 passkey 登录后,再让用户提交合成 HTTPS 订单。屏幕上似乎只点了一次“用设备解锁”,服务器却要判断三件不同的事:这是先前注册的凭据吗?这个凭据是在本网站发起、且回应的是这次挑战吗?认证器是否按站点政策完成了用户验证?单说“用了非对称密码学”无法回答其中任何一道题。 凭据私钥在哪,服务器保存什么 WebAuthn 的注册阶段,认证器针对一个 relying party(RP,依赖方,例如 orders.test)创建凭据,私钥由认证器或平台的凭据管理机制持有;服务端保存凭据标识与公钥,并把它关联到允许登录的账户及 RP。注册的来源、证明政策、哪些公钥可以保存,本身需要单独审查。下面实验预置一条合成注册记录,因而只能讨论登录断言,不能顺带宣称已验证真实注册或 attestation。 登录时服务端先生成一次性、不可预测的 challenge,浏览器提供站点 origin 信息并请求认证器生成断言。认证器对自身的 authenticatorData 加上浏览器产生的 clientDataJSON 字节的 SHA-256 摘要签名: 12345678服务端:生...
密码学 30:PoW、哈希链接与共识——签名为什么不能决定共同历史
同一笔尚未花费的输出,持有人先签了付给甲的交易 A,又签了付给乙的交易 B。两个签名都能通过,两个交易却不能在同一条有效历史里都花费它。如果有人给你 A 的交易哈希,甚至给你一个包含 A 的 Merkle 路径,能据此说“甲一定收到了钱”吗?不能。这里缺少的不是第三种签名算法,而是节点对交易规则、区块链接、累积工作和自己接受哪条历史的判断。 签名回答授权,共识回答冲突后的共同视图 钱包的签名把特定 sighash 预映像和控制该输出的密钥绑定。节点还须检查该输出在其要扩展的历史中存在、未被花费,且整笔交易满足脚本和金额规则。A 与 B 均可各自带一个有效签名;在包含 A 的状态下,B 引用的 UTXO 已被消费,因此不能再作为同一有效链的花费。反过来,存在分别以 A、B 为候选的两个竞争区块,不能只看任一个区块里的签名就决定全网以后接受哪个。 123456已知 UTXO ─┬─► 交易 A:给甲 ─► 签名 A 验真 ─► 候选块 X ─┐ └─► 交易 B:给乙 ─► 签名 B 验真 ─► 候选块 Y ─┤ 冲突 ...
密码学 31:HD 钱包和助记词——备份如何恢复很多密钥
钱包第一次显示一串助记词,随后能生成几百个收款地址。备份这串词以后,换一台设备却只看见零个余额:是“签名坏了”吗?更可能是助记词、额外 passphrase、账户派生路径、脚本类型或网络任一项不同。钱包不是一把私钥;它管理密钥、不同脚本或账户的派生方式与恢复所需信息。把“备份助记词”误读成“地址从此只有一种确定解释”,恢复时会产生令人困惑但可避免的结果。 从输入熵到一棵可复现的派生树 BIP 39 先将一定熵、校验位编码为指定词表中的词。词本身只是人可抄录的表示,不是对秘密的加密;读到有效助记词的人也可能恢复签名权。下一步将经过 NFKD 规范化的助记词作为输入、"mnemonic" || NFKD(passphrase) 作为 salt,经 2048 次 PBKDF2-HMAC-SHA512 得到 64 字节 seed。这个 passphrase 不是帮助记忆的标签:换一个字符即得到另一棵树;没有独立的“正确口令标记”帮助钱包判断你输错了哪一个。 BIP 32 再对 seed 做 HMAC-SHA512(key="Bitcoin seed"...
密码学 32:Schnorr 与 Taproot——签名结构怎样改变支出与披露
一个 Bitcoin 输出有“持有人直接签名”与“符合某个备用条件”两条支出路径。看到链上的付款地址,就能猜出备用条件吗?通常不能直接从 Taproot 输出看出未被用过的脚本分支;但实际走脚本分支支出时,交易必须公开被用的脚本及其承诺路径。有人据此宣称“Taproot 给所有交易完全匿名”,这是把某次支出披露的范围夸大成了对地址、金额、关联数据与未来历史的整体隐私保证。 先把 Schnorr 签名和支出条件分开 BIP 340 定义 secp256k1 上 x-only 公钥(32 字节)和 64 字节 Schnorr 签名;当前规范接受任意长度字节串作为消息,早期“必须 32 字节”的限制已经移除。Bitcoin Taproot 的交易签名仍会按 BIP 341 先得到相应 sighash,具体库接口也可能只接收 32 字节摘要;不要把应用层 BIP 340 能签任意消息,误读成 Taproot 可跳过交易摘要规则。它不是“用私钥加密消息”:交易内容仍可读,签名只对相应字节和密钥关系给出可公开核查的证据。nonce 生成须遵守规范,复用等实现错误可能泄露私钥;tagged h...
密码学 33:BLS 为什么适合聚合投票——账户签名与验证者签名
有人给你一份聚合签名,说“四个验证者一起同意了这个区块”。验签为真就等于区块有足够票数、已经最终确定吗?不行。你至少要知道这四个公钥对应谁、该时刻谁有投票资格和多少权重、他们各自签的哪个消息与域、聚合里实际有哪些成员,再按协议状态判断阈值。聚合解决的是验证和传输大量相关签名的一部分成本,不是共识规则本身。 不要拿交易签名去解释验证者投票 28 的 Ethereum type-2 交易由执行层 EOA 用 secp256k1 授权:确定账户、nonce、链 ID 和交易字节后,执行客户端还需核对余额、费用和执行规则。共识层验证者的 BLS 签名则用于对规定的共识消息(如 attestation 指向的目标)投票,签名字节由其签名根及 domain 等上下文决定。两种签名各有独立的密钥持有人、验证对象与状态来源;拿“交易账户验签通过”推出“验证者已投票”,或反过来,都是换了命题。 12345678执行层:钱包 secp256k1 ─► 有类型交易的签名字节 ─► 账户规则检查共识层:验证者 BLS 私钥 ─► 指定 slot/root/domain 的签名 ...
密码学 34:承诺与零知识——公开输入、秘密见证与证明关系
一家服务说:“证明你知道一个秘密,且本次公开金额没有超过公开限额;但不要在验证消息里直接发秘密。”听起来像要找一种能把一切都藏起来的“魔法签名”。实际上必须先写清:被证明的关系是什么、哪些输入留在验证者眼前、哪些是秘密见证,以及哪些业务事实根本没有进入关系。若“账户里确实有这么多余额”没有写进关系,再漂亮的证明也回答不了余额问题。 三个对象先分开 承诺是将某个值绑定进可核查的摘要或群元素;验证通常需要可信的承诺值以及证明者提供的打开数据。只对低熵订单号做 SHA-256 并公开摘要,并不能自动藏住订单号:旁观者可以列举所有可能值重算摘要。需要隐藏性时要考虑随机盲化、高熵秘密以及具体方案的安全假设;“只有散列看不出原文”不是普适保证。 关系定义验证者想确认的判断,如“我知道一个 secret,其 Poseidon 摘要等于公开 commitment,并且公开 amount <= limit”。secret 是本关系的见证,commitment、amount、limit 是公开输入。若 amount 本身公开,零知识性质也不能将 amount 隐藏;若哈希秘密只有四位,公开 c...
密码学 36:密钥如何生成、保存、轮换与撤销——KMS、信封加密与恢复
服务将一笔合成订单加密进数据库,后来轮换了保管密钥,旧订单却都打不开。另一服务宣称“已经撤销密钥”,此前被复制出去的旧明文却依然能读。这两种故障都说明密钥生命周期不只是调用一次加密函数:必须明确谁持有哪个密钥、哪里记录它的版本、轮换有没有重包裹历史密钥、灾难后拿什么恢复,以及删除权限不能追回已泄漏的材料。 从数据密钥到封装密钥 信封加密通常用随机数据密钥 DEK 保护内容,再用受管封装密钥 KEK 保护 DEK。数据密文、两层使用的算法和 nonce、KEK 标识、必要的关联数据必须作为一个可解析的记录保存:后来服务才能知道找谁解开、该在哪些订单上下文使用。记录标识是选择钥匙的索引,不是钥匙本身;一个 “kid=old” 字符串不应让应用直接相信该密文的来源或拿另一个 KEK 强行解开。 123456订单明文 ── AES-GCM(DEK, nonceA, AAD=订单ID) ─► 数据密文 + tag │DEK ── AES-GCM(KEK-old, nonceB, AAD=keyID-old) ─► 封装 DEK + tag轮换:...
密码学 37:算法正确为什么仍会失败——随机数复用、侧信道与验证边界
团队使用成熟密码库,单元测试里的签名和加密都验过,却把 AEAD 的同一个 key/nonce 用来加密两份订单;或者在 ECDSA 签名时复用了签名随机标量。这不是“数学算法被破解”,而是调用者破坏了算法要求的输入条件。回想 05 的四类值:密码 salt、AEAD nonce、签名 nonce、业务防重放序号不共享一个“随机数就行”的规则。 复用为何具体危险 ECDSA 对特定消息摘要 z 与随机标量 k 的一种标准算式是 s = k⁻¹(z + r·d) mod n:d 是签名私钥,r 来自同一临时曲线点。如果同一私钥对不同 z 复用相同 k,两份签名用相同的 r,且差值可逆时,攻击者从公开的 (r,s1,z1)、(r,s2,z2) 解出 k=(z1-z2)/(s1-s2) mod n,进而求 d=(s1·k-z1)/r mod n。恢复的是私钥本身,不是“签名可以重播”这么弱的结果。ECDSA 实际实现还要核对曲线、nonce 生成、低 s 变体和消息预处理,不能拿手算的玩具公式替真正的曲线库。 AES-GCM 的安全要求同一个密钥的 nonce 不重用。GCM 使用计数...
密码学 38:结课一——解释并验证一次 HTTPS 订单请求
浏览器向 orders.test 提交一笔合成订单:order=demo-001;quantity=1。如果页面展示“TLS 连接安全”,是不是订单就绝不会重复执行,服务器也必然不会篡改履约结果?并不是。结课先把网络通道、请求应用认证和订单业务事实画到同一条链上,逐层设计能失败的验证。所谓“成功”必须能指向一次具体输入、秘密持有人、可核对输出和信任起点。 第一张图:握手的信任边界 客户端已有预期主机名 orders.test 和只交给这个实验客户端的临时 CA。服务端有对应叶证书及其私钥,握手时还协商临时密钥交换材料。证书链签名告诉客户端公钥由指定信任锚所授权的签发关系连接而来;检查 SAN 和用途才把服务端与预期主机名联系起来。TLS 1.3 的 CertificateVerify 以服务器证书对应私钥签握手摘要,Finished 用派生出的握手密钥认证前面的握手内容;证书 CA 签名、服务器握手签名与 Finished 各认证不同对象,不能缩成“服务器拿私钥加密订单”。 12345678客户端:预期服务名 orders.test + 单独传入的测试 CA ├──► ...










