Skip to content

把签名规范变成逐层可复算的验证 ​

从消息到严格签名验证路线在这里交付五类真实执行:ECDSA点与标量、RFC6979候选状态、PureEd25519字节与余因子、RSA-FDH模拟表、RSA-PSS编码门禁。下载标准库核验器,运行python foundation-signature-mechanisms-check.py,得到包含完整签名、编码、候选轨迹和反例的JSON。python -O仍保留全部显式检查。

所有内置私钥、seed和盐都是公开离线样例。不要用它们创建账户、证书或真实授权。下载器不访问网络、不读取用户密钥;Python大整数与条件分支也不满足生产恒时要求。有限回归检验实现,正文的代数和归约承担一般结论。

一、在小曲线上同时验签和恢复泄漏 ​

固定曲线y2=x3+2x+2(mod17),G=(5,1)、阶q=19。用d=7得到Q=(0,6),用k=3得到R=(10,6)。令两个消息整数分别为4、9,输出两份签名(10,12)、(10,1)。

先复算第一份:3−1=13(mod19),s=13(4+70)mod19=12。再从公开的两份签名恢复k=(4−9)/(12−1)mod19=3,代回得到d=7。分母求的是模19逆元,不是浮点除法。

验证者第一份计算w=8,u1=13,u2=4,重建13G+4Q=3G。把第一份s改为7,也会接受,重建点变为(10,11)。输出正确签名并不意味着同一消息只有一种可接受签名。

结构迁移让第二份使用相反临时量q−k=16,保留消息整数9。第二份现在为(10,18),相同r仍存在,但套用“同一k”公式得到错误(k,d)=(4,12);相反k的方程用s1+s2作分母,恢复真正k=3。下载JSON的opposite_nonce同时给出错误私钥对应的公钥,方便验出它与Q不同。

再检查两个重试出口:k=7产生r=0;d=7、z=21、k=6产生s=0。两者都没有签名输出。主脚本穷举18个私钥、19个消息整数、18个候选,6156次中5184份有效、972次需重试。

二、让候选生成器经历两次不同拒绝 ​

这里固定RFC6979 SHA-256,含勘误3812的s=0重试。教学q=19只有5位,而编码长度仍为1字节:bits2int(ff)=31,bits2octets(ff)=0c。int2octets(18)=12,再bits2int得到2,显示非整字节长度下二者不互逆。

输入d=7、消息ASCII retry/7。生成器实际轨迹为:

次序 候选k 签名层决定 下一步
1 22 未进签名层,k≥19 K、V按拒绝规则更新
2 6 在范围内,但r=16、s=0 在同一生成器中继续更新
3 5 r=9、s=13 输出签名

JSON保留每行完整K、V。核对22没有被模19变成3,6被拒后没有重新初始化。公开例子的秘密状态可以展示;真实签名服务不能照搬这项日志。

随后转到标准P-256,使用RFC6979附录A.2.5公开私钥与sample、test两组消息,逐字比较k、r、s的完整官方值,并用点运算验证。小阶示例检验错误分支,标准向量检验互操作字节,两者解决不同问题。

迁移保持教学摘要最左5位不变、只改后面的位,比较初始化B是否变化;再把同一输入转换用于256位q,重算保留范围。不能把小例的摘要碰撞直接称作SHA-256被攻破。

三、分别列出Ed25519三种接受合同 ​

本实验实现RFC8032的PureEd25519,不是ctx或ph。公钥32字节,签名64字节;点必须规范解码,S必须满足0≤S<L。第一组空消息官方向量的公钥以d75a9801开头、签名R以e5564300开头;JSON存完整值,另外核对1字节及2字节消息向量。

对每组向量,把消息追加x、删去一个签名字节、追加一个字节,以及给S加L,都应拒绝。单独把y编码成p,或给x=0的点设置符号位1,也必须在点解码阶段拒绝。

然后使用规范点编码构造以下记录。T=(0,−1)是阶2点;“严格密钥”只增加A非单位元且[L]A=单位元的公钥政策,不改变R的规则。

公钥A′与签名点R′ S 乘8方程 不乘8方程 严格密钥+乘8
A′=单位元,R′=单位元 0 通过 通过 拒绝公钥
A′=单位元,R′=T 0 通过 拒绝 拒绝公钥
A′=aB为诚实公钥,R′=7B+T 7+ka模L 通过 拒绝 通过

第三行实际按新R字节重新计算k,再使用公开教学秘密a构造S;JSON字段mixed_R_known_secret_fixture为true/false/true。这说明只约束公钥为素数阶,并不会把乘8验证变成不乘8验证。它也没有证明外部攻击者能在不知道a时生成这份签名。

迁移时把消息换掉,却保持第三行原S不变,原来重新计算的挑战不再匹配,通常会拒绝;若继续使用已知a重新签,则又是一份不同的自制样例。比较的是接受规则,不是假定拥有私钥的实验突然变成密码攻击。

四、交一份RSA-FDH的模拟表 ​

固定教学N=143、e=7、d=43,单位群有120个元素。先枚举单位群确认e次幂是置换;每个像的逆像都唯一。实际消息采用既定字段编码,字段依次为Theoryroad/lesson/v1、signature、allow=demo。教学全宽哈希拒绝第一个候选,第二个得到42,签名为3,因为37mod143=42。

理想ROM证明使用另一张可编程表。公开挑战Y=30,对应未知给模拟器的逆像;教学验算者知道其为17。请求顺序是哈希a、签名b、哈希c、最后伪造d。猜J=4时:

消息 首次编号 哈希答复 模拟器知道的逆像
a 1 128 2
b 2 42 3
c 3 47 5
d 4 30 未知

b的签名请求可由3回答;d的有效伪造17就反演Y。猜J=2则在b请求签名时中止;猜1或3不会从d的输出得到挑战逆像。脚本枚举四种猜法,恰有一次恢复挑战。

另外直接输出此前未查过的消息unseen与17。finish必须补建该消息的哈希表项,再进行有效性与新消息检查,不能因没查过就忽略它。正文的总槽数Q_H+Q_S+1中,加1正为这类输出保留位置。

迁移将b先签名、再重复哈希,要求表只占一行;再尝试把已签b当作最后伪造,验证“密码方程成立”不等于“赢了新消息攻击游戏”。具体SHA-256扩展与理想可编程随机表是两个实验,不把前者的有限通过替换后者的归约假设。

五、把PSS逐字节门禁接在RSA后面 ​

参数固定为RFC8017 RSA-PSS、SHA-256、MGF1-SHA-256和32字节盐。消息ASCII Theoryroad offline PSS lesson,盐是字节00到1f。取公开RSA Laboratories Example1及Example2的测试密钥数值;原资料的签名向量使用SHA-1,这里的SHA-256输出为本实验重新计算。

模数位数 签名字节k emBits emLen DB字节 PS字节 最高保留位
1024 128 1023 128 95 62 1
1025 129 1024 128 95 62 0

每份EM由95字节maskedDB、32字节H和bc组成。MGF1的三块摘要用计数器00000000、00000001、00000002产生,最后截去多余的一字节。JSON保留完整EM与两份RSA签名;两行本例EM相同,只因其首字节天然最高位为0,不能据此删掉两种合同的差异。

负例要分层交付:

  • 在EM层分别破坏PS零字节、分隔符、salt、H、尾标与1024位合同的保留高位,全部拒绝
  • 对“分隔符01改02”的坏EM,重新用公开教学d执行RSA私钥运算;公开模幂还原了这份坏EM,但PSS仍拒绝
  • 在S层删一个字节、把代表整数设为N、以20字节盐政策验证32字节盐签名,分别拒绝
  • 对1025位N,取m=2^1024<N,再形成对应RSA签名;公开运算得到的m装不进128字节EM,必须在I2OSP步骤拒绝

两份EM所有单比特翻转共2048项都被拒绝。named_corruptions_rejected和i2osp_1025bit_overflow_rejected另把关键门禁具名列出,避免只报一个总计。

结构迁移改用空盐:SHA-256要求最少34字节EM,最小emBits=265,PS恰好为空。编码和验证必须都拿到sLen=0政策;DB末尾取零字节应该得到空串,不能被语言切片[-0:]变成整个DB。再把emBits降到264,应因空间不够拒绝编码。

六、最终验收物 ​

交付运行JSON、使用的规范版本与验证变体,以及以下解释:ECDSA相反k为何共享r、RFC6979为何拒绝而不模约简、Ed25519严格公钥政策为何仍不同于强方程、FDH为何补最终新查询、PSS为何k不一定等于emLen。

成本也分层记录。候选生成统计实际HMAC尝试,ECDSA/Ed25519统计群运算及消息哈希;FDH模拟器还要计算单位采样与gcd,不能只数公开模幂;PSS记录消息哈希、掩码字节量和RSA指数运算。保留K/V、完整签名或编码日志需要额外输出空间。没有一项有限实验声称自动证明真实密钥生成、侧信道安全或协议身份绑定。