1use core::fmt;
38use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
39
40use crate::curve_edwards::EdwardsCurve;
41use crate::point_ops::PointOps;
42use fp::field_ops::FieldOps;
43
44#[derive(Debug, Clone, Copy)]
46pub struct EdwardsPoint<F: FieldOps> {
47 pub x: F,
49 pub y: F,
51}
52
53impl<F> fmt::Display for EdwardsPoint<F>
54where
55 F: FieldOps + fmt::Display,
56{
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 if self.is_identity() {
59 if f.alternate() {
60 if F::characteristic()[0] != 2 {
61 write!(f, "EdwardsPoint {{ O = (0,1) }}")
62 } else {
63 write!(f, "EdwardsPoint {{ O = (0,0) }}")
64 }
65 } else {
66 write!(f, "O")
67 }
68 } else if f.alternate() {
69 write!(f, "EdwardsPoint {{ x = {}, y = {} }}", self.x, self.y)
70 } else {
71 write!(f, "({}, {})", self.x, self.y)
72 }
73 }
74}
75
76impl<F: FieldOps> PartialEq for EdwardsPoint<F> {
81 fn eq(&self, other: &Self) -> bool {
82 self.x == other.x && self.y == other.y
83 }
84}
85
86impl<F: FieldOps> Eq for EdwardsPoint<F> {}
87
88impl<F: FieldOps> EdwardsPoint<F> {
93 pub fn new(x: F, y: F) -> Self {
95 Self { x, y }
96 }
97
98 pub fn identity() -> Self {
102 if F::characteristic()[0] != 2 {
103 Self {
104 x: F::zero(),
105 y: F::one(),
106 }
107 } else {
108 Self {
109 x: F::zero(),
110 y: F::zero(),
111 }
112 }
113 }
114
115 pub fn is_identity(&self) -> bool {
117 if F::characteristic()[0] != 2 {
118 self.x == F::zero() && self.y == F::one()
119 } else {
120 self.x == F::zero() && self.y == F::zero()
121 }
122 }
123}
124
125impl<F> ConditionallySelectable for EdwardsPoint<F>
130where
131 F: FieldOps + Copy,
132{
133 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
134 Self {
135 x: F::conditional_select(&a.x, &b.x, choice),
136 y: F::conditional_select(&a.y, &b.y, choice),
137 }
138 }
139
140 fn conditional_assign(&mut self, other: &Self, choice: Choice) {
141 self.x.conditional_assign(&other.x, choice);
142 self.y.conditional_assign(&other.y, choice);
143 }
144
145 fn conditional_swap(a: &mut Self, b: &mut Self, choice: Choice) {
146 F::conditional_swap(&mut a.x, &mut b.x, choice);
147 F::conditional_swap(&mut a.y, &mut b.y, choice);
148 }
149}
150
151impl<F> ConstantTimeEq for EdwardsPoint<F>
152where
153 F: FieldOps + Copy + ConstantTimeEq,
154{
155 fn ct_eq(&self, other: &Self) -> Choice {
156 self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y)
157 }
158
159 fn ct_ne(&self, other: &Self) -> Choice {
160 !self.ct_eq(other)
161 }
162}
163
164impl<F: FieldOps> EdwardsPoint<F> {
169 pub fn negate(&self, _curve: &EdwardsCurve<F>) -> Self {
173 if F::characteristic()[0] != 2 {
174 Self::new(-self.x, self.y)
175 } else {
176 Self::new(self.y, self.x)
177 }
178 }
179
180 pub fn add(&self, other: &Self, curve: &EdwardsCurve<F>) -> Self {
182 if F::characteristic()[0] != 2 {
183 self.add_odd(other, curve)
184 } else {
185 self.add_binary(other, curve)
186 }
187 }
188
189 pub fn double(&self, curve: &EdwardsCurve<F>) -> Self {
192 self.add(self, curve)
193 }
194
195 pub fn scalar_mul(&self, k: &[u64], curve: &EdwardsCurve<F>) -> Self {
197 let mut result = Self::identity();
198
199 for &limb in k.iter().rev() {
200 for bit in (0..64).rev() {
201 let doubled = result.double(curve);
202 let added = doubled.add(self, curve);
203 let choice = Choice::from(((limb >> bit) & 1) as u8);
204 result = Self::conditional_select(&doubled, &added, choice);
205 }
206 }
207
208 result
209 }
210
211 fn add_odd(&self, other: &Self, curve: &EdwardsCurve<F>) -> Self {
219 let d = curve.d2;
220
221 let x1y2 = self.x * other.y;
222 let y1x2 = self.y * other.x;
223 let x1x2 = self.x * other.x;
224 let y1y2 = self.y * other.y;
225
226 let dxy = d * x1x2 * y1y2;
227
228 let one = F::one();
229 let x_num = x1y2 + y1x2;
230 let x_den = one + dxy;
231 let y_num = y1y2 - x1x2;
232 let y_den = one - dxy;
233
234 let x_den_inv = x_den
235 .invert()
236 .into_option()
237 .expect("Edwards addition: x-denominator must be invertible");
238 let y_den_inv = y_den
239 .invert()
240 .into_option()
241 .expect("Edwards addition: y-denominator must be invertible");
242
243 Self::new(x_num * x_den_inv, y_num * y_den_inv)
244 }
245
246 fn add_binary(&self, other: &Self, curve: &EdwardsCurve<F>) -> Self {
259 let x1 = self.x;
260 let y1 = self.y;
261 let x2 = other.x;
262 let y2 = other.y;
263 let d1 = curve.d1;
264 let d2 = curve.d2;
265
266 let w1 = x1 + y1;
267 let w2 = x2 + y2;
268
269 let a = <F as FieldOps>::square(&x1) + x1;
270 let b = <F as FieldOps>::square(&y1) + y1;
271
272 let d2_w1w2 = d2 * w1 * w2;
273 let x1x2 = x1 * x2;
274 let y1y2 = y1 * y2;
275
276 let x_num = d1 * (x1 + x2) + d2_w1w2 + a * (x2 * (y1 + y2 + F::one()) + y1y2);
277 let x_den = d1 + a * w2;
278
279 let y_num = d1 * (y1 + y2) + d2_w1w2 + b * (y2 * (x1 + x2 + F::one()) + x1x2);
280 let y_den = d1 + b * w2;
281
282 let x_den_inv = x_den
283 .invert()
284 .into_option()
285 .expect("binary Edwards addition: x-denom must be invertible");
286 let y_den_inv = y_den
287 .invert()
288 .into_option()
289 .expect("binary Edwards addition: y-denom must be invertible");
290
291 Self::new(x_num * x_den_inv, y_num * y_den_inv)
292 }
293}
294
295impl<F: FieldOps> EdwardsPoint<F> {
300 pub fn w_diff_add(w1: &F, w2: &F, w3: &F, curve: &EdwardsCurve<F>) -> F {
304 let r = *w2 * *w3;
305 let s = <F as FieldOps>::square(&r);
306 let one = F::one();
307 let t = r * (one + *w2 + *w3) + s;
308
309 let d2_over_d1 = curve.d2 * curve.d1.invert().into_option().expect("d1 invertible");
310 let coeff = d2_over_d1 + one;
311
312 let den = curve.d1 + t + coeff * s;
313 let den_inv = den
314 .invert()
315 .into_option()
316 .expect("w-diff-add denominator invertible");
317
318 t * den_inv + *w1
319 }
320
321 pub fn w_double(w2: &F, curve: &EdwardsCurve<F>) -> F {
325 let a = <F as FieldOps>::square(w2);
326 let j = <F as FieldOps>::square(&a);
327
328 let d2_over_d1 = curve.d2 * curve.d1.invert().into_option().expect("d1 invertible");
329
330 let num = a + j;
331 let den = curve.d1 + a + d2_over_d1 * j;
332 let den_inv = den
333 .invert()
334 .into_option()
335 .expect("w-double denominator invertible");
336
337 num * den_inv
338 }
339}
340
341impl<F: FieldOps> PointOps for EdwardsPoint<F> {
346 type BaseField = F;
347 type Curve = EdwardsCurve<F>;
348
349 fn identity(_curve: &Self::Curve) -> Self {
350 EdwardsPoint::<F>::identity()
351 }
352
353 fn is_identity(&self) -> bool {
354 EdwardsPoint::<F>::is_identity(self)
355 }
356
357 fn negate(&self, curve: &Self::Curve) -> Self {
358 EdwardsPoint::<F>::negate(self, curve)
359 }
360
361 fn scalar_mul(&self, k: &[u64], curve: &Self::Curve) -> Self {
362 EdwardsPoint::<F>::scalar_mul(self, k, curve)
363 }
364}