lambdaworks_math/elliptic_curve/edwards/
point.rs1use crate::{
2 cyclic_group::IsGroup,
3 elliptic_curve::{
4 point::ProjectivePoint,
5 traits::{EllipticCurveError, FromAffine, IsEllipticCurve},
6 },
7 field::element::FieldElement,
8};
9
10use super::traits::IsEdwards;
11
12#[derive(Clone, Debug)]
13pub struct EdwardsProjectivePoint<E: IsEllipticCurve>(ProjectivePoint<E>);
14
15impl<E: IsEllipticCurve + IsEdwards> EdwardsProjectivePoint<E> {
16 pub fn new(value: [FieldElement<E::BaseField>; 3]) -> Result<Self, EllipticCurveError> {
18 let (x, y, z) = (&value[0], &value[1], &value[2]);
19
20 if x == &FieldElement::<E::BaseField>::zero() && z == y {
23 return Ok(Self(ProjectivePoint::new([
24 FieldElement::<E::BaseField>::zero(),
25 FieldElement::<E::BaseField>::one(),
26 FieldElement::<E::BaseField>::one(),
27 ])));
28 }
29 if z != &FieldElement::<E::BaseField>::zero()
30 && E::defining_equation_projective(x, y, z) == FieldElement::<E::BaseField>::zero()
31 {
32 Ok(Self(ProjectivePoint::new(value)))
33 } else {
34 Err(EllipticCurveError::InvalidPoint)
35 }
36 }
37
38 pub fn x(&self) -> &FieldElement<E::BaseField> {
40 self.0.x()
41 }
42
43 pub fn y(&self) -> &FieldElement<E::BaseField> {
45 self.0.y()
46 }
47
48 pub fn z(&self) -> &FieldElement<E::BaseField> {
50 self.0.z()
51 }
52
53 pub fn coordinates(&self) -> &[FieldElement<E::BaseField>; 3] {
55 self.0.coordinates()
56 }
57
58 pub fn to_affine(&self) -> Self {
62 Self(self.0.to_affine())
63 }
64}
65
66impl<E: IsEllipticCurve> PartialEq for EdwardsProjectivePoint<E> {
67 fn eq(&self, other: &Self) -> bool {
68 self.0 == other.0
69 }
70}
71
72impl<E: IsEdwards> FromAffine<E::BaseField> for EdwardsProjectivePoint<E> {
73 fn from_affine(
74 x: FieldElement<E::BaseField>,
75 y: FieldElement<E::BaseField>,
76 ) -> Result<Self, EllipticCurveError> {
77 let coordinates = [x, y, FieldElement::one()];
78 EdwardsProjectivePoint::new(coordinates)
79 }
80}
81
82impl<E: IsEllipticCurve> Eq for EdwardsProjectivePoint<E> {}
83
84impl<E: IsEdwards> IsGroup for EdwardsProjectivePoint<E> {
85 fn neutral_element() -> Self {
94 let point = Self::new([
98 FieldElement::zero(),
99 FieldElement::one(),
100 FieldElement::one(),
101 ]);
102 point.unwrap()
103 }
104
105 fn is_neutral_element(&self) -> bool {
106 let [px, py, pz] = self.coordinates();
107 px == &FieldElement::zero() && py == pz
108 }
109
110 fn operate_with(&self, other: &Self) -> Self {
121 let (s_affine, o_affine) = (self.to_affine(), other.to_affine());
123
124 let [x1, y1, _] = s_affine.coordinates();
125 let [x2, y2, _] = o_affine.coordinates();
126
127 let one = FieldElement::one();
128 let (x1y2, y1x2) = (x1 * y2, y1 * x2);
129 let (x1x2, y1y2) = (x1 * x2, y1 * y2);
130 let dx1x2y1y2 = E::d() * &x1x2 * &y1y2;
131
132 let num_s1 = &x1y2 + &y1x2;
133 let den_s1 = &one + &dx1x2y1y2;
134
135 let num_s2 = &y1y2 - E::a() * &x1x2;
136 let den_s2 = &one - &dx1x2y1y2;
137 let x_coord = (&num_s1 / &den_s1).unwrap();
141 let y_coord = (&num_s2 / &den_s2).unwrap();
142 let point = Self::new([x_coord, y_coord, one]);
143 point.unwrap()
144 }
145
146 fn neg(&self) -> Self {
153 let [px, py, pz] = self.coordinates();
154 let point = Self::new([-px, py.clone(), pz.clone()]);
158 point.unwrap()
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use crate::{
165 cyclic_group::IsGroup,
166 elliptic_curve::{
167 edwards::{curves::tiny_jub_jub::TinyJubJubEdwards, point::EdwardsProjectivePoint},
168 traits::{EllipticCurveError, IsEllipticCurve},
169 },
170 field::element::FieldElement,
171 };
172
173 fn create_point(x: u64, y: u64) -> EdwardsProjectivePoint<TinyJubJubEdwards> {
174 TinyJubJubEdwards::create_point_from_affine(FieldElement::from(x), FieldElement::from(y))
175 .unwrap()
176 }
177
178 #[test]
179 fn create_valid_point_works() {
180 let p = TinyJubJubEdwards::create_point_from_affine(
181 FieldElement::from(5),
182 FieldElement::from(5),
183 )
184 .unwrap();
185 assert_eq!(p.x(), &FieldElement::from(5));
186 assert_eq!(p.y(), &FieldElement::from(5));
187 assert_eq!(p.z(), &FieldElement::from(1));
188 }
189
190 #[test]
191 fn create_invalid_point_returns_invalid_point_error() {
192 let result = TinyJubJubEdwards::create_point_from_affine(
193 FieldElement::from(5),
194 FieldElement::from(4),
195 );
196 assert_eq!(result.unwrap_err(), EllipticCurveError::InvalidPoint);
197 }
198
199 #[test]
200 fn operate_with_works_for_points_in_tiny_jub_jub() {
201 let p = EdwardsProjectivePoint::<TinyJubJubEdwards>::new([
202 FieldElement::from(5),
203 FieldElement::from(5),
204 FieldElement::from(1),
205 ])
206 .unwrap();
207 let q = EdwardsProjectivePoint::<TinyJubJubEdwards>::new([
208 FieldElement::from(8),
209 FieldElement::from(5),
210 FieldElement::from(1),
211 ])
212 .unwrap();
213 let expected = EdwardsProjectivePoint::<TinyJubJubEdwards>::new([
214 FieldElement::from(0),
215 FieldElement::from(1),
216 FieldElement::from(1),
217 ])
218 .unwrap();
219 assert_eq!(p.operate_with(&q), expected);
220 }
221
222 #[test]
223 fn test_negation_in_edwards() {
224 let a = create_point(5, 5);
225 let b = create_point(13 - 5, 5);
226
227 assert_eq!(a.neg(), b);
228 assert!(a.operate_with(&b).is_neutral_element());
229 }
230
231 #[test]
232 fn operate_with_works_and_cycles_in_tiny_jub_jub() {
233 let g = create_point(12, 11);
234 assert_eq!(g.operate_with_self(0_u16), create_point(0, 1));
235 assert_eq!(g.operate_with_self(1_u16), create_point(12, 11));
236 assert_eq!(g.operate_with_self(2_u16), create_point(8, 5));
237 assert_eq!(g.operate_with_self(3_u16), create_point(11, 6));
238 assert_eq!(g.operate_with_self(4_u16), create_point(6, 9));
239 assert_eq!(g.operate_with_self(5_u16), create_point(10, 0));
240 assert_eq!(g.operate_with_self(6_u16), create_point(6, 4));
241 assert_eq!(g.operate_with_self(7_u16), create_point(11, 7));
242 assert_eq!(g.operate_with_self(8_u16), create_point(8, 8));
243 assert_eq!(g.operate_with_self(9_u16), create_point(12, 2));
244 assert_eq!(g.operate_with_self(10_u16), create_point(0, 12));
245 assert_eq!(g.operate_with_self(11_u16), create_point(1, 2));
246 assert_eq!(g.operate_with_self(12_u16), create_point(5, 8));
247 assert_eq!(g.operate_with_self(13_u16), create_point(2, 7));
248 assert_eq!(g.operate_with_self(14_u16), create_point(7, 4));
249 assert_eq!(g.operate_with_self(15_u16), create_point(3, 0));
250 assert_eq!(g.operate_with_self(16_u16), create_point(7, 9));
251 assert_eq!(g.operate_with_self(17_u16), create_point(2, 6));
252 assert_eq!(g.operate_with_self(18_u16), create_point(5, 5));
253 assert_eq!(g.operate_with_self(19_u16), create_point(1, 11));
254 assert_eq!(g.operate_with_self(20_u16), create_point(0, 1));
255 }
256}