diff --git a/crypto/evrf/embedwards25519/src/lib.rs b/crypto/evrf/embedwards25519/src/lib.rs index 9db6423b..b3826fcf 100644 --- a/crypto/evrf/embedwards25519/src/lib.rs +++ b/crypto/evrf/embedwards25519/src/lib.rs @@ -37,6 +37,7 @@ impl ShortWeierstrass for Embedwards25519 { const B: FieldElement = FieldElement(DalekScalar::from_bits(hex_literal::hex!( "5f07603a853f20370b682036210d463e64903a23ea669d07ca26cfc13f594209" ))); + const PRIME_ORDER: bool = true; const GENERATOR: Affine = Affine::from_xy_unchecked( FieldElement::ONE, FieldElement(DalekScalar::from_bits(hex_literal::hex!( diff --git a/crypto/evrf/secq256k1/src/lib.rs b/crypto/evrf/secq256k1/src/lib.rs index 5ec9e529..c0a7b8ef 100644 --- a/crypto/evrf/secq256k1/src/lib.rs +++ b/crypto/evrf/secq256k1/src/lib.rs @@ -47,6 +47,7 @@ impl ShortWeierstrass for Secq256k1 { let six = four.add(&two); six.add(&FieldElement::ONE) }; + const PRIME_ORDER: bool = true; const GENERATOR: Affine = Affine::from_xy_unchecked(FieldElement::ONE, { let y_be = hex_literal::hex!("0c7c97045a2074634909abdf82c9bd0248916189041f2af0c1b800d1ffc278c0"); diff --git a/crypto/short-weierstrass/src/lib.rs b/crypto/short-weierstrass/src/lib.rs index 74e7fb1d..3df9a446 100644 --- a/crypto/short-weierstrass/src/lib.rs +++ b/crypto/short-weierstrass/src/lib.rs @@ -22,6 +22,8 @@ pub trait ShortWeierstrass: 'static + Sized + Debug { const A: Self::FieldElement; /// The constant `B` from the curve equation. const B: Self::FieldElement; + /// If the elliptic curve is of prime order. + const PRIME_ORDER: bool; /// A generator of this elliptic curve's largest prime-order subgroup. const GENERATOR: Affine; /// The scalar type for the elliptic curve's largest prime-order subgroup. @@ -44,6 +46,6 @@ pub trait ShortWeierstrass: 'static + Sized + Debug { /// If the point is outside the largest prime-order subgroup and isn't the identity point. /// - /// This may immediately return `Choice::new(0)` for curves of prime order. + /// This SHOULD immediately return `Choice::new(0)` for curves of prime order. fn has_torsion_element(point: Projective) -> Choice; } diff --git a/crypto/short-weierstrass/src/projective.rs b/crypto/short-weierstrass/src/projective.rs index 58c59ffa..c4218c9d 100644 --- a/crypto/short-weierstrass/src/projective.rs +++ b/crypto/short-weierstrass/src/projective.rs @@ -77,16 +77,11 @@ impl ConditionallyNegatable for Projective { } } -impl Add for Projective { - type Output = Self; +impl Projective { // 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 { + fn add_if_composite_order(self, other: Self) -> Self { let Self { x: X1, y: Y1, z: Z1 } = self; - let Self { x: X2, y: Y2, z: Z2 } = p2; + let Self { x: X2, y: Y2, z: Z2 } = other; let Y1Z2 = Y1 * Z2; let X1Z2 = X1 * Z2; @@ -104,18 +99,84 @@ impl Add for Projective { 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 same_x_coordinate = (self.x * other.z).ct_eq(&(other.x * self.z)); + let same_y_coordinate = (self.y * other.z).ct_eq(&(other.y * self.z)); let res = <_>::conditional_select( &res, &Self::IDENTITY, - (self.is_identity_internal() & p2.is_identity_internal()) | + (self.is_identity_internal() & other.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()) + let res = <_>::conditional_select(&res, &other, self.is_identity_internal()); + <_>::conditional_select(&res, &self, other.is_identity_internal()) + } + + // add-2015-rcb + fn add_if_prime_order(self, other: Self) -> Self { + let b3 = C::B + C::B + C::B; + + let X1 = self.x; + let Y1 = self.y; + let Z1 = self.z; + let X2 = other.x; + let Y2 = other.y; + let Z2 = other.z; + + let t0 = X1 * X2; + let t1 = Y1 * Y2; + let t2 = Z1 * Z2; + let t3 = X1 + Y1; + let t4 = X2 + Y2; + let t3 = t3 * t4; + let t4 = t0 + t1; + let t3 = t3 - t4; + let t4 = X1 + Z1; + let t5 = X2 + Z2; + let t4 = t4 * t5; + let t5 = t0 + t2; + let t4 = t4 - t5; + let t5 = Y1 + Z1; + let X3 = Y2 + Z2; + let t5 = t5 * X3; + let X3 = t1 + t2; + let t5 = t5 - X3; + let Z3 = C::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::A * t2; + let t4 = b3 * t4; + let t1 = t1 + t2; + let t2 = t0 - t2; + let t2 = C::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; + + Projective { x: X3, y: Y3, z: Z3 } + } +} + +impl Add for Projective { + type Output = Self; + fn add(self, other: Self) -> Self { + if C::PRIME_ORDER { + self.add_if_prime_order(other) + } else { + self.add_if_composite_order(other) + } } } impl Sub for Projective {