use crypto_bigint::{impl_modulus, modular::ConstMontyForm, U256};
impl_modulus!(
Sm2FieldModulus,
U256,
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"
);
impl_modulus!(
Sm2GroupOrder,
U256,
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
);
pub type Fp = ConstMontyForm<Sm2FieldModulus, { U256::LIMBS }>;
pub type Fn = ConstMontyForm<Sm2GroupOrder, { U256::LIMBS }>;
pub const CURVE_A: Fp = Fp::new(&U256::from_be_hex(
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
));
pub const CURVE_B: Fp = Fp::new(&U256::from_be_hex(
"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
));
pub const GX: Fp = Fp::new(&U256::from_be_hex(
"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
));
pub const GY: Fp = Fp::new(&U256::from_be_hex(
"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0",
));
pub const FIELD_MODULUS: U256 =
U256::from_be_hex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF");
pub const GROUP_ORDER: U256 =
U256::from_be_hex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123");
pub const GROUP_ORDER_MINUS_1: U256 =
U256::from_be_hex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54122");
#[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
}
}
pub fn fp_sqrt(a: &Fp) -> Option<Fp> {
let exp = U256::from_be_hex("3FFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC00000004000000000000000");
let candidate = a.pow(&exp);
if candidate.square() == *a {
Some(candidate)
} 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
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fp_add_sub_symmetric() {
let a = fp_from_bytes(&[
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01,
]);
let b = fp_from_bytes(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02,
]);
let sum = fp_add(&a, &b);
let diff = fp_sub(&sum, &b);
assert_eq!(fp_to_bytes(&diff), fp_to_bytes(&a));
}
#[test]
fn test_fp_mul_by_one() {
let gx = GX;
let result = fp_mul(&gx, &Fp::ONE);
assert_eq!(fp_to_bytes(&result), fp_to_bytes(&gx));
}
#[test]
fn test_fp_inv_roundtrip() {
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 的逆元应存在");
assert_eq!(fp_mul(&two, &inv), Fp::ONE);
}
#[test]
fn test_fp_zero_has_no_inv() {
assert!(fp_inv(&Fp::ZERO).is_none());
}
#[test]
fn test_fp_sqrt_of_four() {
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 root = fp_sqrt(&four).expect("4 应有平方根");
assert_eq!(fp_square(&root), four);
}
#[test]
fn test_fn_inv_roundtrip() {
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);
}
}