use crypto_bigint::{impl_modulus, modular::ConstMontyForm, U256};
impl_modulus!(
Sm9FieldModulus,
U256,
"B640000002A3A6F1D603AB4FF58EC74521F2934B1A7AEEDBE56F9B27E351457D"
);
impl_modulus!(
Sm9GroupOrder,
U256,
"B640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25"
);
pub type Fp = ConstMontyForm<Sm9FieldModulus, { U256::LIMBS }>;
pub type Fn = ConstMontyForm<Sm9GroupOrder, { U256::LIMBS }>;
pub const G1X: Fp = Fp::new(&U256::from_be_hex(
"93DE051D62BF718FF5ED0704487D01D6E1E4086909DC3280E8C4E4817C66DDDD",
));
pub const G1Y: Fp = Fp::new(&U256::from_be_hex(
"21FE8DDA4F21E607631065125C395BBC1C1C00CBFA6024350C464CD70A3EA616",
));
pub const FIELD_MODULUS: U256 =
U256::from_be_hex("B640000002A3A6F1D603AB4FF58EC74521F2934B1A7AEEDBE56F9B27E351457D");
pub const GROUP_ORDER: U256 =
U256::from_be_hex("B640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25");
pub const GROUP_ORDER_MINUS_1: U256 =
U256::from_be_hex("B640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF24");
#[inline]
pub fn fp_from_bytes(bytes: &[u8; 32]) -> Fp {
Fp::new(&U256::from_be_slice(bytes))
}
#[inline]
pub fn fp_to_bytes(a: &Fp) -> [u8; 32] {
a.retrieve().to_be_bytes()
}
#[inline]
pub fn fn_from_bytes(bytes: &[u8; 32]) -> Fn {
Fn::new(&U256::from_be_slice(bytes))
}
#[inline]
pub fn fn_to_bytes(a: &Fn) -> [u8; 32] {
a.retrieve().to_be_bytes()
}
#[inline]
pub fn fp_add(a: &Fp, b: &Fp) -> Fp {
a.add(b)
}
#[inline]
pub fn fp_sub(a: &Fp, b: &Fp) -> Fp {
a.sub(b)
}
#[inline]
pub fn fp_mul(a: &Fp, b: &Fp) -> Fp {
a.mul(b)
}
#[inline]
pub fn fp_neg(a: &Fp) -> Fp {
a.neg()
}
#[inline]
pub fn fp_square(a: &Fp) -> Fp {
a.square()
}
pub fn fp_inv(a: &Fp) -> Option<Fp> {
let inv = a.inv();
if bool::from(inv.is_some()) {
Some(inv.unwrap())
} else {
None
}
}
#[inline]
pub fn fn_add(a: &Fn, b: &Fn) -> Fn {
a.add(b)
}
#[inline]
pub fn fn_sub(a: &Fn, b: &Fn) -> Fn {
a.sub(b)
}
#[inline]
pub fn fn_mul(a: &Fn, b: &Fn) -> Fn {
a.mul(b)
}
#[inline]
pub fn fn_neg(a: &Fn) -> Fn {
a.neg()
}
pub fn fn_inv(a: &Fn) -> Option<Fn> {
let inv = a.inv();
if bool::from(inv.is_some()) {
Some(inv.unwrap())
} else {
None
}
}
pub fn fp_sqrt(a: &Fp) -> Option<Fp> {
const S: u32 = 2;
const Q: U256 =
U256::from_be_hex("2D90000000A8E9BC7580EAD3FD63B1D1487CA4D2C69EBBB6F95BE6C9F8D4515F");
const Q_PLUS_1_DIV_2: U256 =
U256::from_be_hex("16C80000005474DE3AC07569FEB1D8E8A43E5269634F5DDB7CADF364FC6A28B0");
const EULER_EXP: U256 =
U256::from_be_hex("5B2000000151D378EB01D5A7FAC763A290F949A58D3D776DF2B7CD93F1A8A2BE");
const Z_VAL: U256 =
U256::from_be_hex("0000000000000000000000000000000000000000000000000000000000000005");
if *a == Fp::ZERO {
return Some(Fp::ZERO);
}
let euler = a.pow(&EULER_EXP);
if euler != Fp::ONE {
return None;
}
let z = Fp::new(&Z_VAL);
let mut m = S;
let mut c = z.pow(&Q); let mut t = a.pow(&Q); let mut r = a.pow(&Q_PLUS_1_DIV_2);
for _ in 0..S {
if t == Fp::ONE {
break;
}
let mut i = 0u32;
let mut tmp = t;
for j in 1..m {
tmp = tmp.square();
if tmp == Fp::ONE && i == 0 {
i = j;
}
}
if i == 0 {
return None;
}
let mut b = c;
for _ in 0..(m - i - 1) {
b = b.square();
}
m = i;
c = b.square(); t = t.mul(&c); r = r.mul(&b); }
if r.square() == *a {
Some(r)
} else {
None
}
}
#[inline]
pub fn fp_is_square(a: &Fp) -> bool {
if *a == Fp::ZERO {
return true;
}
const EULER_EXP: U256 =
U256::from_be_hex("5B2000000151D378EB01D5A7FAC763A290F949A58D3D776DF2B7CD93F1A8A2BE");
a.pow(&EULER_EXP) == Fp::ONE
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fp_add_sub() {
let a = fp_from_bytes(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1,
]);
let b = fp_from_bytes(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2,
]);
assert_eq!(fp_to_bytes(&fp_sub(&fp_add(&a, &b), &b)), fp_to_bytes(&a));
}
#[test]
fn test_fp_inv() {
let two = fp_from_bytes(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2,
]);
let inv = fp_inv(&two).expect("2^-1 应存在");
assert_eq!(fp_mul(&two, &inv), Fp::ONE);
}
#[test]
fn test_fn_inv() {
let three = fn_from_bytes(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 3,
]);
let inv = fn_inv(&three).expect("3^-1 应存在");
assert_eq!(fn_mul(&three, &inv), Fn::ONE);
}
#[test]
fn test_fp_sqrt_basic() {
let four = fp_from_bytes(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 4,
]);
let sqrt4 = fp_sqrt(&four).expect("4 应有平方根");
assert_eq!(fp_square(&sqrt4), four, "sqrt(4)^2 应等于 4");
}
#[test]
fn test_fp_sqrt_zero() {
assert_eq!(fp_sqrt(&Fp::ZERO), Some(Fp::ZERO));
}
#[test]
fn test_fp_is_square() {
let four = fp_from_bytes(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 4,
]);
assert!(fp_is_square(&four));
assert!(fp_is_square(&Fp::ZERO));
let three = fp_from_bytes(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 3,
]);
let _ = fp_is_square(&three);
}
}