group/tests/
mod.rs

1use alloc::vec::Vec;
2use core::ops::{Mul, Neg};
3use ff::{Field, PrimeField};
4use rand::SeedableRng;
5use rand_xorshift::XorShiftRng;
6
7use crate::{
8    prime::{PrimeCurve, PrimeCurveAffine},
9    wnaf::WnafGroup,
10    GroupEncoding, UncompressedEncoding,
11};
12
13pub fn curve_tests<G: PrimeCurve>() {
14    let mut rng = XorShiftRng::from_seed([
15        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
16        0xe5,
17    ]);
18
19    // Negation edge case with identity.
20    {
21        let z = G::identity().neg();
22        assert!(bool::from(z.is_identity()));
23    }
24
25    // Doubling edge case with identity.
26    {
27        let z = G::identity().double();
28        assert!(bool::from(z.is_identity()));
29    }
30
31    // Addition edge cases with identity
32    {
33        let mut r = G::random(&mut rng);
34        let rcopy = r;
35        r.add_assign(&G::identity());
36        assert_eq!(r, rcopy);
37        r.add_assign(&G::Affine::identity());
38        assert_eq!(r, rcopy);
39
40        let mut z = G::identity();
41        z.add_assign(&G::identity());
42        assert!(bool::from(z.is_identity()));
43        z.add_assign(&G::Affine::identity());
44        assert!(bool::from(z.is_identity()));
45
46        let mut z2 = z;
47        z2.add_assign(&r);
48
49        z.add_assign(&r.to_affine());
50
51        assert_eq!(z, z2);
52        assert_eq!(z, r);
53    }
54
55    // Transformations
56    {
57        let a = G::random(&mut rng);
58        let b = a.to_affine().to_curve();
59        let c = a.to_affine().to_curve().to_affine().to_curve();
60        assert_eq!(a, b);
61        assert_eq!(b, c);
62    }
63
64    random_addition_tests::<G>();
65    random_multiplication_tests::<G>();
66    random_doubling_tests::<G>();
67    random_negation_tests::<G>();
68    random_transformation_tests::<G>();
69    random_compressed_encoding_tests::<G>();
70}
71
72pub fn random_wnaf_tests<G: WnafGroup>() {
73    use crate::wnaf::*;
74
75    let mut rng = XorShiftRng::from_seed([
76        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
77        0xe5,
78    ]);
79
80    {
81        let mut table = vec![];
82        let mut wnaf = vec![];
83
84        for w in 2..14 {
85            for _ in 0..100 {
86                let g = G::random(&mut rng);
87                let s = G::Scalar::random(&mut rng);
88                let mut g1 = g;
89                g1.mul_assign(s);
90
91                wnaf_table(&mut table, g, w);
92                wnaf_form(&mut wnaf, s.to_repr(), w);
93                let g2 = wnaf_exp(&table, &wnaf);
94
95                assert_eq!(g1, g2);
96            }
97        }
98    }
99
100    {
101        fn only_compiles_if_send<S: Send>(_: &S) {}
102
103        for _ in 0..100 {
104            let g = G::random(&mut rng);
105            let s = G::Scalar::random(&mut rng);
106            let mut g1 = g;
107            g1.mul_assign(s);
108
109            let g2 = {
110                let mut wnaf = Wnaf::new();
111                wnaf.base(g, 1).scalar(&s)
112            };
113            let g3 = {
114                let mut wnaf = Wnaf::new();
115                wnaf.scalar(&s).base(g)
116            };
117            let g4 = {
118                let mut wnaf = Wnaf::new();
119                let mut shared = wnaf.base(g, 1).shared();
120
121                only_compiles_if_send(&shared);
122
123                shared.scalar(&s)
124            };
125            let g5 = {
126                let mut wnaf = Wnaf::new();
127                let mut shared = wnaf.scalar(&s).shared();
128
129                only_compiles_if_send(&shared);
130
131                shared.base(g)
132            };
133
134            let g6 = {
135                let mut wnaf = Wnaf::new();
136                {
137                    // Populate the vectors.
138                    wnaf.base(G::random(&mut rng), 1)
139                        .scalar(&G::Scalar::random(&mut rng));
140                }
141                wnaf.base(g, 1).scalar(&s)
142            };
143            let g7 = {
144                let mut wnaf = Wnaf::new();
145                {
146                    // Populate the vectors.
147                    wnaf.base(G::random(&mut rng), 1)
148                        .scalar(&G::Scalar::random(&mut rng));
149                }
150                wnaf.scalar(&s).base(g)
151            };
152            let g8 = {
153                let mut wnaf = Wnaf::new();
154                {
155                    // Populate the vectors.
156                    wnaf.base(G::random(&mut rng), 1)
157                        .scalar(&G::Scalar::random(&mut rng));
158                }
159                let mut shared = wnaf.base(g, 1).shared();
160
161                only_compiles_if_send(&shared);
162
163                shared.scalar(&s)
164            };
165            let g9 = {
166                let mut wnaf = Wnaf::new();
167                {
168                    // Populate the vectors.
169                    wnaf.base(G::random(&mut rng), 1)
170                        .scalar(&G::Scalar::random(&mut rng));
171                }
172                let mut shared = wnaf.scalar(&s).shared();
173
174                only_compiles_if_send(&shared);
175
176                shared.base(g)
177            };
178
179            assert_eq!(g1, g2);
180            assert_eq!(g1, g3);
181            assert_eq!(g1, g4);
182            assert_eq!(g1, g5);
183            assert_eq!(g1, g6);
184            assert_eq!(g1, g7);
185            assert_eq!(g1, g8);
186            assert_eq!(g1, g9);
187        }
188    }
189}
190
191fn random_negation_tests<G: PrimeCurve>() {
192    let mut rng = XorShiftRng::from_seed([
193        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
194        0xe5,
195    ]);
196
197    for _ in 0..1000 {
198        let r = G::random(&mut rng);
199
200        let s = G::Scalar::random(&mut rng);
201        let sneg = s.neg();
202
203        let mut t1 = r;
204        t1.mul_assign(s);
205
206        let mut t2 = r;
207        t2.mul_assign(sneg);
208
209        let mut t3 = t1;
210        t3.add_assign(&t2);
211        assert!(bool::from(t3.is_identity()));
212
213        let mut t4 = t1;
214        t4.add_assign(&t2.to_affine());
215        assert!(bool::from(t4.is_identity()));
216
217        assert_eq!(t1.neg(), t2);
218    }
219}
220
221fn random_doubling_tests<G: PrimeCurve>() {
222    let mut rng = XorShiftRng::from_seed([
223        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
224        0xe5,
225    ]);
226
227    for _ in 0..1000 {
228        let mut a = G::random(&mut rng);
229        let mut b = G::random(&mut rng);
230
231        // 2(a + b)
232        let tmp1 = (a + b).double();
233
234        // 2a + 2b
235        a = a.double();
236        b = b.double();
237
238        let mut tmp2 = a;
239        tmp2.add_assign(&b);
240
241        let mut tmp3 = a;
242        tmp3.add_assign(&b.to_affine());
243
244        assert_eq!(tmp1, tmp2);
245        assert_eq!(tmp1, tmp3);
246    }
247}
248
249fn random_multiplication_tests<G: PrimeCurve>() {
250    let mut rng = XorShiftRng::from_seed([
251        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
252        0xe5,
253    ]);
254
255    for _ in 0..1000 {
256        let mut a = G::random(&mut rng);
257        let mut b = G::random(&mut rng);
258        let a_affine = a.to_affine();
259        let b_affine = b.to_affine();
260
261        let s = G::Scalar::random(&mut rng);
262
263        // s ( a + b )
264        let mut tmp1 = a;
265        tmp1.add_assign(&b);
266        tmp1.mul_assign(s);
267
268        // sa + sb
269        a.mul_assign(s);
270        b.mul_assign(s);
271
272        let mut tmp2 = a;
273        tmp2.add_assign(&b);
274
275        // Affine multiplication
276        let mut tmp3 = Mul::<G::Scalar>::mul(a_affine, s);
277        tmp3.add_assign(Mul::<G::Scalar>::mul(b_affine, s));
278
279        assert_eq!(tmp1, tmp2);
280        assert_eq!(tmp1, tmp3);
281    }
282}
283
284fn random_addition_tests<G: PrimeCurve>() {
285    let mut rng = XorShiftRng::from_seed([
286        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
287        0xe5,
288    ]);
289
290    for _ in 0..1000 {
291        let a = G::random(&mut rng);
292        let b = G::random(&mut rng);
293        let c = G::random(&mut rng);
294        let a_affine = a.to_affine();
295        let b_affine = b.to_affine();
296        let c_affine = c.to_affine();
297
298        // a + a should equal the doubling
299        {
300            let mut aplusa = a;
301            aplusa.add_assign(&a);
302
303            let mut aplusamixed = a;
304            aplusamixed.add_assign(&a.to_affine());
305
306            let adouble = a.double();
307
308            assert_eq!(aplusa, adouble);
309            assert_eq!(aplusa, aplusamixed);
310        }
311
312        let mut tmp = vec![G::identity(); 6];
313
314        // (a + b) + c
315        tmp[0] = a;
316        tmp[0].add_assign(&b);
317        tmp[0].add_assign(&c);
318
319        // a + (b + c)
320        tmp[1] = b;
321        tmp[1].add_assign(&c);
322        tmp[1].add_assign(&a);
323
324        // (a + c) + b
325        tmp[2] = a;
326        tmp[2].add_assign(&c);
327        tmp[2].add_assign(&b);
328
329        // Mixed addition
330
331        // (a + b) + c
332        tmp[3] = a_affine.to_curve();
333        tmp[3].add_assign(&b_affine);
334        tmp[3].add_assign(&c_affine);
335
336        // a + (b + c)
337        tmp[4] = b_affine.to_curve();
338        tmp[4].add_assign(&c_affine);
339        tmp[4].add_assign(&a_affine);
340
341        // (a + c) + b
342        tmp[5] = a_affine.to_curve();
343        tmp[5].add_assign(&c_affine);
344        tmp[5].add_assign(&b_affine);
345
346        // Comparisons
347        for i in 0..6 {
348            for j in 0..6 {
349                assert_eq!(tmp[i], tmp[j]);
350                assert_eq!(tmp[i].to_affine(), tmp[j].to_affine());
351            }
352
353            assert!(tmp[i] != a);
354            assert!(tmp[i] != b);
355            assert!(tmp[i] != c);
356
357            assert!(a != tmp[i]);
358            assert!(b != tmp[i]);
359            assert!(c != tmp[i]);
360        }
361    }
362}
363
364fn random_transformation_tests<G: PrimeCurve>() {
365    let mut rng = XorShiftRng::from_seed([
366        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
367        0xe5,
368    ]);
369
370    for _ in 0..1000 {
371        let g = G::random(&mut rng);
372        let g_affine = g.to_affine();
373        let g_projective = g_affine.to_curve();
374        assert_eq!(g, g_projective);
375    }
376
377    // Batch normalization
378    for _ in 0..10 {
379        let mut v = (0..1000).map(|_| G::random(&mut rng)).collect::<Vec<_>>();
380
381        use rand::distributions::{Distribution, Uniform};
382        let between = Uniform::new(0, 1000);
383        // Sprinkle in some normalized points
384        for _ in 0..5 {
385            v[between.sample(&mut rng)] = G::identity();
386        }
387        for _ in 0..5 {
388            let s = between.sample(&mut rng);
389            v[s] = v[s].to_affine().to_curve();
390        }
391
392        let expected_v = v.iter().map(|v| v.to_affine()).collect::<Vec<_>>();
393
394        let mut normalized = vec![G::Affine::identity(); v.len()];
395        G::batch_normalize(&v, &mut normalized);
396
397        assert_eq!(normalized, expected_v);
398    }
399}
400
401fn random_compressed_encoding_tests<G: PrimeCurve>() {
402    let mut rng = XorShiftRng::from_seed([
403        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
404        0xe5,
405    ]);
406
407    assert_eq!(
408        G::Affine::from_bytes(&G::Affine::identity().to_bytes()).unwrap(),
409        G::Affine::identity()
410    );
411
412    for _ in 0..1000 {
413        let mut r = G::random(&mut rng).to_affine();
414
415        let compressed = r.to_bytes();
416        let de_compressed = G::Affine::from_bytes(&compressed).unwrap();
417        assert_eq!(de_compressed, r);
418
419        r = r.neg();
420
421        let compressed = r.to_bytes();
422        let de_compressed = G::Affine::from_bytes(&compressed).unwrap();
423        assert_eq!(de_compressed, r);
424    }
425}
426
427pub fn random_uncompressed_encoding_tests<G: PrimeCurve>()
428where
429    <G as PrimeCurve>::Affine: UncompressedEncoding,
430{
431    let mut rng = XorShiftRng::from_seed([
432        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
433        0xe5,
434    ]);
435
436    assert_eq!(
437        G::Affine::from_uncompressed(&G::Affine::identity().to_uncompressed()).unwrap(),
438        G::Affine::identity()
439    );
440
441    for _ in 0..1000 {
442        let r = G::random(&mut rng).to_affine();
443
444        let uncompressed = r.to_uncompressed();
445        let de_uncompressed = G::Affine::from_uncompressed(&uncompressed).unwrap();
446        assert_eq!(de_uncompressed, r);
447    }
448}