lambdaworks_math/elliptic_curve/edwards/curves/bandersnatch/
curve.rs

1pub use super::field::FqField;
2use crate::elliptic_curve::edwards::point::EdwardsProjectivePoint;
3use crate::elliptic_curve::traits::IsEllipticCurve;
4use crate::{elliptic_curve::edwards::traits::IsEdwards, field::element::FieldElement};
5
6pub type BaseBandersnatchFieldElement = FqField;
7
8#[derive(Clone, Debug)]
9pub struct BandersnatchCurve;
10
11impl IsEllipticCurve for BandersnatchCurve {
12    type BaseField = BaseBandersnatchFieldElement;
13    type PointRepresentation = EdwardsProjectivePoint<Self>;
14
15    /// Returns the generator point of the Bandersnatch curve.
16    ///
17    /// The generator point is defined with coordinates `(x, y, 1)`, where `x` and `y`
18    /// are precomputed constants that belong to the curve.
19    ///
20    /// # Safety
21    ///
22    /// - The generator values are taken from the [Arkworks implementation](https://github.com/arkworks-rs/curves/blob/5a41d7f27a703a7ea9c48512a4148443ec6c747e/ed_on_bls12_381_bandersnatch/src/curves/mod.rs#L120)
23    ///   and have been converted to hexadecimal.
24    /// - `unwrap()` does not panic because:
25    ///   - The generator point is **known to be valid** on the curve.
26    ///   - The function only uses **hardcoded** and **verified** constants.
27    /// - This function should **never** be modified unless the new generator is fully verified.
28    fn generator() -> Self::PointRepresentation {
29        // SAFETY:
30        // - The generator point coordinates (x, y) are taken from a well-tested,
31        //   verified implementation.
32        // - The constructor will only fail if the values are invalid, which is
33        //   impossible given that they are constants taken from a trusted source.
34        let point = Self::PointRepresentation::new([
35            FieldElement::<Self::BaseField>::new_base(
36                "29C132CC2C0B34C5743711777BBE42F32B79C022AD998465E1E71866A252AE18",
37            ),
38            FieldElement::<Self::BaseField>::new_base(
39                "2A6C669EDA123E0F157D8B50BADCD586358CAD81EEE464605E3167B6CC974166",
40            ),
41            FieldElement::one(),
42        ]);
43        point.unwrap()
44    }
45}
46
47impl IsEdwards for BandersnatchCurve {
48    fn a() -> FieldElement<Self::BaseField> {
49        FieldElement::<Self::BaseField>::new_base(
50            "73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFEFFFFFFFC",
51        )
52    }
53
54    fn d() -> FieldElement<Self::BaseField> {
55        FieldElement::<Self::BaseField>::new_base(
56            "6389C12633C267CBC66E3BF86BE3B6D8CB66677177E54F92B369F2F5188D58E7",
57        )
58    }
59}
60
61#[cfg(test)]
62mod tests {
63
64    use super::*;
65    use crate::{
66        cyclic_group::IsGroup, elliptic_curve::traits::EllipticCurveError,
67        field::element::FieldElement, unsigned_integer::element::U256,
68    };
69
70    #[allow(clippy::upper_case_acronyms)]
71    type FEE = FieldElement<BaseBandersnatchFieldElement>;
72
73    fn point_1() -> EdwardsProjectivePoint<BandersnatchCurve> {
74        let x = FEE::new_base("29C132CC2C0B34C5743711777BBE42F32B79C022AD998465E1E71866A252AE18");
75        let y = FEE::new_base("2A6C669EDA123E0F157D8B50BADCD586358CAD81EEE464605E3167B6CC974166");
76
77        BandersnatchCurve::create_point_from_affine(x, y).unwrap()
78    }
79
80    #[test]
81    fn test_scalar_mul() {
82        let g = BandersnatchCurve::generator();
83        let result1 = g.operate_with_self(5u16);
84
85        assert_eq!(
86            result1.x().clone(),
87            FEE::new_base("68CBECE0B8FB55450410CBC058928A567EED293D168FAEF44BFDE25F943AABE0")
88        );
89
90        let scalar =
91            U256::from_hex("1CFB69D4CA675F520CCE760202687600FF8F87007419047174FD06B52876E7E6")
92                .unwrap();
93        let result2 = g.operate_with_self(scalar);
94
95        assert_eq!(
96            result2.x().clone(),
97            FEE::new_base("68CBECE0B8FB55450410CBC058928A567EED293D168FAEF44BFDE25F943AABE0")
98        );
99    }
100
101    #[test]
102    fn test_create_valid_point_works() {
103        let p = BandersnatchCurve::generator();
104
105        assert_eq!(p, p.clone());
106    }
107
108    #[test]
109    fn create_valid_point_works() {
110        let p = point_1();
111        assert_eq!(
112            *p.x(),
113            FEE::new_base("29C132CC2C0B34C5743711777BBE42F32B79C022AD998465E1E71866A252AE18")
114        );
115        assert_eq!(
116            *p.y(),
117            FEE::new_base("2A6C669EDA123E0F157D8B50BADCD586358CAD81EEE464605E3167B6CC974166")
118        );
119        assert_eq!(*p.z(), FEE::new_base("1"));
120    }
121
122    #[test]
123    fn create_invalid_points_panics() {
124        assert_eq!(
125            BandersnatchCurve::create_point_from_affine(FEE::from(1), FEE::from(1)).unwrap_err(),
126            EllipticCurveError::InvalidPoint
127        )
128    }
129
130    #[test]
131    fn equality_works() {
132        let g = BandersnatchCurve::generator();
133        let g2 = g.operate_with(&g);
134        assert_ne!(&g2, &g);
135        assert_eq!(&g, &g);
136    }
137
138    #[test]
139    fn operate_with_self_works_1() {
140        let g = BandersnatchCurve::generator();
141        assert_eq!(
142            g.operate_with(&g).operate_with(&g),
143            g.operate_with_self(3_u16)
144        );
145    }
146}