use core::ops::*;
use subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable};
use zeroize::DefaultIsZeroes;
use rand_core::RngCore;
use group::ff::Field;
use crate::{ShortWeierstrass, Projective};
#[derive(Debug)]
pub struct Affine<C: ShortWeierstrass> {
pub(crate) x: C::FieldElement,
pub(crate) y: C::FieldElement,
}
impl<C: ShortWeierstrass> Clone for Affine<C> {
fn clone(&self) -> Self {
*self
}
}
impl<C: ShortWeierstrass> Copy for Affine<C> {}
impl<C: ShortWeierstrass> Affine<C> {
pub fn try_from(projective: Projective<C>) -> CtOption<Self> {
projective.z.invert().map(|z_inv| Self { x: projective.x * z_inv, y: projective.y * z_inv })
}
}
impl<C: ShortWeierstrass> Default for Affine<C> {
fn default() -> Self {
C::GENERATOR
}
}
impl<C: ShortWeierstrass> DefaultIsZeroes for Affine<C> {}
impl<C: ShortWeierstrass> ConstantTimeEq for Affine<C> {
fn ct_eq(&self, other: &Self) -> Choice {
self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y)
}
}
impl<C: ShortWeierstrass> PartialEq for Affine<C> {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl<C: ShortWeierstrass> Eq for Affine<C> {}
impl<C: ShortWeierstrass> ConditionallySelectable for Affine<C> {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
let x = C::FieldElement::conditional_select(&a.x, &b.x, choice);
let y = C::FieldElement::conditional_select(&a.y, &b.y, choice);
Affine { x, y }
}
}
impl<C: ShortWeierstrass> Neg for Affine<C> {
type Output = Self;
fn neg(mut self) -> Self::Output {
self.y = -self.y;
self
}
}
impl<C: ShortWeierstrass> ConditionallyNegatable for Affine<C> {
fn conditional_negate(&mut self, negate: Choice) {
self.y = <_>::conditional_select(&self.y, &-self.y, negate);
}
}
impl<C: ShortWeierstrass> Affine<C> {
pub const fn from_xy_unchecked(x: C::FieldElement, y: C::FieldElement) -> Self { Self { x, y } }
pub fn coordinates(self) -> (C::FieldElement, C::FieldElement) {
(self.x, self.y)
}
pub fn random(mut rng: impl RngCore) -> Self {
loop {
let x = C::FieldElement::random(&mut rng);
let y_square = ((x.square() + C::A) * x) + C::B;
let Some(mut y) = Option::<C::FieldElement>::from(y_square.sqrt()) else { continue };
if (rng.next_u64() % 2) == 1 {
y = -y;
}
return Self { x, y };
}
}
}