准备发布 v0.1.0

- 添加 Apache-2.0 许可证
- 添加 CHANGELOG.md 变更日志
- 添加 SECURITY.md 安全策略
- 添加 README.zh-CN.md 中文文档
- 添加 rustfmt.toml 代码格式配置
- 添加 scripts/pre_publish_check.sh 发布检查脚本
- 更新 Cargo.toml 元数据(分类、关键词、文档链接)
- 完善 README.md 示例代码
- 优化 SM2/SM9 性能和测试覆盖率
This commit is contained in:
huangxt
2026-03-07 19:27:41 +08:00
parent bec7f277ce
commit 8ad52ecac0
23 changed files with 1275 additions and 361 deletions
+38 -25
View File
@@ -98,7 +98,7 @@ impl JacobianPoint {
/// 点倍运算(Jacobian 坐标,a=-3 优化公式,完全常量时间)
///
/// 公式来自 https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
/// 公式来自 <https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b>
/// SM2 曲线 a = p-3 ≡ -3 (mod p),使用 a=-3 特化公式降低乘法次数。
///
/// # 安全性
@@ -128,7 +128,11 @@ impl JacobianPoint {
&double2(&double1(&gamma2)),
);
let d = JacobianPoint { x: x3, y: y3, z: z3 };
let d = JacobianPoint {
x: x3,
y: y3,
z: z3,
};
// Reason: 无穷远点的倍点仍为无穷远点;用掩码选择替代 if 分支,
// 避免 scalar_mul 热路径中泄露哪些迭代位为前导零。
JacobianPoint::conditional_select(&d, self, self.ct_is_infinity())
@@ -136,7 +140,7 @@ impl JacobianPoint {
/// 点加运算(完全常量时间,无条件分支)
///
/// 公式来自 https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
/// 公式来自 <https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl>
///
/// # 安全性
/// 采用"计算所有情况 + 掩码选择"策略,消除全部退化情况的条件分支:
@@ -176,7 +180,11 @@ impl JacobianPoint {
let y3 = fp_sub(&fp_mul(&r, &fp_sub(&u1h2, &x3)), &fp_mul(&s1, &h3));
// Z3 = H·Z1·Z2 (当 H==0 时 z3=0,即 INFINITY,与下面掩码一致)
let z3 = fp_mul(&fp_mul(&h, &p.z), &q.z);
let normal = JacobianPoint { x: x3, y: y3, z: z3 };
let normal = JacobianPoint {
x: x3,
y: y3,
z: z3,
};
// 预计算 P==Q 退化情况的结果(无条件执行,结果由掩码决定是否使用)
let double_p = p.double();
@@ -186,12 +194,12 @@ impl JacobianPoint {
let result = normal;
// 优先级 2P == -Q → INFINITYh==0 且 r≠0
let result = JacobianPoint::conditional_select(
&result, &JacobianPoint::INFINITY, h_is_zero & !r_is_zero,
&result,
&JacobianPoint::INFINITY,
h_is_zero & !r_is_zero,
);
// 优先级 3P == Q → double(P)h==0 且 r==0
let result = JacobianPoint::conditional_select(
&result, &double_p, h_is_zero & r_is_zero,
);
let result = JacobianPoint::conditional_select(&result, &double_p, h_is_zero & r_is_zero);
// 优先级 4:Q 是无穷远 → P(加法单位元)
let result = JacobianPoint::conditional_select(&result, p, q.ct_is_infinity());
// 优先级 5(最高):P 是无穷远 → Q
@@ -250,6 +258,7 @@ fn double2(a: &Fp) -> Fp {
/// - X1·Z2² 简化为 X10 次乘法)
/// - Y1·Z2³ 简化为 Y10 次乘法)
/// - Z3 中的 Z2 乘法(Z3 = H·Z1,而非 H·Z1·Z2
///
/// 共节省约 3~4 次域乘法,用于预计算表构建和 multi_scalar_mul 内循环。
///
/// # 安全性
@@ -258,10 +267,10 @@ fn add_mixed(p: &JacobianPoint, q: &AffinePoint) -> JacobianPoint {
use subtle::ConstantTimeEq;
// Z_Q = 1,故 u1 = X1s1 = Y1(无需额外乘法)
let z1sq = fp_square(&p.z); // Z1²
let z1cu = fp_mul(&p.z, &z1sq); // Z1³
let u2 = fp_mul(&q.x, &z1sq); // X2·Z1²
let s2 = fp_mul(&q.y, &z1cu); // Y2·Z1³
let z1sq = fp_square(&p.z); // Z1²
let z1cu = fp_mul(&p.z, &z1sq); // Z1³
let u2 = fp_mul(&q.x, &z1sq); // X2·Z1²
let s2 = fp_mul(&q.y, &z1cu); // Y2·Z1³
let h = fp_sub(&u2, &p.x);
let r = fp_sub(&s2, &p.y);
@@ -269,28 +278,29 @@ fn add_mixed(p: &JacobianPoint, q: &AffinePoint) -> JacobianPoint {
let h_is_zero = fp_to_bytes(&h).ct_eq(&[0u8; 32]);
let r_is_zero = fp_to_bytes(&r).ct_eq(&[0u8; 32]);
let h2 = fp_square(&h);
let h3 = fp_mul(&h, &h2);
let h2 = fp_square(&h);
let h3 = fp_mul(&h, &h2);
let u1h2 = fp_mul(&p.x, &h2);
let x3 = fp_sub(&fp_sub(&fp_square(&r), &h3), &double1(&u1h2));
let y3 = fp_sub(
&fp_mul(&r, &fp_sub(&u1h2, &x3)),
&fp_mul(&p.y, &h3),
);
let y3 = fp_sub(&fp_mul(&r, &fp_sub(&u1h2, &x3)), &fp_mul(&p.y, &h3));
// Reason: Z_Q = 1,故 Z3 = H·Z1·Z2 = H·Z1,节省一次乘法
let z3 = fp_mul(&h, &p.z);
let normal = JacobianPoint { x: x3, y: y3, z: z3 };
let normal = JacobianPoint {
x: x3,
y: y3,
z: z3,
};
let double_p = p.double();
let result = normal;
let result = JacobianPoint::conditional_select(
&result, &JacobianPoint::INFINITY, h_is_zero & !r_is_zero,
);
let result = JacobianPoint::conditional_select(
&result, &double_p, h_is_zero & r_is_zero,
&result,
&JacobianPoint::INFINITY,
h_is_zero & !r_is_zero,
);
let result = JacobianPoint::conditional_select(&result, &double_p, h_is_zero & r_is_zero);
// P = INFINITY → 返回 Q(注:预计算表中 Q 绝不是无穷远点,
// 但在通用调用中仍需正确处理)
let q_jac = JacobianPoint::from_affine(q);
@@ -328,7 +338,7 @@ fn scalar_mul_g_window(k: &U256) -> JacobianPoint {
for _ in 0..4 {
result = result.double();
}
let window = (byte >> 4) as u8;
let window = byte >> 4;
// 常量时间表查找:遍历 1..=15,用 ct_eq 选出 table[window]
let mut sel = JacobianPoint::INFINITY;
for j in 1u8..=15 {
@@ -592,6 +602,9 @@ mod tests {
y: fp_neg(&g.y),
z: g.z,
};
assert!(JacobianPoint::add(&g, &g_neg).is_infinity(), "G + (-G) 应为无穷远点");
assert!(
JacobianPoint::add(&g, &g_neg).is_infinity(),
"G + (-G) 应为无穷远点"
);
}
}
+48 -12
View File
@@ -63,26 +63,62 @@ pub(super) fn compress(state: &mut [u32; 8], block: &[u8; 64]) {
// Reason: 将 64 轮分两段展开,消除 ff/gg/T 中的 if 分支。
// j = 0..15FF = x^y^zGG = x^y^z
for j in 0..16 {
let ss1 = a.rotate_left(12).wrapping_add(e).wrapping_add(T[j]).rotate_left(7);
let ss1 = a
.rotate_left(12)
.wrapping_add(e)
.wrapping_add(T[j])
.rotate_left(7);
let ss2 = ss1 ^ a.rotate_left(12);
let tt1 = (a ^ b ^ c).wrapping_add(d).wrapping_add(ss2).wrapping_add(w[j] ^ w[j + 4]);
let tt2 = (e ^ f ^ g).wrapping_add(h).wrapping_add(ss1).wrapping_add(w[j]);
d = c; c = b.rotate_left(9); b = a; a = tt1;
h = g; g = f.rotate_left(19); f = e; e = p0(tt2);
let tt1 = (a ^ b ^ c)
.wrapping_add(d)
.wrapping_add(ss2)
.wrapping_add(w[j] ^ w[j + 4]);
let tt2 = (e ^ f ^ g)
.wrapping_add(h)
.wrapping_add(ss1)
.wrapping_add(w[j]);
d = c;
c = b.rotate_left(9);
b = a;
a = tt1;
h = g;
g = f.rotate_left(19);
f = e;
e = p0(tt2);
}
// j = 16..63FF = majority(x,y,z)GG = choice(x,y,z)
for j in 16..64 {
let ss1 = a.rotate_left(12).wrapping_add(e).wrapping_add(T[j]).rotate_left(7);
let ss1 = a
.rotate_left(12)
.wrapping_add(e)
.wrapping_add(T[j])
.rotate_left(7);
let ss2 = ss1 ^ a.rotate_left(12);
let tt1 = ((a & b) | (a & c) | (b & c))
.wrapping_add(d).wrapping_add(ss2).wrapping_add(w[j] ^ w[j + 4]);
.wrapping_add(d)
.wrapping_add(ss2)
.wrapping_add(w[j] ^ w[j + 4]);
let tt2 = ((e & f) | (!e & g))
.wrapping_add(h).wrapping_add(ss1).wrapping_add(w[j]);
d = c; c = b.rotate_left(9); b = a; a = tt1;
h = g; g = f.rotate_left(19); f = e; e = p0(tt2);
.wrapping_add(h)
.wrapping_add(ss1)
.wrapping_add(w[j]);
d = c;
c = b.rotate_left(9);
b = a;
a = tt1;
h = g;
g = f.rotate_left(19);
f = e;
e = p0(tt2);
}
state[0] ^= a; state[1] ^= b; state[2] ^= c; state[3] ^= d;
state[4] ^= e; state[5] ^= f; state[6] ^= g; state[7] ^= h;
state[0] ^= a;
state[1] ^= b;
state[2] ^= c;
state[3] ^= d;
state[4] ^= e;
state[5] ^= f;
state[6] ^= g;
state[7] ^= h;
}
+205 -126
View File
@@ -39,6 +39,7 @@ const CK: [u32; 32] = [
///
/// 仅使用 `&`/`^`/`|`/`!` 位运算,零内存访问,无条件分支。
/// 每个中间变量为 0 或 1(对应输入字节的各个位平面)。
#[allow(dead_code)]
#[inline]
pub(crate) fn sbox_ct(x: u8) -> u8 {
// 提取输入字节的 8 个位(b0 = LSB, b7 = MSB
@@ -53,19 +54,19 @@ pub(crate) fn sbox_ct(x: u8) -> u8 {
// ── 输入线性层(input function)──────────────────────────────────────────
// Reason: 将输入 8 位映射为中间变量 g0..g7, m0..m9,为 GF(2^4) 求逆做准备。
let t1 = b7 ^ b5;
let t2 = 1 ^ (b5 ^ b1); // NOT(b5 ^ b1) = g4
let g5 = 1 ^ b0; // NOT(b0)
let t3 = 1 ^ (b0 ^ t2); // NOT(b0 ^ t2) = m1
let t4 = b6 ^ b2; // m4
let t5 = b3 ^ t3; // g3
let t6 = b4 ^ t1; // m0
let t7 = b1 ^ t5; // g1
let t8 = b1 ^ t4; // m2
let t9 = t6 ^ t8; // m8
let t10 = t6 ^ t7; // g0
let t11 = 1 ^ (b3 ^ t1); // NOT(b3 ^ t1) = m5
let t12 = 1 ^ (b6 ^ t9); // NOT(b6 ^ t9) = m9
let t1 = b7 ^ b5;
let t2 = 1 ^ (b5 ^ b1); // NOT(b5 ^ b1) = g4
let g5 = 1 ^ b0; // NOT(b0)
let t3 = 1 ^ (b0 ^ t2); // NOT(b0 ^ t2) = m1
let t4 = b6 ^ b2; // m4
let t5 = b3 ^ t3; // g3
let t6 = b4 ^ t1; // m0
let t7 = b1 ^ t5; // g1
let t8 = b1 ^ t4; // m2
let t9 = t6 ^ t8; // m8
let t10 = t6 ^ t7; // g0
let t11 = 1 ^ (b3 ^ t1); // NOT(b3 ^ t1) = m5
let t12 = 1 ^ (b6 ^ t9); // NOT(b6 ^ t9) = m9
let g0 = t10;
let g1 = t7;
@@ -87,47 +88,47 @@ pub(crate) fn sbox_ct(x: u8) -> u8 {
// ── Top 函数(GF(2^4) 求逆的输入准备)────────────────────────────────────
// Reason: 将 16 个中间变量组合为 p0..p3,供 GF(2^2) 中间层使用。
let t2t = m0 & m1;
let t3t = g0 & g4;
let t4t = g3 & g7;
let t7t = g3 | g7;
let t2t = m0 & m1;
let t3t = g0 & g4;
let t4t = g3 & g7;
let t7t = g3 | g7;
let t11t = m4 & m5;
let t10t = m3 & m2;
let t12t = m3 | m2;
let t6t = g6 | g2;
let t9t = m6 | m7;
let t5t = m8 & m9;
let t8t = m8 | m9;
let t6t = g6 | g2;
let t9t = m6 | m7;
let t5t = m8 & m9;
let t8t = m8 | m9;
let t14t = t3t ^ t2t;
let t16t = t5t ^ t14t;
let t20t = t16t ^ t7t;
let t17t = t9t ^ t10t;
let t18t = t11t ^ t12t;
let p2 = t20t ^ t18t;
let p0 = t6t ^ t16t;
let t1t = g5 & g1;
let p2 = t20t ^ t18t;
let p0 = t6t ^ t16t;
let t1t = g5 & g1;
let t13t = t1t ^ t2t;
let t15t = t13t ^ t4t;
let p3 = (t6t ^ t15t) ^ t17t;
let p1 = t8t ^ t15t;
let p3 = (t6t ^ t15t) ^ t17t;
let p1 = t8t ^ t15t;
// ── Middle 函数(GF(2^2) 求逆)───────────────────────────────────────────
// Reason: 在 GF(2^2) 上对 (p0,p1,p2,p3) 组成的元素进行求逆,输出 l0..l3。
let t0m = p1 & p2;
let t1m = p3 & p0;
let t2m = p0 & p2;
let t3m = p1 & p3;
let t4m = t0m & t2m;
let t5m = t1m ^ t3m;
let t6m = t5m | p0;
let t7m = t2m | p3;
let l3 = t4m ^ t6m;
let t9m = t7m ^ t3m;
let l0 = t0m ^ t9m;
let t0m = p1 & p2;
let t1m = p3 & p0;
let t2m = p0 & p2;
let t3m = p1 & p3;
let t4m = t0m & t2m;
let t5m = t1m ^ t3m;
let t6m = t5m | p0;
let t7m = t2m | p3;
let l3 = t4m ^ t6m;
let t9m = t7m ^ t3m;
let l0 = t0m ^ t9m;
let t11m = p2 | t5m;
let l1 = t11m ^ t1m;
let l1 = t11m ^ t1m;
let t12m = p1 | t2m;
let l2 = t12m ^ t5m;
let l2 = t12m ^ t5m;
// ── Bottom 函数(GF(2^4) 求逆的输出组合)─────────────────────────────────
// Reason: 将 l0..l3 与输入中间变量结合,得到 r0..r11(12 个中间结果)。
@@ -137,42 +138,59 @@ pub(crate) fn sbox_ct(x: u8) -> u8 {
let k0 = l0 ^ l1;
let k1 = k2 ^ k3;
let e0 = m1 & k0; let e1 = g5 & l1; let r0 = e0 ^ e1;
let e2 = g4 & l0; let r1 = e2 ^ e1;
let e3 = m7 & k3; let e4 = m5 & k2; let r2 = e3 ^ e4;
let e5 = m3 & k1; let r3 = e5 ^ e4;
let e6 = m9 & k4; let e7 = g7 & l3; let r4 = e6 ^ e7;
let e8 = g6 & l2; let r5 = e8 ^ e7;
let e9 = m0 & k0; let e10 = g1 & l1; let r6 = e9 ^ e10;
let e11 = g0 & l0; let r7 = e11 ^ e10;
let e12 = m6 & k3; let e13 = m4 & k2; let r8 = e12 ^ e13;
let e14 = m2 & k1; let r9 = e14 ^ e13;
let e15 = m8 & k4; let e16 = g3 & l3; let r10 = e15 ^ e16;
let e17 = g2 & l2; let r11 = e17 ^ e16;
let e0 = m1 & k0;
let e1 = g5 & l1;
let r0 = e0 ^ e1;
let e2 = g4 & l0;
let r1 = e2 ^ e1;
let e3 = m7 & k3;
let e4 = m5 & k2;
let r2 = e3 ^ e4;
let e5 = m3 & k1;
let r3 = e5 ^ e4;
let e6 = m9 & k4;
let e7 = g7 & l3;
let r4 = e6 ^ e7;
let e8 = g6 & l2;
let r5 = e8 ^ e7;
let e9 = m0 & k0;
let e10 = g1 & l1;
let r6 = e9 ^ e10;
let e11 = g0 & l0;
let r7 = e11 ^ e10;
let e12 = m6 & k3;
let e13 = m4 & k2;
let r8 = e12 ^ e13;
let e14 = m2 & k1;
let r9 = e14 ^ e13;
let e15 = m8 & k4;
let e16 = g3 & l3;
let r10 = e15 ^ e16;
let e17 = g2 & l2;
let r11 = e17 ^ e16;
// ── 输出线性层(output function)──────────────────────────────────────────
// Reason: 将 r0..r11 组合为输出字节的 8 个位。
let t1o = r7 ^ r9;
let t2o = r1 ^ t1o;
let t3o = r3 ^ t2o;
let t4o = r5 ^ r3;
let t5o = r4 ^ t4o;
let t6o = r0 ^ r4;
let t7o = r11 ^ r7;
let t1o = r7 ^ r9;
let t2o = r1 ^ t1o;
let t3o = r3 ^ t2o;
let t4o = r5 ^ r3;
let t5o = r4 ^ t4o;
let t6o = r0 ^ r4;
let t7o = r11 ^ r7;
let b5o = t1o ^ t4o;
let b2o = t1o ^ t6o;
let b5o = t1o ^ t4o;
let b2o = t1o ^ t6o;
let t10o = r2 ^ t5o;
let b3o = r10 ^ r8;
let b1o = 1 ^ (t3o ^ b3o);
let b6o = t10o ^ b1o;
let b4o = 1 ^ (t3o ^ t7o);
let b0o = t6o ^ b4o;
let b7o = 1 ^ (r10 ^ r6);
let b3o = r10 ^ r8;
let b1o = 1 ^ (t3o ^ b3o);
let b6o = t10o ^ b1o;
let b4o = 1 ^ (t3o ^ t7o);
let b0o = t6o ^ b4o;
let b7o = 1 ^ (r10 ^ r6);
// 将 8 个输出位重组为字节
b0o | (b1o << 1) | (b2o << 2) | (b3o << 3)
| (b4o << 4) | (b5o << 5) | (b6o << 6) | (b7o << 7)
b0o | (b1o << 1) | (b2o << 2) | (b3o << 3) | (b4o << 4) | (b5o << 5) | (b6o << 6) | (b7o << 7)
}
/// SM4 τ 变换:4 字节 u32 一次性位切片 S-box(常量时间,4-way 并行)
@@ -197,8 +215,8 @@ fn tau(a: u32) -> u32 {
// Reason: 打包后每个 u32 变量的 bit-j 对应第 j 个字节的该位面,
// XOR/AND/OR 在 4 个独立"通道"上并行执行,语义不变。
let mut bits = [0u32; 8];
for i in 0..8usize {
bits[i] = ((bytes[0] >> i) & 1) as u32
for (i, bit) in bits.iter_mut().enumerate() {
*bit = ((bytes[0] >> i) & 1) as u32
| (((bytes[1] >> i) & 1) as u32) << 1
| (((bytes[2] >> i) & 1) as u32) << 2
| (((bytes[3] >> i) & 1) as u32) << 3;
@@ -208,75 +226,136 @@ fn tau(a: u32) -> u32 {
// ── S-box 布尔电路(与 sbox_ct 完全相同,1 → 0xF)────────────────────
// Reason: sbox_ct 用 `1 ^ x` 表示 NOT;此处 4 通道并行故改为 `0xF ^ x`
// 使 4 个 bit 位置都被正确取反,其余位运算(^/&/|)无需修改。
let t1 = b7 ^ b5;
let t2 = 0xF ^ (b5 ^ b1);
let g5 = 0xF ^ b0;
let t3 = 0xF ^ (b0 ^ t2);
let t4 = b6 ^ b2;
let t5 = b3 ^ t3;
let t6 = b4 ^ t1;
let t7 = b1 ^ t5;
let t8 = b1 ^ t4;
let t9 = t6 ^ t8;
let t1 = b7 ^ b5;
let t2 = 0xF ^ (b5 ^ b1);
let g5 = 0xF ^ b0;
let t3 = 0xF ^ (b0 ^ t2);
let t4 = b6 ^ b2;
let t5 = b3 ^ t3;
let t6 = b4 ^ t1;
let t7 = b1 ^ t5;
let t8 = b1 ^ t4;
let t9 = t6 ^ t8;
let t10 = t6 ^ t7;
let t11 = 0xF ^ (b3 ^ t1);
let t12 = 0xF ^ (b6 ^ t9);
let g0 = t10; let g1 = t7; let g2 = t4 ^ t10; let g3 = t5;
let g4 = t2; let g6 = t11 ^ t2; let g7 = t12 ^ (t11 ^ t2);
let m0 = t6; let m1 = t3; let m2 = t8; let m3 = t3 ^ t12;
let m4 = t4; let m5 = t11; let m6 = b1; let m7 = t11 ^ m3;
let m8 = t9; let m9 = t12;
let g0 = t10;
let g1 = t7;
let g2 = t4 ^ t10;
let g3 = t5;
let g4 = t2;
let g6 = t11 ^ t2;
let g7 = t12 ^ (t11 ^ t2);
let m0 = t6;
let m1 = t3;
let m2 = t8;
let m3 = t3 ^ t12;
let m4 = t4;
let m5 = t11;
let m6 = b1;
let m7 = t11 ^ m3;
let m8 = t9;
let m9 = t12;
let t2t = m0 & m1; let t3t = g0 & g4; let t4t = g3 & g7;
let t7t = g3 | g7; let t11t = m4 & m5; let t10t = m3 & m2;
let t12t = m3 | m2; let t6t = g6 | g2; let t9t = m6 | m7;
let t5t = m8 & m9; let t8t = m8 | m9;
let t14t = t3t ^ t2t; let t16t = t5t ^ t14t; let t20t = t16t ^ t7t;
let t17t = t9t ^ t10t; let t18t = t11t ^ t12t;
let p2 = t20t ^ t18t; let p0 = t6t ^ t16t;
let t1t = g5 & g1; let t13t = t1t ^ t2t; let t15t = t13t ^ t4t;
let p3 = (t6t ^ t15t) ^ t17t; let p1 = t8t ^ t15t;
let t2t = m0 & m1;
let t3t = g0 & g4;
let t4t = g3 & g7;
let t7t = g3 | g7;
let t11t = m4 & m5;
let t10t = m3 & m2;
let t12t = m3 | m2;
let t6t = g6 | g2;
let t9t = m6 | m7;
let t5t = m8 & m9;
let t8t = m8 | m9;
let t14t = t3t ^ t2t;
let t16t = t5t ^ t14t;
let t20t = t16t ^ t7t;
let t17t = t9t ^ t10t;
let t18t = t11t ^ t12t;
let p2 = t20t ^ t18t;
let p0 = t6t ^ t16t;
let t1t = g5 & g1;
let t13t = t1t ^ t2t;
let t15t = t13t ^ t4t;
let p3 = (t6t ^ t15t) ^ t17t;
let p1 = t8t ^ t15t;
let t0m = p1 & p2; let t1m = p3 & p0; let t2m = p0 & p2;
let t3m = p1 & p3; let t4m = t0m & t2m; let t5m = t1m ^ t3m;
let t6m = t5m | p0; let t7m = t2m | p3;
let l3 = t4m ^ t6m; let t9m = t7m ^ t3m; let l0 = t0m ^ t9m;
let t11m = p2 | t5m; let l1 = t11m ^ t1m;
let t12m = p1 | t2m; let l2 = t12m ^ t5m;
let t0m = p1 & p2;
let t1m = p3 & p0;
let t2m = p0 & p2;
let t3m = p1 & p3;
let t4m = t0m & t2m;
let t5m = t1m ^ t3m;
let t6m = t5m | p0;
let t7m = t2m | p3;
let l3 = t4m ^ t6m;
let t9m = t7m ^ t3m;
let l0 = t0m ^ t9m;
let t11m = p2 | t5m;
let l1 = t11m ^ t1m;
let t12m = p1 | t2m;
let l2 = t12m ^ t5m;
let k4 = l2 ^ l3; let k3 = l1 ^ l3; let k2 = l0 ^ l2;
let k0 = l0 ^ l1; let k1 = k2 ^ k3;
let k4 = l2 ^ l3;
let k3 = l1 ^ l3;
let k2 = l0 ^ l2;
let k0 = l0 ^ l1;
let k1 = k2 ^ k3;
let e0 = m1 & k0; let e1 = g5 & l1; let r0 = e0 ^ e1;
let e2 = g4 & l0; let r1 = e2 ^ e1;
let e3 = m7 & k3; let e4 = m5 & k2; let r2 = e3 ^ e4;
let e5 = m3 & k1; let r3 = e5 ^ e4;
let e6 = m9 & k4; let e7 = g7 & l3; let r4 = e6 ^ e7;
let e8 = g6 & l2; let r5 = e8 ^ e7;
let e9 = m0 & k0; let e10 = g1 & l1; let r6 = e9 ^ e10;
let e11 = g0 & l0; let r7 = e11 ^ e10;
let e12 = m6 & k3; let e13 = m4 & k2; let r8 = e12 ^ e13;
let e14 = m2 & k1; let r9 = e14 ^ e13;
let e15 = m8 & k4; let e16 = g3 & l3; let r10 = e15 ^ e16;
let e17 = g2 & l2; let r11 = e17 ^ e16;
let e0 = m1 & k0;
let e1 = g5 & l1;
let r0 = e0 ^ e1;
let e2 = g4 & l0;
let r1 = e2 ^ e1;
let e3 = m7 & k3;
let e4 = m5 & k2;
let r2 = e3 ^ e4;
let e5 = m3 & k1;
let r3 = e5 ^ e4;
let e6 = m9 & k4;
let e7 = g7 & l3;
let r4 = e6 ^ e7;
let e8 = g6 & l2;
let r5 = e8 ^ e7;
let e9 = m0 & k0;
let e10 = g1 & l1;
let r6 = e9 ^ e10;
let e11 = g0 & l0;
let r7 = e11 ^ e10;
let e12 = m6 & k3;
let e13 = m4 & k2;
let r8 = e12 ^ e13;
let e14 = m2 & k1;
let r9 = e14 ^ e13;
let e15 = m8 & k4;
let e16 = g3 & l3;
let r10 = e15 ^ e16;
let e17 = g2 & l2;
let r11 = e17 ^ e16;
let t1o = r7 ^ r9; let t2o = r1 ^ t1o; let t3o = r3 ^ t2o;
let t4o = r5 ^ r3; let t5o = r4 ^ t4o; let t6o = r0 ^ r4;
let t7o = r11 ^ r7;
let b5o = t1o ^ t4o; let b2o = t1o ^ t6o; let t10o = r2 ^ t5o;
let b3o = r10 ^ r8;
let b1o = 0xF ^ (t3o ^ b3o);
let b6o = t10o ^ b1o;
let b4o = 0xF ^ (t3o ^ t7o);
let b0o = t6o ^ b4o;
let b7o = 0xF ^ (r10 ^ r6);
let t1o = r7 ^ r9;
let t2o = r1 ^ t1o;
let t3o = r3 ^ t2o;
let t4o = r5 ^ r3;
let t5o = r4 ^ t4o;
let t6o = r0 ^ r4;
let t7o = r11 ^ r7;
let b5o = t1o ^ t4o;
let b2o = t1o ^ t6o;
let t10o = r2 ^ t5o;
let b3o = r10 ^ r8;
let b1o = 0xF ^ (t3o ^ b3o);
let b6o = t10o ^ b1o;
let b4o = 0xF ^ (t3o ^ t7o);
let b0o = t6o ^ b4o;
let b7o = 0xF ^ (r10 ^ r6);
// ── 解包:8 个 u32 低 4 位 → 4 个输出字节 ──────────────────────────────
let ob = [b0o, b1o, b2o, b3o, b4o, b5o, b6o, b7o];
let mut out = [0u8; 4];
for i in 0..8usize {
let v = ob[i];
for (i, &v) in ob.iter().enumerate() {
out[0] |= ((v & 1) as u8) << i;
out[1] |= (((v >> 1) & 1) as u8) << i;
out[2] |= (((v >> 2) & 1) as u8) << i;
+1 -1
View File
@@ -770,7 +770,7 @@ mod tests {
);
// 非 16 倍数
assert!(
sm4_encrypt_xts(&key1, &key2, &tweak, b"not-aligned-data").is_err() == false,
sm4_encrypt_xts(&key1, &key2, &tweak, b"not-aligned-data").is_ok(),
"正好 16 字节不应返回错误"
);
assert!(
+85 -33
View File
@@ -1,9 +1,9 @@
//! SM9 BN256 六次/十二次扩域 Fp6 / Fp12
//!
//! 塔式扩域:
//! Fp2 = Fp[u]/(u²+2)
//! Fp6 = Fp2[v]/(v³-u) 即 v³ = u
//! Fp12 = Fp6[w]/(w²-v) 即 w² = v
//! `Fp2 = Fp[u]/(u²+2)`
//! `Fp6 = Fp2[v]/(v³-u)` 即 v³ = u
//! `Fp12 = Fp6[w]/(w²-v)` 即 w² = v
//!
//! Frobenius 系数为编译期常量,源自 GB/T 38635.1-2020 及参考实现。
@@ -527,7 +527,6 @@ pub fn fp12_mul_by_line(f: &Fp12, l: &LineEval) -> Fp12 {
fp12_mul(f, &line_fp12)
}
#[cfg(test)]
mod tests {
use super::*;
@@ -592,15 +591,25 @@ mod tests {
/// 验证稀疏线函数乘法与全量 fp12_mul 结果一致
#[test]
fn test_fp12_mul_by_line_matches_full_mul() { // 构造一个非平凡的 f
fn test_fp12_mul_by_line_matches_full_mul() {
// 构造一个非平凡的 f
let f = Fp12 {
c0: Fp6 {
c0: Fp2 { c0: Fp::ONE, c1: Fp::ONE },
c1: Fp2 { c0: Fp::ONE, c1: Fp::ZERO },
c0: Fp2 {
c0: Fp::ONE,
c1: Fp::ONE,
},
c1: Fp2 {
c0: Fp::ONE,
c1: Fp::ZERO,
},
c2: Fp2::ZERO,
},
c1: Fp6 {
c0: Fp2 { c0: Fp::ZERO, c1: Fp::ONE },
c0: Fp2 {
c0: Fp::ZERO,
c1: Fp::ONE,
},
c1: Fp2::ZERO,
c2: Fp2::ZERO,
},
@@ -608,9 +617,18 @@ mod tests {
// 构造非零线函数
let l = LineEval {
a: Fp2 { c0: Fp::ONE, c1: Fp::ONE },
b: Fp2 { c0: Fp::ONE, c1: Fp::ZERO },
c: Fp2 { c0: Fp::ZERO, c1: Fp::ONE },
a: Fp2 {
c0: Fp::ONE,
c1: Fp::ONE,
},
b: Fp2 {
c0: Fp::ONE,
c1: Fp::ZERO,
},
c: Fp2 {
c0: Fp::ZERO,
c1: Fp::ONE,
},
};
// 稀疏乘法结果
@@ -619,8 +637,16 @@ mod tests {
// 构造全量 Fp12 线函数并做全量乘法(与 fp12_mul_by_line slot 保持一致)
// 槽位约定:a→c0.c0(1), b→c1.c1(vw), c→c1.c2(v²w)
let line_full = Fp12 {
c0: Fp6 { c0: l.a, c1: Fp2::ZERO, c2: Fp2::ZERO },
c1: Fp6 { c0: Fp2::ZERO, c1: l.b, c2: l.c },
c0: Fp6 {
c0: l.a,
c1: Fp2::ZERO,
c2: Fp2::ZERO,
},
c1: Fp6 {
c0: Fp2::ZERO,
c1: l.b,
c2: l.c,
},
};
let full = fp12_mul(&f, &line_full);
@@ -632,17 +658,34 @@ mod tests {
fn test_frob_w3_derivation() {
// 验证 fp12 Frobenius 一致性:frob_p(frob_p(f)) == frob_p2(f)
let f = Fp12 {
c0: Fp6 { c0: Fp2 { c0: Fp::ONE, c1: Fp::ONE }, c1: Fp2::ONE, c2: Fp2::ZERO },
c1: Fp6 { c0: Fp2::ONE, c1: Fp2::ZERO, c2: Fp2::ZERO },
c0: Fp6 {
c0: Fp2 {
c0: Fp::ONE,
c1: Fp::ONE,
},
c1: Fp2::ONE,
c2: Fp2::ZERO,
},
c1: Fp6 {
c0: Fp2::ONE,
c1: Fp2::ZERO,
c2: Fp2::ZERO,
},
};
let fp1 = fp12_frobenius_p(&f);
let fp1p1 = fp12_frobenius_p(&fp1); // frob_p^2(f)
let fp1p1 = fp12_frobenius_p(&fp1); // frob_p^2(f)
let fp2 = fp12_frobenius_p2(&f);
assert_eq!(fp1p1, fp2, "frob_p(frob_p(f)) != frob_p2(f)fp12 Frobenius 不一致");
assert_eq!(
fp1p1, fp2,
"frob_p(frob_p(f)) != frob_p2(f)fp12 Frobenius 不一致"
);
let fp2p1 = fp12_frobenius_p(&fp2); // frob_p^3(f)
let fp2p1 = fp12_frobenius_p(&fp2); // frob_p^3(f)
let fp3 = fp12_frobenius_p3(&f);
assert_eq!(fp2p1, fp3, "frob_p(frob_p2(f)) != frob_p3(f)fp12_frobenius_p3 系数错误");
assert_eq!(
fp2p1, fp3,
"frob_p(frob_p2(f)) != frob_p3(f)fp12_frobenius_p3 系数错误"
);
}
/// 验证 Fp6 Frobenius 保持 ONE
@@ -662,7 +705,10 @@ mod tests {
fn test_frob_v1_squared() {
use crate::sm9::fields::fp2::fp2_mul;
let v1_sq = fp2_mul(&FROB_V1_0, &FROB_V1_0);
assert_eq!(v1_sq, FROB_V1_1, "FROB_V1_0² 应等于 FROB_V1_1fp6 Frobenius 一致性)");
assert_eq!(
v1_sq, FROB_V1_1,
"FROB_V1_0² 应等于 FROB_V1_1fp6 Frobenius 一致性)"
);
}
/// 计算 u^{(p-1)/3} 并与 FROB_V1_0 对比(验证常量正确性)
@@ -671,14 +717,15 @@ mod tests {
#[test]
fn test_frob_v1_0_value_correct() {
use crate::sm9::fields::fp::FIELD_MODULUS;
use crate::sm9::fields::fp2::{fp2_mul, fp2_square};
use subtle::ConditionallySelectable;
use crate::sm9::fields::fp2::fp2_mul;
// 计算 u^{(p-1)/3} 其中 u = (0, 1) ∈ Fp2
let pm1 = FIELD_MODULUS.wrapping_sub(&crypto_bigint::U256::ONE);
let (pm1_div3, rem) = pm1.div_rem(&crypto_bigint::NonZero::new(crypto_bigint::U256::from(3u32)).unwrap());
let (pm1_div3, rem) =
pm1.div_rem(&crypto_bigint::NonZero::new(crypto_bigint::U256::from(3u32)).unwrap());
assert_eq!(rem, crypto_bigint::U256::ZERO, "(p-1) 应被 3 整除");
let (pm1_div6, _) = pm1.div_rem(&crypto_bigint::NonZero::new(crypto_bigint::U256::from(6u32)).unwrap());
let (pm1_div6, _) =
pm1.div_rem(&crypto_bigint::NonZero::new(crypto_bigint::U256::from(6u32)).unwrap());
fn fp2_pow_exp(base: &Fp2, exp: &crypto_bigint::U256) -> Fp2 {
use crate::sm9::fields::fp2::{fp2_mul, fp2_square};
@@ -696,7 +743,10 @@ mod tests {
result
}
let u = Fp2 { c0: crate::sm9::fields::fp::Fp::ZERO, c1: crate::sm9::fields::fp::Fp::ONE };
let u = Fp2 {
c0: crate::sm9::fields::fp::Fp::ZERO,
c1: crate::sm9::fields::fp::Fp::ONE,
};
// 正确的 γ_{1,1} = u^{(p-1)/3}
let correct_v1_0 = fp2_pow_exp(&u, &pm1_div3);
// 正确的 δ_{1,1} = u^{(p-1)/6}FROB_W1
@@ -708,7 +758,8 @@ mod tests {
// 打印正确的常量值(以标准 32 字节大端 hex 格式,供直接写入代码)
assert_eq!(
correct_v1_0, FROB_V1_0,
correct_v1_0,
FROB_V1_0,
"FROB_V1_0 需更新:正确值={:02X?}, FROB_W1 正确值 c0={:02X?} c1={:02X?}",
correct_v1_0.c0.retrieve().to_be_bytes(),
correct_w1.c0.retrieve().to_be_bytes(),
@@ -743,24 +794,25 @@ mod g2_frob_tests {
let p = FIELD_MODULUS;
let pm1 = p.wrapping_sub(&crypto_bigint::U256::ONE);
let u = Fp2 { c0: Fp::ZERO, c1: Fp::ONE };
let u = Fp2 {
c0: Fp::ZERO,
c1: Fp::ONE,
};
let pm1_div2 = pm1.wrapping_shr(1);
let u_pm1_div2 = fp2_pow_exp(&u, &pm1_div2);
let (pm1_div3, _) = pm1.div_rem(&crypto_bigint::NonZero::new(crypto_bigint::U256::from(3u32)).unwrap());
let (pm1_div3, _) =
pm1.div_rem(&crypto_bigint::NonZero::new(crypto_bigint::U256::from(3u32)).unwrap());
let u_pm1_div3 = fp2_pow_exp(&u, &pm1_div3);
let pp1 = p.wrapping_add(&crypto_bigint::U256::ONE);
let u_pm21_div3 = fp2_pow_exp(&u_pm1_div3, &pp1);
let u_pm21_div2 = fp2_pow_exp(&u_pm1_div2, &pp1);
// Reason: 验证 G2 Frobenius 修正常量与计算值一致
// u^{(p-1)/2} 应等于 G2_FROB_Y1
assert_eq!(u_pm1_div2, G2_FROB_Y1,
"u^(p-1)/2 应等于 G2_FROB_Y1");
assert_eq!(u_pm1_div2, G2_FROB_Y1, "u^(p-1)/2 应等于 G2_FROB_Y1");
// u^{(p²-1)/3} 应等于 G2_FROB_X2
assert_eq!(u_pm21_div3, G2_FROB_X2,
"u^(p2-1)/3 应等于 G2_FROB_X2");
assert_eq!(u_pm21_div3, G2_FROB_X2, "u^(p2-1)/3 应等于 G2_FROB_X2");
}
}
+1 -2
View File
@@ -1,6 +1,6 @@
//! SM9 BN256 二次扩域 Fp2
//!
//! Fp2 = Fp[u] / (u² + 2)
//! `Fp2 = Fp[u] / (u² + 2)`
//! 即 u² = -2
//!
//! 元素表示为 a = a0 + a1·u,其中 a0, a1 ∈ Fp
@@ -177,7 +177,6 @@ pub fn fp2_conjugate(a: &Fp2) -> Fp2 {
#[cfg(test)]
mod tests {
use super::*;
use crate::sm9::fields::fp::fp_from_bytes;
fn fp2_one() -> Fp2 {
Fp2::ONE
+1 -1
View File
@@ -88,7 +88,7 @@ impl G1Jacobian {
/// 点倍运算(BN256 a=0 专用公式)
///
/// 公式来自 https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
/// 公式来自 <https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l>
pub fn double(&self) -> Self {
if self.is_infinity() {
return *self;
+4 -4
View File
@@ -149,9 +149,9 @@ impl G2Jacobian {
// c = -3X₁²·Z₁² = -e·z1sq(在 eval_line_at_p 中乘以 xP→c1.c2(v²w)
let z1sq = fp2_square(z1);
let line = LineEval {
a: fp2_mul_u(&fp2_mul(&z3, &z1sq)), // 2Y₁Z₁³·u(×yP→c0.c0
a: fp2_mul_u(&fp2_mul(&z3, &z1sq)), // 2Y₁Z₁³·u(×yP→c0.c0
b: fp2_sub(&fp2_mul(x1, &e), &fp2_add(&b, &b)), // 3X₁³-2Y₁²(→c1.c1(vw)
c: fp2_neg(&fp2_mul(&e, &z1sq)), // -3X₁²Z₁²(×xP→c1.c2(v²w)
c: fp2_neg(&fp2_mul(&e, &z1sq)), // -3X₁²Z₁²(×xP→c1.c2(v²w)
};
(
@@ -190,9 +190,9 @@ impl G2Jacobian {
// b = X₁·Y₂·Z₁ - X₂·Y₁(常数项→c1.c1(vw)
// c = -(Y₂Z₁³-Y₁) = -rr已算,在 eval_line_at_p 中乘以 xP→c1.c2(v²w)
let line = LineEval {
a: fp2_mul_u(&z3), // H·Z₁·u(×yP→c0.c0
a: fp2_mul_u(&z3), // H·Z₁·u(×yP→c0.c0
b: fp2_sub(&fp2_mul(&fp2_mul(x1, z1), y2), &fp2_mul(x2, y1)), // X₁Y₂Z₁-X₂Y₁(→c1.c1(vw)
c: fp2_neg(&r), // -(Y₂Z₁³-Y₁)(×xP→c1.c2(v²w)
c: fp2_neg(&r), // -(Y₂Z₁³-Y₁)(×xP→c1.c2(v²w)
};
(
+86 -36
View File
@@ -158,7 +158,7 @@ pub fn generate_sign_master_keypair<R: RngCore>(rng: &mut R) -> (Sm9MasterPrivKe
/// GB/T 38635.2-2020 §6.1
/// t1 = H1(ID||hid, N) + ks
/// t2 = ks · t1^{-1} mod N(注意:不是 t1^{-1}·P1,而是 ks·t1^{-1}·P1
/// dA = [t2]P1
/// dA = \[t2\]P1
/// hid = 0x01(签名)
pub fn generate_sign_user_key(
master_priv: &Sm9MasterPrivKey,
@@ -218,7 +218,7 @@ pub fn generate_enc_master_keypair<R: RngCore>(rng: &mut R) -> (Sm9MasterPrivKey
/// GB/T 38635.1-2020 §6.1(加密密钥派生):
/// t1 = H1(ID||hid, N) + ke
/// t2 = ke · t1^{-1} mod N
/// de = [t2]P1
/// de = \[t2\]P1
pub fn generate_enc_user_key(
master_priv: &Sm9MasterPrivKey,
id: &[u8],
@@ -576,7 +576,7 @@ mod tests {
#[test]
fn test_generate_sign_master_keypair() {
let mut rng = FakeRng([0x42u8; 32]);
let (ks, ppub) = generate_sign_master_keypair(&mut rng);
let (_ks, ppub) = generate_sign_master_keypair(&mut rng);
// 验证 ppub 在 G2 上
let p = G2Affine::from_bytes(ppub.as_bytes()).expect("公钥应有效");
assert!(p.is_on_curve());
@@ -607,7 +607,7 @@ mod tests {
#[test]
fn test_pairing_bilinear() {
use crate::sm9::fields::fp12::{fp12_mul, Fp12};
use crate::sm9::fields::fp12::fp12_mul;
use crate::sm9::groups::g1::{G1Affine, G1Jacobian};
use crate::sm9::groups::g2::{G2Affine, G2Jacobian};
use crate::sm9::pairing::pairing;
@@ -617,24 +617,33 @@ mod tests {
let q = G2Affine::generator();
// 验证 G1 scalar_mul(2) == G1.double()
let g1_2_by_mul = G1Jacobian::scalar_mul_g1(&U256::from(2u32)).to_affine().unwrap();
let g1_2_by_mul = G1Jacobian::scalar_mul_g1(&U256::from(2u32))
.to_affine()
.unwrap();
let g1_jac = G1Jacobian::from_affine(&p);
let g1_2_by_double = g1_jac.double().to_affine().unwrap();
use crate::sm9::fields::fp::fp_to_bytes;
assert_eq!(
fp_to_bytes(&g1_2_by_mul.x), fp_to_bytes(&g1_2_by_double.x),
fp_to_bytes(&g1_2_by_mul.x),
fp_to_bytes(&g1_2_by_double.x),
"G1 scalar_mul(2) != G1.double() in x"
);
assert_eq!(
fp_to_bytes(&g1_2_by_mul.y), fp_to_bytes(&g1_2_by_double.y),
fp_to_bytes(&g1_2_by_mul.y),
fp_to_bytes(&g1_2_by_double.y),
"G1 scalar_mul(2) != G1.double() in y"
);
// 验证 G2 scalar_mul(2) == G2.double()
let g2_jac = G2Jacobian::from_affine(&q);
let g2_2_by_mul = G2Jacobian::scalar_mul_g2(&U256::from(2u32)).to_affine().unwrap();
let g2_2_by_mul = G2Jacobian::scalar_mul_g2(&U256::from(2u32))
.to_affine()
.unwrap();
let g2_2_by_double = g2_jac.double().to_affine().unwrap();
assert_eq!(g2_2_by_mul, g2_2_by_double, "G2 scalar_mul(2) != G2.double()");
assert_eq!(
g2_2_by_mul, g2_2_by_double,
"G2 scalar_mul(2) != G2.double()"
);
// e(2G1, G2) == e(G1, G2)^2
let e_2g1_g2 = pairing(&g1_2_by_mul, &q);
@@ -643,25 +652,30 @@ mod tests {
// 中间验证:用 G1+G1 (点加法)得到 2G1
let g1_jac2 = G1Jacobian::from_affine(&p);
let g1_add_g1 = G1Jacobian::add(&G1Jacobian::from_affine(&p), &g1_jac2).to_affine().unwrap();
let g1_add_g1 = G1Jacobian::add(&G1Jacobian::from_affine(&p), &g1_jac2)
.to_affine()
.unwrap();
let e_addg1_g2 = pairing(&g1_add_g1, &q);
assert_eq!(e_addg1_g2, e_sq, "e(G1+G1,G2) != e(G1,G2)²(用点加法)");
assert_eq!(e_2g1_g2, e_sq, "配对双线性性验证失败:e(2G1,G2) != e(G1,G2)²");
assert_eq!(
e_2g1_g2, e_sq,
"配对双线性性验证失败:e(2G1,G2) != e(G1,G2)²"
);
// e(G1, 2G2) == e(G1, G2)^2
let e_g1_2g2 = pairing(&p, &g2_2_by_mul);
assert_eq!(e_g1_2g2, e_sq, "配对双线性性验证失败:e(G1,2G2) != e(G1,G2)²");
assert_eq!(
e_g1_2g2, e_sq,
"配对双线性性验证失败:e(G1,2G2) != e(G1,G2)²"
);
}
}
#[cfg(test)]
mod pairing_tests {
use super::*;
use crate::sm9::fields::fp12::{
fp12_conjugate, fp12_frobenius_p, fp12_frobenius_p2, fp12_frobenius_p3,
fp12_inv, fp12_mul, fp12_square, Fp12,
};
use crate::sm9::fields::fp12::{fp12_conjugate, fp12_frobenius_p, fp12_mul, fp12_square, Fp12};
use crate::sm9::groups::g1::{G1Affine, G1Jacobian};
use crate::sm9::groups::g2::{G2Affine, G2Jacobian};
use crate::sm9::pairing::{final_exp, miller_loop, pairing};
@@ -671,7 +685,9 @@ mod pairing_tests {
fn test_pairing_double_only() {
let p = G1Affine::generator();
let q = G2Affine::generator();
let g1_2 = G1Jacobian::scalar_mul_g1(&U256::from(2u32)).to_affine().unwrap();
let g1_2 = G1Jacobian::scalar_mul_g1(&U256::from(2u32))
.to_affine()
.unwrap();
let e_g1_g2 = pairing(&p, &q);
let e_sq = fp12_mul(&e_g1_g2, &e_g1_g2);
@@ -687,7 +703,9 @@ mod pairing_tests {
fn test_miller_loop_raw_bilinear() {
let p = G1Affine::generator();
let q = G2Affine::generator();
let g1_2 = G1Jacobian::scalar_mul_g1(&U256::from(2u32)).to_affine().unwrap();
let g1_2 = G1Jacobian::scalar_mul_g1(&U256::from(2u32))
.to_affine()
.unwrap();
let ml1 = miller_loop(&q, &p);
let ml2 = miller_loop(&q, &g1_2);
@@ -699,14 +717,20 @@ mod pairing_tests {
let ml1_sq_inv = fp12_inv(&ml1_sq).expect("inv should exist");
let ratio = fp12_mul(&ml2, &ml1_sq_inv);
let ratio_exp = final_exp(&ratio);
assert_eq!(ratio_exp, Fp12::ONE, "final_exp(ml(2G1,G2)/ml(G1,G2)^2) != 1");
assert_eq!(
ratio_exp,
Fp12::ONE,
"final_exp(ml(2G1,G2)/ml(G1,G2)^2) != 1"
);
}
#[test]
fn test_miller_loop_bilinear() {
let p = G1Affine::generator();
let q = G2Affine::generator();
let g1_2 = G1Jacobian::scalar_mul_g1(&U256::from(2u32)).to_affine().unwrap();
let g1_2 = G1Jacobian::scalar_mul_g1(&U256::from(2u32))
.to_affine()
.unwrap();
let ml_g1_g2 = miller_loop(&q, &p);
let ml_2g1_g2 = miller_loop(&q, &g1_2);
@@ -714,7 +738,10 @@ mod pairing_tests {
let gt1 = final_exp(&ml_g1_g2);
let gt2 = final_exp(&ml_2g1_g2);
let gt1_sq = fp12_square(&gt1);
assert_eq!(gt2, gt1_sq, "final_exp(ml(2G1,G2)) != final_exp(ml(G1,G2))^2");
assert_eq!(
gt2, gt1_sq,
"final_exp(ml(2G1,G2)) != final_exp(ml(G1,G2))^2"
);
}
#[test]
@@ -736,7 +763,11 @@ mod pairing_tests {
base = fp12_mul(&base, &base);
}
}
assert_eq!(result, Fp12::ONE, "e(G1,G2)^n != 1: GT element not in subgroup");
assert_eq!(
result,
Fp12::ONE,
"e(G1,G2)^n != 1: GT element not in subgroup"
);
}
/// 验证 ml^{p^6} == conjugate(ml)Frobenius 正确性检查)
@@ -746,8 +777,9 @@ mod pairing_tests {
let q = G2Affine::generator();
let ml = miller_loop(&q, &p);
let ml_p6 = fp12_frobenius_p(&fp12_frobenius_p(&fp12_frobenius_p(
&fp12_frobenius_p(&fp12_frobenius_p(&fp12_frobenius_p(&ml))))));
let ml_p6 = fp12_frobenius_p(&fp12_frobenius_p(&fp12_frobenius_p(&fp12_frobenius_p(
&fp12_frobenius_p(&fp12_frobenius_p(&ml)),
))));
let ml_conj = fp12_conjugate(&ml);
assert_eq!(ml_p6, ml_conj, "ml^{{p^6}} != conjugate(ml)");
}
@@ -759,7 +791,6 @@ mod pairing_tests {
#[test]
fn test_single_double_step_line() {
use crate::sm9::fields::fp::fp_to_bytes;
use crate::sm9::fields::fp12::fp12_inv;
let g1 = G1Affine::generator();
let g2 = G2Affine::generator();
@@ -773,7 +804,9 @@ mod pairing_tests {
let g1_jac = G1Jacobian::from_affine(&g1);
let g1_2_by_add = G1Jacobian::add(&g1_jac, &g1_jac).to_affine().unwrap();
// 用标量乘法计算 2·G1
let g1_2_by_mul = G1Jacobian::scalar_mul_g1(&U256::from(2u32)).to_affine().unwrap();
let g1_2_by_mul = G1Jacobian::scalar_mul_g1(&U256::from(2u32))
.to_affine()
.unwrap();
// 验证两种方式得到相同的 2G1
assert_eq!(
@@ -788,7 +821,9 @@ mod pairing_tests {
);
// 检验 G2 侧双线性性:e(G1, 2G2) == e(G1, G2)^2
let g2_2 = G2Jacobian::scalar_mul_g2(&U256::from(2u32)).to_affine().unwrap();
let g2_2 = G2Jacobian::scalar_mul_g2(&U256::from(2u32))
.to_affine()
.unwrap();
let e_g1_2g2 = pairing(&g1, &g2_2);
let e_g1_g2_sq = fp12_mul(&e1, &e1);
assert_eq!(
@@ -804,25 +839,40 @@ mod pairing_tests {
/// 约定:a -> c0.c0(1 slot), b -> c0.c1(v slot), c -> c1.c0(w slot)
#[test]
fn test_line_eval_equivalence() {
use crate::sm9::fields::fp12::{
fp12_mul, fp12_mul_by_line, Fp12, Fp6, LineEval,
};
use crate::sm9::fields::fp2::Fp2;
use crate::sm9::fields::fp::Fp;
use crate::sm9::fields::fp12::{fp12_mul, fp12_mul_by_line, Fp12, Fp6, LineEval};
use crate::sm9::fields::fp2::Fp2;
// 验证 fp12_mul_by_line 等价于按约定槽位构造 full Fp12 再乘
// 约定:a -> c0.c0(1 slot), b -> c1.c1(vw slot), c -> c1.c2(v²w slot)
let line = LineEval {
a: Fp2 { c0: Fp::ONE, c1: Fp::ZERO },
b: Fp2 { c0: Fp::ONE, c1: Fp::ZERO },
c: Fp2 { c0: Fp::ONE, c1: Fp::ZERO },
a: Fp2 {
c0: Fp::ONE,
c1: Fp::ZERO,
},
b: Fp2 {
c0: Fp::ONE,
c1: Fp::ZERO,
},
c: Fp2 {
c0: Fp::ONE,
c1: Fp::ZERO,
},
};
let f = Fp12::ONE;
let sparse_result = fp12_mul_by_line(&f, &line);
// 按相同槽位手动构造 full Fp12(槽位 {c0.c0=a, c1.c1(vw)=b, c1.c2(v²w)=c}
let full_line = Fp12 {
c0: Fp6 { c0: line.a, c1: Fp2::ZERO, c2: Fp2::ZERO },
c1: Fp6 { c0: Fp2::ZERO, c1: line.b, c2: line.c },
c0: Fp6 {
c0: line.a,
c1: Fp2::ZERO,
c2: Fp2::ZERO,
},
c1: Fp6 {
c0: Fp2::ZERO,
c1: line.b,
c2: line.c,
},
};
let full_result = fp12_mul(&f, &full_line);
assert_eq!(
+21 -22
View File
@@ -9,9 +9,8 @@
use crate::sm9::fields::fp::Fp;
use crate::sm9::fields::fp12::{
fp12_conjugate, fp12_frobenius_p, fp12_frobenius_p2, fp12_frobenius_p3,
fp12_inv, fp12_mul, fp12_mul_by_line, fp12_square, Fp12, LineEval,
G2_FROB_X1_INV, G2_FROB_Y1_INV, G2_FROB_X2_INV,
fp12_conjugate, fp12_frobenius_p, fp12_frobenius_p2, fp12_frobenius_p3, fp12_inv, fp12_mul,
fp12_mul_by_line, fp12_square, Fp12, LineEval, G2_FROB_X1_INV, G2_FROB_X2_INV, G2_FROB_Y1_INV,
};
use crate::sm9::fields::fp2::{fp2_frobenius, fp2_mul, fp2_mul_fp};
use crate::sm9::groups::g1::G1Affine;
@@ -63,7 +62,7 @@ fn g2_frobenius_p2_neg(q: &G2Affine) -> G2Affine {
fn eval_line_at_p(line: &LineEval, px: &Fp, py: &Fp) -> LineEval {
LineEval {
a: fp2_mul_fp(&line.a, py), // a × yP(放 c0.c0 槽)
b: line.b, // 常数项不变(放 c0.c1 v 槽)
b: line.b, // 常数项不变(放 c0.c1 v 槽)
c: fp2_mul_fp(&line.c, px), // c × xP(放 c1.c0 w 槽)
}
}
@@ -167,25 +166,25 @@ const SM9_NINE: u128 = 9;
/// Reason: Beuchat et al. 分解针对标准 BN256(以太坊参数),不适用于 SM9 BN256。
/// 此函数使用 sm9_core 的 final_exp_last_chunk 算法(基于 SM9_A2/A3 常量)。
fn final_exp_hard(f: &Fp12) -> Fp12 {
let a = fp12_cyclotomic_pow(f, SM9_A3); // f^{A3}
let b = fp12_inv(&a).unwrap_or(Fp12::ONE); // f^{-A3}
let c = fp12_frobenius_p(&b); // f^{-A3*p}
let d = fp12_mul(&c, &b); // f^{-A3*(p+1)}
let e = fp12_mul(&d, &b); // f^{-A3*(p+2)}
let f_p1 = fp12_frobenius_p(f); // f^p
let g = fp12_mul(f, &f_p1); // f^{p+1}
let h = fp12_cyclotomic_pow(&g, SM9_NINE); // f^{9(p+1)}
let i = fp12_mul(&e, &h); // f^{-A3*(p+2)+9(p+1)}
let j = fp12_square(f); // f^2
let k = fp12_square(&j); // f^4
let l = fp12_mul(&k, &i); // f^{4 + -A3*(p+2) + 9(p+1)}
let m = fp12_square(&f_p1); // f^{2p}
let n = fp12_mul(&d, &m); // f^{-A3*(p+1)+2p}
let o = fp12_frobenius_p2(f); // f^{p^2}
let p_var = fp12_mul(&o, &n); // f^{p^2-A3*(p+1)+2p}
let q = fp12_cyclotomic_pow(&p_var, SM9_A2); // ...^{A2}
let a = fp12_cyclotomic_pow(f, SM9_A3); // f^{A3}
let b = fp12_inv(&a).unwrap_or(Fp12::ONE); // f^{-A3}
let c = fp12_frobenius_p(&b); // f^{-A3*p}
let d = fp12_mul(&c, &b); // f^{-A3*(p+1)}
let e = fp12_mul(&d, &b); // f^{-A3*(p+2)}
let f_p1 = fp12_frobenius_p(f); // f^p
let g = fp12_mul(f, &f_p1); // f^{p+1}
let h = fp12_cyclotomic_pow(&g, SM9_NINE); // f^{9(p+1)}
let i = fp12_mul(&e, &h); // f^{-A3*(p+2)+9(p+1)}
let j = fp12_square(f); // f^2
let k = fp12_square(&j); // f^4
let l = fp12_mul(&k, &i); // f^{4 + -A3*(p+2) + 9(p+1)}
let m = fp12_square(&f_p1); // f^{2p}
let n = fp12_mul(&d, &m); // f^{-A3*(p+1)+2p}
let o = fp12_frobenius_p2(f); // f^{p^2}
let p_var = fp12_mul(&o, &n); // f^{p^2-A3*(p+1)+2p}
let q = fp12_cyclotomic_pow(&p_var, SM9_A2); // ...^{A2}
let r = fp12_mul(&q, &l);
let s = fp12_frobenius_p3(f); // f^{p^3}
let s = fp12_frobenius_p3(f); // f^{p^3}
fp12_mul(&s, &r)
}