☰
第 23-1 篇:国密 SM3 与 KAT 红线——先有答案,再写实现
2026/9/28 18:02:27 网站建设 项目流程

1. 知识点:为什么密码学需要"KAT 红线"

普通工程代码可以"看起来对 + 边界测试过"就发布。密码学不行:

  • 错一位就是整体失效:哈希/加解密是雪崩式的,一个常量抄错,输出跟标准毫无相似度,但"看起来"很随机——靠人眼根本验不出来;
  • 标准答案免费可得:GM/T 0004(SM3)等标准附录给了官方向量(如SM3("abc") = 66c7f0f4…)。把这些向量写进自检,等于给实现装了"出厂校准"——先有答案,再写实现;
  • 红线要能隔离:理想的自检是"哪个原语错就哪个红",而不是一团 FAIL 让你猜——所以 KAT 要按原语分组跑。

引擎的源码注释(vllm_crypto.c4–5 行)把这条纪律写得很直白:位级正确性由独立测试驱动用国密标准 KAT 向量逐字节验证(red line)。文档进一步说明该驱动(vllm_crypto_test.c)未随仓库分发(权重保护与可验证推理方案 224 行)——本日我们自己搭最小 harness,把这条红线在板上立起来。

2. 对应代码:最小 KAT harness(crypto_kat.c)

对着vllm_crypto.h的公开 API,写一个零依赖 harness,验证四件事:

vc_sm3("abc", 3, d) → 与 66c7f0f4… 对拍(SM3 官方向量) vc_sm3("", 0, d) → 与 1ab21d83… 对拍(空串向量) vc_sm3 分块输入(3+61 字节喂 update)→ 与 "abcd"*16 的 64B 向量对拍(走填充+缓冲路径) vc_sm4_setkey_enc + crypt_block → 与标准单块向量 681edf34… 对拍 vc_sm2_sign/verify → 功能回环 + 篡改 r 后必须验不过

编译方式(板端,与引擎同一份vllm_crypto.c):

gcc -O2 -I<repo>/include -I<repo>/include/common \ crypto_kat.c <repo>/src/common/vllm_crypto.c -o crypto_kat -lm

3. 改动后果:板端 KAT 实测——红线为什么是红线

实测口径:RK3588 / aarch64 / 2026-09-07 / gcc -O2。

原始实现: [PASS] SM3("abc") 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0 [PASS] SM3("") 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b [PASS] SM3(64B "abcd"*16, 3+61) debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732 [PASS] SM4-ECB KAT (block) [PASS] SM2 sign/verify roundtrip [PASS] SM2 tamper rejected (r' != r) KAT: ALL PASS (red line green) 篡改后(把 SM3_IV[0] 的 0x7380166f 改成 0x7380166e,其余不动): [FAIL] SM3("abc") 7a3773dc0de682e8…(与标准无一位相同) [FAIL] SM3("") 1d6d2431… [FAIL] SM3(64B, 3+61) 8dfe48ba… [PASS] SM4-ECB KAT (block) ← 不受影响 [PASS] SM2 sign/verify roundtrip ← 不受影响 KAT: FAILURES PRESENT

三个教训:

  1. 一个十六进制位 = 输出全变:0x7380166f → 0x7380166e只是 IV 最低位 -1,三个 SM3 输出立刻与标准毫无相似度——这正是"人眼验不出来、KAT 一秒钟抓出来"的实证;
  2. 红线能隔离:改的是 SM3 的 IV,SM4/SM2 的 PASS 不受牵连——如果有一天自检"全红",那是更严重的问题(可能构建链被污染);单条红,则精确指向那一个原语;
  3. 为什么驱动不随仓库分发也拦不住我们:标准向量是公开知识,任何拿到vllm_crypto.c的人都能自己把红线立起来复验——源码开放 + 标准公开 = 可审计,这正是本仓库 AGPL 双许可叙事下"可验证"的技术底座。

4. 学员调试任务

A 档(板端/本地动手)

  1. 复刻本文:搭crypto_kat.c编译运行,确认 6 行 PASS;
  2. 依次单独篡改:a)SM3_IV[0];b) 压缩常量0x79cc4519;c)P0的旋转位数——每次重编跑 KAT,记录"哪几行 FAIL、SM4/SM2 是否受影响",体会红线的隔离粒度;
  3. 给 harness 加一个你自己的向量:SM3("中国")的期望值先用另一个可信实现算好(python 有hashlib.new('sm3')的话),再让引擎实现跑,体会"先有答案再实现"。

B 档(纯读源码)

读vllm_crypto.c1–127 行,回答:

  1. GET_U32_BE/PUT_U32_BE宏(22–28 行)在做什么,为什么 SM3 要大端取字?
  2. vc_sm3_update的"整块直压 + 余块缓冲"两条路径(90–103 行)分别处理什么情况?
  3. 若把vc_sm3_final里while (buflen != 56)的填充循环改成先算要补几个 0 再一次性 update,行为等价吗?为什么这样写更"防御"(提示:长度计数c->n的进位)?

预期输出:你自己的 KAT 输出(全绿)+ 至少一次"篡改→单原语 FAIL"的实验记录。

收尾

  • 本篇源码点名:vllm_crypto.c(红线注释 4–5、IV 33–36)、vllm_crypto.h、权重保护与可验证推理方案.md
  • 开源仓库:Kestrel-LLM (Gitee)(AGPL-3.0-or-later 或商业许可,二选一)
  • 下篇预告:红线证明实现是对的,那 SM3 内部到底怎么把"abc"搅成 32 字节摘要的?23-2 逐段导读:填充、消息扩展 W/W'、64 轮压缩。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询