Skip to content

Commit

Permalink
p256: implement AffinePoint::identity() and ::is_identity()
Browse files Browse the repository at this point in the history
This is a corresponding change ala #165, but for the `p256` crate.
  • Loading branch information
tarcieri committed Sep 5, 2020
1 parent 2377afa commit e56ab3b
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 29 deletions.
7 changes: 5 additions & 2 deletions k256/src/arithmetic/affine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,11 @@ impl FromEncodedPoint<Secp256k1> 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())
})
})
Expand Down
5 changes: 3 additions & 2 deletions k256/src/arithmetic/projective.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ pub struct ProjectivePoint {

impl From<AffinePoint> 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)
}
}

Expand Down
47 changes: 40 additions & 7 deletions p256/src/arithmetic/affine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,44 @@ 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 {
fn conditional_select(a: &AffinePoint, b: &AffinePoint, choice: Choice) -> 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()
}
}

Expand Down Expand Up @@ -64,6 +88,7 @@ impl Generator for AffinePoint {
0x37, 0xbf, 0x51, 0xf5
])
.unwrap(),
infinity: Choice::from(0),
}
}
}
Expand All @@ -82,7 +107,11 @@ impl Decompress<NistP256> for AffinePoint {
!(beta.is_odd() ^ y_is_odd),
);

Self { x, y }
Self {
x,
y,
infinity: Choice::from(0),
}
})
})
}
Expand All @@ -108,7 +137,12 @@ impl FromEncodedPoint<NistP256> 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))
})
})
}
Expand All @@ -133,9 +167,7 @@ impl Mul<NonZeroScalar> 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()
}
}

Expand All @@ -146,6 +178,7 @@ impl Neg for AffinePoint {
AffinePoint {
x: self.x,
y: -self.y,
infinity: self.infinity,
}
}
}
Expand Down Expand Up @@ -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);
}

Expand Down
37 changes: 21 additions & 16 deletions p256/src/arithmetic/projective.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -18,11 +18,12 @@ pub struct ProjectivePoint {

impl From<AffinePoint> 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)
}
}

Expand Down Expand Up @@ -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<AffinePoint> {
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`.
Expand Down Expand Up @@ -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()
));
}

Expand Down Expand Up @@ -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(),
Expand All @@ -408,7 +413,7 @@ mod tests {
ADD_TEST_VECTORS[i]
);

p = p + &generator;
p += &generator;
}
}

Expand All @@ -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(),
Expand All @@ -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(),
Expand Down Expand Up @@ -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(),
Expand Down
3 changes: 1 addition & 2 deletions p256/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ impl SignPrimitive<NistP256> 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
Expand Down Expand Up @@ -117,7 +117,6 @@ impl VerifyPrimitive<NistP256> for AffinePoint {

let x = ((&ProjectivePoint::generator() * &u1) + &(ProjectivePoint::from(*self) * &u2))
.to_affine()
.unwrap()
.x;

if Scalar::from_bytes_reduced(&x.to_bytes()) == *r {
Expand Down

0 comments on commit e56ab3b

Please sign in to comment.