From c2497b2f36aca47f2cb595448972b92c01121311 Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Wed, 8 Oct 2025 16:35:16 +0800 Subject: [PATCH] =?UTF-8?q?Created=20sm2=5Fz256=5Floong64.S=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=88=86=E6=9E=90=20(markdown)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sm2_z256_loong64.S-代码分析.md | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 sm2_z256_loong64.S-代码分析.md diff --git a/sm2_z256_loong64.S-代码分析.md b/sm2_z256_loong64.S-代码分析.md new file mode 100644 index 0000000..b22d51c --- /dev/null +++ b/sm2_z256_loong64.S-代码分析.md @@ -0,0 +1,69 @@ +# 代码来源 +代码来自`GmSSL`的一个未合并的PR:https://github.com/DengJianbo-loongson/GmSSL/blob/2497946ac6458ae1fb6931b66804dbc62cfffe44/src/sm2_z256_loong64.S + +# 函数说明 +## __sm2_z256_modp_add +实现`(t0, t1, t2, t3) = (t0, t1, t2, t3) + (a4, a5, a6, a7)`,每个代表64位整数,从低到高排列,也就是说`t0`和`a4`是最低64位数,也就是多字(Multi-Word)加法。 + +**总体实现思路**: +1. 在RISC(如龙芯/LoongArch、MIPS)架构中,没有x86那样的进位标识寄存器,所以进位都要用`sltu` (无符号小于)等指令手动计算。 +1. 使用加`1`来实现`mod P`,这里的`1`为 $2^{256} - P$ 。 +1. 使用`or`合并进位(carry)。 +1. 使用`masknez`和`maskeqz`来选择最终结果。 + +## __sm2_z256_modp_dbl +实现`(t0, t1, t2, t3) = (t0, t1, t2, t3)*2`,double运算。 + +**总体实现思路**: +1. 使用移位操作:`srli.d`,`srli.d`和算术运算`alsl.d`实现double运算。`alsl.d $t3, $t3, $t5, 1`表示`t3 = t3<<1 + t5` +1. 其它和`__sm2_z256_modp_add`实现一致。 + +https://github.com/DengJianbo-loongson/GmSSL/blob/2497946ac6458ae1fb6931b66804dbc62cfffe44/src/sm2_z256_loong64.S#L94 +```asm + add.d $t5, $t1, $t8 //no carry + add.d $t5, $t5, $a1 +``` +改为 +```asm + add.d $t5, $a1, $t8 //no carry + add.d $t5, $t5, $t1 +``` +虽然不影响最终结果,但改完后的 `//no carry` 注释才成立 (这里`t8`的值为`0x00000000ffffffff`,`a1`为上一个字加法进位)。 + +https://github.com/DengJianbo-loongson/GmSSL/blob/2497946ac6458ae1fb6931b66804dbc62cfffe44/src/sm2_z256_loong64.S#L104 +```asm +add.d $a2, $a2, $a1 +``` +改为 +```asm +or $a2, $a2, $a1 +``` +也可以,其实我们只关注`a2`的值是0还是非0。 + +## __sm2_z256_modp_sub +计算 `(t0, t1, t2, t3) = (t0, t1, t2, t3) - (a4, a5, a6, a7)`。 + +**总体实现思路**: +1. 和加法一样,在RISC(如龙芯/LoongArch、MIPS)架构中,没有x86那样的借位标识寄存器,所以借位都要用`sltu` (无符号小于)等指令手动计算。 +1. 如果最后一个字的减法有借位,则再减`1`来实现`mod P`,这里的`1`为 $2^{256} - P$ ;否则再减的就是0。 +1. 使用`maskeqz`来选择减数是0还是`1`。 + +## __sm2_z256_modp_neg_sub +计算`(t0, t1, t2, t3) = (t0, t1, t2, t3) - (a4, a5, a6, a7)`。 + +和上面方法类似。 + +## __sm2_z256_modp_haf +计算 `(t0, t1, t2, t3) = (t0, t1, t2, t3) / 2`。 + +**总体实现思路**: +1. 如果该数是奇数,则先减`1`,这里的`1`为 $2^{256} - P$ ,相当于先加P;否则先减的就是0。 +1. 通过`andi $a2, $t0, 1`取最低位值。 +1. 使用`maskeqz`来选择减数是0还是`1`。 +1. 通过`srli.d`和`bstrins.d`进行除2操作。`bstrins.d $t0, $t1, 63, 63`表示`t0[63] = t1[0]`,`t0`的其它位值保持不变。 + +## __sm2_z256_modp_mont_mul +按字蒙哥马利模约减乘法(WW-MM),计算 `(t0,t1,t2,t3) = (a4,a5,a6,a7) * (t0,t1,t2,t3)`。 + + +