primeorder/
point_arithmetic.rs1use elliptic_curve::{Field, subtle::ConditionallySelectable};
7
8use crate::{AffinePoint, PrimeCurveParams, ProjectivePoint};
9
10mod sealed {
11 use crate::{AffinePoint, PrimeCurveParams, ProjectivePoint};
12
13 pub trait PointArithmetic<C: PrimeCurveParams> {
18 fn add_assign(lhs: &mut ProjectivePoint<C>, rhs: &ProjectivePoint<C>);
20
21 fn add_assign_mixed(lhs: &mut ProjectivePoint<C>, rhs: &AffinePoint<C>);
23
24 fn double_in_place(point: &mut ProjectivePoint<C>);
26 }
27}
28
29pub(crate) use sealed::PointArithmetic;
31
32#[inline(always)]
34fn debug_assert_equation_a_is_minus_three<C: PrimeCurveParams>() {
35 debug_assert_eq!(
36 C::EQUATION_A,
37 -C::FieldElement::from(3),
38 "this implementation is only valid for C::EQUATION_A = -3"
39 );
40}
41
42#[inline(always)]
43fn debug_assert_equation_a_is_zero<C: PrimeCurveParams>() {
44 debug_assert_eq!(
45 C::EQUATION_A,
46 C::FieldElement::ZERO,
47 "this implementation is only valid for C::EQUATION_A = 0"
48 );
49}
50
51#[derive(Clone, Copy, Debug)]
54pub struct EquationAIsGeneric;
55
56impl<C: PrimeCurveParams> PointArithmetic<C> for EquationAIsGeneric {
57 fn add_assign(lhs: &mut ProjectivePoint<C>, rhs: &ProjectivePoint<C>) {
65 let b3 = C::FieldElement::from(3) * C::EQUATION_B;
66
67 let t0 = lhs.x * rhs.x; let t1 = lhs.y * rhs.y; let t2 = lhs.z * rhs.z; let t3 = lhs.x + lhs.y; let t4 = rhs.x + rhs.y; let t3 = t3 * t4; let t4 = t0 + t1; let t3 = t3 - t4; let t4 = lhs.x + lhs.z; let t5 = rhs.x + rhs.z; let t4 = t4 * t5; let t5 = t0 + t2; let t4 = t4 - t5; let t5 = lhs.y + lhs.z; let x3 = rhs.y + rhs.z; let t5 = t5 * x3; let x3 = t1 + t2; let t5 = t5 - x3; let z3 = C::EQUATION_A * t4; let x3 = b3 * t2; let z3 = x3 + z3; let x3 = t1 - z3; let z3 = t1 + z3; let y3 = x3 * z3; let t1 = t0 + t0; let t1 = t1 + t0; let t2 = C::EQUATION_A * t2; let t4 = b3 * t4; let t1 = t1 + t2; let t2 = t0 - t2; let t2 = C::EQUATION_A * t2; let t4 = t4 + t2; let t0 = t1 * t4; let y3 = y3 + t0; let t0 = t5 * t4; let x3 = t3 * x3; let x3 = x3 - t0; let t0 = t3 * t1; let z3 = t5 * z3; let z3 = z3 + t0; lhs.x = x3;
109 lhs.y = y3;
110 lhs.z = z3;
111 }
112
113 fn add_assign_mixed(lhs: &mut ProjectivePoint<C>, rhs: &AffinePoint<C>) {
121 let b3 = C::EQUATION_B * C::FieldElement::from(3);
122
123 let t0 = lhs.x * rhs.x; let t1 = lhs.y * rhs.y; let t3 = rhs.x + rhs.y; let t4 = lhs.x + lhs.y; let t3 = t3 * t4; let t4 = t0 + t1; let t3 = t3 - t4; let t4 = rhs.x * lhs.z; let t4 = t4 + lhs.x; let t5 = rhs.y * lhs.z; let t5 = t5 + lhs.y; let z3 = C::EQUATION_A * t4; let x3 = b3 * lhs.z; let z3 = x3 + z3; let x3 = t1 - z3; let z3 = t1 + z3; let y3 = x3 * z3; let t1 = t0 + t0; let t1 = t1 + t0; let t2 = C::EQUATION_A * lhs.z; let t4 = b3 * t4; let t1 = t1 + t2; let t2 = t0 - t2; let t2 = C::EQUATION_A * t2; let t4 = t4 + t2; let t0 = t1 * t4; let y3 = y3 + t0; let t0 = t5 * t4; let x3 = t3 * x3; let x3 = x3 - t0; let t0 = t3 * t1; let z3 = t5 * z3; let z3 = z3 + t0; lhs.x.conditional_assign(&x3, !rhs.is_identity());
158 lhs.y.conditional_assign(&y3, !rhs.is_identity());
159 lhs.z.conditional_assign(&z3, !rhs.is_identity());
160 }
161
162 fn double_in_place(point: &mut ProjectivePoint<C>) {
170 let b3 = C::EQUATION_B * C::FieldElement::from(3);
171
172 let t0 = point.x.square(); let t1 = point.y.square(); let t2 = point.z.square(); let t3 = point.x * point.y; let t3 = t3 + t3; let z3 = point.x * point.z; let z3 = z3 + z3; let x3 = C::EQUATION_A * z3; let y3 = b3 * t2; let y3 = x3 + y3; let x3 = t1 - y3; let y3 = t1 + y3; let y3 = x3 * y3; let x3 = t3 * x3; let z3 = b3 * z3; let t2 = C::EQUATION_A * t2; let t3 = t0 - t2; let t3 = C::EQUATION_A * t3; let t3 = t3 + z3; let z3 = t0 + t0; let t0 = z3 + t0; let t0 = t0 + t2; let t0 = t0 * t3; let y3 = y3 + t0; let t2 = point.y * point.z; let t2 = t2 + t2; let t0 = t2 * t3; let x3 = x3 - t0; let z3 = t2 * t1; let z3 = z3 + z3; let z3 = z3 + z3; point.x = x3;
205 point.y = y3;
206 point.z = z3;
207 }
208}
209
210#[derive(Clone, Copy, Debug)]
212pub struct EquationAIsMinusThree;
213
214impl<C: PrimeCurveParams> PointArithmetic<C> for EquationAIsMinusThree {
215 fn add_assign(lhs: &mut ProjectivePoint<C>, rhs: &ProjectivePoint<C>) {
223 debug_assert_equation_a_is_minus_three::<C>();
224
225 let xx = lhs.x * rhs.x; let yy = lhs.y * rhs.y; let zz = lhs.z * rhs.z; let xy_pairs = ((lhs.x + lhs.y) * (rhs.x + rhs.y)) - (xx + yy); let yz_pairs = ((lhs.y + lhs.z) * (rhs.y + rhs.z)) - (yy + zz); let xz_pairs = ((lhs.x + lhs.z) * (rhs.x + rhs.z)) - (xx + zz); let bzz_part = xz_pairs - (C::EQUATION_B * zz); let bzz3_part = bzz_part.double() + bzz_part; let yy_m_bzz3 = yy - bzz3_part; let yy_p_bzz3 = yy + bzz3_part; let zz3 = zz.double() + zz; let bxz_part = (C::EQUATION_B * xz_pairs) - (zz3 + xx); let bxz3_part = bxz_part.double() + bxz_part; let xx3_m_zz3 = xx.double() + xx - zz3; lhs.x = (yy_p_bzz3 * xy_pairs) - (yz_pairs * bxz3_part); lhs.y = (yy_p_bzz3 * yy_m_bzz3) + (xx3_m_zz3 * bxz3_part); lhs.z = (yy_m_bzz3 * yz_pairs) + (xy_pairs * xx3_m_zz3); }
246
247 fn add_assign_mixed(lhs: &mut ProjectivePoint<C>, rhs: &AffinePoint<C>) {
255 debug_assert_equation_a_is_minus_three::<C>();
256
257 let xx = lhs.x * rhs.x; let yy = lhs.y * rhs.y; let xy_pairs = ((lhs.x + lhs.y) * (rhs.x + rhs.y)) - (xx + yy); let yz_pairs = (rhs.y * lhs.z) + lhs.y; let xz_pairs = (rhs.x * lhs.z) + lhs.x; let bz_part = xz_pairs - (C::EQUATION_B * lhs.z); let bz3_part = bz_part.double() + bz_part; let yy_m_bzz3 = yy - bz3_part; let yy_p_bzz3 = yy + bz3_part; let z3 = lhs.z.double() + lhs.z; let bxz_part = (C::EQUATION_B * xz_pairs) - (z3 + xx); let bxz3_part = bxz_part.double() + bxz_part; let xx3_m_zz3 = xx.double() + xx - z3; let x = (yy_p_bzz3 * xy_pairs) - (yz_pairs * bxz3_part); let y = (yy_p_bzz3 * yy_m_bzz3) + (xx3_m_zz3 * bxz3_part); let z = (yy_m_bzz3 * yz_pairs) + (xy_pairs * xx3_m_zz3); lhs.x.conditional_assign(&x, !rhs.is_identity());
278 lhs.y.conditional_assign(&y, !rhs.is_identity());
279 lhs.z.conditional_assign(&z, !rhs.is_identity());
280 }
281
282 fn double_in_place(point: &mut ProjectivePoint<C>) {
290 debug_assert_equation_a_is_minus_three::<C>();
291
292 let xx = point.x.square(); let yy = point.y.square(); let zz = point.z.square(); let xy2 = (point.x * point.y).double(); let xz2 = (point.x * point.z).double(); let bzz_part = (C::EQUATION_B * zz) - xz2; let bzz3_part = bzz_part.double() + bzz_part; let yy_m_bzz3 = yy - bzz3_part; let yy_p_bzz3 = yy + bzz3_part; let y_frag = yy_p_bzz3 * yy_m_bzz3; let x_frag = yy_m_bzz3 * xy2; let zz3 = zz.double() + zz; let bxz2_part = (C::EQUATION_B * xz2) - (zz3 + xx); let bxz6_part = bxz2_part.double() + bxz2_part; let xx3_m_zz3 = xx.double() + xx - zz3; let y = y_frag + (xx3_m_zz3 * bxz6_part); let yz2 = (point.y * point.z).double(); let x = x_frag - (bxz6_part * yz2); let z = (yz2 * yy).double().double(); point.x = x;
316 point.y = y;
317 point.z = z;
318 }
319}
320
321#[derive(Clone, Copy, Debug)]
323pub struct EquationAIsZero;
324
325impl<C: PrimeCurveParams> PointArithmetic<C> for EquationAIsZero {
326 fn add_assign(lhs: &mut ProjectivePoint<C>, rhs: &ProjectivePoint<C>) {
334 debug_assert_equation_a_is_zero::<C>();
335
336 let b3 = C::FieldElement::from(3) * C::EQUATION_B;
337
338 let t0 = lhs.x * rhs.x; let t1 = lhs.y * rhs.y; let t2 = lhs.z * rhs.z; let t3 = lhs.x + lhs.y; let t4 = rhs.x + rhs.y; let t3 = t3 * t4; let t4 = t0 + t1; let t3 = t3 - t4; let t4 = lhs.y + lhs.z; let x3 = rhs.y + rhs.z; let t4 = t4 * x3; let x3 = t1 + t2; let t4 = t4 - x3; let x3 = lhs.x + lhs.z; let y3 = rhs.x + rhs.z; let x3 = x3 * y3; let y3 = t0 + t2; let y3 = x3 - y3; let x3 = t0.double(); let t0 = x3 + t0; let t2 = b3 * t2; let z3 = t1 + t2; let t1 = t1 - t2; let y3 = b3 * y3; let x3 = t4 * y3; let t2 = t3 * t1; let x3 = t2 - x3; let y3 = y3 * t0; let t1 = t1 * z3; let y3 = t1 + y3; let t0 = t0 * t3; let z3 = z3 * t4; let z3 = z3 + t0; lhs.x = x3;
373 lhs.y = y3;
374 lhs.z = z3;
375 }
376
377 fn add_assign_mixed(lhs: &mut ProjectivePoint<C>, rhs: &AffinePoint<C>) {
385 debug_assert_equation_a_is_zero::<C>();
386
387 let b3 = C::EQUATION_B * C::FieldElement::from(3);
388
389 let t0 = lhs.x * rhs.x; let t1 = lhs.y * rhs.y; let t3 = rhs.x + rhs.y; let t4 = lhs.x + lhs.y; let t3 = t3 * t4; let t4 = t0 + t1; let t3 = t3 - t4; let t4 = rhs.y * lhs.z; let t4 = t4 + lhs.y; let y3 = rhs.x * lhs.z; let y3 = y3 + lhs.x; let x3 = t0.double(); let t0 = x3 + t0; let t2 = b3 * lhs.z; let z3 = t1 + t2; let t1 = t1 - t2; let y3 = b3 * y3; let x3 = t4 * y3; let t2 = t3 * t1; let x3 = t2 - x3; let y3 = y3 * t0; let t1 = t1 * z3; let y3 = t1 + y3; let t0 = t0 * t3; let z3 = z3 * t4; let z3 = z3 + t0; lhs.x.conditional_assign(&x3, !rhs.is_identity());
417 lhs.y.conditional_assign(&y3, !rhs.is_identity());
418 lhs.z.conditional_assign(&z3, !rhs.is_identity());
419 }
420
421 fn double_in_place(point: &mut ProjectivePoint<C>) {
429 debug_assert_equation_a_is_zero::<C>();
430
431 let b3 = C::EQUATION_B * C::FieldElement::from(3);
432
433 let t0 = point.y.square(); let z3 = t0.double(); let z3 = z3.double(); let z3 = z3.double(); let t1 = point.y * point.z; let t2 = point.z.square(); let t2 = b3 * t2; let x3 = t2 * z3; let y3 = t0 + t2; let z3 = t1 * z3; let t1 = t2.double(); let t2 = t1 + t2; let t0 = t0 - t2; let y3 = t0 * y3; let y3 = x3 + y3; let t1 = point.x * point.y; let x3 = t0 * t1; let x3 = x3.double(); point.x = x3;
453 point.y = y3;
454 point.z = z3;
455 }
456}