Skip to main content

primefield/
dev.rs

1/// Write a series of `criterion`-based benchmarks for a field implementation.
2#[macro_export]
3macro_rules! bench_field {
4    ($name:ident, $desc:expr, $fe_a:expr, $fe_b:expr) => {
5        fn bench_add<M: ::criterion::measurement::Measurement>(
6            group: &mut ::criterion::BenchmarkGroup<'_, M>,
7        ) {
8            let x = core::hint::black_box($fe_a);
9            let y = core::hint::black_box($fe_b);
10            group.bench_function("add", |b| b.iter(|| x + y));
11        }
12
13        fn bench_sub<M: ::criterion::measurement::Measurement>(
14            group: &mut ::criterion::BenchmarkGroup<'_, M>,
15        ) {
16            let x = core::hint::black_box($fe_a);
17            let y = core::hint::black_box($fe_b);
18            group.bench_function("sub", |b| b.iter(|| x - y));
19        }
20
21        fn bench_mul<M: ::criterion::measurement::Measurement>(
22            group: &mut ::criterion::BenchmarkGroup<'_, M>,
23        ) {
24            let x = core::hint::black_box($fe_a);
25            let y = core::hint::black_box($fe_b);
26            group.bench_function("mul", |b| b.iter(|| x * y));
27        }
28
29        fn bench_neg<M: ::criterion::measurement::Measurement>(
30            group: &mut ::criterion::BenchmarkGroup<'_, M>,
31        ) {
32            let x = core::hint::black_box($fe_a);
33            group.bench_function("neg", |b| b.iter(|| -x));
34        }
35
36        fn bench_invert<M: ::criterion::measurement::Measurement>(
37            group: &mut ::criterion::BenchmarkGroup<'_, M>,
38        ) {
39            let x = core::hint::black_box($fe_a);
40            group.bench_function("invert", |b| b.iter(|| x.invert()));
41        }
42
43        fn bench_square<'a, M: ::criterion::measurement::Measurement>(
44            group: &mut ::criterion::BenchmarkGroup<'a, M>,
45        ) {
46            let x = core::hint::black_box($fe_a);
47            group.bench_function("square", |b| b.iter(|| x.square()));
48        }
49
50        fn bench_sqrt<'a, M: ::criterion::measurement::Measurement>(
51            group: &mut ::criterion::BenchmarkGroup<'a, M>,
52        ) {
53            use ::primefield::ff::Field;
54            let x = core::hint::black_box($fe_a);
55            group.bench_function("sqrt", |b| b.iter(|| x.sqrt()));
56        }
57
58        fn $name(c: &mut ::criterion::Criterion) {
59            let mut group = c.benchmark_group($desc);
60            bench_add(&mut group);
61            bench_sub(&mut group);
62            bench_mul(&mut group);
63            bench_neg(&mut group);
64            bench_invert(&mut group);
65            bench_square(&mut group);
66            bench_sqrt(&mut group);
67            group.finish();
68        }
69    };
70}
71
72/// Implement all tests for a type which impls the `PrimeField` trait.
73#[macro_export]
74macro_rules! test_primefield {
75    ($fe:tt, $uint:ident) => {
76        $crate::test_primefield_constants!($fe, $uint);
77        $crate::test_field_identity!($fe);
78        $crate::test_field_invert!($fe);
79        $crate::test_field_sqrt!($fe);
80    };
81}
82
83/// Implement tests for constants defined by the `PrimeField` trait.
84#[macro_export]
85macro_rules! test_primefield_constants {
86    ($fe:tt, $uint:ident) => {
87        #[allow(unused_imports)]
88        use $crate::{bigint::modular::Retrieve as _, ff::PrimeField as _};
89
90        // TODO(tarcieri): support for fields with little endian-encoded modulus
91        const MODULUS: $crate::bigint::Odd<$uint> = $crate::bigint::Odd::from_be_hex($fe::MODULUS);
92        const T: $uint = $crate::compute_t(MODULUS.as_ref());
93
94        #[test]
95        fn delta_constant() {
96            // DELTA^{t} mod m == 1
97            assert_eq!($fe::DELTA.pow_vartime(&T), $fe::ONE);
98        }
99
100        // TODO(tarcieri): check generator has order `modulus - 1`
101        #[test]
102        fn multiplicative_generator_constant() {
103            // Sanity-check that the generator is a quadratic non-residue
104            assert_eq!(
105                $fe::MULTIPLICATIVE_GENERATOR
106                    .retrieve()
107                    .jacobi_symbol(&MODULUS),
108                $crate::bigint::JacobiSymbol::MinusOne
109            );
110        }
111
112        #[test]
113        fn root_of_unity_constant() {
114            // ROOT_OF_UNITY^{2^s} mod m == 1
115            assert_eq!($fe::ROOT_OF_UNITY.sqn_vartime($fe::S as usize), $fe::ONE);
116
117            // MULTIPLICATIVE_GENERATOR^{t} mod m == ROOT_OF_UNITY
118            assert_eq!(
119                $fe::MULTIPLICATIVE_GENERATOR.pow_vartime(&T),
120                $fe::ROOT_OF_UNITY
121            )
122        }
123
124        #[test]
125        fn root_of_unity_inv_constant() {
126            assert_eq!($fe::ROOT_OF_UNITY * $fe::ROOT_OF_UNITY_INV, $fe::ONE);
127        }
128
129        #[test]
130        fn two_inv_constant() {
131            assert_eq!($fe::from(2u32) * $fe::TWO_INV, $fe::ONE);
132        }
133    };
134}
135
136/// Implement field element identity tests.
137#[macro_export]
138macro_rules! test_field_identity {
139    ($fe:tt) => {
140        #[test]
141        fn zero_is_additive_identity() {
142            let zero = $fe::ZERO;
143            let one = $fe::ONE;
144            assert_eq!(zero.add(&zero), zero);
145            assert_eq!(one.add(&zero), one);
146        }
147
148        #[test]
149        fn one_is_multiplicative_identity() {
150            let one = $fe::ONE;
151            assert_eq!(one.multiply(&one), one);
152        }
153    };
154}
155
156/// Implement field element inversion tests.
157#[macro_export]
158macro_rules! test_field_invert {
159    ($fe:tt) => {
160        #[test]
161        fn invert() {
162            let one = $fe::ONE;
163            assert_eq!(one.invert().unwrap(), one);
164
165            let three = one + &one + &one;
166            let inv_three = three.invert().unwrap();
167            assert_eq!(three * &inv_three, one);
168
169            let minus_three = -three;
170            let inv_minus_three = minus_three.invert().unwrap();
171            assert_eq!(inv_minus_three, -inv_three);
172            assert_eq!(three * &inv_minus_three, -one);
173        }
174    };
175}
176
177/// Implement field element square root tests.
178#[macro_export]
179macro_rules! test_field_sqrt {
180    ($fe:tt) => {
181        #[test]
182        fn sqrt() {
183            for &n in &[1u64, 4, 9, 16, 25, 36, 49, 64] {
184                let fe = $fe::from(n);
185                let sqrt = $crate::ff::Field::sqrt(&fe).unwrap();
186                assert_eq!(sqrt.square(), fe);
187            }
188        }
189    };
190}