lambdaworks_math/elliptic_curve/short_weierstrass/curves/secq256k1/
curve.rs

1use crate::elliptic_curve::short_weierstrass::point::ShortWeierstrassProjectivePoint;
2use crate::elliptic_curve::traits::IsEllipticCurve;
3use crate::field::fields::secp256k1_scalarfield::Secp256k1ScalarField;
4use crate::{
5    elliptic_curve::short_weierstrass::traits::IsShortWeierstrass, field::element::FieldElement,
6};
7
8#[derive(Clone, Debug)]
9pub struct Secq256k1Curve;
10
11impl IsEllipticCurve for Secq256k1Curve {
12    type BaseField = Secp256k1ScalarField;
13    type PointRepresentation = ShortWeierstrassProjectivePoint<Self>;
14
15    fn generator() -> Self::PointRepresentation {
16        // SAFETY:
17        // - The generator point is mathematically verified to be a valid point on the curve.
18        // - `unwrap()` is safe because the provided coordinates satisfy the curve equation.
19        let point = Self::PointRepresentation::new([
20            FieldElement::<Self::BaseField>::from_hex_unchecked(
21                "76C39F5585CB160EB6B06C87A2CE32E23134E45A097781A6A24288E37702EDA6",
22            ),
23            FieldElement::<Self::BaseField>::from_hex_unchecked(
24                "3FFC646C7B2918B5DC2D265A8E82A7F7D18983D26E8DC055A4120DDAD952677F",
25            ),
26            FieldElement::one(),
27        ]);
28        point.unwrap()
29    }
30}
31
32impl IsShortWeierstrass for Secq256k1Curve {
33    fn a() -> FieldElement<Self::BaseField> {
34        FieldElement::from(0)
35    }
36
37    fn b() -> FieldElement<Self::BaseField> {
38        FieldElement::from(7)
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use crate::{
46        cyclic_group::IsGroup, elliptic_curve::traits::EllipticCurveError,
47        field::element::FieldElement, unsigned_integer::element::U256,
48    };
49
50    use super::Secq256k1Curve;
51
52    #[allow(clippy::upper_case_acronyms)]
53    type FE = FieldElement<Secp256k1ScalarField>;
54
55    fn point_1() -> ShortWeierstrassProjectivePoint<Secq256k1Curve> {
56        let x = FE::from_hex_unchecked(
57            "76C39F5585CB160EB6B06C87A2CE32E23134E45A097781A6A24288E37702EDA6",
58        );
59        let y = FE::from_hex_unchecked(
60            "3FFC646C7B2918B5DC2D265A8E82A7F7D18983D26E8DC055A4120DDAD952677F",
61        );
62        Secq256k1Curve::create_point_from_affine(x, y).unwrap()
63    }
64
65    fn point_1_times_5() -> ShortWeierstrassProjectivePoint<Secq256k1Curve> {
66        let x = FE::from_hex_unchecked(
67            "8656a2c13dd0a3bfa362d2ff8c00281341ff3a79cbbe8857f2d20b398041a21a",
68        );
69        let y = FE::from_hex_unchecked(
70            "468ed8bcfcd4ed2b3bf154414b9e48d8c5ce54f6616846a7cf6a725f70d34a63",
71        );
72        let z = FE::from_hex_unchecked(
73            "bb26eae3d2b9603d98dff86d87175f442e539c07bbe4ef5712e47c4d72c89734",
74        );
75        ShortWeierstrassProjectivePoint::<Secq256k1Curve>::new([x, y, z]).unwrap()
76    }
77
78    #[test]
79    fn adding_five_times_point_1_works() {
80        let point_1 = point_1();
81        let point_1_times_5 = point_1_times_5();
82        assert_eq!(point_1.operate_with_self(5_u16), point_1_times_5);
83    }
84
85    #[test]
86    fn create_valid_point_works() {
87        let p = point_1();
88        assert_eq!(
89            *p.x(),
90            FE::from_hex_unchecked(
91                "76C39F5585CB160EB6B06C87A2CE32E23134E45A097781A6A24288E37702EDA6"
92            )
93        );
94        assert_eq!(
95            *p.y(),
96            FE::from_hex_unchecked(
97                "3FFC646C7B2918B5DC2D265A8E82A7F7D18983D26E8DC055A4120DDAD952677F"
98            )
99        );
100        assert_eq!(*p.z(), FE::from_hex_unchecked("1"));
101    }
102
103    #[test]
104    fn create_invalid_points_returns_an_error() {
105        assert_eq!(
106            Secq256k1Curve::create_point_from_affine(FE::from(0), FE::from(1)),
107            Err(EllipticCurveError::InvalidPoint)
108        );
109    }
110
111    #[test]
112    fn equality_works() {
113        let g = Secq256k1Curve::generator();
114        let g2 = g.operate_with_self(2_u16);
115        let g2_other = g.operate_with(&g);
116        assert_ne!(&g2, &g);
117        assert_eq!(&g, &g);
118        assert_eq!(&g2, &g2_other);
119    }
120
121    #[test]
122    fn g_operated_with_g_satifies_ec_equation() {
123        let g = Secq256k1Curve::generator();
124        let g2 = g.operate_with_self(2_u16);
125
126        // get x and y from affine coordinates
127        let g2_affine = g2.to_affine();
128        let x = g2_affine.x();
129        let y = g2_affine.y();
130
131        // calculate both sides of secq256k1 curve equation
132        let seven = Secq256k1Curve::b();
133        let y_sq_0 = x.pow(3_u16) + seven;
134        let y_sq_1 = y.pow(2_u16);
135
136        assert_eq!(y_sq_0, y_sq_1);
137    }
138
139    #[test]
140    fn operate_with_self_works() {
141        let g = Secq256k1Curve::generator();
142        assert_eq!(
143            g.operate_with(&g).operate_with(&g),
144            g.operate_with_self(3_u16)
145        );
146    }
147
148    #[test]
149    fn generator_has_right_order() {
150        let g = Secq256k1Curve::generator();
151        assert_eq!(
152            g.operate_with_self(U256::from_hex_unchecked(
153                "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"
154            ))
155            .to_affine(),
156            ShortWeierstrassProjectivePoint::neutral_element()
157        );
158    }
159
160    #[test]
161    /// (r - 5)g = rg - 5g = 0 - 5g = -5g
162    fn inverse_works() {
163        let g = Secq256k1Curve::generator();
164        assert_eq!(
165            g.operate_with_self(U256::from_hex_unchecked(
166                "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2A"
167            ))
168            .to_affine(),
169            g.operate_with_self(5u64).neg().to_affine()
170        );
171    }
172}