use crate::{
edwards_bls12::*,
templates::twisted_edwards_extended::tests::{edwards_test, montgomery_conversion_test},
traits::{
tests_field::{field_serialization_test, field_test, primefield_test},
tests_group::*,
tests_projective::curve_tests,
AffineCurve,
MontgomeryParameters,
ProjectiveCurve,
TwistedEdwardsParameters,
},
};
use snarkvm_fields::{Field, LegendreSymbol, One, SquareRootField, Zero};
use snarkvm_utilities::{
rand::{TestRng, Uniform},
to_bytes_le,
ToBytes,
};
use rand::Rng;
#[test]
fn test_edwards_bls12_fr() {
let mut rng = TestRng::default();
let a: Fr = rng.gen();
let b: Fr = rng.gen();
field_test(a, b, &mut rng);
primefield_test::<Fr>(&mut rng);
field_serialization_test::<Fr>(&mut rng);
}
#[test]
fn test_edwards_bls12_fq() {
let mut rng = TestRng::default();
let a: Fq = rng.gen();
let b: Fq = rng.gen();
field_test(a, b, &mut rng);
primefield_test::<Fq>(&mut rng);
field_serialization_test::<Fq>(&mut rng);
}
#[test]
fn test_projective_curve() {
let mut rng = TestRng::default();
curve_tests::<EdwardsProjective>(&mut rng);
edwards_test::<EdwardsParameters>(&mut rng);
}
#[test]
fn test_projective_group() {
let mut rng = TestRng::default();
for _i in 0..10 {
let a = rng.gen();
let b = rng.gen();
projective_test::<EdwardsProjective>(a, b, &mut rng);
}
}
#[test]
fn test_affine_group() {
let mut rng = TestRng::default();
for _i in 0..10 {
let a: EdwardsAffine = rng.gen();
affine_test::<EdwardsAffine>(a);
}
}
#[test]
fn test_generator() {
let generator = EdwardsAffine::prime_subgroup_generator();
assert!(generator.is_on_curve());
assert!(generator.is_in_correct_subgroup_assuming_on_curve());
}
#[test]
fn test_conversion() {
let mut rng = TestRng::default();
let a: EdwardsAffine = rng.gen();
let b: EdwardsAffine = rng.gen();
assert_eq!(a.to_projective().to_affine(), a);
assert_eq!(b.to_projective().to_affine(), b);
}
#[test]
fn test_montgomery_conversion() {
montgomery_conversion_test::<EdwardsParameters>();
}
#[test]
#[allow(clippy::many_single_char_names)]
fn test_edwards_to_montgomery_point() {
let mut rng = TestRng::default();
let a: EdwardsAffine = rng.gen();
let (x, y) = (a.x, a.y);
let (u, v) = {
let numerator = Fq::one() + y;
let denominator = Fq::one() - y;
let u = numerator * (denominator.inverse().unwrap());
let v = numerator * ((denominator * x).inverse().unwrap());
(u, v)
};
{
const A: Fq = <EdwardsParameters as MontgomeryParameters>::MONTGOMERY_A;
const B: Fq = <EdwardsParameters as MontgomeryParameters>::MONTGOMERY_B;
let v2 = v.square();
let u2 = u.square();
let u3 = u2 * u;
assert_eq!(B * v2, u3 + (A * u2) + u);
}
let (x_reconstructed, y_reconstructed) = {
let x = u * v.inverse().unwrap();
let numerator = u - Fq::one();
let denominator = u + Fq::one();
let y = numerator * denominator.inverse().unwrap();
(x, y)
};
assert_eq!(x, x_reconstructed);
assert_eq!(y, y_reconstructed);
}
#[ignore]
#[test]
fn print_montgomery_to_weierstrass_parameters() {
const A: Fq = <EdwardsParameters as MontgomeryParameters>::MONTGOMERY_A;
const B: Fq = <EdwardsParameters as MontgomeryParameters>::MONTGOMERY_B;
let two = Fq::one() + Fq::one();
let three = Fq::one() + two;
let nine = three + (three + three);
let twenty_seven = nine + (nine + nine);
let a2 = A.square();
let a3 = A * a2;
let b2 = B.square();
let b3 = B * b2;
let numerator = three - a2;
let denominator = three * b2;
let a = numerator * denominator.inverse().unwrap();
let numerator = (two * a3) - (nine * A);
let denominator = twenty_seven * b3;
let b = numerator * denominator.inverse().unwrap();
println!("A - {}\nB - {}", a, b);
}
#[test]
#[allow(clippy::many_single_char_names)]
fn test_isomorphism() {
let mut rng = TestRng::default();
let fr_element: Fr = Fr::rand(&mut rng);
println!("Starting Fr element is - {:?}", fr_element);
let fq_element = {
let output = Fq::from_random_bytes(&to_bytes_le![fr_element].unwrap());
assert!(output.is_some());
output.unwrap()
};
println!("Starting Fq element is {:?}", fq_element);
const A: Fq = <EdwardsParameters as MontgomeryParameters>::MONTGOMERY_A;
const B: Fq = <EdwardsParameters as MontgomeryParameters>::MONTGOMERY_B;
let (a, b) = {
let a = A * B.inverse().unwrap();
let b = Fq::one() * B.square().inverse().unwrap();
(a, b)
};
let (u, v) = {
let r = fq_element;
let u = <EdwardsParameters as TwistedEdwardsParameters>::EDWARDS_D;
let ur2 = r.square() * u;
{
assert!(!r.is_zero());
assert!(u.legendre().is_qnr());
assert_ne!(Fq::one() + ur2, Fq::zero());
let a2 = a.square();
assert_ne!(a2 * ur2, (Fq::one() + ur2).square() * b);
}
let v = (Fq::one() + ur2).inverse().unwrap() * (-a);
let v2 = v.square();
let v3 = v2 * v;
let av2 = a * v2;
let bv = b * v;
let e = (v3 + (av2 + bv)).legendre();
let two = Fq::one().double();
let x = match e {
LegendreSymbol::Zero => -(a * two.inverse().unwrap()),
LegendreSymbol::QuadraticResidue => v,
LegendreSymbol::QuadraticNonResidue => (-v) - a,
};
let x2 = x.square();
let x3 = x2 * x;
let ax2 = a * x2;
let bx = b * x;
let value = (x3 + (ax2 + bx)).sqrt().unwrap();
let y = match e {
LegendreSymbol::Zero => Fq::zero(),
LegendreSymbol::QuadraticResidue => -value,
LegendreSymbol::QuadraticNonResidue => value,
};
(x, y)
};
{
let v2 = v.square();
let u2 = u.square();
let u3 = u2 * u;
assert_eq!(v2, u3 + (a * u2) + (b * u));
}
let (s, t) = {
let s = u * B;
let t = v * B;
{
let t2 = t.square();
let s2 = s.square();
let s3 = s2 * s;
assert_eq!(B * t2, s3 + (A * s2) + s);
}
(s, t)
};
let (x, y) = {
let x = s * t.inverse().unwrap();
let numerator = s - Fq::one();
let denominator = s + Fq::one();
let y = numerator * denominator.inverse().unwrap();
(x, y)
};
let group = EdwardsAffine::new(x, y, x * y);
println!("{:?}", group);
let (u_reconstructed, v_reconstructed) = {
let numerator = Fq::one() + y;
let denominator = Fq::one() - y;
let u = numerator * (denominator.inverse().unwrap());
let v = numerator * ((denominator * x).inverse().unwrap());
{
let v2 = v.square();
let u2 = u.square();
let u3 = u2 * u;
assert_eq!(B * v2, u3 + (A * u2) + u);
}
let u = u * B.inverse().unwrap();
let v = v * B.inverse().unwrap();
{
let v2 = v.square();
let u2 = u.square();
let u3 = u2 * u;
assert_eq!(v2, u3 + (a * u2) + (b * u));
}
(u, v)
};
assert_eq!(u, u_reconstructed);
assert_eq!(v, v_reconstructed);
let fq_element_reconstructed = {
let x = u_reconstructed;
let u = <EdwardsParameters as TwistedEdwardsParameters>::EDWARDS_D;
{
assert!(u.legendre().is_qnr());
assert_ne!(x, -a);
if y.is_zero() {
assert!(x.is_zero());
}
assert_eq!((-(u * x) * (x + a)).legendre(), LegendreSymbol::QuadraticResidue);
}
println!("\ngroup legendre - {:?}", y.legendre());
let numerator = -x;
let denominator = (x + a) * u;
let value1 = (numerator * denominator.inverse().unwrap()).sqrt();
let numerator = -x - a;
let denominator = x * u;
let value2 = (numerator * denominator.inverse().unwrap()).sqrt();
let mut recovered_value = None;
if let Some(value) = value1 {
if fq_element == value {
println!("SUCCESS 1");
recovered_value = Some(value);
} else if fq_element == -value {
println!("SUCCESS 2");
recovered_value = Some(-value);
}
}
if let Some(value) = value2 {
if fq_element == value {
println!("SUCCESS 3");
recovered_value = Some(value)
} else if fq_element == -value {
println!("SUCCESS 4");
recovered_value = Some(-value);
}
}
if recovered_value.is_none() {
println!("FAILED");
panic!()
}
recovered_value.unwrap()
};
let fr_element_reconstructed = {
let output = Fr::from_random_bytes(&to_bytes_le![fq_element_reconstructed].unwrap());
assert!(output.is_some());
output.unwrap()
};
assert_eq!(fr_element, fr_element_reconstructed);
}