pub mod fields;
pub mod groups;
pub mod pairing;
pub mod utils;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use crypto_bigint::{Zero, U256};
use rand_core::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::error::Error;
use crate::sm3::Sm3Hasher;
use crate::sm9::fields::fp::{fn_add, fn_inv, fn_mul, Fn, GROUP_ORDER, GROUP_ORDER_MINUS_1};
use crate::sm9::fields::fp12::{fp12_mul, Fp12};
use crate::sm9::groups::g1::{G1Affine, G1Jacobian};
use crate::sm9::groups::g2::{G2Affine, G2Jacobian};
use crate::sm9::pairing::pairing;
use crate::sm9::utils::{fp12_to_bytes_for_kdf, sm9_h1, sm9_h2};
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct Sm9SignPrivKey {
bytes: [u8; 65],
}
impl Sm9SignPrivKey {
pub fn from_bytes(bytes: &[u8; 65]) -> Result<Self, Error> {
let p = G1Affine::from_bytes(bytes)?;
if !p.is_on_curve() {
return Err(Error::InvalidPrivateKey);
}
Ok(Sm9SignPrivKey { bytes: *bytes })
}
pub fn as_bytes(&self) -> &[u8; 65] {
&self.bytes
}
}
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct Sm9MasterPrivKey {
bytes: [u8; 32],
}
impl Sm9MasterPrivKey {
pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, Error> {
let s = U256::from_be_slice(bytes);
if bool::from(s.is_zero()) || s >= GROUP_ORDER_MINUS_1 {
return Err(Error::InvalidPrivateKey);
}
Ok(Sm9MasterPrivKey { bytes: *bytes })
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.bytes
}
}
#[derive(Clone, Debug)]
pub struct Sm9SignPubKey {
bytes: [u8; 128],
}
impl Sm9SignPubKey {
pub fn from_bytes(bytes: &[u8; 128]) -> Result<Self, Error> {
let p = G2Affine::from_bytes(bytes)?;
if !p.is_on_curve() {
return Err(Error::InvalidPublicKey);
}
Ok(Sm9SignPubKey { bytes: *bytes })
}
pub fn as_bytes(&self) -> &[u8; 128] {
&self.bytes
}
}
#[derive(Clone, Debug)]
pub struct Sm9EncPubKey {
bytes: [u8; 128],
}
impl Sm9EncPubKey {
pub fn from_bytes(bytes: &[u8; 128]) -> Result<Self, Error> {
let p = G2Affine::from_bytes(bytes)?;
if !p.is_on_curve() {
return Err(Error::InvalidPublicKey);
}
Ok(Sm9EncPubKey { bytes: *bytes })
}
pub fn as_bytes(&self) -> &[u8; 128] {
&self.bytes
}
}
pub fn generate_sign_master_keypair<R: RngCore>(rng: &mut R) -> (Sm9MasterPrivKey, Sm9SignPubKey) {
loop {
let mut ks_bytes = [0u8; 32];
rng.fill_bytes(&mut ks_bytes);
let ks = U256::from_be_slice(&ks_bytes);
if bool::from(ks.is_zero()) || ks >= GROUP_ORDER_MINUS_1 {
ks_bytes.zeroize();
continue;
}
let ppub = G2Jacobian::scalar_mul_g2(&ks).to_affine().unwrap();
let priv_key = Sm9MasterPrivKey { bytes: ks_bytes };
let pub_key = Sm9SignPubKey {
bytes: ppub.to_bytes(),
};
return (priv_key, pub_key);
}
}
pub fn generate_sign_user_key(
master_priv: &Sm9MasterPrivKey,
id: &[u8],
) -> Result<Sm9SignPrivKey, Error> {
let ks = U256::from_be_slice(master_priv.as_bytes());
let h = sm9_h1(id, 0x01);
let t1_fn = fn_add(&Fn::new(&ks), &Fn::new(&h));
let t1 = t1_fn.retrieve();
if bool::from(t1.is_zero()) {
return Err(Error::ZeroScalar);
}
let t1_inv = fn_inv(&t1_fn).ok_or(Error::ZeroScalar)?;
let ks_fn = Fn::new(&ks);
let t2_fn = fn_mul(&ks_fn, &t1_inv);
let t2 = t2_fn.retrieve();
if bool::from(t2.is_zero()) {
return Err(Error::ZeroScalar);
}
let da = G1Jacobian::scalar_mul_g1(&t2).to_affine()?;
Ok(Sm9SignPrivKey {
bytes: da.to_bytes(),
})
}
pub fn generate_enc_master_keypair<R: RngCore>(rng: &mut R) -> (Sm9MasterPrivKey, Sm9EncPubKey) {
loop {
let mut ke_bytes = [0u8; 32];
rng.fill_bytes(&mut ke_bytes);
let ke = U256::from_be_slice(&ke_bytes);
if bool::from(ke.is_zero()) || ke >= GROUP_ORDER_MINUS_1 {
ke_bytes.zeroize();
continue;
}
let ppub = G2Jacobian::scalar_mul_g2(&ke).to_affine().unwrap();
let priv_key = Sm9MasterPrivKey { bytes: ke_bytes };
let pub_key = Sm9EncPubKey {
bytes: ppub.to_bytes(),
};
return (priv_key, pub_key);
}
}
pub fn generate_enc_user_key(
master_priv: &Sm9MasterPrivKey,
id: &[u8],
) -> Result<Sm9SignPrivKey, Error> {
let ke = U256::from_be_slice(master_priv.as_bytes());
let h = sm9_h1(id, 0x03); let t1_fn = fn_add(&Fn::new(&ke), &Fn::new(&h));
let t1 = t1_fn.retrieve();
if bool::from(t1.is_zero()) {
return Err(Error::ZeroScalar);
}
let t1_inv = fn_inv(&t1_fn).ok_or(Error::ZeroScalar)?;
let ke_fn = Fn::new(&ke);
let t2_fn = fn_mul(&ke_fn, &t1_inv);
let t2 = t2_fn.retrieve();
if bool::from(t2.is_zero()) {
return Err(Error::ZeroScalar);
}
let de = G1Jacobian::scalar_mul_g1(&t2).to_affine()?;
Ok(Sm9SignPrivKey {
bytes: de.to_bytes(),
})
}
pub fn sm9_sign<R: RngCore>(
msg: &[u8],
da: &Sm9SignPrivKey,
sign_pub: &Sm9SignPubKey,
rng: &mut R,
) -> Result<([u8; 32], [u8; 65]), Error> {
let da_point = G1Affine::from_bytes(da.as_bytes())?;
let ppub = G2Affine::from_bytes(sign_pub.as_bytes())?;
loop {
let mut r_bytes = [0u8; 32];
rng.fill_bytes(&mut r_bytes);
let r = U256::from_be_slice(&r_bytes);
r_bytes.zeroize();
if bool::from(r.is_zero()) || r >= GROUP_ORDER {
continue;
}
let g = pairing(&G1Affine::generator(), &ppub);
let w = fp12_pow(&g, &r);
let w_bytes = fp12_to_bytes_for_kdf(&w);
let h_val = sm9_h2(msg, &w_bytes);
if bool::from(h_val.is_zero()) {
continue;
}
let h_fn = Fn::new(&h_val);
let r_fn = Fn::new(&r);
let l_fn = {
use crate::sm9::fields::fp::fn_sub;
fn_sub(&r_fn, &h_fn)
};
let l = l_fn.retrieve();
if bool::from(l.is_zero()) {
continue;
}
let da_jac = G1Jacobian::from_affine(&da_point);
let s = G1Jacobian::scalar_mul(&l, &da_jac).to_affine()?;
let mut h_out = [0u8; 32];
h_out.copy_from_slice(&h_val.to_be_bytes());
return Ok((h_out, s.to_bytes()));
}
}
pub fn sm9_verify(
msg: &[u8],
h: &[u8; 32],
s: &[u8; 65],
id: &[u8],
sign_pub: &Sm9SignPubKey,
) -> Result<(), Error> {
let h_val = U256::from_be_slice(h);
if bool::from(h_val.is_zero()) || h_val >= GROUP_ORDER {
return Err(Error::InvalidSignature);
}
let s_point = G1Affine::from_bytes(s).map_err(|_| Error::InvalidSignature)?;
if !s_point.is_on_curve() {
return Err(Error::InvalidSignature);
}
let ppub = G2Affine::from_bytes(sign_pub.as_bytes())?;
let g = pairing(&G1Affine::generator(), &ppub);
let t = fp12_pow(&g, &h_val);
let h1 = sm9_h1(id, 0x01);
let h1g2 = G2Jacobian::scalar_mul_g2(&h1).to_affine()?;
let ppub_jac = G2Jacobian::from_affine(&ppub);
let h1g2_jac = G2Jacobian::from_affine(&h1g2);
let p_jac = G2Jacobian::add_jac(&ppub_jac, &h1g2_jac);
let p = p_jac.to_affine()?;
let u = pairing(&s_point, &p);
let w_prime = fp12_mul(&u, &t);
let w_prime_bytes = fp12_to_bytes_for_kdf(&w_prime);
let h_check = sm9_h2(msg, &w_prime_bytes);
let h_check_bytes = h_check.to_be_bytes();
if h.ct_eq(&h_check_bytes).unwrap_u8() != 1 {
return Err(Error::Sm9VerifyFailed);
}
Ok(())
}
#[cfg(feature = "alloc")]
pub fn sm9_encrypt<R: RngCore>(
id: &[u8],
message: &[u8],
enc_pub: &Sm9EncPubKey,
rng: &mut R,
) -> Result<Vec<u8>, Error> {
use crate::sm9::utils::sm9_kdf;
let ppub_e = G2Affine::from_bytes(enc_pub.as_bytes())?;
loop {
let mut r_bytes = [0u8; 32];
rng.fill_bytes(&mut r_bytes);
let r = U256::from_be_slice(&r_bytes);
r_bytes.zeroize();
if bool::from(r.is_zero()) || r >= GROUP_ORDER {
continue;
}
let h1 = sm9_h1(id, 0x03);
let h1p2 = G2Jacobian::scalar_mul_g2(&h1).to_affine()?;
let h1p2_jac = G2Jacobian::from_affine(&h1p2);
let ppub_jac = G2Jacobian::from_affine(&ppub_e);
let qb_jac = G2Jacobian::add_jac(&h1p2_jac, &ppub_jac);
let qb = qb_jac.to_affine()?;
let c1_jac = G2Jacobian::scalar_mul(&r, &G2Jacobian::from_affine(&qb));
let c1_aff = c1_jac.to_affine()?;
let c1_bytes = c1_aff.to_bytes();
let g = pairing(&G1Affine::generator(), &ppub_e);
let w = fp12_pow(&g, &r);
let w_bytes = fp12_to_bytes_for_kdf(&w);
let klen = message.len() + 32;
let mut kdf_input = Vec::with_capacity(128 + 384 + id.len());
kdf_input.extend_from_slice(&c1_bytes);
kdf_input.extend_from_slice(&w_bytes);
kdf_input.extend_from_slice(id);
let k = sm9_kdf(&kdf_input, klen);
if k.iter().all(|&b| b == 0) {
continue;
}
let k1 = &k[..message.len()];
let _k2 = &k[message.len()..];
let c2: Vec<u8> = message
.iter()
.zip(k1.iter())
.map(|(&m, &k)| m ^ k)
.collect();
let mut h = Sm3Hasher::new();
h.update(&c2);
h.update(&w_bytes);
h.update(id);
let c3 = h.finalize();
let mut output = Vec::with_capacity(128 + 32 + message.len());
output.extend_from_slice(&c1_bytes);
output.extend_from_slice(&c3);
output.extend_from_slice(&c2);
return Ok(output);
}
}
#[cfg(feature = "alloc")]
pub fn sm9_decrypt(
id: &[u8],
ciphertext: &[u8],
de: &Sm9SignPrivKey, ) -> Result<Vec<u8>, Error> {
use crate::sm9::utils::sm9_kdf;
if ciphertext.len() < 160 {
return Err(Error::InvalidInputLength);
}
let c1_bytes: [u8; 128] = ciphertext[0..128].try_into().unwrap();
let c3: [u8; 32] = ciphertext[128..160].try_into().unwrap();
let c2 = &ciphertext[160..];
let c1 = G2Affine::from_bytes(&c1_bytes)?;
let de_point = G1Affine::from_bytes(de.as_bytes())?;
let w = pairing(&de_point, &c1);
let w_bytes = fp12_to_bytes_for_kdf(&w);
let klen = c2.len() + 32;
let mut kdf_input = Vec::with_capacity(128 + 384 + id.len());
kdf_input.extend_from_slice(&c1_bytes);
kdf_input.extend_from_slice(&w_bytes);
kdf_input.extend_from_slice(id);
let k = sm9_kdf(&kdf_input, klen);
if k.iter().all(|&b| b == 0) {
return Err(Error::Sm9DecryptFailed);
}
let k1 = &k[..c2.len()];
let _k2 = &k[c2.len()..];
let m: Vec<u8> = c2.iter().zip(k1.iter()).map(|(&c, &k)| c ^ k).collect();
let mut h = Sm3Hasher::new();
h.update(c2);
h.update(&w_bytes);
h.update(id);
let c3_computed = h.finalize();
if c3.ct_eq(&c3_computed).unwrap_u8() != 1 {
return Err(Error::Sm9DecryptFailed);
}
Ok(m)
}
fn fp12_pow(f: &Fp12, k: &U256) -> Fp12 {
let mut result = Fp12::ONE;
let mut base = *f;
for byte in k.to_be_bytes().iter().rev() {
for bit in 0..8 {
let product = fp12_mul(&result, &base);
let choice = Choice::from((byte >> bit) & 1);
result = Fp12::conditional_select(&result, &product, choice);
base = fp12_mul(&base, &base);
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
struct FakeRng([u8; 32]);
impl RngCore for FakeRng {
fn next_u32(&mut self) -> u32 {
0
}
fn next_u64(&mut self) -> u64 {
0
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
for (i, b) in dest.iter_mut().enumerate() {
*b = self.0[i % 32];
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
}
#[test]
fn test_generate_sign_master_keypair() {
let mut rng = FakeRng([0x42u8; 32]);
let (_ks, ppub) = generate_sign_master_keypair(&mut rng);
let p = G2Affine::from_bytes(ppub.as_bytes()).expect("公钥应有效");
assert!(p.is_on_curve());
}
#[test]
fn test_generate_user_sign_key() {
let mut rng = FakeRng([0x42u8; 32]);
let (ks, _ppub) = generate_sign_master_keypair(&mut rng);
let id = b"Alice";
let da = generate_sign_user_key(&ks, id).expect("签名私钥生成应成功");
let p = G1Affine::from_bytes(da.as_bytes()).expect("私钥点应有效");
assert!(p.is_on_curve());
}
#[test]
fn test_sign_verify_roundtrip() {
let mut rng = FakeRng([0x42u8; 32]);
let (master_priv, sign_pub) = generate_sign_master_keypair(&mut rng);
let pub_key = Sm9SignPubKey::from_bytes(sign_pub.as_bytes()).unwrap();
let id = b"Alice";
let da = generate_sign_user_key(&master_priv, id).expect("用户签名私钥应生成成功");
let msg = b"hello sm9";
let (h, s) = sm9_sign(msg, &da, &pub_key, &mut rng).expect("签名应成功");
sm9_verify(msg, &h, &s, id, &pub_key).expect("验签应成功");
}
#[test]
fn test_pairing_bilinear() {
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;
use crypto_bigint::U256;
let p = G1Affine::generator();
let q = G2Affine::generator();
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),
"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),
"G1 scalar_mul(2) != G1.double() in y"
);
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_double = g2_jac.double().to_affine().unwrap();
assert_eq!(
g2_2_by_mul, g2_2_by_double,
"G2 scalar_mul(2) != G2.double()"
);
let e_2g1_g2 = pairing(&g1_2_by_mul, &q);
let e_g1_g2 = pairing(&p, &q);
let e_sq = fp12_mul(&e_g1_g2, &e_g1_g2);
let g1_jac2 = G1Jacobian::from_affine(&p);
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)²"
);
let e_g1_2g2 = pairing(&p, &g2_2_by_mul);
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_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};
use crypto_bigint::U256;
#[test]
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 e_g1_g2 = pairing(&p, &q);
let e_sq = fp12_mul(&e_g1_g2, &e_g1_g2);
let e_2g1_g2 = pairing(&g1_2, &q);
assert_eq!(e_2g1_g2, e_sq, "e(2G1,G2) != e(G1,G2)² via scalar_mul");
}
#[test]
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 ml1 = miller_loop(&q, &p);
let ml2 = miller_loop(&q, &g1_2);
use crate::sm9::fields::fp12::fp12_inv;
let ml1_sq = fp12_mul(&ml1, &ml1);
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"
);
}
#[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 ml_g1_g2 = miller_loop(&q, &p);
let ml_2g1_g2 = miller_loop(&q, &g1_2);
let gt1 = final_exp(&ml_g1_g2);
let gt2 = final_exp(&ml_2g1_g2);
let gt1_sq = fp12_square(>1);
assert_eq!(
gt2, gt1_sq,
"final_exp(ml(2G1,G2)) != final_exp(ml(G1,G2))^2"
);
}
#[test]
fn test_final_exp_gt_order() {
use crate::sm9::fields::fp::GROUP_ORDER;
let p = G1Affine::generator();
let q = G2Affine::generator();
let ml = miller_loop(&q, &p);
let gt = final_exp(&ml);
let n = GROUP_ORDER;
let mut result = Fp12::ONE;
let mut base = gt;
for byte in n.to_be_bytes().iter().rev() {
for bit in 0..8 {
let product = fp12_mul(&result, &base);
let choice = subtle::Choice::from((byte >> bit) & 1);
result = Fp12::conditional_select(&result, &product, choice);
base = fp12_mul(&base, &base);
}
}
assert_eq!(
result,
Fp12::ONE,
"e(G1,G2)^n != 1: GT element not in subgroup"
);
}
#[test]
fn test_miller_loop_p6_conjugate() {
let p = G1Affine::generator();
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_conj = fp12_conjugate(&ml);
assert_eq!(ml_p6, ml_conj, "ml^{{p^6}} != conjugate(ml)");
}
#[test]
fn test_single_double_step_line() {
use crate::sm9::fields::fp::fp_to_bytes;
let g1 = G1Affine::generator();
let g2 = G2Affine::generator();
let e1 = pairing(&g1, &g2);
let e2 = pairing(&g1, &g2);
assert_eq!(e1, e2, "pairing is not deterministic");
let g1_jac = G1Jacobian::from_affine(&g1);
let g1_2_by_add = G1Jacobian::add(&g1_jac, &g1_jac).to_affine().unwrap();
let g1_2_by_mul = G1Jacobian::scalar_mul_g1(&U256::from(2u32))
.to_affine()
.unwrap();
assert_eq!(
fp_to_bytes(&g1_2_by_add.x),
fp_to_bytes(&g1_2_by_mul.x),
"G1 add vs mul: x 坐标不同"
);
assert_eq!(
fp_to_bytes(&g1_2_by_add.y),
fp_to_bytes(&g1_2_by_mul.y),
"G1 add vs mul: y 坐标不同"
);
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!(
e_g1_2g2, e_g1_g2_sq,
"e(G1, 2G2) != e(G1,G2)^2 — G2 侧双线性性失败"
);
}
#[test]
fn test_line_eval_equivalence() {
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;
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,
},
};
let f = Fp12::ONE;
let sparse_result = fp12_mul_by_line(&f, &line);
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,
},
};
let full_result = fp12_mul(&f, &full_line);
assert_eq!(
sparse_result, full_result,
"fp12_mul_by_line 槽位不匹配: 期望约定 (c0.c0=a, c1.c1(vw)=b, c1.c2(v²w)=c)"
);
}
}