use crate::curve::edwards::EdwardsPoint;
use crate::field::FieldElement;
use crate::*;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
#[cfg(feature = "zeroize")]
use zeroize::DefaultIsZeroes;
#[derive(Copy, Clone, Debug)]
pub struct AffinePoint {
pub(crate) x: FieldElement,
pub(crate) y: FieldElement,
}
impl Default for AffinePoint {
fn default() -> Self {
Self::IDENTITY
}
}
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 PartialEq for AffinePoint {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl Eq for AffinePoint {}
impl elliptic_curve::point::AffineCoordinates for AffinePoint {
type FieldRepr = Ed448FieldBytes;
fn x(&self) -> Self::FieldRepr {
Ed448FieldBytes::from(self.x.to_bytes_extended())
}
fn y_is_odd(&self) -> Choice {
self.y.is_negative()
}
}
#[cfg(feature = "zeroize")]
impl DefaultIsZeroes for AffinePoint {}
impl AffinePoint {
pub const IDENTITY: AffinePoint = AffinePoint {
x: FieldElement::ZERO,
y: FieldElement::ONE,
};
pub(crate) fn isogeny(&self) -> Self {
let x = self.x;
let y = self.y;
let mut t0 = x.square(); let t1 = t0 + FieldElement::ONE; t0 -= FieldElement::ONE; let mut t2 = y.square(); t2 = t2.double(); let t3 = x.double();
let mut t4 = t0 * y; t4 = t4.double(); let xNum = t4.double();
let mut t5 = t0.square(); t4 = t5 + t2; let xDen = t4 + t2;
t5 *= x; t4 = t2 * t3; let yNum = t4 - t5;
t4 = t1 * t2; let yDen = t5 - t4;
Self {
x: xNum * xDen.invert(),
y: yNum * yDen.invert(),
}
}
pub fn to_edwards(&self) -> EdwardsPoint {
EdwardsPoint {
X: self.x,
Y: self.y,
Z: FieldElement::ONE,
T: self.x * self.y,
}
}
pub fn x(&self) -> [u8; 56] {
self.x.to_bytes()
}
pub fn y(&self) -> [u8; 56] {
self.y.to_bytes()
}
}