ff_group_tests/
group.rs

1use rand_core::RngCore;
2use group::{
3  ff::{Field, PrimeFieldBits},
4  Group,
5  prime::PrimeGroup,
6};
7
8use crate::prime_field::{test_prime_field, test_prime_field_bits};
9
10/// Test equality.
11pub fn test_eq<G: Group>() {
12  assert_eq!(G::identity(), G::identity(), "identity != identity");
13  assert_eq!(G::generator(), G::generator(), "generator != generator");
14  assert!(G::identity() != G::generator(), "identity == generator");
15}
16
17/// Test identity.
18pub fn test_identity<G: Group>() {
19  assert!(bool::from(G::identity().is_identity()), "identity wasn't identity");
20  assert!(
21    bool::from((G::identity() + G::identity()).is_identity()),
22    "identity + identity wasn't identity"
23  );
24  assert!(
25    bool::from((G::generator() - G::generator()).is_identity()),
26    "generator - generator wasn't identity"
27  );
28  assert!(!bool::from(G::generator().is_identity()), "is_identity claimed generator was identity");
29}
30
31/// Sanity check the generator.
32pub fn test_generator<G: Group>() {
33  assert!(G::generator() != G::identity(), "generator was identity");
34  assert!(
35    (G::generator() + G::generator()) != G::generator(),
36    "generator added to itself was identity"
37  );
38}
39
40/// Test doubling of group elements.
41pub fn test_double<G: Group>() {
42  assert!(bool::from(G::identity().double().is_identity()), "identity.double() wasn't identity");
43  assert_eq!(
44    G::generator() + G::generator(),
45    G::generator().double(),
46    "generator + generator != generator.double()"
47  );
48}
49
50/// Test addition.
51pub fn test_add<G: Group>() {
52  assert_eq!(G::identity() + G::identity(), G::identity(), "identity + identity != identity");
53  assert_eq!(G::identity() + G::generator(), G::generator(), "identity + generator != generator");
54  assert_eq!(G::generator() + G::identity(), G::generator(), "generator + identity != generator");
55
56  let two = G::generator().double();
57  assert_eq!(G::generator() + G::generator(), two, "generator + generator != two");
58  let four = two.double();
59  assert_eq!(
60    G::generator() + G::generator() + G::generator() + G::generator(),
61    four,
62    "generator + generator + generator + generator != four"
63  );
64}
65
66/// Test summation.
67pub fn test_sum<G: Group>() {
68  assert_eq!(
69    [G::generator(), G::generator()].iter().sum::<G>(),
70    G::generator().double(),
71    "[generator, generator].sum() != two"
72  );
73  assert_eq!(
74    [G::generator().double(), G::generator()].iter().sum::<G>(),
75    G::generator().double() + G::generator(),
76    "[generator.double(), generator].sum() != three"
77  );
78}
79
80/// Test negation.
81pub fn test_neg<G: Group>() {
82  assert_eq!(G::identity(), G::identity().neg(), "identity != -identity");
83  assert_eq!(
84    G::generator() + G::generator().neg(),
85    G::identity(),
86    "generator + -generator != identity"
87  );
88}
89
90/// Test subtraction.
91pub fn test_sub<G: Group>() {
92  assert_eq!(G::generator() - G::generator(), G::identity(), "generator - generator != identity");
93  let two = G::generator() + G::generator();
94  assert_eq!(two - G::generator(), G::generator(), "two - one != one");
95}
96
97/// Test scalar multiplication
98pub fn test_mul<G: Group>() {
99  assert_eq!(G::generator() * G::Scalar::from(0), G::identity(), "generator * 0 != identity");
100  assert_eq!(G::generator() * G::Scalar::from(1), G::generator(), "generator * 1 != generator");
101  assert_eq!(
102    G::generator() * G::Scalar::from(2),
103    G::generator() + G::generator(),
104    "generator * 2 != generator + generator"
105  );
106  assert_eq!(G::identity() * G::Scalar::from(2), G::identity(), "identity * 2 != identity");
107}
108
109/// Test `((order - 1) * G) + G == identity`.
110pub fn test_order<G: Group>() {
111  let minus_one = G::generator() * (G::Scalar::ZERO - G::Scalar::ONE);
112  assert!(minus_one != G::identity(), "(modulus - 1) * G was identity");
113  assert_eq!(minus_one + G::generator(), G::identity(), "((modulus - 1) * G) + G wasn't identity");
114}
115
116/// Test random.
117pub fn test_random<R: RngCore, G: Group>(rng: &mut R) {
118  let a = G::random(&mut *rng);
119  assert!(!bool::from(a.is_identity()), "random returned identity");
120
121  // Run up to 128 times so small groups, which may occasionally return the same element twice,
122  // are statistically unlikely to fail
123  // Groups of order <= 2 will always fail this test due to lack of distinct elements to sample
124  // from
125  let mut pass = false;
126  for _ in 0 .. 128 {
127    let b = G::random(&mut *rng);
128    assert!(!bool::from(b.is_identity()), "random returned identity");
129
130    // This test passes if a distinct element is returned at least once
131    if b != a {
132      pass = true;
133    }
134  }
135  assert!(pass, "random always returned the same value");
136}
137
138/// Run all tests on groups implementing Group.
139pub fn test_group<R: RngCore, G: Group>(rng: &mut R) {
140  test_prime_field::<R, G::Scalar>(rng);
141
142  test_eq::<G>();
143  test_identity::<G>();
144  test_generator::<G>();
145  test_double::<G>();
146  test_add::<G>();
147  test_sum::<G>();
148  test_neg::<G>();
149  test_sub::<G>();
150  test_mul::<G>();
151  test_order::<G>();
152  test_random::<R, G>(rng);
153}
154
155/// Test encoding and decoding of group elements.
156pub fn test_encoding<G: PrimeGroup>() {
157  let test = |point: G, msg| -> G {
158    let bytes = point.to_bytes();
159    let mut repr = G::Repr::default();
160    repr.as_mut().copy_from_slice(bytes.as_ref());
161    let decoded = G::from_bytes(&repr).unwrap();
162    assert_eq!(point, decoded, "{msg} couldn't be encoded and decoded");
163    assert_eq!(
164      point,
165      G::from_bytes_unchecked(&repr).unwrap(),
166      "{msg} couldn't be encoded and decoded",
167    );
168    decoded
169  };
170  assert!(bool::from(test(G::identity(), "identity").is_identity()));
171  test(G::generator(), "generator");
172  test(G::generator() + G::generator(), "(generator * 2)");
173}
174
175/// Run all tests on groups implementing PrimeGroup (Group + GroupEncoding).
176pub fn test_prime_group<R: RngCore, G: PrimeGroup>(rng: &mut R) {
177  test_group::<R, G>(rng);
178
179  test_encoding::<G>();
180}
181
182/// Run all tests offered by this crate on the group.
183pub fn test_prime_group_bits<R: RngCore, G: PrimeGroup<Scalar: PrimeFieldBits>>(rng: &mut R) {
184  test_prime_field_bits::<R, G::Scalar>(rng);
185  test_prime_group::<R, G>(rng);
186}
187
188// Run these tests against k256/p256
189// This ensures that these tests are well formed and won't error for valid implementations,
190// assuming the validity of k256/p256
191// While k256 and p256 may be malformed in a way which coincides with a faulty test, this is
192// considered unlikely
193// The other option, not running against any libraries, would leave faulty tests completely
194// undetected
195
196#[test]
197fn test_k256() {
198  test_prime_group_bits::<_, k256::ProjectivePoint>(&mut rand_core::OsRng);
199}
200
201#[test]
202fn test_p256() {
203  test_prime_group_bits::<_, p256::ProjectivePoint>(&mut rand_core::OsRng);
204}
205
206#[test]
207fn test_bls12_381() {
208  test_prime_group_bits::<_, bls12_381::G1Projective>(&mut rand_core::OsRng);
209  test_prime_group_bits::<_, bls12_381::G2Projective>(&mut rand_core::OsRng);
210}
211
212#[test]
213fn test_pallas_vesta() {
214  test_prime_group_bits::<_, pasta_curves::pallas::Point>(&mut rand_core::OsRng);
215  test_prime_group_bits::<_, pasta_curves::vesta::Point>(&mut rand_core::OsRng);
216}