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() { let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); // Negation edge case with identity. { let z = G::identity().neg(); assert!(bool::from(z.is_identity())); } // Doubling edge case with identity. { let z = G::identity().double(); assert!(bool::from(z.is_identity())); } // Addition edge cases with 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); } // Transformations { 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::(); random_multiplication_tests::(); random_doubling_tests::(); random_negation_tests::(); random_transformation_tests::(); random_compressed_encoding_tests::(); } pub fn random_wnaf_tests() { 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) {} 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(); { // Populate the vectors. 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(); { // Populate the vectors. 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(); { // Populate the vectors. 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(); { // Populate the vectors. 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() { 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() { 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); // 2(a + b) let tmp1 = (a + b).double(); // 2a + 2b 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() { 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); // s ( a + b ) let mut tmp1 = a; tmp1.add_assign(&b); tmp1.mul_assign(s); // sa + sb a.mul_assign(s); b.mul_assign(s); let mut tmp2 = a; tmp2.add_assign(&b); // Affine multiplication let mut tmp3 = Mul::::mul(a_affine, s); tmp3.add_assign(Mul::::mul(b_affine, s)); assert_eq!(tmp1, tmp2); assert_eq!(tmp1, tmp3); } } fn random_addition_tests() { 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(); // a + a should equal the doubling { 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]; // (a + b) + c tmp[0] = a; tmp[0].add_assign(&b); tmp[0].add_assign(&c); // a + (b + c) tmp[1] = b; tmp[1].add_assign(&c); tmp[1].add_assign(&a); // (a + c) + b tmp[2] = a; tmp[2].add_assign(&c); tmp[2].add_assign(&b); // Mixed addition // (a + b) + c tmp[3] = a_affine.to_curve(); tmp[3].add_assign(&b_affine); tmp[3].add_assign(&c_affine); // a + (b + c) tmp[4] = b_affine.to_curve(); tmp[4].add_assign(&c_affine); tmp[4].add_assign(&a_affine); // (a + c) + b tmp[5] = a_affine.to_curve(); tmp[5].add_assign(&c_affine); tmp[5].add_assign(&b_affine); // Comparisons 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() { 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); } // Batch normalization for _ in 0..10 { let mut v = (0..1000).map(|_| G::random(&mut rng)).collect::>(); use rand::distributions::{Distribution, Uniform}; let between = Uniform::new(0, 1000); // Sprinkle in some normalized points 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::>(); 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() { 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() where ::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); } }