#![allow(non_snake_case)]
use crate::field::FieldElement;
use crate::scalar::Scalar;
use crate::montgomery::MontgomeryPoint;
use crate::constants;
use crate::traits::Identity;
use crate::traits::ops::*;
use subtle::{Choice, ConstantTimeEq};
use rand::{Rng, thread_rng};
use std::default::Default;
use std::fmt::Debug;
use core::ops::{Index, IndexMut};
use std::ops::{Add, Sub, Mul, Neg};
pub fn double_and_add<'b, 'a, T>(point: &'a T, scalar: &'b Scalar) -> T
where for<'c> &'c T: Add<Output = T> + Double<Output = T>,
T: Identity + Clone {
let mut N = point.clone();
let mut n = scalar.clone();
let mut Q = T::identity();
while n != Scalar::zero() {
if !n.is_even() {
Q = &Q + &N;
};
N = N.double();
n = n.inner_half();
}
Q
}
pub fn mul_by_cofactor<'a, T>(point: &'a T) -> T
where for<'c> &'c T: Mul<&'c Scalar, Output = T> {
point * &Scalar::from(&8u8)
}
pub fn mul_by_pow_2<'a, 'b, T>(point: &'a T, _k: &'b u64) -> T
where for<'c> &'c T: Mul<&'c Scalar, Output = T> {
point * &Scalar::two_pow_k(_k)
}
pub(self) fn find_xx(y: &FieldElement) -> FieldElement {
let a = y.square() - FieldElement::one();
let b = (constants::EDWARDS_D * y.square()) - constants::EDWARDS_A;
a / b
}
#[derive(Copy, Clone)]
pub struct CompressedEdwardsY(pub [u8; 32]);
impl ConstantTimeEq for CompressedEdwardsY {
fn ct_eq(&self, other: &CompressedEdwardsY) -> Choice {
self.to_bytes().ct_eq(&other.to_bytes())
}
}
impl PartialEq for CompressedEdwardsY {
fn eq(&self, other: &CompressedEdwardsY) -> bool {
self.ct_eq(&other).unwrap_u8() == 1u8
}
}
impl Eq for CompressedEdwardsY {}
impl Index<usize> for CompressedEdwardsY {
type Output = u8;
fn index(&self, _index: usize) -> &u8 {
&(self.0[_index])
}
}
impl IndexMut<usize> for CompressedEdwardsY {
fn index_mut(&mut self, _index: usize) -> &mut u8 {
&mut (self.0[_index])
}
}
impl Debug for CompressedEdwardsY {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "CompressedEdwardsY: {:?}", self.to_bytes())
}
}
impl Default for CompressedEdwardsY {
fn default() -> CompressedEdwardsY {
CompressedEdwardsY::identity()
}
}
impl<'a> Neg for &'a CompressedEdwardsY {
type Output = CompressedEdwardsY;
fn neg(self) -> CompressedEdwardsY {
(-&self.decompress().unwrap()).compress()
}
}
impl Neg for CompressedEdwardsY {
type Output = CompressedEdwardsY;
fn neg(self) -> CompressedEdwardsY {
-& self
}
}
impl Identity for CompressedEdwardsY {
fn identity() -> CompressedEdwardsY {
CompressedEdwardsY([1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0])
}
}
impl CompressedEdwardsY {
pub fn from_slice(bytes: &[u8]) -> CompressedEdwardsY {
let mut tmp = [0u8; 32];
tmp.copy_from_slice(bytes);
CompressedEdwardsY(tmp)
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
pub fn decompress(&self) -> Option<EdwardsPoint> {
let sign = Choice::from(self[31] >> 7 as u8);
let mut y = self.clone();
y[31] &= 0b0000_1111;
EdwardsPoint::new_from_y_coord(&FieldElement::from_bytes(&y.to_bytes()), sign)
}
}
#[derive(Copy, Clone)]
pub struct EdwardsPoint {
pub X: FieldElement,
pub Y: FieldElement,
pub Z: FieldElement,
pub T: FieldElement,
}
impl Debug for EdwardsPoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "
EdwardsPoint {{
X: {:?},
Y: {:?},
Z: {:?},
T: {:?}
}};", self.X, self.Y, self.Z, self.T)
}
}
impl ConstantTimeEq for EdwardsPoint {
fn ct_eq(&self, other: &EdwardsPoint) -> Choice {
AffinePoint::from(self).ct_eq(&AffinePoint::from(other))
}
}
impl PartialEq for EdwardsPoint {
fn eq(&self, other: &EdwardsPoint) -> bool {
self.ct_eq(other).unwrap_u8() == 1u8
}
}
impl Eq for EdwardsPoint {}
impl Default for EdwardsPoint {
fn default() -> EdwardsPoint {
EdwardsPoint::identity()
}
}
impl Identity for EdwardsPoint {
fn identity() -> EdwardsPoint {
EdwardsPoint {
X: FieldElement::zero(),
Y: FieldElement::one(),
Z: FieldElement::one(),
T: FieldElement::zero()
}
}
}
impl<'a> From<&'a ProjectivePoint> for EdwardsPoint {
fn from(point: &'a ProjectivePoint) -> EdwardsPoint {
EdwardsPoint {
X: &point.X * &point.Z,
Y: &point.Y * &point.Z,
Z: point.Z.square(),
T: &point.X * &point.Y
}
}
}
impl<'a> From<&'a AffinePoint> for EdwardsPoint {
fn from(point: &'a AffinePoint) -> EdwardsPoint {
EdwardsPoint {
X: point.X,
Y: point.Y,
Z: FieldElement::one(),
T: point.X * point.Y
}
}
}
impl<'a> Neg for &'a EdwardsPoint {
type Output = EdwardsPoint;
fn neg(self) -> EdwardsPoint {
EdwardsPoint{
X: -&self.X,
Y: self.Y,
Z: self.Z,
T: -&self.T,
}
}
}
impl Neg for EdwardsPoint {
type Output = EdwardsPoint;
fn neg(self) -> EdwardsPoint {
-&self
}
}
impl<'a, 'b> Add<&'b EdwardsPoint> for &'a EdwardsPoint {
type Output = EdwardsPoint;
#[inline]
fn add(self, other: &'b EdwardsPoint) -> EdwardsPoint {
let A = &self.X * &other.X;
let B = &self.Y * &other.Y;
let C = &constants::EDWARDS_D * &(&self.T * &other.T);
let D = &self.Z * &other.Z;
let E = &(&(&(&self.X + &self.Y) * &(&other.X + &other.Y)) - &A) - &B;
let F = &D - &C;
let G = &D + &C;
let H = &B + &A;
EdwardsPoint {
X: &E * &F,
Y: &G * &H,
Z: &F * &G,
T: &E * &H
}
}
}
impl<'a, 'b> Sub<&'b EdwardsPoint> for &'a EdwardsPoint {
type Output = EdwardsPoint;
fn sub(self, other: &'b EdwardsPoint) -> EdwardsPoint {
let other_neg = -other;
let A = &self.X * &other_neg.X;
let B = &self.Y * &other_neg.Y;
let C = &constants::EDWARDS_D * &(&self.T * &other_neg.T);
let D = &self.Z * &other_neg.Z;
let E = &(&(&(&self.X + &self.Y) * &(&other_neg.X + &other_neg.Y)) - &A) - &B;
let F = &D - &C;
let G = &D + &C;
let H = &B - &(&constants::EDWARDS_A * &A);
EdwardsPoint {
X: &E * &F,
Y: &G * &H,
Z: &F * &G,
T: &E * &H
}
}
}
impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint {
type Output = EdwardsPoint;
fn mul(self, scalar: &'b Scalar) -> EdwardsPoint {
double_and_add(self, scalar)
}
}
impl Mul<Scalar> for EdwardsPoint {
type Output = EdwardsPoint;
fn mul(self, scalar: Scalar) -> EdwardsPoint {
double_and_add(&self, &scalar)
}
}
impl<'a> Double for &'a EdwardsPoint {
type Output = EdwardsPoint;
fn double(self) -> EdwardsPoint {
let two: FieldElement = FieldElement::from(&2u8);
let A = self.X.square();
let B = self.Y.square();
let C = two * self.Z.square();
let D = -A;
let E = (self.X + self.Y) * (self.X + self.Y) -A -B;
let G = D + B;
let F = G - C;
let H = D - B;
EdwardsPoint {
X: E * F,
Y: G * H,
Z: F * G,
T: E * H
}
}
}
impl EdwardsPoint {
pub fn to_montgomery(&self) -> MontgomeryPoint {
unimplemented!()
}
pub fn compress(&self) -> CompressedEdwardsY {
let mut sign = Choice::from(0u8);
let res = find_xx(&self.Y).mod_sqrt(sign).unwrap();
if res != self.X {sign = Choice::from(1u8);};
let mut compr = self.Y.to_bytes();
compr[31] |= sign.unwrap_u8() << 7;
CompressedEdwardsY::from_slice(&compr)
}
pub fn new_from_y_coord(y: &FieldElement, sign: Choice) -> Option<EdwardsPoint> {
match ProjectivePoint::new_from_y_coord(&y, sign) {
None => return None,
Some(point) => return Some(EdwardsPoint::from(&point)),
}
}
pub fn new_random_point() -> EdwardsPoint {
EdwardsPoint::from(&ProjectivePoint::new_random_point())
}
}
#[derive(Copy, Clone)]
pub struct ProjectivePoint {
pub X: FieldElement,
pub Y: FieldElement,
pub Z: FieldElement
}
impl Debug for ProjectivePoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "
ProjectivePoint {{
X: {:?},
Y: {:?},
Z: {:?}
}};", self.X, self.Y, self.Z)
}
}
impl ConstantTimeEq for ProjectivePoint {
fn ct_eq(&self, other: &ProjectivePoint) -> Choice {
AffinePoint::from(self).ct_eq(&AffinePoint::from(other))
}
}
impl PartialEq for ProjectivePoint {
fn eq(&self, other: &ProjectivePoint) -> bool {
self.ct_eq(other).unwrap_u8() == 1u8
}
}
impl Eq for ProjectivePoint {}
impl Default for ProjectivePoint {
fn default() -> ProjectivePoint {
ProjectivePoint::identity()
}
}
impl Identity for ProjectivePoint {
fn identity() -> ProjectivePoint {
ProjectivePoint {
X: FieldElement::zero(),
Y: FieldElement::one(),
Z: FieldElement::one()
}
}
}
impl<'a> From<&'a EdwardsPoint> for ProjectivePoint {
fn from(point: &'a EdwardsPoint) -> ProjectivePoint {
ProjectivePoint{
X: point.X,
Y: point.Y,
Z: point.Z
}
}
}
impl<'a> From<&'a AffinePoint> for ProjectivePoint {
fn from(point: &'a AffinePoint) -> ProjectivePoint {
ProjectivePoint {
X: point.X,
Y: point.Y,
Z: FieldElement::one()
}
}
}
impl<'a> Neg for &'a ProjectivePoint {
type Output = ProjectivePoint;
fn neg(self) -> ProjectivePoint {
ProjectivePoint{
X: -&self.X,
Y: self.Y,
Z: self.Z
}
}
}
impl Neg for ProjectivePoint {
type Output = ProjectivePoint;
fn neg(self) -> ProjectivePoint {
-&self
}
}
impl<'a, 'b> Add<&'b ProjectivePoint> for &'a ProjectivePoint {
type Output = ProjectivePoint;
#[inline]
fn add(self, other: &'b ProjectivePoint) -> ProjectivePoint {
let A = self.Z * other.Z;
let B = A.square();
let C = self.X * other.X;
let D = self.Y * other.Y;
let E = constants::EDWARDS_D * C * D;
let F = B - E;
let G = B + E;
ProjectivePoint {
X: A * (F * (((self.X + self.Y) * (other.X + other.Y) - C) - D)),
Y: A * G * (D + C),
Z: F * G
}
}
}
impl Add<ProjectivePoint> for ProjectivePoint {
type Output = ProjectivePoint;
#[inline]
fn add(self, other: ProjectivePoint) -> ProjectivePoint {
&self + &other
}
}
impl<'a, 'b> Sub<&'b ProjectivePoint> for &'a ProjectivePoint {
type Output = ProjectivePoint;
fn sub(self, other: &'b ProjectivePoint) -> ProjectivePoint {
self + &(-other)
}
}
impl Sub<ProjectivePoint> for ProjectivePoint {
type Output = ProjectivePoint;
#[inline]
fn sub(self, other: ProjectivePoint) -> ProjectivePoint {
&self - &other
}
}
impl<'a, 'b> Mul<&'a Scalar> for &'b ProjectivePoint {
type Output = ProjectivePoint;
fn mul(self, scalar: &'a Scalar) -> ProjectivePoint {
double_and_add(self, scalar)
}
}
impl Mul<Scalar> for ProjectivePoint {
type Output = ProjectivePoint;
fn mul(self, scalar: Scalar) -> ProjectivePoint {
&self * &scalar
}
}
impl<'a> Double for &'a ProjectivePoint {
type Output = ProjectivePoint;
fn double(self) -> ProjectivePoint {
let B = (&self.X + &self.Y).square();
let C = self.X.square();
let D = self.Y.square();
let E = &constants::EDWARDS_A * &C;
let F = &E + &D;
let H = self.Z.square();
let J = &F - &(&FieldElement::from(&2u8) * &H);
ProjectivePoint {
X: &(&(&B - &C) -&D) * &J,
Y: &F * &(&E - &D),
Z: &F *&J
}
}
}
impl ProjectivePoint {
pub fn new_from_y_coord(y: &FieldElement, sign: Choice) -> Option<ProjectivePoint> {
let x;
let xx = (y.square() - FieldElement::one()) / ((constants::EDWARDS_D * y.square()) - constants::EDWARDS_A);
match xx.mod_sqrt(sign) {
None => return None,
Some(_x) => x = _x,
};
Some(ProjectivePoint {
X: x,
Y: y.clone(),
Z: FieldElement::one()
})
}
pub fn new_random_point() -> ProjectivePoint {
let y = FieldElement::generate_random();
let sign = Choice::from(thread_rng().gen_range(0u8, 1u8));
match ProjectivePoint::new_from_y_coord(&y, sign) {
None => ProjectivePoint::new_random_point(),
Some(point) => return point,
}
}
}
pub struct AffinePoint {
pub X: FieldElement,
pub Y: FieldElement
}
impl Debug for AffinePoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "
AffinePoint {{
X: {:?},
Y: {:?}
}};", self.X, self.Y)
}
}
impl Default for AffinePoint {
fn default() -> AffinePoint {
AffinePoint::identity()
}
}
impl Identity for AffinePoint {
fn identity() -> AffinePoint {
AffinePoint {
X: FieldElement::zero(),
Y: FieldElement::one()
}
}
}
impl ConstantTimeEq for AffinePoint {
fn ct_eq(&self, other: &Self) -> Choice {
self.X.ct_eq(&other.X) & self.Y.ct_eq(&other.Y)
}
}
impl PartialEq for AffinePoint {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(&other).unwrap_u8() == 1u8
}
}
impl Eq for AffinePoint {}
impl<'a> From<&'a EdwardsPoint> for AffinePoint {
fn from(point: &'a EdwardsPoint) -> AffinePoint {
let A = point.Z.inverse();
AffinePoint {
X: point.X * A,
Y: point.Y * A
}
}
}
impl<'a> From<&'a ProjectivePoint> for AffinePoint {
fn from(point: &'a ProjectivePoint) -> AffinePoint {
AffinePoint {
X: point.X * point.Z.inverse(),
Y: point.Y * point.Z.inverse()
}
}
}
impl<'a> Neg for &'a AffinePoint {
type Output = AffinePoint;
fn neg(self) -> AffinePoint {
AffinePoint{
X: -&self.X,
Y: self.Y
}
}
}
impl Neg for AffinePoint {
type Output = AffinePoint;
fn neg(self) -> AffinePoint {
-&self
}
}
#[allow(dead_code)]
#[cfg(test)]
pub mod tests {
use super::*;
pub(self) static P1_AFFINE: AffinePoint = AffinePoint {
X: FieldElement([23, 0, 0, 0, 0]),
Y: FieldElement([1664892896009688, 132583819244870, 812547420185263, 637811013879057, 13284180325998])
};
pub(self) static P2_AFFINE: AffinePoint = AffinePoint {
X: FieldElement([68, 0, 0, 0, 0]),
Y: FieldElement([1799957170131195, 4493955741554471, 4409493758224495, 3389415867291423, 16342693473584]),
};
pub(self) static P1_EXTENDED: EdwardsPoint = EdwardsPoint {
X: FieldElement([23, 0, 0, 0, 0]),
Y: FieldElement([1664892896009688, 132583819244870, 812547420185263, 637811013879057, 13284180325998]),
Z: FieldElement([1, 0, 0, 0, 0]),
T: FieldElement([4351986304670635, 4020128726404030, 674192131526433, 1158854437106827, 6468984742885])
};
pub(self) static P2_EXTENDED: EdwardsPoint = EdwardsPoint {
X: FieldElement([68, 0, 0, 0, 0]),
Y: FieldElement([1799957170131195, 4493955741554471, 4409493758224495, 3389415867291423, 16342693473584]),
Z: FieldElement([1, 0, 0, 0, 0]),
T: FieldElement([3505259403500377, 292342788271022, 2608000066641474, 796697979921534, 2995435405555])
};
pub(self) static P4_EXTENDED: EdwardsPoint = EdwardsPoint {
X: FieldElement([1933054591726350, 4403792816774408, 3029093546253310, 1134491999944368, 8146384875494]),
Y: FieldElement([3369514960042642, 4355698098047571, 1547650124195635, 1314697306673062, 12051634278308]),
Z: FieldElement([576719056868307, 1763329757922533, 3184642959683715, 2550235128581121, 11094626825862]),
T: FieldElement([4345938036071968, 1280347559053553, 3286762790776823, 3577757860131876, 6505793015434])
};
pub(self) static P3_EXTENDED: EdwardsPoint = EdwardsPoint {
X: FieldElement([3851124475403222, 3539758816612178, 1146717153316815, 2152796892260637, 5956037993247]),
Y: FieldElement([980361497621373, 1671502808757874, 2143986549518967, 1109176323830729, 9039277193734]),
Z: FieldElement([2942534902618579, 3556685217095302, 1974617438797742, 1657071371119364, 16635295697052]),
T: FieldElement([2487305805734419, 681684275336734, 499518740758148, 156812857292600, 3978688323434])
};
pub(self) static P1_PROJECTIVE: ProjectivePoint = ProjectivePoint {
X: FieldElement([23, 0, 0, 0, 0]),
Y: FieldElement([1664892896009688, 132583819244870, 812547420185263, 637811013879057, 13284180325998]),
Z: FieldElement([1, 0, 0, 0, 0])
};
pub(self) static P2_PROJECTIVE: ProjectivePoint = ProjectivePoint {
X: FieldElement([68, 0, 0, 0, 0]),
Y: FieldElement([1799957170131195, 4493955741554471, 4409493758224495, 3389415867291423, 16342693473584]),
Z: FieldElement([1, 0, 0, 0, 0])
};
pub(self) static P4_PROJECTIVE: ProjectivePoint = ProjectivePoint {
X: FieldElement([1933054591726350, 4403792816774408, 3029093546253310, 1134491999944368, 8146384875494]),
Y: FieldElement([3369514960042642, 4355698098047571, 1547650124195635, 1314697306673062, 12051634278308]),
Z: FieldElement([576719056868307, 1763329757922533, 3184642959683715, 2550235128581121, 11094626825862])
};
pub(self) static P3_PROJECTIVE: ProjectivePoint = ProjectivePoint {
X: FieldElement([3851124475403222, 3539758816612178, 1146717153316815, 2152796892260637, 5956037993247]),
Y: FieldElement([980361497621373, 1671502808757874, 2143986549518967, 1109176323830729, 9039277193734]),
Z: FieldElement([2942534902618579, 3556685217095302, 1974617438797742, 1657071371119364, 16635295697052])
};
pub(self) static P1_COMPRESSED: CompressedEdwardsY = CompressedEdwardsY([216, 221, 167, 21, 54, 234, 101, 84, 47,
55, 89, 137, 7, 175, 226, 87, 240, 1, 227,
18, 81, 168, 46, 95, 65, 36, 110, 118, 217,
246, 20, 140]);
pub(self) static P2_COMPRESSED: CompressedEdwardsY = CompressedEdwardsY([251, 144, 188, 47, 13, 101, 118,
114, 201, 185, 169, 115, 255, 111,
40, 25, 69, 105, 170, 255, 113, 65,
12, 126, 170, 192, 48, 109, 112, 20,
221, 14]);
#[test]
fn from_projective_to_extended() {
let p3_extended_proj = ProjectivePoint {
X: FieldElement([23, 0, 0, 0, 0]),
Y: FieldElement([1664892896009688, 132583819244870, 812547420185263, 637811013879057, 13284180325998]),
Z: FieldElement([1, 0, 0, 0, 0])
};
assert!(EdwardsPoint::from(&p3_extended_proj) == P1_EXTENDED);
}
#[test]
fn from_extended_to_projective() {
let p3_extended_proj = ProjectivePoint {
X: FieldElement([23, 0, 0, 0, 0]),
Y: FieldElement([1664892896009688, 132583819244870, 812547420185263, 637811013879057, 13284180325998]),
Z: FieldElement([1, 0, 0, 0, 0])
};
assert!(p3_extended_proj == ProjectivePoint::from(&P1_EXTENDED));
}
#[test]
fn extended_point_neg() {
let a = EdwardsPoint::default();
let inv_a = EdwardsPoint {
X: FieldElement::zero(),
Y: FieldElement::one(),
Z: FieldElement::one(),
T: FieldElement::zero()
};
let res = -a;
assert!(res == inv_a);
}
#[test]
fn extended_coords_neg_identity() {
let res = - &EdwardsPoint::identity();
assert!(res == EdwardsPoint::identity())
}
#[test]
fn extended_point_addition() {
let res = &P1_EXTENDED + &P2_EXTENDED;
assert!(res == P4_EXTENDED);
}
#[test]
fn extended_point_doubling_by_addition() {
let res: EdwardsPoint = &P1_EXTENDED + &P1_EXTENDED;
assert!(res == P3_EXTENDED);
}
#[test]
fn extended_point_doubling() {
let res = P1_EXTENDED.double();
assert!(res == P3_EXTENDED);
}
#[test]
fn extended_double_and_add() {
let expect = P1_EXTENDED.double().double().double();
let res = P1_EXTENDED * Scalar::from(&8u8);
assert!(expect == res);
}
#[test]
fn extended_point_generation() {
let y2 = FieldElement([1799957170131195, 4493955741554471, 4409493758224495, 3389415867291423, 16342693473584]);
let p2 = EdwardsPoint::new_from_y_coord(&y2, Choice::from(0u8)).unwrap();
assert!(p2 == P2_EXTENDED);
let y1 = FieldElement([1664892896009688, 132583819244870, 812547420185263, 637811013879057, 13284180325998]);
let p1 = EdwardsPoint::new_from_y_coord(&y1, Choice::from(1u8)).unwrap();
assert!(p1 == P1_EXTENDED);
let y_failure = FieldElement::from(&15u8);
let p_fail = EdwardsPoint::new_from_y_coord(&y_failure, Choice::from(0u8));
assert!(p_fail.is_none())
}
#[test]
fn projective_point_neg() {
let a = ProjectivePoint::default();
let inv_a = ProjectivePoint {
X: FieldElement::zero(),
Y: FieldElement::one(),
Z: FieldElement::one()
};
let res = -a;
assert!(res == inv_a);
}
#[test]
fn projective_coords_neg_identity() {
let res = - &ProjectivePoint::identity();
assert!(res == ProjectivePoint::identity())
}
#[test]
fn projective_point_addition() {
let res = P1_PROJECTIVE + P2_PROJECTIVE;
assert!(res == P4_PROJECTIVE);
}
#[test]
fn projective_point_doubling() {
let res = P1_PROJECTIVE.double();
assert!(res == P3_PROJECTIVE);
}
#[test]
fn projective_double_and_add() {
let expect = P1_PROJECTIVE.double().double().double();
let res = P1_PROJECTIVE * Scalar::from(&8u8);
assert!(expect == res);
}
#[test]
fn projective_point_generation() {
let y2 = FieldElement([1799957170131195, 4493955741554471, 4409493758224495, 3389415867291423, 16342693473584]);
let p2 = ProjectivePoint::new_from_y_coord(&y2, Choice::from(0u8)).unwrap();
assert!(p2 == P2_PROJECTIVE);
let y1 = FieldElement([1664892896009688, 132583819244870, 812547420185263, 637811013879057, 13284180325998]);
let p1 = ProjectivePoint::new_from_y_coord(&y1, Choice::from(1u8)).unwrap();
assert!(p1 == P1_PROJECTIVE);
let y_failure = FieldElement::from(&15u8);
let p_fail = ProjectivePoint::new_from_y_coord(&y_failure, Choice::from(0u8));
assert!(p_fail.is_none())
}
#[test]
fn affine_point_ct_eq() {
assert!(P1_AFFINE.ct_eq(&P2_AFFINE).unwrap_u8() == 0u8);
assert!(P1_AFFINE.ct_eq(&P1_AFFINE).unwrap_u8() == 1u8);
assert!(AffinePoint::from(&P3_PROJECTIVE)
.ct_eq(&AffinePoint::from(&P1_PROJECTIVE.double())).
unwrap_u8()
== 1u8);
}
#[test]
fn affine_point_eq() {
assert!(P1_AFFINE == P1_AFFINE);
assert!(P1_AFFINE != P2_AFFINE);
assert!(AffinePoint::from(&P3_PROJECTIVE) == AffinePoint::from(&P1_PROJECTIVE.double()));
}
#[test]
fn point_compression() {
println!("{:?}", P1_EXTENDED.compress());
let compr = CompressedEdwardsY::from_slice(&[216, 221, 167, 21, 54, 234, 101, 84,
47, 55, 89, 137, 7, 175, 226, 87, 240,
1, 227, 18, 81, 168, 46, 95, 65, 36, 110,
118, 217, 246, 20, 140]);
assert!(compr == P1_EXTENDED.compress());
let compr2 = CompressedEdwardsY::from_slice(&[251, 144, 188, 47, 13, 101, 118,
114, 201, 185, 169, 115, 255, 111,
40, 25, 69, 105, 170, 255, 113, 65,
12, 126, 170, 192, 48, 109, 112, 20,
221, 14]);
assert!(compr2 == P2_EXTENDED.compress());
}
#[test]
fn point_decompression() {
assert!(P1_COMPRESSED.decompress().unwrap() == P1_EXTENDED);
assert!(P2_COMPRESSED.decompress().unwrap() == P2_EXTENDED);
let fail_compr = CompressedEdwardsY::from_slice(&[251, 144, 188, 47, 13, 101, 118,
114, 201, 185, 169, 115, 255, 111,
40, 25, 69, 105, 170, 255, 113, 65,
12, 126, 170, 192, 48, 109, 112, 20,
221, 149]);
assert!(fail_compr.decompress().is_none());
}
}