use core::{hint::black_box, borrow::Borrow, ops::*, iter::Sum}; use subtle::{Choice, ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable}; use zeroize::{Zeroize, DefaultIsZeroes}; use rand_core::RngCore; use group::{ ff::{Field, PrimeFieldBits}, Group, }; use crate::{ShortWeierstrass, Affine}; /// A point represented with projective coordinates. #[derive(Debug)] pub struct Projective { pub(crate) x: C::FieldElement, pub(crate) y: C::FieldElement, pub(crate) z: C::FieldElement, } impl Clone for Projective { fn clone(&self) -> Self { *self } } impl Copy for Projective {} impl From> for Projective { fn from(affine: Affine) -> Self { Self { x: affine.x, y: affine.y, z: C::FieldElement::ONE } } } impl Default for Projective { fn default() -> Self { Self::IDENTITY } } impl DefaultIsZeroes for Projective {} impl ConstantTimeEq for Projective { fn ct_eq(&self, other: &Self) -> Choice { let c1 = (self.x * other.z).ct_eq(&(other.x * self.z)); let c2 = (self.y * other.z).ct_eq(&(other.y * self.z)); c1 & c2 } } impl PartialEq for Projective { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() } } impl Eq for Projective {} impl ConditionallySelectable for Projective { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { let x = C::FieldElement::conditional_select(&a.x, &b.x, choice); let y = C::FieldElement::conditional_select(&a.y, &b.y, choice); let z = C::FieldElement::conditional_select(&a.z, &b.z, choice); Projective { x, y, z } } } impl Neg for Projective { type Output = Self; fn neg(mut self) -> Self::Output { self.y = -self.y; self } } impl ConditionallyNegatable for Projective { fn conditional_negate(&mut self, negate: Choice) { self.y = <_>::conditional_select(&self.y, &-self.y, negate); } } impl Add for Projective { type Output = Self; // add-1998-cmo-2 /* We don't use the complete formulas from 2015 as they require the curve is prime order, when we do not. */ fn add(self, p2: Self) -> Self { let Self { x: X1, y: Y1, z: Z1 } = self; let Self { x: X2, y: Y2, z: Z2 } = p2; let Y1Z2 = Y1 * Z2; let X1Z2 = X1 * Z2; let Z1Z2 = Z1 * Z2; let u = (Y2 * Z1) - Y1Z2; let uu = u.square(); let v = (X2 * Z1) - X1Z2; let vv = v.square(); let vvv = v * vv; let R = vv * X1Z2; let A = (uu * Z1Z2) - vvv - R.double(); let X3 = v * A; let Y3 = (u * (R - A)) - (vvv * Y1Z2); let Z3 = vvv * Z1Z2; let res = Self { x: X3, y: Y3, z: Z3 }; let same_x_coordinate = (self.x * p2.z).ct_eq(&(p2.x * self.z)); let same_y_coordinate = (self.y * p2.z).ct_eq(&(p2.y * self.z)); let res = <_>::conditional_select( &res, &Self::IDENTITY, (self.is_identity_internal() & p2.is_identity_internal()) | (same_x_coordinate & (!same_y_coordinate)), ); let res = <_>::conditional_select(&res, &self.double_internal(), same_x_coordinate & same_y_coordinate); let res = <_>::conditional_select(&res, &p2, self.is_identity_internal()); <_>::conditional_select(&res, &self, p2.is_identity_internal()) } } impl Sub for Projective { type Output = Self; fn sub(self, p2: Self) -> Self { self + -p2 } } impl AddAssign for Projective { fn add_assign(&mut self, p2: Self) { *self = *self + p2; } } impl SubAssign for Projective { fn sub_assign(&mut self, p2: Self) { *self = *self - p2; } } impl Add<&Self> for Projective { type Output = Self; fn add(self, p2: &Self) -> Self { self + *p2 } } impl Sub<&Self> for Projective { type Output = Self; fn sub(self, p2: &Self) -> Self { self - *p2 } } impl AddAssign<&Self> for Projective { fn add_assign(&mut self, p2: &Self) { *self = *self + p2; } } impl SubAssign<&Self> for Projective { fn sub_assign(&mut self, p2: &Self) { *self = *self - p2; } } impl Projective { /// The additive identity, or point at infinity. pub const IDENTITY: Self = Projective { x: C::FieldElement::ZERO, y: C::FieldElement::ONE, z: C::FieldElement::ZERO }; /// A generator of this elliptic curve. pub const GENERATOR: Self = Projective { x: C::GENERATOR.x, y: C::GENERATOR.y, z: C::FieldElement::ONE }; fn is_identity_internal(&self) -> Choice { self.z.ct_eq(&C::FieldElement::ZERO) } // dbl-1998-cmo-2 fn double_internal(&self) -> Self { let Self { x: X1, y: Y1, z: Z1 } = *self; let X1X1 = X1.square(); let w = (C::A * Z1.square()) + X1X1.double() + X1X1; let s = Y1 * Z1; let ss = s.square(); let sss = s * ss; let R = Y1 * s; let B = X1 * R; let B4 = B.double().double(); let h = w.square() - B4.double(); let X3 = (h * s).double(); let Y3 = w * (B4 - h) - R.square().double().double().double(); let Z3 = sss.double().double().double(); let res = Self { x: X3, y: Y3, z: Z3 }; <_>::conditional_select(&res, &Self::IDENTITY, self.is_identity_internal()) } } impl Sum for Projective { fn sum>(iter: I) -> Self { let mut res = Self::IDENTITY; for item in iter { res += item; } res } } impl<'a, C: ShortWeierstrass> Sum<&'a Self> for Projective { fn sum>(iter: I) -> Self { let mut res = Self::IDENTITY; for item in iter { res += item; } res } } impl> Projective { /// Sample a random on-curve point with an unknown discrete logarithm w.r.t. any other points. pub fn random(rng: impl RngCore) -> Self { Self::from(Affine::random(rng)) } /// If this point is the additive identity. pub fn is_identity(&self) -> Choice { self.is_identity_internal() } /// The sum of this point with itself. pub fn double(&self) -> Self { self.double_internal() } } impl, S: Borrow> Mul for Projective { type Output = Self; fn mul(self, scalar: S) -> Self { let mut table = [Self::IDENTITY; 16]; table[1] = self; for i in 2 .. 16 { table[i] = table[i - 1] + self; } let mut res = Self::identity(); let mut bits = 0; for (i, mut bit) in scalar.borrow().to_le_bits().iter_mut().rev().enumerate() { fn u8_from_bool(bit_ref: &mut bool) -> u8 { let bit_ref = black_box(bit_ref); let mut bit = black_box(*bit_ref); let res = black_box(u8::from(bit)); bit.zeroize(); debug_assert!((res | 1) == 1); bit_ref.zeroize(); res } bits <<= 1; let mut bit = u8_from_bool(bit.deref_mut()); bits |= bit; bit.zeroize(); if ((i + 1) % 4) == 0 { if i != 3 { for _ in 0 .. 4 { res = res.double(); } } let mut term = table[0]; for (j, candidate) in table[1 ..].iter().enumerate() { let j = j + 1; term = Self::conditional_select(&term, candidate, usize::from(bits).ct_eq(&j)); } res += term; bits = 0; } } res } } impl, S: Borrow> MulAssign for Projective { fn mul_assign(&mut self, scalar: S) { *self = *self * scalar.borrow(); } } /* impl> Mul<&C::Scalar> for Projective { type Output = Self; fn mul(self, scalar: &C::Scalar) -> Self { self * *scalar } } impl> MulAssign<&C::Scalar> for Projective { fn mul_assign(&mut self, scalar: &C::Scalar) { *self *= *scalar; } } */ impl> Group for Projective { type Scalar = C::Scalar; fn random(rng: impl RngCore) -> Self { Self::from(Affine::::random(rng)) } fn identity() -> Self { Self::IDENTITY } fn generator() -> Self { C::GENERATOR.into() } fn is_identity(&self) -> Choice { self.is_identity_internal() } fn double(&self) -> Self { self.double_internal() } }