sp1_curves/edwards/
mod.rs1pub mod ed25519;
2
3use generic_array::GenericArray;
4use num::{BigUint, Zero};
5use serde::{Deserialize, Serialize};
6
7use super::CurveType;
8use crate::{
9 params::{FieldParameters, NumLimbs},
10 AffinePoint, EllipticCurve, EllipticCurveParameters,
11};
12
13use crate::{edwards::ed25519::Ed25519BaseField, params::NumWords};
14use typenum::Unsigned;
15
16pub type Limbs = <Ed25519BaseField as NumLimbs>::Limbs;
17pub const NUM_LIMBS: usize = Limbs::USIZE;
18
19pub type WordsFieldElement = <Ed25519BaseField as NumWords>::WordsFieldElement;
20pub const WORDS_FIELD_ELEMENT: usize = WordsFieldElement::USIZE;
21
22#[allow(unused)]
23pub type WordsCurvePoint = <Ed25519BaseField as NumWords>::WordsCurvePoint;
24pub const WORDS_CURVE_POINT: usize = WordsCurvePoint::USIZE;
25
26pub trait EdwardsParameters: EllipticCurveParameters {
27 const D: GenericArray<u8, <Self::BaseField as NumLimbs>::Limbs>;
28
29 fn generator() -> (BigUint, BigUint);
30
31 fn prime_group_order() -> BigUint;
32
33 fn d_biguint() -> BigUint {
34 let mut modulus = BigUint::zero();
35 for (i, limb) in Self::D.iter().enumerate() {
36 modulus += BigUint::from(*limb) << (8 * i);
37 }
38 modulus
39 }
40
41 fn neutral() -> (BigUint, BigUint) {
42 (BigUint::from(0u32), BigUint::from(1u32))
43 }
44}
45
46#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
47#[serde(bound = "")]
48pub struct EdwardsCurve<E: EdwardsParameters>(pub E);
49
50impl<E: EdwardsParameters> EdwardsParameters for EdwardsCurve<E> {
51 const D: GenericArray<u8, <Self::BaseField as NumLimbs>::Limbs> = E::D;
52
53 fn generator() -> (BigUint, BigUint) {
54 E::generator()
55 }
56
57 fn prime_group_order() -> BigUint {
58 E::prime_group_order()
59 }
60
61 fn d_biguint() -> BigUint {
62 E::d_biguint()
63 }
64
65 fn neutral() -> (BigUint, BigUint) {
66 E::neutral()
67 }
68}
69
70impl<E: EdwardsParameters> EllipticCurveParameters for EdwardsCurve<E> {
71 type BaseField = E::BaseField;
72 const CURVE_TYPE: CurveType = E::CURVE_TYPE;
73}
74
75impl<E: EdwardsParameters> EdwardsCurve<E> {
76 pub fn prime_group_order() -> BigUint {
77 E::prime_group_order()
78 }
79
80 pub fn neutral() -> AffinePoint<Self> {
81 let (x, y) = E::neutral();
82 AffinePoint::new(x, y)
83 }
84}
85
86impl<E: EdwardsParameters> EllipticCurve for EdwardsCurve<E> {
87 fn ec_add(p: &AffinePoint<Self>, q: &AffinePoint<Self>) -> AffinePoint<Self> {
88 p.ed_add(q)
89 }
90
91 fn ec_double(p: &AffinePoint<Self>) -> AffinePoint<Self> {
92 p.ed_double()
93 }
94
95 fn ec_generator() -> AffinePoint<Self> {
96 let (x, y) = E::generator();
97 AffinePoint::new(x, y)
98 }
99
100 fn ec_neutral() -> Option<AffinePoint<Self>> {
101 Some(Self::neutral())
102 }
103
104 fn ec_neg(p: &AffinePoint<Self>) -> AffinePoint<Self> {
105 let modulus = E::BaseField::modulus();
106 AffinePoint::new(&modulus - &p.x, p.y.clone())
107 }
108}
109
110impl<E: EdwardsParameters> AffinePoint<EdwardsCurve<E>> {
111 pub(crate) fn ed_add(
112 &self,
113 other: &AffinePoint<EdwardsCurve<E>>,
114 ) -> AffinePoint<EdwardsCurve<E>> {
115 let p = <E as EllipticCurveParameters>::BaseField::modulus();
116 let x_3n = (&self.x * &other.y + &self.y * &other.x) % &p;
117 let y_3n = (&self.y * &other.y + &self.x * &other.x) % &p;
118
119 let all_xy = (&self.x * &self.y * &other.x * &other.y) % &p;
120 let d = E::d_biguint();
121 let dxy = (d * &all_xy) % &p;
122 let den_x = ((1u32 + &dxy) % &p).modpow(&(&p - 2u32), &p);
123 let den_y = ((1u32 + &p - &dxy) % &p).modpow(&(&p - 2u32), &p);
124
125 let x_3 = (&x_3n * &den_x) % &p;
126 let y_3 = (&y_3n * &den_y) % &p;
127
128 AffinePoint::new(x_3, y_3)
129 }
130
131 pub(crate) fn ed_double(&self) -> AffinePoint<EdwardsCurve<E>> {
132 self.ed_add(self)
133 }
134}
135
136#[cfg(test)]
137mod tests {
138
139 use num::bigint::RandBigInt;
140 use rand::thread_rng;
141
142 use super::*;
143 use crate::edwards::ed25519::{Ed25519, Ed25519Parameters};
144
145 #[test]
146 fn test_bigint_ed_add() {
147 type E = Ed25519;
148 let neutral = E::neutral();
149 let base = E::ec_generator();
150
151 assert_eq!(&base + &neutral, base);
152 assert_eq!(&neutral + &base, base);
153 assert_eq!(&neutral + &neutral, neutral);
154 }
155
156 #[test]
157 fn test_biguint_scalar_mul() {
158 type E = Ed25519;
159 let base = E::ec_generator();
160
161 let d = Ed25519Parameters::d_biguint();
162 let p = <E as EllipticCurveParameters>::BaseField::modulus();
163 assert_eq!((d * 121666u32) % &p, (&p - 121665u32) % &p);
164
165 let mut rng = thread_rng();
166 for _ in 0..10 {
167 let x = rng.gen_biguint(24);
168 let y = rng.gen_biguint(25);
169
170 let x_base = &base * &x;
171 let y_x_base = &x_base * &y;
172 let xy = &x * &y;
173 let xy_base = &base * &xy;
174 assert_eq!(y_x_base, xy_base);
175 }
176
177 let order = BigUint::from(2u32).pow(252) +
178 BigUint::from(27742317777372353535851937790883648493u128);
179 assert_eq!(base, &base + &(&base * &order));
180 }
181}