diff --git a/k256/src/arithmetic/affine.rs b/k256/src/arithmetic/affine.rs index 5afad501..f19de9ad 100644 --- a/k256/src/arithmetic/affine.rs +++ b/k256/src/arithmetic/affine.rs @@ -139,8 +139,11 @@ impl FromEncodedPoint for AffinePoint { // Check that the point is on the curve let lhs = (y * &y).negate(1); let rhs = x * &x * &x + &CURVE_EQUATION_B; - let infinity = Choice::from(0); - let point = AffinePoint { x, y, infinity }; + let point = AffinePoint { + x, + y, + infinity: Choice::from(0), + }; CtOption::new(point, (lhs + &rhs).normalizes_to_zero()) }) }) diff --git a/k256/src/arithmetic/projective.rs b/k256/src/arithmetic/projective.rs index 2a8efc23..f5afddcc 100644 --- a/k256/src/arithmetic/projective.rs +++ b/k256/src/arithmetic/projective.rs @@ -27,11 +27,12 @@ pub struct ProjectivePoint { impl From for ProjectivePoint { fn from(p: AffinePoint) -> Self { - ProjectivePoint { + let projective = ProjectivePoint { x: p.x, y: p.y, z: FieldElement::one(), - } + }; + Self::conditional_select(&projective, &Self::identity(), p.infinity) } } diff --git a/p256/src/arithmetic/affine.rs b/p256/src/arithmetic/affine.rs index e05710f1..7e3f8897 100644 --- a/p256/src/arithmetic/affine.rs +++ b/p256/src/arithmetic/affine.rs @@ -20,6 +20,23 @@ use elliptic_curve::zeroize::Zeroize; pub struct AffinePoint { pub(crate) x: FieldElement, pub(crate) y: FieldElement, + pub(super) infinity: Choice, +} + +impl AffinePoint { + /// Returns the identity of the group: the point at infinity. + pub fn identity() -> AffinePoint { + Self { + x: FieldElement::zero(), + y: FieldElement::zero(), + infinity: Choice::from(1), + } + } + + /// Is this point the identity point? + pub fn is_identity(&self) -> Choice { + self.infinity + } } impl ConditionallySelectable for AffinePoint { @@ -27,13 +44,20 @@ impl ConditionallySelectable for AffinePoint { AffinePoint { x: FieldElement::conditional_select(&a.x, &b.x, choice), y: FieldElement::conditional_select(&a.y, &b.y, choice), + infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice), } } } impl ConstantTimeEq for AffinePoint { fn ct_eq(&self, other: &AffinePoint) -> Choice { - self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y) + self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y) & !(self.infinity ^ other.infinity) + } +} + +impl Default for AffinePoint { + fn default() -> Self { + Self::identity() } } @@ -64,6 +88,7 @@ impl Generator for AffinePoint { 0x37, 0xbf, 0x51, 0xf5 ]) .unwrap(), + infinity: Choice::from(0), } } } @@ -82,7 +107,11 @@ impl Decompress for AffinePoint { !(beta.is_odd() ^ y_is_odd), ); - Self { x, y } + Self { + x, + y, + infinity: Choice::from(0), + } }) }) } @@ -108,7 +137,12 @@ impl FromEncodedPoint for AffinePoint { // Check that the point is on the curve let lhs = y * &y; let rhs = x * &x * &x + &(CURVE_EQUATION_A * &x) + &CURVE_EQUATION_B; - CtOption::new(AffinePoint { x, y }, lhs.ct_eq(&rhs)) + let point = AffinePoint { + x, + y, + infinity: Choice::from(0), + }; + CtOption::new(point, lhs.ct_eq(&rhs)) }) }) } @@ -133,9 +167,7 @@ impl Mul for AffinePoint { type Output = AffinePoint; fn mul(self, scalar: NonZeroScalar) -> Self { - (ProjectivePoint::from(self) * scalar.as_ref()) - .to_affine() - .unwrap() + (ProjectivePoint::from(self) * scalar.as_ref()).to_affine() } } @@ -146,6 +178,7 @@ impl Neg for AffinePoint { AffinePoint { x: self.x, y: -self.y, + infinity: self.infinity, } } } @@ -192,7 +225,7 @@ mod tests { let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); assert_eq!(point, AffinePoint::generator()); - let res: EncodedPoint = point.to_encoded_point(true).into(); + let res: EncodedPoint = point.to_encoded_point(true); assert_eq!(res, pubkey); } diff --git a/p256/src/arithmetic/projective.rs b/p256/src/arithmetic/projective.rs index edeefd0a..18e1d086 100644 --- a/p256/src/arithmetic/projective.rs +++ b/p256/src/arithmetic/projective.rs @@ -4,7 +4,7 @@ use super::{AffinePoint, FieldElement, Scalar, CURVE_EQUATION_B}; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use elliptic_curve::{ point::Generator, - subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, + subtle::{Choice, ConditionallySelectable, ConstantTimeEq}, }; /// A point on the secp256r1 curve in projective coordinates. @@ -18,11 +18,12 @@ pub struct ProjectivePoint { impl From for ProjectivePoint { fn from(p: AffinePoint) -> Self { - ProjectivePoint { + let projective = ProjectivePoint { x: p.x, y: p.y, z: FieldElement::one(), - } + }; + Self::conditional_select(&projective, &Self::identity(), p.infinity) } } @@ -65,11 +66,15 @@ impl ProjectivePoint { } /// Returns the affine representation of this point, or `None` if it is the identity. - pub fn to_affine(&self) -> CtOption { - self.z.invert().map(|zinv| AffinePoint { - x: self.x * &zinv, - y: self.y * &zinv, - }) + pub fn to_affine(&self) -> AffinePoint { + self.z + .invert() + .map(|zinv| AffinePoint { + x: self.x * &zinv, + y: self.y * &zinv, + infinity: Choice::from(0), + }) + .unwrap_or_else(AffinePoint::identity) } /// Returns `-self`. @@ -363,11 +368,11 @@ mod tests { ProjectivePoint::from(basepoint_affine), basepoint_projective, ); - assert_eq!(basepoint_projective.to_affine().unwrap(), basepoint_affine); + assert_eq!(basepoint_projective.to_affine(), basepoint_affine); + assert!(!bool::from(basepoint_projective.to_affine().is_identity())); - // The projective identity does not have an affine representation. assert!(bool::from( - ProjectivePoint::identity().to_affine().is_none() + ProjectivePoint::identity().to_affine().is_identity() )); } @@ -399,7 +404,7 @@ mod tests { let mut p = generator; for i in 0..ADD_TEST_VECTORS.len() { - let affine = p.to_affine().unwrap(); + let affine = p.to_affine(); assert_eq!( ( hex::encode(affine.x.to_bytes()).to_uppercase().as_str(), @@ -408,7 +413,7 @@ mod tests { ADD_TEST_VECTORS[i] ); - p = p + &generator; + p += &generator; } } @@ -418,7 +423,7 @@ mod tests { let mut p = ProjectivePoint::generator(); for i in 0..ADD_TEST_VECTORS.len() { - let affine = p.to_affine().unwrap(); + let affine = p.to_affine(); assert_eq!( ( hex::encode(affine.x.to_bytes()).to_uppercase().as_str(), @@ -437,7 +442,7 @@ mod tests { let mut p = generator; for i in 0..2 { - let affine = p.to_affine().unwrap(); + let affine = p.to_affine(); assert_eq!( ( hex::encode(affine.x.to_bytes()).to_uppercase().as_str(), @@ -494,7 +499,7 @@ mod tests { ) })) { - let res = (generator * &k).to_affine().unwrap(); + let res = (generator * &k).to_affine(); assert_eq!( ( hex::encode(res.x.to_bytes()).to_uppercase().as_str(), diff --git a/p256/src/ecdsa.rs b/p256/src/ecdsa.rs index f2452da8..b98aa6a1 100644 --- a/p256/src/ecdsa.rs +++ b/p256/src/ecdsa.rs @@ -89,7 +89,7 @@ impl SignPrimitive for Scalar { let k_inverse = k_inverse.unwrap(); // Compute `x`-coordinate of affine point 𝑘×𝑮 - let x = (ProjectivePoint::generator() * k).to_affine().unwrap().x; + let x = (ProjectivePoint::generator() * k).to_affine().x; // Lift `x` (element of base field) to serialized big endian integer, // then reduce it to an element of the scalar field @@ -117,7 +117,6 @@ impl VerifyPrimitive for AffinePoint { let x = ((&ProjectivePoint::generator() * &u1) + &(ProjectivePoint::from(*self) * &u2)) .to_affine() - .unwrap() .x; if Scalar::from_bytes_reduced(&x.to_bytes()) == *r {