密码学 26:私钥、公钥、地址与钱包为什么是不同对象
钱包界面只显示一条收款地址,却能管理多条链、多个账户、找零和不同的接收方式。把“私钥→公钥→地址”画成三格直线,确实能解释某一类外部账户,却解释不了为什么 Bitcoin 同一公钥能对应不同地址、为什么合约也有地址,以及只有地址的钱包为什么不能签交易。地址是告诉付款者如何指向一种接收条件的编码,钱包则是保存、发现、构造并可能签署相关交易的程序或设备。 从一个临时私钥到两种 Bitcoin 接收方式 在本章的临时实验中,coincurve 随机生成一把 secp256k1 私钥;绝不保存到 Git 或文章中。对应公钥有 33 字节压缩表示和 65 字节以 04 开头的非压缩表示。密码学上的椭圆曲线点相同,但进入后续哈希的字节序列不同。Bitcoin 常见 P2PKH、P2WPKH v0 可以取压缩公钥的 SHA256→RIPEMD160,生成 20 字节 HASH160,然后选择不同的锁定条件与网络编码: 123456一次性 Bitcoin 签名私钥 ─曲线乘法─> secp256k1 公钥点 └─33 字节...
密码学 23:API 请求认证为什么还需要规范化、时间与消费状态
一笔合成订单通过 HTTPS 发到服务端,订单正文 order=demo-001;quantity=1,客户端和服务端另约定用 HMAC 验证这笔 API 请求。第一次成功后,攻击者原封不动重发先前捕获的请求:请求体没被改,HMAC 依然正确。攻击者不必知道秘密,也可能让业务再次处理这笔订单。这不是 HMAC 被破解,而是校验输入里缺了一道“此请求是否已经生效”的判断。 签名哪些字节,谁持有密钥 HMAC 的计算方和验证方都必须有同一共享秘密;服务端也能生成同样的 MAC。因此它和钱包私钥签名交易不一样:交易可由其他参与者用公钥验证,而 HMAC 的服务端一方不能凭自己也能制造的 MAC 向第三方证明“只有客户端能生成”。TLS 又是第三件事:浏览器确认连的是 orders.test 并加密连接,不自动把 HTTP 订单绑定到应用层的权限或一次性消费状态。 为了让 HMAC 验证表达明确含义,发送者与验证者必须对同一串字节达成一致。例如只签 body、不签 HTTP 路径,原本针对 /orders 的正文在另一个端点也可能变成有意义的输入。简单用 method + path + ...
密码学 28:Ethereum 交易与 EIP-712 授权——两个 nonce 与两个验证点
钱包签了一条合成订单授权,并经 HTTPS RPC 送出一笔测试交易。签名都来自同一钱包私钥,为什么交易会因为账户 nonce 用过而失败,而订单授权还可能被再次兑现?这两个对象在不同的地方使用不同的消费状态:交易由执行层节点处理,链下类型化授权由部署它的应用或合约处理。EIP-712 帮助双方就类型与域达成一致,但原规范明确说它不包含重放保护。 一把私钥签两种不同的字节 选定 EIP-1559 的 0x02 类型交易,签名输入不是界面上的“转 100 wei”几个汉字。它包括 chain ID、此账户在这条链的交易 nonce、费率上限、gas limit、目的地址、数量、data 和 access list 的指定 RLP 编码,前面还有类型字节。节点先按此交易类型核对签名,再看账户余额、nonce、费用、gas 和执行规则;EIP-1559 的链 ID 必须绑定到目标链,不应仅因为椭圆曲线验签成立就忽略它。 12345678钱包私钥 ├─ 交易 type 0x02:keccak256(0x02 || RLP(chainId, accountNonce, │ ma...
密码学 27:Bitcoin 交易到底签哪些字节——UTXO、锁定条件与 sighash
钱包要从一个合成 Bitcoin 输出拿出 7000 sat,准备付给别人 5000 sat;假设剩余 2000 sat 作为手续费。有人说“把交易哈希签一下就行”。但交易序列化有见证数据、有上一笔交易的输出金额,还有多种 sighash 标志:究竟是哪些字节进签名,签名以后为什么节点还要查这笔输出有没有被别人先花? 本章只取一种确定的条件:Bitcoin 隔离见证 v0 的原生 P2WPKH、SIGHASH_ALL。它足以把输入、旧输出、收款方以及消费状态分开;legacy 旧式 sighash 与 Taproot 的 BIP 341 采用其他规则,不可直接复制这段算法。 拥有私钥与有权花费某个输出是两道判断 Bitcoin 使用 UTXO:上一次交易的某个输出含金额及锁定脚本;本次交易输入引用它的 outpoint(前交易 ID 和输出索引),并提交能满足锁定条件的数据。对本例 P2WPKH 而言,旧输出的见证程序为 OP_0 <20字节HASH160(压缩公钥)>,这笔花费的 witness 提交签名及压缩公钥;节点把公钥哈希与旧输出预期值核对,再按指定签名算法...
密码学 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...
密码学 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) ...
密码学 34:承诺与零知识——公开输入、秘密见证与证明关系
一家服务说:“证明你知道一个秘密,且本次公开金额没有超过公开限额;但不要在验证消息里直接发秘密。”听起来像要找一种能把一切都藏起来的“魔法签名”。实际上必须先写清:被证明的关系是什么、哪些输入留在验证者眼前、哪些是秘密见证,以及哪些业务事实根本没有进入关系。若“账户里确实有这么多余额”没有写进关系,再漂亮的证明也回答不了余额问题。 三个对象先分开 承诺是将某个值绑定进可核查的摘要或群元素;验证通常需要可信的承诺值以及证明者提供的打开数据。只对低熵订单号做 SHA-256 并公开摘要,并不能自动藏住订单号:旁观者可以列举所有可能值重算摘要。需要隐藏性时要考虑随机盲化、高熵秘密以及具体方案的安全假设;“只有散列看不出原文”不是普适保证。 关系定义验证者想确认的判断,如“我知道一个 secret,其 Poseidon 摘要等于公开 commitment,并且公开 amount <= limit”。secret 是本关系的见证,commitment、amount、limit 是公开输入。若 amount 本身公开,零知识性质也不能将 amount 隐藏;若哈希秘密只有四位,公开 c...
密码学 35:有效性证明为什么不自动给出隐私、可用性与最终结果
假设一个系统展示了“新状态根有有效证明”,但就是不公布用户这批交易的数据。用户能仅凭一个证明恢复自己账户的状态、重新计算余额,或者安全退出吗?不能直接推出。反过来,把交易数据都发出来,也不等于状态转移经过证明,更不等于实际链已经结算、具有要求的最终性。一个有效性证明只证明它明确编码的关系,不会越过规范的边界替运行者承担数据服务、社会共识或现实交付责任。 把批次拆成五个问题 给定旧状态根 S、新状态根 S′ 和必要的批次公开输入,一份有效性证明可以约束“存在满足给定转移规则的见证,使旧状态按该关系得到 S′”。要达到可用状态还须检查具体证明系统/电路究竟约束了什么:若没有约束签名、交易顺序、余额或者提现条件,验证者不会凭想象补上。再检查证明是否已由期望的结算层或合约接受;“有人本地验真一份 proof”和“相关状态已在期望链上确认”是两种证据。 数据可用性问第三方是否能拿到重建状态、观察账户或退出所需的数据,约束证明真假不能让被扣留的原始字节自动出现。链上发布、外部数据层和有效性证明各有验证和信任假设;即使某阶段可下载,也不表示有永久存储保证。隐私问公开了什么:包含证明和合法性证明...













