use noether::{
AssociativeAddition, AssociativeMultiplication, CommutativeAddition, CommutativeMultiplication,
Distributive, FiniteField,
};
use num_traits::{Euclid, Inv, One, Zero};
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq)]
pub struct FieldElement<const L: usize>([u64; L]);
impl<const L: usize> Zero for FieldElement<L> {
fn zero() -> Self {
Self([0; L])
}
fn is_zero(&self) -> bool {
self.0[0] == 0
}
}
impl<const L: usize> One for FieldElement<L> {
fn one() -> Self {
let mut arr = [0; L];
arr[0] = 1;
Self(arr)
}
}
impl<const L: usize> Add for FieldElement<L> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let mut result = [0; L];
let mut carry = 0u64;
for (i, (&self_val, &rhs_val)) in self.0.iter().zip(rhs.0.iter()).enumerate() {
let sum = self_val as u128 + rhs_val as u128 + carry as u128;
result[i] = sum as u64;
carry = (sum >> 64) as u64;
}
Self(result)
}
}
impl<const L: usize> Mul for FieldElement<L> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
let mut result = [0u64; L];
for (i, &self_val) in self.0.iter().enumerate() {
let mut carry = 0u128;
for (j, &rhs_val) in rhs.0.iter().enumerate() {
if i + j >= L {
break;
}
let prod = (self_val as u128) * (rhs_val as u128) + (result[i + j] as u128) + carry;
result[i + j] = prod as u64;
carry = prod >> 64;
}
}
Self(result)
}
}
#[derive(Clone, Copy, Debug)]
pub struct FinitePrimeField<const L: usize, const D: usize> {
modulus: [u64; L],
_value: [u64; L],
}
impl<const L: usize, const D: usize> FinitePrimeField<L, D> {
const _ZERO: [u64; L] = Self::zero_array();
pub const fn new(modulus: [u64; L], value: [u64; L]) -> Self {
if D != 2 * L {
panic!("Double size D must be twice the size of the field L");
}
Self {
modulus,
_value: value,
}
}
const fn zero_array() -> [u64; L] {
[0; L]
}
}
impl<const L: usize, const D: usize> Add for FinitePrimeField<L, D> {
type Output = Self;
fn add(self, _other: Self) -> Self {
Self::new(self.modulus, Self::zero_array())
}
}
impl<const L: usize, const D: usize> AddAssign for FinitePrimeField<L, D> {
fn add_assign(&mut self, _rhs: Self) {
todo!()
}
}
impl<const L: usize, const D: usize> Zero for FinitePrimeField<L, D> {
fn zero() -> Self {
todo!()
}
fn is_zero(&self) -> bool {
todo!()
}
}
impl<const L: usize, const D: usize> Neg for FinitePrimeField<L, D> {
type Output = Self;
fn neg(self) -> Self {
Self::new(self.modulus, Self::zero_array())
}
}
impl<const L: usize, const D: usize> Sub for FinitePrimeField<L, D> {
type Output = Self;
fn sub(self, _other: Self) -> Self {
Self::new(self.modulus, Self::zero_array())
}
}
impl<const L: usize, const D: usize> SubAssign for FinitePrimeField<L, D> {
fn sub_assign(&mut self, _rhs: Self) {
todo!()
}
}
impl<const L: usize, const D: usize> PartialEq for FinitePrimeField<L, D> {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl<const L: usize, const D: usize> Mul for FinitePrimeField<L, D> {
type Output = Self;
fn mul(self, _other: Self) -> Self {
Self::new(self.modulus, Self::zero_array())
}
}
impl<const L: usize, const D: usize> One for FinitePrimeField<L, D> {
fn one() -> Self {
todo!()
}
}
impl<const L: usize, const D: usize> MulAssign for FinitePrimeField<L, D> {
fn mul_assign(&mut self, _rhs: Self) {
todo!()
}
}
impl<const L: usize, const D: usize> Inv for FinitePrimeField<L, D> {
type Output = Self;
fn inv(self) -> Self {
Self::new(self.modulus, Self::zero_array())
}
}
impl<const L: usize, const D: usize> Euclid for FinitePrimeField<L, D> {
fn div_euclid(&self, _v: &Self) -> Self {
todo!()
}
fn rem_euclid(&self, _v: &Self) -> Self {
todo!()
}
}
impl<const L: usize, const D: usize> Rem for FinitePrimeField<L, D> {
type Output = Self;
fn rem(self, _rhs: Self) -> Self::Output {
todo!()
}
}
impl<const L: usize, const D: usize> Div for FinitePrimeField<L, D> {
type Output = Self;
fn div(self, _other: Self) -> Self {
Self::new(self.modulus, Self::zero_array())
}
}
impl<const L: usize, const D: usize> DivAssign<Self> for FinitePrimeField<L, D> {
fn div_assign(&mut self, _rhs: Self) {
todo!()
}
}
impl<const L: usize, const D: usize> CommutativeAddition for FinitePrimeField<L, D> {}
impl<const L: usize, const D: usize> CommutativeMultiplication for FinitePrimeField<L, D> {}
impl<const L: usize, const D: usize> AssociativeAddition for FinitePrimeField<L, D> {}
impl<const L: usize, const D: usize> AssociativeMultiplication for FinitePrimeField<L, D> {}
impl<const L: usize, const D: usize> Distributive for FinitePrimeField<L, D> {}
impl<const L: usize, const D: usize> FiniteField for FinitePrimeField<L, D> {
type ScalarType = FieldElement<L>;
fn characteristic() -> u64 {
2 }
fn order() -> u64 {
4 }
}
fn main() {
let a = FinitePrimeField::<4, 8>::new(
[
0x3C208C16D87CFD47,
0x97816A916871CA8D,
0xB85045B68181585D,
0x30644E72E131A029,
],
[1, 2, 3, 4],
);
let b = FinitePrimeField::<4, 8>::new(
[
0x3C208C16D87CFD47,
0x97816A916871CA8D,
0xB85045B68181585D,
0x30644E72E131A029,
],
[5, 6, 7, 8],
);
let c = a + b;
println!("{:?}", c);
let d = a - b;
println!("{:?}", d);
let e = a * b;
println!("{:?}", e);
let f = a / b;
println!("{:?}", f);
let g = a.inv();
println!("{:?}", g);
let h = -a;
println!("{:?}", h);
let i = a == b;
println!("{:?}", i);
let j = a != b;
println!("{:?}", j);
let k = a + b;
println!("{:?}", k);
let l = a - b;
println!("{:?}", l);
let m = a * b;
println!("{:?}", m);
let n = a / b;
println!("{:?}", n);
let o = a.inv();
println!("{:?}", o);
let p = -a;
println!("{:?}", p);
let q = a == b;
println!("{:?}", q);
let r = a != b;
println!("{:?}", r);
let s = a + b;
println!("{:?}", s);
let t = a - b;
println!("{:?}", t);
let u = a * b;
println!("{:?}", u);
let v = a / b;
println!("{:?}", v);
let w = a.inv();
println!("{:?}", w);
let x = -a;
println!("{:?}", x);
}