2021-07-22 13:08:14 -07:00
|
|
|
#[macro_export]
|
|
|
|
|
macro_rules! test_field_arithmetic {
|
|
|
|
|
($field:ty) => {
|
|
|
|
|
mod field_arithmetic {
|
2021-09-07 14:17:15 -07:00
|
|
|
use num::bigint::BigUint;
|
2021-07-29 11:45:58 -07:00
|
|
|
use rand::Rng;
|
2021-07-22 13:08:14 -07:00
|
|
|
|
2021-07-29 22:00:29 -07:00
|
|
|
use crate::field::field_types::Field;
|
2021-07-22 13:08:14 -07:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn batch_inversion() {
|
|
|
|
|
let xs = (1..=3)
|
|
|
|
|
.map(|i| <$field>::from_canonical_u64(i))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
let invs = <$field>::batch_multiplicative_inverse(&xs);
|
|
|
|
|
for (x, inv) in xs.into_iter().zip(invs) {
|
|
|
|
|
assert_eq!(x * inv, <$field>::ONE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn primitive_root_order() {
|
|
|
|
|
for n_power in 0..8 {
|
|
|
|
|
let root = <$field>::primitive_root_of_unity(n_power);
|
|
|
|
|
let order = <$field>::generator_order(root);
|
|
|
|
|
assert_eq!(order, 1 << n_power, "2^{}'th primitive root", n_power);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn negation() {
|
2021-09-07 14:17:15 -07:00
|
|
|
type F = $field;
|
2021-07-22 13:08:14 -07:00
|
|
|
|
2021-09-07 14:17:15 -07:00
|
|
|
for x in [F::ZERO, F::ONE, F::TWO, F::NEG_ONE] {
|
|
|
|
|
assert_eq!(x + -x, F::ZERO);
|
2021-07-22 13:08:14 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn exponentiation() {
|
|
|
|
|
type F = $field;
|
|
|
|
|
|
2021-09-05 10:27:11 -07:00
|
|
|
assert_eq!(F::ZERO.exp_u64(0), <F>::ONE);
|
|
|
|
|
assert_eq!(F::ONE.exp_u64(0), <F>::ONE);
|
|
|
|
|
assert_eq!(F::TWO.exp_u64(0), <F>::ONE);
|
2021-07-22 13:08:14 -07:00
|
|
|
|
2021-09-05 10:27:11 -07:00
|
|
|
assert_eq!(F::ZERO.exp_u64(1), <F>::ZERO);
|
|
|
|
|
assert_eq!(F::ONE.exp_u64(1), <F>::ONE);
|
|
|
|
|
assert_eq!(F::TWO.exp_u64(1), <F>::TWO);
|
2021-07-22 13:08:14 -07:00
|
|
|
|
2021-09-05 10:27:11 -07:00
|
|
|
assert_eq!(F::ZERO.kth_root_u64(1), <F>::ZERO);
|
|
|
|
|
assert_eq!(F::ONE.kth_root_u64(1), <F>::ONE);
|
|
|
|
|
assert_eq!(F::TWO.kth_root_u64(1), <F>::TWO);
|
2021-07-22 13:08:14 -07:00
|
|
|
|
|
|
|
|
for power in 1..10 {
|
2021-09-05 10:27:11 -07:00
|
|
|
if F::is_monomial_permutation_u64(power) {
|
2021-07-22 13:08:14 -07:00
|
|
|
let x = F::rand();
|
2021-09-05 10:27:11 -07:00
|
|
|
assert_eq!(x.exp_u64(power).kth_root_u64(power), x);
|
2021-07-22 13:08:14 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn exponentiation_large() {
|
|
|
|
|
type F = $field;
|
|
|
|
|
|
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
|
|
|
|
|
|
let base = F::rand();
|
|
|
|
|
let pow = BigUint::from(rng.gen::<u64>());
|
|
|
|
|
let cycles = rng.gen::<u32>();
|
|
|
|
|
let mul_group_order = F::order() - 1u32;
|
|
|
|
|
let big_pow = &pow + &mul_group_order * cycles;
|
|
|
|
|
let big_pow_wrong = &pow + &mul_group_order * cycles + 1u32;
|
|
|
|
|
|
2021-07-22 13:16:12 -07:00
|
|
|
assert_eq!(base.exp_biguint(&pow), base.exp_biguint(&big_pow));
|
|
|
|
|
assert_ne!(base.exp_biguint(&pow), base.exp_biguint(&big_pow_wrong));
|
2021-07-22 13:08:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn inverse_2exp() {
|
|
|
|
|
// Just check consistency with try_inverse()
|
|
|
|
|
type F = $field;
|
|
|
|
|
|
|
|
|
|
let v = <F as Field>::PrimeField::TWO_ADICITY;
|
|
|
|
|
|
|
|
|
|
for e in [0, 1, 2, 3, 4, v - 2, v - 1, v, v + 1, v + 2, 123 * v] {
|
2021-09-05 10:27:11 -07:00
|
|
|
let x = F::TWO.exp_u64(e as u64).inverse();
|
2021-07-22 13:08:14 -07:00
|
|
|
let y = F::inverse_2exp(e);
|
|
|
|
|
assert_eq!(x, y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|