Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions field/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ seq-macro = "0.3"
proc-macro2 = {version = "1", optional = true }
quote = {version = "1", optional = true }

[dev-dependencies]
proptest = "1"

[features]
use_division = []
proc_macro_ops = ["proc-macro2", "quote"]
Expand Down
188 changes: 178 additions & 10 deletions field/src/baby_bear/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ impl Field for BabyBearField {
const TWO: Self = Self::new(2);
const MINUS_ONE: Self = Self::new(Self::ORDER - 1);

type CharField = Self;

#[cfg_attr(not(feature = "no_inline"), inline(always))]
fn is_zero(&self) -> bool {
self.is_zero_impl()
Expand Down Expand Up @@ -522,25 +524,191 @@ impl crate::TwoAdicField for BabyBearField {
#[cfg(test)]
mod test {
use super::*;
use crate::field::Field;
use proptest::prelude::*;

#[test]
fn calculator() {
let one = BabyBearField::ONE;
// one = 268435454
dbg!(one);
dbg!(one.0);

dbg!(BabyBearField::TWO_ADICITY_GENERATORS);
dbg!(BabyBearField::TWO_ADICITY_GENERATORS_INVERSED);
fn arb_babybear() -> impl Strategy<Value = u32> {
0..BabyBearField::ORDER
}

#[test]
fn test_inversion_chain() {
let el = BabyBearField::new(42);
let pow = BabyBearField::CHARACTERISTICS - 2;
dbg!(pow);
let naive_inverse = el.pow(pow);
let faster_inverse = el.inverse_impl().unwrap();
assert_eq!(naive_inverse, faster_inverse);
}

// --- Field axiom tests ---

proptest! {
#[test]
fn add_commutative(a in arb_babybear(), b in arb_babybear()) {
let fa = BabyBearField::new(a);
let fb = BabyBearField::new(b);
let mut ab = fa; ab.add_assign(&fb);
let mut ba = fb; ba.add_assign(&fa);
prop_assert_eq!(ab, ba);
}

#[test]
fn add_associative(a in arb_babybear(), b in arb_babybear(), c in arb_babybear()) {
let fa = BabyBearField::new(a);
let fb = BabyBearField::new(b);
let fc = BabyBearField::new(c);
let mut ab = fa; ab.add_assign(&fb);
let mut abc_left = ab; abc_left.add_assign(&fc);
let mut bc = fb; bc.add_assign(&fc);
let mut abc_right = fa; abc_right.add_assign(&bc);
prop_assert_eq!(abc_left, abc_right);
}

#[test]
fn add_identity(a in arb_babybear()) {
let fa = BabyBearField::new(a);
let mut r = fa;
r.add_assign(&BabyBearField::ZERO);
prop_assert_eq!(r, fa);
}

#[test]
fn add_inverse(a in arb_babybear()) {
let fa = BabyBearField::new(a);
let mut neg = fa; neg.negate();
let mut sum = fa; sum.add_assign(&neg);
prop_assert_eq!(sum, BabyBearField::ZERO);
}

#[test]
fn mul_commutative(a in arb_babybear(), b in arb_babybear()) {
let fa = BabyBearField::new(a);
let fb = BabyBearField::new(b);
let mut ab = fa; ab.mul_assign(&fb);
let mut ba = fb; ba.mul_assign(&fa);
prop_assert_eq!(ab, ba);
}

#[test]
fn mul_associative(a in arb_babybear(), b in arb_babybear(), c in arb_babybear()) {
let fa = BabyBearField::new(a);
let fb = BabyBearField::new(b);
let fc = BabyBearField::new(c);
let mut ab = fa; ab.mul_assign(&fb);
let mut abc_left = ab; abc_left.mul_assign(&fc);
let mut bc = fb; bc.mul_assign(&fc);
let mut abc_right = fa; abc_right.mul_assign(&bc);
prop_assert_eq!(abc_left, abc_right);
}

#[test]
fn mul_identity(a in arb_babybear()) {
let fa = BabyBearField::new(a);
let mut r = fa;
r.mul_assign(&BabyBearField::ONE);
prop_assert_eq!(r, fa);
}

#[test]
fn mul_inverse(a in 1..BabyBearField::ORDER) {
let fa = BabyBearField::new(a);
let inv = fa.inverse().unwrap();
let mut product = fa;
product.mul_assign(&inv);
prop_assert_eq!(product, BabyBearField::ONE);
}

#[test]
fn distributive(a in arb_babybear(), b in arb_babybear(), c in arb_babybear()) {
let fa = BabyBearField::new(a);
let fb = BabyBearField::new(b);
let fc = BabyBearField::new(c);
let mut bc = fb; bc.add_assign(&fc);
let mut left = fa; left.mul_assign(&bc);
let mut ab = fa; ab.mul_assign(&fb);
let mut ac = fa; ac.mul_assign(&fc);
let mut right = ab; right.add_assign(&ac);
prop_assert_eq!(left, right);
}

#[test]
fn sub_is_add_neg(a in arb_babybear(), b in arb_babybear()) {
let fa = BabyBearField::new(a);
let fb = BabyBearField::new(b);
let mut via_sub = fa; via_sub.sub_assign(&fb);
let mut neg_b = fb; neg_b.negate();
let mut via_add = fa; via_add.add_assign(&neg_b);
prop_assert_eq!(via_sub, via_add);
}

#[test]
fn double_is_add_self(a in arb_babybear()) {
let fa = BabyBearField::new(a);
let mut doubled = fa; doubled.double();
let mut added = fa; added.add_assign(&fa);
prop_assert_eq!(doubled, added);
}

#[test]
fn square_is_mul_self(a in arb_babybear()) {
let fa = BabyBearField::new(a);
let mut squared = fa; squared.square();
let mut mulled = fa; mulled.mul_assign(&fa);
prop_assert_eq!(squared, mulled);
}
}

// --- Const value and generator tests ---

#[test]
fn two_adicity_generators_are_valid() {
for k in 1..=27 {
let g = BabyBearField::TWO_ADICITY_GENERATORS[k];
let mut powered = g;
for _ in 0..k {
powered.square();
}
assert_eq!(powered, BabyBearField::ONE, "generator[{k}]^(2^{k}) != 1");

let mut half_powered = g;
for _ in 0..k - 1 {
half_powered.square();
}
assert_ne!(
half_powered,
BabyBearField::ONE,
"generator[{k}] has order < 2^{k}"
);
}
}

#[test]
fn two_adicity_generators_inversed_are_correct() {
for k in 0..=27 {
let g = BabyBearField::TWO_ADICITY_GENERATORS[k];
let g_inv = BabyBearField::TWO_ADICITY_GENERATORS_INVERSED[k];
let mut product = g;
product.mul_assign(&g_inv);
assert_eq!(
product,
BabyBearField::ONE,
"generator[{k}] * inverse[{k}] != 1"
);
}
}

#[test]
fn const_values_are_correct() {
assert_eq!(BabyBearField::NON_RES.to_u32(), 11);

let mut two_halves = BabyBearField::HALF;
two_halves.double();
assert_eq!(two_halves, BabyBearField::ONE);

assert_eq!(BabyBearField::TWO.to_u32(), 2);

let mut should_be_zero = BabyBearField::MINUS_ONE;
should_be_zero.add_assign(&BabyBearField::ONE);
assert_eq!(should_be_zero, BabyBearField::ZERO);
}
}
119 changes: 119 additions & 0 deletions field/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ impl Field for Mersenne31Field {
const MINUS_ONE: Self = Self(Self::ORDER - 1);
const TWO: Self = Self(2);

type CharField = Self;

#[cfg_attr(not(feature = "no_inline"), inline(always))]
fn is_zero(&self) -> bool {
self.is_zero_impl()
Expand Down Expand Up @@ -514,3 +516,120 @@ impl BaseField<2> for Mersenne31Field {
Self::mul_by_non_residue_impl(elem);
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::field::Field;
use proptest::prelude::*;

fn arb_mersenne31() -> impl Strategy<Value = u32> {
0..Mersenne31Field::ORDER
}

proptest! {
#[test]
fn add_commutative(a in arb_mersenne31(), b in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let fb = Mersenne31Field::new(b);
let mut ab = fa; ab.add_assign(&fb);
let mut ba = fb; ba.add_assign(&fa);
prop_assert_eq!(ab, ba);
}

#[test]
fn add_associative(a in arb_mersenne31(), b in arb_mersenne31(), c in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let fb = Mersenne31Field::new(b);
let fc = Mersenne31Field::new(c);
let mut ab = fa; ab.add_assign(&fb);
let mut abc_left = ab; abc_left.add_assign(&fc);
let mut bc = fb; bc.add_assign(&fc);
let mut abc_right = fa; abc_right.add_assign(&bc);
prop_assert_eq!(abc_left, abc_right);
}

#[test]
fn add_identity(a in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let mut r = fa;
r.add_assign(&Mersenne31Field::ZERO);
prop_assert_eq!(r, fa);
}

#[test]
fn add_inverse(a in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let mut neg = fa; neg.negate();
let mut sum = fa; sum.add_assign(&neg);
prop_assert_eq!(sum, Mersenne31Field::ZERO);
}

#[test]
fn mul_commutative(a in arb_mersenne31(), b in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let fb = Mersenne31Field::new(b);
let mut ab = fa; ab.mul_assign(&fb);
let mut ba = fb; ba.mul_assign(&fa);
prop_assert_eq!(ab, ba);
}

#[test]
fn mul_associative(a in arb_mersenne31(), b in arb_mersenne31(), c in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let fb = Mersenne31Field::new(b);
let fc = Mersenne31Field::new(c);
let mut ab = fa; ab.mul_assign(&fb);
let mut abc_left = ab; abc_left.mul_assign(&fc);
let mut bc = fb; bc.mul_assign(&fc);
let mut abc_right = fa; abc_right.mul_assign(&bc);
prop_assert_eq!(abc_left, abc_right);
}

#[test]
fn mul_identity(a in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let mut r = fa;
r.mul_assign(&Mersenne31Field::ONE);
prop_assert_eq!(r, fa);
}

#[test]
fn mul_inverse(a in 1..Mersenne31Field::ORDER) {
let fa = Mersenne31Field::new(a);
let inv = fa.inverse().unwrap();
let mut product = fa;
product.mul_assign(&inv);
prop_assert_eq!(product, Mersenne31Field::ONE);
}

#[test]
fn distributive(a in arb_mersenne31(), b in arb_mersenne31(), c in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let fb = Mersenne31Field::new(b);
let fc = Mersenne31Field::new(c);
let mut bc = fb; bc.add_assign(&fc);
let mut left = fa; left.mul_assign(&bc);
let mut ab = fa; ab.mul_assign(&fb);
let mut ac = fa; ac.mul_assign(&fc);
let mut right = ab; right.add_assign(&ac);
prop_assert_eq!(left, right);
}

#[test]
fn double_is_add_self(a in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let mut doubled = fa; doubled.double();
let mut added = fa; added.add_assign(&fa);
prop_assert_eq!(doubled, added);
}

#[test]
fn square_is_mul_self(a in arb_mersenne31()) {
let fa = Mersenne31Field::new(a);
let mut squared = fa; squared.square();
let mut mulled = fa; mulled.mul_assign(&fa);
prop_assert_eq!(squared, mulled);
}
}
}
Loading
Loading