C++实现X.690 DER二进制基2编码REAL值的尾数规范化疑问
结论
你给出的编码09 04 80 FC 02 05是32.3125的正确DER二进制基2编码。需要明确的是:对DER编码的基2格式ASN.1 REAL值,将缩放因子F固定为0不是可选的实现选择,而是标准的强制要求。
标准规则说明
X.690-0207 8.5.7.4对CER/DER的二进制REAL编码有明确的唯一性约束,其中基2编码的要求如下:
- 缩放因子F必须取0,禁止取1、2、3(这三个取值仅在非canonical的BER编码中允许使用,DER下会导致编码不合法)
- 整数尾数N必须取能表示该值的最小正奇整数,也就是你引用条款中提到的“反复移位直到最低有效位为1”。如果N是偶数,说明你可以将N右移1位、指数加1得到更小的N,不符合DER编码唯一的要求。
- 指数和尾数都必须使用最短长度编码:指数用能容纳数值的最少字节数的二补码有符号整数表示,尾数用无前置零字节的大端无符号整数表示。
对你的计算和编码的验证
- 你调用
std::frexp得到尾数0.5048828125、指数6的结果是正确的,符合std::frexp返回值在[0.5, 1)区间的定义。 - 你反复乘2直到尾数为整数的步骤,只要在第一次得到整数时就停止,得到的N必然是奇数:如果N是偶数,说明你可以少乘一次2就得到整数(N/2),不会停在偶数N的位置。你最终得到N=517(奇数)、指数-4,完全符合DER的规范化要求。
- 编码逐段校验:
09是ASN.1 REAL类型的固定tag,正确04是内容段长度4字节,计算正确(1字节标志位 + 1字节指数 + 2字节尾数)- 标志位
0x80转二进制为10000000:最高位1表示二进制编码,次两位00表示基2,接下来1位0表示正数,再两位00表示F=0,最后两位00表示指数长度为1字节,完全符合格式要求 0xFC是1字节二补码表示的-4,是-4的最短编码形式,正确0x02 0x05是大端无符号整数517,无前置零字节,是最短尾数编码,正确
实现注意事项
- 你当前的算法在输入为C++
double这类原生二进制浮点数时是成立的,因为这类值本身就是有限二进制分数,总能通过乘2得到整数;如果是十进制输入,直接转double可能引入精度误差,需要额外处理。 - 如果是普通BER编码,F可以取0-3的任意值,只要N为整数编码就合法,但同一值会对应多种编码结果;DER要求编码唯一,必须严格遵守F=0、N为最小奇数、最短长度编码的规则。
内容的提问来源于stack exchange,提问作者FaisalM
相关产品推荐
相关产品推荐

