use alloc::vec::Vec;
use core::ops::{Mul, Neg};
use ff::{Field, PrimeField};
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use crate::{
prime::{PrimeCurve, PrimeCurveAffine},
wnaf::WnafGroup,
GroupEncoding, UncompressedEncoding,
};
pub fn curve_tests<G: PrimeCurve>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
{
let z = G::identity().neg();
assert!(bool::from(z.is_identity()));
}
{
let z = G::identity().double();
assert!(bool::from(z.is_identity()));
}
{
let mut r = G::random(&mut rng);
let rcopy = r;
r.add_assign(&G::identity());
assert_eq!(r, rcopy);
r.add_assign(&G::Affine::identity());
assert_eq!(r, rcopy);
let mut z = G::identity();
z.add_assign(&G::identity());
assert!(bool::from(z.is_identity()));
z.add_assign(&G::Affine::identity());
assert!(bool::from(z.is_identity()));
let mut z2 = z;
z2.add_assign(&r);
z.add_assign(&r.to_affine());
assert_eq!(z, z2);
assert_eq!(z, r);
}
{
let a = G::random(&mut rng);
let b = a.to_affine().to_curve();
let c = a.to_affine().to_curve().to_affine().to_curve();
assert_eq!(a, b);
assert_eq!(b, c);
}
random_addition_tests::<G>();
random_multiplication_tests::<G>();
random_doubling_tests::<G>();
random_negation_tests::<G>();
random_transformation_tests::<G>();
random_compressed_encoding_tests::<G>();
}
pub fn random_wnaf_tests<G: WnafGroup>() {
use crate::wnaf::*;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
{
let mut table = vec![];
let mut wnaf = vec![];
for w in 2..14 {
for _ in 0..100 {
let g = G::random(&mut rng);
let s = G::Scalar::random(&mut rng);
let mut g1 = g;
g1.mul_assign(s);
wnaf_table(&mut table, g, w);
wnaf_form(&mut wnaf, s.to_repr(), w);
let g2 = wnaf_exp(&table, &wnaf);
assert_eq!(g1, g2);
}
}
}
{
fn only_compiles_if_send<S: Send>(_: &S) {}
for _ in 0..100 {
let g = G::random(&mut rng);
let s = G::Scalar::random(&mut rng);
let mut g1 = g;
g1.mul_assign(s);
let g2 = {
let mut wnaf = Wnaf::new();
wnaf.base(g, 1).scalar(&s)
};
let g3 = {
let mut wnaf = Wnaf::new();
wnaf.scalar(&s).base(g)
};
let g4 = {
let mut wnaf = Wnaf::new();
let mut shared = wnaf.base(g, 1).shared();
only_compiles_if_send(&shared);
shared.scalar(&s)
};
let g5 = {
let mut wnaf = Wnaf::new();
let mut shared = wnaf.scalar(&s).shared();
only_compiles_if_send(&shared);
shared.base(g)
};
let g6 = {
let mut wnaf = Wnaf::new();
{
wnaf.base(G::random(&mut rng), 1)
.scalar(&G::Scalar::random(&mut rng));
}
wnaf.base(g, 1).scalar(&s)
};
let g7 = {
let mut wnaf = Wnaf::new();
{
wnaf.base(G::random(&mut rng), 1)
.scalar(&G::Scalar::random(&mut rng));
}
wnaf.scalar(&s).base(g)
};
let g8 = {
let mut wnaf = Wnaf::new();
{
wnaf.base(G::random(&mut rng), 1)
.scalar(&G::Scalar::random(&mut rng));
}
let mut shared = wnaf.base(g, 1).shared();
only_compiles_if_send(&shared);
shared.scalar(&s)
};
let g9 = {
let mut wnaf = Wnaf::new();
{
wnaf.base(G::random(&mut rng), 1)
.scalar(&G::Scalar::random(&mut rng));
}
let mut shared = wnaf.scalar(&s).shared();
only_compiles_if_send(&shared);
shared.base(g)
};
assert_eq!(g1, g2);
assert_eq!(g1, g3);
assert_eq!(g1, g4);
assert_eq!(g1, g5);
assert_eq!(g1, g6);
assert_eq!(g1, g7);
assert_eq!(g1, g8);
assert_eq!(g1, g9);
}
}
}
fn random_negation_tests<G: PrimeCurve>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
let r = G::random(&mut rng);
let s = G::Scalar::random(&mut rng);
let sneg = s.neg();
let mut t1 = r;
t1.mul_assign(s);
let mut t2 = r;
t2.mul_assign(sneg);
let mut t3 = t1;
t3.add_assign(&t2);
assert!(bool::from(t3.is_identity()));
let mut t4 = t1;
t4.add_assign(&t2.to_affine());
assert!(bool::from(t4.is_identity()));
assert_eq!(t1.neg(), t2);
}
}
fn random_doubling_tests<G: PrimeCurve>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
let mut a = G::random(&mut rng);
let mut b = G::random(&mut rng);
let tmp1 = (a + b).double();
a = a.double();
b = b.double();
let mut tmp2 = a;
tmp2.add_assign(&b);
let mut tmp3 = a;
tmp3.add_assign(&b.to_affine());
assert_eq!(tmp1, tmp2);
assert_eq!(tmp1, tmp3);
}
}
fn random_multiplication_tests<G: PrimeCurve>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
let mut a = G::random(&mut rng);
let mut b = G::random(&mut rng);
let a_affine = a.to_affine();
let b_affine = b.to_affine();
let s = G::Scalar::random(&mut rng);
let mut tmp1 = a;
tmp1.add_assign(&b);
tmp1.mul_assign(s);
a.mul_assign(s);
b.mul_assign(s);
let mut tmp2 = a;
tmp2.add_assign(&b);
let mut tmp3 = Mul::<G::Scalar>::mul(a_affine, s);
tmp3.add_assign(Mul::<G::Scalar>::mul(b_affine, s));
assert_eq!(tmp1, tmp2);
assert_eq!(tmp1, tmp3);
}
}
fn random_addition_tests<G: PrimeCurve>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
let a = G::random(&mut rng);
let b = G::random(&mut rng);
let c = G::random(&mut rng);
let a_affine = a.to_affine();
let b_affine = b.to_affine();
let c_affine = c.to_affine();
{
let mut aplusa = a;
aplusa.add_assign(&a);
let mut aplusamixed = a;
aplusamixed.add_assign(&a.to_affine());
let adouble = a.double();
assert_eq!(aplusa, adouble);
assert_eq!(aplusa, aplusamixed);
}
let mut tmp = vec![G::identity(); 6];
tmp[0] = a;
tmp[0].add_assign(&b);
tmp[0].add_assign(&c);
tmp[1] = b;
tmp[1].add_assign(&c);
tmp[1].add_assign(&a);
tmp[2] = a;
tmp[2].add_assign(&c);
tmp[2].add_assign(&b);
tmp[3] = a_affine.to_curve();
tmp[3].add_assign(&b_affine);
tmp[3].add_assign(&c_affine);
tmp[4] = b_affine.to_curve();
tmp[4].add_assign(&c_affine);
tmp[4].add_assign(&a_affine);
tmp[5] = a_affine.to_curve();
tmp[5].add_assign(&c_affine);
tmp[5].add_assign(&b_affine);
for i in 0..6 {
for j in 0..6 {
assert_eq!(tmp[i], tmp[j]);
assert_eq!(tmp[i].to_affine(), tmp[j].to_affine());
}
assert!(tmp[i] != a);
assert!(tmp[i] != b);
assert!(tmp[i] != c);
assert!(a != tmp[i]);
assert!(b != tmp[i]);
assert!(c != tmp[i]);
}
}
}
fn random_transformation_tests<G: PrimeCurve>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
let g = G::random(&mut rng);
let g_affine = g.to_affine();
let g_projective = g_affine.to_curve();
assert_eq!(g, g_projective);
}
for _ in 0..10 {
let mut v = (0..1000).map(|_| G::random(&mut rng)).collect::<Vec<_>>();
use rand::distributions::{Distribution, Uniform};
let between = Uniform::new(0, 1000);
for _ in 0..5 {
v[between.sample(&mut rng)] = G::identity();
}
for _ in 0..5 {
let s = between.sample(&mut rng);
v[s] = v[s].to_affine().to_curve();
}
let expected_v = v.iter().map(|v| v.to_affine()).collect::<Vec<_>>();
let mut normalized = vec![G::Affine::identity(); v.len()];
G::batch_normalize(&v, &mut normalized);
assert_eq!(normalized, expected_v);
}
}
fn random_compressed_encoding_tests<G: PrimeCurve>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
assert_eq!(
G::Affine::from_bytes(&G::Affine::identity().to_bytes()).unwrap(),
G::Affine::identity()
);
for _ in 0..1000 {
let mut r = G::random(&mut rng).to_affine();
let compressed = r.to_bytes();
let de_compressed = G::Affine::from_bytes(&compressed).unwrap();
assert_eq!(de_compressed, r);
r = r.neg();
let compressed = r.to_bytes();
let de_compressed = G::Affine::from_bytes(&compressed).unwrap();
assert_eq!(de_compressed, r);
}
}
pub fn random_uncompressed_encoding_tests<G: PrimeCurve>()
where
<G as PrimeCurve>::Affine: UncompressedEncoding,
{
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
assert_eq!(
G::Affine::from_uncompressed(&G::Affine::identity().to_uncompressed()).unwrap(),
G::Affine::identity()
);
for _ in 0..1000 {
let r = G::random(&mut rng).to_affine();
let uncompressed = r.to_uncompressed();
let de_uncompressed = G::Affine::from_uncompressed(&uncompressed).unwrap();
assert_eq!(de_uncompressed, r);
}
}