Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions curve25519-dalek/src/edwards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@
// affine and projective cakes and eat both of them too.
#![allow(non_snake_case)]

mod affine;

use cfg_if::cfg_if;
use core::array::TryFromSliceError;
use core::borrow::Borrow;
Expand Down Expand Up @@ -146,6 +148,8 @@ use crate::traits::BasepointTable;
use crate::traits::ValidityCheck;
use crate::traits::{Identity, IsIdentity};

use affine::AffinePoint;

#[cfg(feature = "alloc")]
use crate::traits::MultiscalarMul;
#[cfg(feature = "alloc")]
Expand Down Expand Up @@ -528,7 +532,7 @@ impl EdwardsPoint {
}
}

/// Dehomogenize to a AffineNielsPoint.
/// Dehomogenize to a `AffineNielsPoint`.
/// Mainly for testing.
pub(crate) fn as_affine_niels(&self) -> AffineNielsPoint {
let recip = self.Z.invert();
Expand All @@ -542,6 +546,14 @@ impl EdwardsPoint {
}
}

/// Convert to `AffinePoint`.
pub(crate) fn to_affine(self) -> AffinePoint {
let recip = self.Z.invert();
let x = &self.X * &recip;
let y = &self.Y * &recip;
AffinePoint { x, y }
}

/// Convert this `EdwardsPoint` on the Edwards model to the
/// corresponding `MontgomeryPoint` on the Montgomery model.
///
Expand Down Expand Up @@ -587,10 +599,7 @@ impl EdwardsPoint {

/// Compress this point to `CompressedEdwardsY` format.
pub fn compress(&self) -> CompressedEdwardsY {
let recip = self.Z.invert();
let x = &self.X * &recip;
let y = &self.Y * &recip;
Self::compress_affine(x, y)
self.to_affine().compress()
}

/// Compress several `EdwardsPoint`s into `CompressedEdwardsY` format, using a batch inversion
Expand All @@ -606,19 +615,11 @@ impl EdwardsPoint {
.map(|(input, recip)| {
let x = &input.X * recip;
let y = &input.Y * recip;
Self::compress_affine(x, y)
AffinePoint { x, y }.compress()
})
.collect()
}

/// Compress affine Edwards coordinates into `CompressedEdwardsY` format.
#[inline]
fn compress_affine(x: FieldElement, y: FieldElement) -> CompressedEdwardsY {
let mut s = y.to_bytes();
s[31] ^= x.is_negative().unwrap_u8() << 7;
CompressedEdwardsY(s)
}

#[cfg(feature = "digest")]
/// Maps the digest of the input bytes to the curve. This is NOT a hash-to-curve function, as
/// it produces points with a non-uniform distribution. Rather, it performs something that
Expand Down
114 changes: 114 additions & 0 deletions curve25519-dalek/src/edwards/affine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use super::{CompressedEdwardsY, EdwardsPoint};
use crate::traits::Identity;
use crate::{field::FieldElement, Scalar};
use core::ops::Mul;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};

#[cfg(feature = "zeroize")]
use zeroize::DefaultIsZeroes;

/// Affine Edwards point on untwisted curve.
#[derive(Copy, Clone, Debug)]
pub struct AffinePoint {
pub(super) x: FieldElement,
pub(super) y: FieldElement,
}

impl ConstantTimeEq for AffinePoint {
fn ct_eq(&self, other: &Self) -> Choice {
self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y)
}
}

impl ConditionallySelectable for AffinePoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
x: FieldElement::conditional_select(&a.x, &b.x, choice),
y: FieldElement::conditional_select(&a.y, &b.y, choice),
}
}
}

impl Default for AffinePoint {
fn default() -> AffinePoint {
AffinePoint::identity()
}
}

impl Identity for AffinePoint {
fn identity() -> AffinePoint {
AffinePoint {
x: FieldElement::ZERO,
y: FieldElement::ONE,
}
}
}

impl PartialEq for AffinePoint {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}

impl Eq for AffinePoint {}

#[cfg(feature = "zeroize")]
impl DefaultIsZeroes for AffinePoint {}

impl AffinePoint {
/// Convert to extended coordinates.
pub fn to_edwards(self) -> EdwardsPoint {
EdwardsPoint {
X: self.x,
Y: self.y,
Z: FieldElement::ONE,
T: &self.x * &self.y,
}
}

/// Compress affine Edwards coordinates into `CompressedEdwardsY` format.
#[inline]
pub fn compress(self) -> CompressedEdwardsY {
let mut s = self.y.to_bytes();
s[31] ^= self.x.is_negative().unwrap_u8() << 7;
CompressedEdwardsY(s)
}
}

impl Mul<AffinePoint> for Scalar {
type Output = EdwardsPoint;

#[inline]
fn mul(self, rhs: AffinePoint) -> EdwardsPoint {
self * &rhs
}
}

impl Mul<&AffinePoint> for Scalar {
type Output = EdwardsPoint;

#[inline]
fn mul(self, rhs: &AffinePoint) -> EdwardsPoint {
rhs.to_edwards() * self
}
}

#[cfg(test)]
mod tests {
use super::{AffinePoint, EdwardsPoint, Identity};
use crate::constants;

#[test]
fn identity_conversion() {
assert_eq!(
AffinePoint::identity().to_edwards(),
EdwardsPoint::identity()
);
}

#[test]
fn generator_round_trip() {
let basepoint = constants::ED25519_BASEPOINT_POINT;
assert_eq!(basepoint.to_affine().to_edwards(), basepoint);
}
}