1use core::fmt;
23use crate::curve_weierstrass::WeierstrassCurve;
26use crate::point_ops::PointOps;
27use fp::field_ops::FieldOps;
28use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
29
30#[derive(Debug, Clone, Copy)]
35pub struct AffinePoint<F: FieldOps> {
36 pub x: F,
38 pub y: F,
40 pub infinity: bool,
42}
43
44impl<F: FieldOps> PartialEq for AffinePoint<F>
49where
50 F: FieldOps + ConstantTimeEq,
51{
52 fn eq(&self, other: &Self) -> bool {
53 match (self.infinity, other.infinity) {
54 (true, true) => true,
55 (true, false) => false,
56 (false, true) => false,
57 (false, false) => self.x == other.x && self.y == other.y,
58 }
59 }
60}
61
62impl<F> fmt::Display for AffinePoint<F>
63where
64 F: FieldOps + fmt::Display,
65{
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 if self.infinity {
68 if f.alternate() {
69 write!(f, "AffinePoint {{ O }}")
70 } else {
71 write!(f, "O")
72 }
73 } else if f.alternate() {
74 write!(f, "AffinePoint {{ x = {}, y = {} }}", self.x, self.y)
75 } else {
76 write!(f, "({}, {})", self.x, self.y)
77 }
78 }
79}
80
81
82
83impl<F: FieldOps> Eq for AffinePoint<F>
84where
85F: FieldOps + ConstantTimeEq
86{ }
87
88impl<F: FieldOps> AffinePoint<F> {
93 pub fn new(x: F, y: F) -> Self {
98 Self {
99 x,
100 y,
101 infinity: false,
102 }
103 }
104
105 pub fn identity() -> Self {
107 Self {
108 x: F::zero(),
109 y: F::zero(),
110 infinity: true,
111 }
112 }
113
114 pub fn is_identity(&self) -> bool {
116 self.infinity
117 }
118}
119
120impl<F> ConditionallySelectable for AffinePoint<F>
125where
126 F: FieldOps + Copy,
127{
128 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
129 let ai = a.infinity as u8;
130 let bi = b.infinity as u8;
131 let infinity = u8::conditional_select(&ai, &bi, choice) != 0;
132
133 Self {
134 x: F::conditional_select(&a.x, &b.x, choice),
135 y: F::conditional_select(&a.y, &b.y, choice),
136 infinity,
137 }
138 }
139
140 fn conditional_assign(&mut self, other: &Self, choice: Choice) {
141 F::conditional_assign(&mut self.x, &other.x, choice);
142 F::conditional_assign(&mut self.y, &other.y, choice);
143
144 let mut inf = self.infinity as u8;
145 let other_inf = other.infinity as u8;
146 inf.conditional_assign(&other_inf, choice);
147 self.infinity = inf != 0;
148 }
149
150 fn conditional_swap(a: &mut Self, b: &mut Self, choice: Choice) {
151 F::conditional_swap(&mut a.x, &mut b.x, choice);
152 F::conditional_swap(&mut a.y, &mut b.y, choice);
153
154 let mut ai = a.infinity as u8;
155 let mut bi = b.infinity as u8;
156 u8::conditional_swap(&mut ai, &mut bi, choice);
157 a.infinity = ai != 0;
158 b.infinity = bi != 0;
159 }
160}
161
162impl<F> ConstantTimeEq for AffinePoint<F>
163where
164 F: FieldOps + Copy + ConstantTimeEq,
165{
166 fn ct_eq(&self, other: &Self) -> Choice {
167 let self_inf = Choice::from(self.infinity as u8);
168 let other_inf = Choice::from(other.infinity as u8);
169
170 let both_inf = self_inf & other_inf;
171 let both_finite = !self_inf & !other_inf;
172 let coords_eq = self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y);
173
174 both_inf | (both_finite & coords_eq)
175 }
176
177 fn ct_ne(&self, other: &Self) -> Choice {
178 !self.ct_eq(other)
179 }
180}
181
182impl<F: FieldOps> AffinePoint<F> {
187 pub fn negate(&self, curve: &WeierstrassCurve<F>) -> Self {
189 if self.infinity {
190 return Self::identity();
191 }
192
193 let neg_y = -self.y - curve.a1 * self.x - curve.a3;
194
195 Self::new(self.x.clone(), neg_y)
196 }
197
198 pub fn double(&self, curve: &WeierstrassCurve<F>) -> Self {
210 if self.infinity {
211 return Self::identity();
212 }
213
214 let denom = <F as FieldOps>::double(&self.y) + curve.a1 * self.x + curve.a3;
216
217 let denom_inv = match denom.invert().into_option() {
219 Some(inv) => inv,
220 None => return Self::identity(),
221 };
222
223 let numer = {
225 let x1_sq = <F as FieldOps>::square(&self.x);
226 let three_x1_sq = x1_sq + <F as FieldOps>::double(&x1_sq);
227 let two_a2_x1 = <F as FieldOps>::double(&(curve.a2 * self.x));
228 let a1y1 = curve.a1 * self.y;
229 three_x1_sq + two_a2_x1 + curve.a4 - a1y1
230 };
231
232 let lambda = numer * denom_inv;
233
234 let x3 = {
236 let lam_sq = <F as FieldOps>::square(&lambda);
237 let a1_lam = curve.a1 * lambda;
238 let two_x1 = <F as FieldOps>::double(&self.x);
239 lam_sq + a1_lam - curve.a2 - two_x1
240 };
241
242 let y3 = {
244 let dx = self.x - x3;
245 let lam_dx = lambda * dx;
246 let a1x3 = curve.a1 * x3;
247
248 lam_dx - self.y - a1x3 - curve.a3
249 };
250
251 Self::new(x3, y3)
252 }
253
254 pub fn add(&self, other: &Self, curve: &WeierstrassCurve<F>) -> Self {
268 if self.infinity {
270 return other.clone();
271 }
272 if other.infinity {
274 return self.clone();
275 }
276
277 if self.x == other.x {
279 if self.y == other.y {
280 return self.double(curve);
282 }
283 return Self::identity();
286 }
287
288 let dx = other.x - self.x;
290 let dy = other.y - self.y;
291
292 let dx_inv = dx
294 .invert()
295 .into_option()
296 .expect("dx must be invertible (x₁ ≠ x₂)");
297 let lambda = dy * dx_inv;
298
299 let x3 = {
301 let lam_sq = <F as FieldOps>::square(&lambda);
302 let a1_lam = curve.a1 * lambda;
303 lam_sq + a1_lam - curve.a2 - self.x - other.x
304 };
305
306 let y3 = {
308 let dx3 = self.x - x3;
309 let lam_dx3 = lambda * dx3;
310 let a1x3 = curve.a1 * x3;
311 lam_dx3 - self.y - a1x3 - curve.a3
312 };
313
314 Self::new(x3, y3)
315 }
316
317 pub fn scalar_mul(&self, k: &[u64], curve: &<AffinePoint<F> as PointOps>::Curve) -> Self {
329 let mut r0 = Self::identity();
330 let mut r1 = self.clone();
331
332 for &limb in k.iter().rev() {
333 for bit in (0..64).rev() {
334 let choice = Choice::from(((limb >> bit) & 1) as u8);
335
336 Self::conditional_swap(&mut r0, &mut r1, choice);
337
338 let sum = r0.add(&r1, curve);
339 let dbl = r0.double(curve);
340 r1 = sum;
341 r0 = dbl;
342
343 Self::conditional_swap(&mut r0, &mut r1, choice);
344 }
345 }
346
347 r0
348 }
349}
350
351impl<F> PointOps for AffinePoint<F>
352where
353 F: FieldOps,
354{
355 type BaseField = F;
356 type Curve = WeierstrassCurve<F>;
357
358 fn identity(_curve: &Self::Curve) -> Self {
359 AffinePoint::<F>::identity()
360 }
361
362 fn is_identity(&self) -> bool {
363 self.infinity
364 }
365
366 fn negate(&self, curve: &Self::Curve) -> Self {
367 AffinePoint::<F>::negate(self, curve)
368 }
369
370 fn scalar_mul(&self, k: &[u64], curve: &Self::Curve) -> Self {
371 AffinePoint::<F>::scalar_mul(self, k, curve)
372 }
373}
374
375impl<F> crate::point_ops::PointAdd for AffinePoint<F>
376where
377 F: FieldOps,
378{
379 fn add(&self, other: &Self, curve: &Self::Curve) -> Self {
380 AffinePoint::<F>::add(self, other, curve)
381 }
382}