lambdaworks_math/elliptic_curve/edwards/curves/
ed448_goldilocks.rs

1use crate::{
2    elliptic_curve::{
3        edwards::{point::EdwardsProjectivePoint, traits::IsEdwards},
4        traits::IsEllipticCurve,
5    },
6    field::{element::FieldElement, fields::p448_goldilocks_prime_field::P448GoldilocksPrimeField},
7};
8
9#[derive(Debug, Clone)]
10pub struct Ed448Goldilocks;
11
12impl IsEllipticCurve for Ed448Goldilocks {
13    type BaseField = P448GoldilocksPrimeField;
14    type PointRepresentation = EdwardsProjectivePoint<Self>;
15
16    /// Returns the generator point of the Ed448-Goldilocks curve.
17    ///
18    /// This generator is taken from [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748#page-6).
19    ///
20    /// # Safety
21    ///
22    /// - The generator coordinates `(x, y, 1)` are well-known, predefined constants.
23    /// - `unwrap()` is used because the values are **known to be valid** points
24    ///   on the Ed448-Goldilocks curve.
25    /// - This function must **not** be modified unless new constants are mathematically verified.
26    fn generator() -> Self::PointRepresentation {
27        // SAFETY:
28        // - These values are taken from RFC 7748 and are known to be valid.
29        // - `unwrap()` is safe because `new()` will only fail if the point is
30        //   invalid, which is **not possible** with hardcoded, verified values.
31        let point= Self::PointRepresentation::new([
32            FieldElement::<Self::BaseField>::from_hex("4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e").unwrap(),
33            FieldElement::<Self::BaseField>::from_hex("693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14").unwrap(),
34            FieldElement::one(),
35        ]);
36        point.unwrap()
37    }
38}
39
40impl IsEdwards for Ed448Goldilocks {
41    fn a() -> FieldElement<Self::BaseField> {
42        FieldElement::one()
43    }
44
45    fn d() -> FieldElement<Self::BaseField> {
46        -FieldElement::from(39081)
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use crate::{
54        cyclic_group::IsGroup, elliptic_curve::traits::EllipticCurveError,
55        field::element::FieldElement,
56    };
57
58    #[allow(clippy::upper_case_acronyms)]
59    type FE = FieldElement<P448GoldilocksPrimeField>;
60
61    fn generator_times_5() -> EdwardsProjectivePoint<Ed448Goldilocks> {
62        let x = FE::from_hex("7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034").unwrap();
63        let y = FE::from_hex("adfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb").unwrap();
64        Ed448Goldilocks::create_point_from_affine(x, y).unwrap()
65    }
66
67    fn point_1() -> EdwardsProjectivePoint<Ed448Goldilocks> {
68        let x = FE::from_hex("c591e0987244569fbb80a8edda5f9c5b30d9e7862acbb19ac0f24b766fe29c5e5782efc0e7a169f0c55c5524f8a9f9333ca985ec56404926").unwrap();
69        let y = FE::from_hex("f969573bf05f19ac5824718d7483d3b83a3ece5847e25487ae2a176290ad2b1cb9c7f4dd55f6ca6c50209556d7fc16e0683c3177356ac9bc").unwrap();
70        Ed448Goldilocks::create_point_from_affine(x, y).unwrap()
71    }
72
73    fn point_1_times_7() -> EdwardsProjectivePoint<Ed448Goldilocks> {
74        let x = FE::from_hex("63c9cd1d79f027458015c2013fc819dd0f46f71c21a11fee0c32998acd17bac5b06d0f2f1e1539cfc33223a6e989b2b119dae9bbb16c3743").unwrap();
75        let y = FE::from_hex("654de66ab8be9fbeec6e72798a0ba2bb39c1888b99104de6cb0acf4516ea5e018bd292a1855f0fea673a5d8e8724d1b19ca52817db624f06").unwrap();
76        Ed448Goldilocks::create_point_from_affine(x, y).unwrap()
77    }
78
79    #[test]
80    fn generator_satisfies_defining_equation() {
81        let g = Ed448Goldilocks::generator().to_affine();
82        assert_eq!(Ed448Goldilocks::defining_equation(g.x(), g.y()), FE::zero());
83    }
84
85    #[test]
86    fn adding_generator_five_times_works() {
87        let g_times_5 = Ed448Goldilocks::generator().operate_with_self(5_u16);
88        assert_eq!(g_times_5, generator_times_5());
89    }
90
91    #[test]
92    fn adding_point_1_seven_times_works() {
93        let point_1 = point_1();
94        let point_1_times_7 = point_1_times_7();
95        assert_eq!(point_1.operate_with_self(7_u16), point_1_times_7);
96    }
97
98    #[test]
99    fn create_valid_point_works() {
100        let p = point_1();
101        assert_eq!(*p.x(), FE::from_hex("c591e0987244569fbb80a8edda5f9c5b30d9e7862acbb19ac0f24b766fe29c5e5782efc0e7a169f0c55c5524f8a9f9333ca985ec56404926").unwrap());
102        assert_eq!(*p.y(), FE::from_hex("f969573bf05f19ac5824718d7483d3b83a3ece5847e25487ae2a176290ad2b1cb9c7f4dd55f6ca6c50209556d7fc16e0683c3177356ac9bc").unwrap());
103        assert_eq!(*p.z(), FE::one());
104    }
105
106    #[test]
107    fn create_invalid_points_panics() {
108        assert_eq!(
109            Ed448Goldilocks::create_point_from_affine(FE::from(1), FE::from(1)).unwrap_err(),
110            EllipticCurveError::InvalidPoint
111        )
112    }
113}