Skip to main content

gmcrypto_core/sm2/
curve.rs

1//! SM2 curve parameters (GB/T 32918.5-2017 §10.1).
2//!
3//! Short Weierstrass over GF(p): y^2 = x^3 + a*x + b (mod p).
4//! Cofactor 1, prime order n. Note `a ≡ -3 (mod p)`, which enables
5//! Renes-Costello-Batina's a=-3 specialized complete-addition formulas.
6
7use crypto_bigint::{U256, const_monty_params};
8
9// p = FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF
10const_monty_params!(
11    PMod,
12    U256,
13    "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"
14);
15
16// n = FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123
17const_monty_params!(
18    NMod,
19    U256,
20    "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
21);
22
23/// Base field GF(p): elements of arithmetic in the curve equation.
24pub type Fp = crypto_bigint::modular::ConstMontyForm<PMod, { U256::LIMBS }>;
25
26/// Scalar field GF(n): elements of arithmetic on private keys and signature
27/// scalars. n is the curve order.
28pub type Fn = crypto_bigint::modular::ConstMontyForm<NMod, { U256::LIMBS }>;
29
30/// Curve constant `b` (the constant term of y^2 = x^3 + a*x + b).
31pub(crate) const B_HEX: &str = "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93";
32
33/// Generator x coordinate.
34#[allow(dead_code)]
35pub(crate) const GX_HEX: &str = "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7";
36
37/// Generator y coordinate.
38#[allow(dead_code)]
39pub(crate) const GY_HEX: &str = "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0";
40
41/// Curve param `b` as a `Fp`.
42#[must_use]
43pub const fn b() -> Fp {
44    Fp::new(&U256::from_be_hex(B_HEX))
45}
46
47/// `3 * b` as a `Fp`. RCB formulas use this constant.
48#[must_use]
49pub fn b3() -> Fp {
50    let b = b();
51    b + b + b
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    #[test]
58    fn moduli_are_correct_size() {
59        assert_eq!(Fp::MODULUS.as_ref().bits(), 256);
60        assert_eq!(Fn::MODULUS.as_ref().bits(), 256);
61    }
62
63    #[test]
64    fn b_is_not_zero() {
65        let b = b();
66        assert_ne!(b.retrieve(), U256::ZERO);
67    }
68
69    #[test]
70    fn b3_equals_3b() {
71        let b = b();
72        let b3 = b3();
73        assert_eq!(b3.retrieve(), (b + b + b).retrieve());
74    }
75
76    /// Sanity: Fp inverse satisfies a * a^-1 = 1 mod p, on a non-trivial input.
77    #[test]
78    fn fp_invert_round_trip() {
79        let a = Fp::new(&U256::from_u64(7));
80        let a_inv = a.invert().expect("7 is invertible mod p");
81        let one = Fp::new(&U256::ONE);
82        assert_eq!((a * a_inv).retrieve(), one.retrieve());
83    }
84
85    /// Sanity: Fn inverse on the small value 5.
86    #[test]
87    fn fn_invert_round_trip() {
88        let a = Fn::new(&U256::from_u64(5));
89        let a_inv = a.invert().expect("5 is invertible mod n");
90        let one = Fn::new(&U256::ONE);
91        assert_eq!((a * a_inv).retrieve(), one.retrieve());
92    }
93
94    /// Inversion of zero must yield `CtOption::none()` — never panics, never returns Some.
95    #[test]
96    fn invert_zero_is_none() {
97        let zero = Fp::new(&U256::ZERO);
98        assert!(bool::from(zero.invert().is_none()));
99    }
100}