Skip to content

Commit

Permalink
more tests and generator
Browse files Browse the repository at this point in the history
  • Loading branch information
0xJepsen committed May 2, 2024
1 parent 65aebfb commit 1ce2f51
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 30 deletions.
128 changes: 98 additions & 30 deletions src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,22 @@ impl Field for PlutoField {
}

fn try_inverse(&self) -> Option<Self> {
// TODO: Fix inverse
Some(Self::new(1))
if self.is_zero() {
return None;
}
let exponent = PLUTO_FIELD_PRIME - 2; // p - 2
let mut result = 1;
let mut base = self.value;
let mut power = exponent;

while power > 0 {
if power & 1 == 1 {
result = result * base % PLUTO_FIELD_PRIME;
}
base = base * base % PLUTO_FIELD_PRIME;
power >>= 1;
}
Some(Self { value: result })
}

#[inline]
Expand Down Expand Up @@ -100,9 +114,8 @@ impl AbstractField for PlutoField {
#[inline]
fn from_wrapped_u64(n: u64) -> Self { Self { value: (n % PLUTO_FIELD_PRIME as u64) as u32 } }

// Sage: GF(2^64 - 2^32 + 1).multiplicative_generator()
// TODO: Find a generator for this field
fn generator() -> Self { Self::new(7) }
// generator for multiplicative subgroup of the field
fn generator() -> Self { Self::new(2) }
}

impl Mul for PlutoField {
Expand All @@ -111,19 +124,6 @@ impl Mul for PlutoField {
fn mul(self, rhs: Self) -> Self { Self { value: (self.value * rhs.value) % 101 } }
}

// /// Montgomery reduction of a value in `0..P << MONTY_BITS`.
// #[inline]
// #[must_use]
// pub(crate) const fn monty_reduce(x: u32) -> u32 {
// let t = x.wrapping_mul(MONTY_MU) & (MONTY_MASK);
// let u = (t * (PLUTO_FIELD_PRIME)) & (MONTY_MASK );

// let (x_sub_u, over) = x.overflowing_sub(u);
// let x_sub_u_hi = (x_sub_u >> MONTY_BITS) as u32;
// let corr = if over { PLUTO_FIELD_PRIME } else { 0 };
// x_sub_u_hi.wrapping_add(corr)
// }

impl Product for PlutoField {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(|x, y| x * y).unwrap_or(Self::one())
Expand Down Expand Up @@ -178,18 +178,6 @@ impl Sub for PlutoField {
}
}

// #[inline]
// #[must_use]
// const fn to_monty(x: u32) -> u32 {
// (((x as u64) << MONTY_BITS) % PLUTO_FIELD_PRIME as u64) as u32
// }

// #[inline]
// #[must_use]
// const fn to_monty_64(x: u64) -> u32 {
// (((x as u128) << MONTY_BITS) % PLUTO_FIELD_PRIME as u128) as u32
// }

mod tests {
use super::*;

Expand Down Expand Up @@ -235,4 +223,84 @@ mod tests {
let f = F::exp_u64_generic(f, 3);
assert_eq!(f, F::from_canonical_u32(8));
}

#[test]
fn addition_subtraction() {
let a = PlutoField::new(50);
let b = PlutoField::new(60);
let c = a + b;
assert_eq!(c.value, 9); // (50 + 60) % 101 = 9

let d = c - a;
assert_eq!(d.value, 60); // (9 - 50) % 101 = 60
}

#[test]
fn multiplicative_inverse() {
let a = PlutoField::new(10);
let a_inv = a.inverse();
let should_be_one = a * a_inv;
assert_eq!(should_be_one.value, 1);
}

#[test]
fn identity_elements() {
let a = PlutoField::new(10);
let zero = PlutoField::new(0);
let one = PlutoField::new(1);
assert_eq!((a + zero).value, a.value);
assert_eq!((a * one).value, a.value);
}

#[test]
fn zero_multiplication() {
let a = PlutoField::new(10);
let zero = PlutoField::new(0);
assert_eq!((a * zero).value, 0);
}

#[test]
fn negation() {
let a = PlutoField::new(10);
let neg_a = -a;
assert_eq!((a + neg_a).value, 0);
}

#[test]
fn inverse_of_inverse() {
let a = PlutoField::new(10);
let a_inv = a.inverse();
let a_inv_inv = a_inv.inverse();
assert_eq!(a_inv_inv.value, a.value);
}

#[test]
fn distributivity() {
let a = PlutoField::new(5);
let b = PlutoField::new(6);
let c = PlutoField::new(7);
assert_eq!((a * (b + c)).value, (a * b + a * c).value);
}

#[test]
fn associativity() {
let a = PlutoField::new(5);
let b = PlutoField::new(6);
let c = PlutoField::new(7);
assert_eq!(((a + b) + c).value, (a + (b + c)).value);
assert_eq!(((a * b) * c).value, (a * (b * c)).value);
}

#[test]
fn non_zero_element() {
let a = PlutoField::new(10);
assert!(!a.is_zero());
}

#[test]
fn power_of_zero() {
let a = PlutoField::new(0);
let b = PlutoField::exp_u64_generic(a, 3);
assert_eq!(b.value, 0);
}
}
53 changes: 53 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,57 @@ use ronkathon::field::PlutoField;
fn main() {
let f = PlutoField::new(1);
println!("hello field={:?}", f);

let g = generator(101);
println!("generator={:?}", g);
}

// algorithm to compute primitive element of field (multiplicative generator)
fn generator(p: u32) -> i32 {
let mut fact = Vec::new();
let phi = p - 1;
let mut n = phi;
let mut i = 2;
while i * i <= n {
if n % i == 0 {
fact.push(i);
while n % i == 0 {
n /= i;
}
}
i += 1;
}
if n > 1 {
fact.push(n);
}

for res in 2..=p {
let mut ok = true;
for &f in &fact {
ok &= powmod(res, phi / f, p) != 1;
if !ok {
break;
}
}
if ok {
return res as i32;
}
}
-1
}

fn powmod(base: u32, exponent: u32, modulus: u32) -> u32 {
let mut base = base as u64;
let mut exponent = exponent;
let modulus = modulus as u64;
let mut result = 1;
base %= modulus;
while exponent > 0 {
if exponent % 2 == 1 {
result = (result * base) % modulus;
}
base = (base * base) % modulus;
exponent >>= 1;
}
result as u32
}

0 comments on commit 1ce2f51

Please sign in to comment.