use crate::cyclic_group::IsGroup;
use crate::errors::ByteConversionError::{FromBEBytesError, FromLEBytesError};
use crate::errors::CreationError;
use crate::errors::DeserializationError;
use crate::field::element::FieldElement;
use crate::field::errors::FieldError;
use crate::field::traits::{IsFFTField, IsField, IsPrimeField};
use crate::traits::{ByteConversion, Deserializable};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct U64PrimeField<const MODULUS: u64>;
pub type U64FieldElement<const MODULUS: u64> = FieldElement<U64PrimeField<MODULUS>>;
pub type F17 = U64PrimeField<17>;
pub type FE17 = U64FieldElement<17>;
impl IsFFTField for F17 {
const TWO_ADICITY: u64 = 4;
const TWO_ADIC_PRIMITVE_ROOT_OF_UNITY: u64 = 3;
}
impl<const MODULUS: u64> IsField for U64PrimeField<MODULUS> {
type BaseType = u64;
fn add(a: &u64, b: &u64) -> u64 {
((*a as u128 + *b as u128) % MODULUS as u128) as u64
}
fn sub(a: &u64, b: &u64) -> u64 {
(((*a as u128 + MODULUS as u128) - *b as u128) % MODULUS as u128) as u64
}
fn neg(a: &u64) -> u64 {
MODULUS - a
}
fn mul(a: &u64, b: &u64) -> u64 {
((*a as u128 * *b as u128) % MODULUS as u128) as u64
}
fn div(a: &u64, b: &u64) -> u64 {
Self::mul(a, &Self::inv(b).unwrap())
}
fn inv(a: &u64) -> Result<u64, FieldError> {
if *a == 0 {
return Err(FieldError::InvZeroError);
}
Ok(Self::pow(a, MODULUS - 2))
}
fn eq(a: &u64, b: &u64) -> bool {
Self::from_u64(*a) == Self::from_u64(*b)
}
fn zero() -> u64 {
0
}
fn one() -> u64 {
1
}
fn from_u64(x: u64) -> u64 {
x % MODULUS
}
fn from_base_type(x: u64) -> u64 {
Self::from_u64(x)
}
}
impl<const MODULUS: u64> Copy for U64FieldElement<MODULUS> {}
impl<const MODULUS: u64> IsPrimeField for U64PrimeField<MODULUS> {
type RepresentativeType = u64;
fn representative(x: &u64) -> u64 {
*x
}
fn field_bit_size() -> usize {
((MODULUS - 1).ilog2() + 1) as usize
}
fn from_hex(hex_string: &str) -> Result<Self::BaseType, CreationError> {
let mut hex_string = hex_string;
let mut char_iterator = hex_string.chars();
if hex_string.len() > 2
&& char_iterator.next().unwrap() == '0'
&& char_iterator.next().unwrap() == 'x'
{
hex_string = &hex_string[2..];
}
u64::from_str_radix(hex_string, 16).map_err(|_| CreationError::InvalidHexString)
}
#[cfg(feature = "std")]
fn to_hex(x: &u64) -> String {
format!("{:X}", x)
}
}
impl<const MODULUS: u64> IsGroup for U64FieldElement<MODULUS> {
fn neutral_element() -> U64FieldElement<MODULUS> {
U64FieldElement::zero()
}
fn operate_with(&self, other: &Self) -> Self {
*self + *other
}
fn neg(&self) -> Self {
-self
}
}
impl<const MODULUS: u64> ByteConversion for U64FieldElement<MODULUS> {
#[cfg(feature = "alloc")]
fn to_bytes_be(&self) -> alloc::vec::Vec<u8> {
u64::to_be_bytes(*self.value()).into()
}
#[cfg(feature = "alloc")]
fn to_bytes_le(&self) -> alloc::vec::Vec<u8> {
u64::to_le_bytes(*self.value()).into()
}
fn from_bytes_be(bytes: &[u8]) -> Result<Self, crate::errors::ByteConversionError> {
let bytes: [u8; 8] = bytes[0..8].try_into().map_err(|_| FromBEBytesError)?;
Ok(Self::from(u64::from_be_bytes(bytes)))
}
fn from_bytes_le(bytes: &[u8]) -> Result<Self, crate::errors::ByteConversionError> {
let bytes: [u8; 8] = bytes[0..8].try_into().map_err(|_| FromLEBytesError)?;
Ok(Self::from(u64::from_le_bytes(bytes)))
}
}
impl<const MODULUS: u64> Deserializable for FieldElement<U64PrimeField<MODULUS>> {
fn deserialize(bytes: &[u8]) -> Result<Self, DeserializationError>
where
Self: Sized,
{
Self::from_bytes_be(bytes).map_err(|x| x.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
const MODULUS: u64 = 13;
type F = U64PrimeField<MODULUS>;
type FE = FieldElement<F>;
#[test]
fn from_hex_for_b_is_11() {
assert_eq!(F::from_hex("B").unwrap(), 11);
}
#[test]
fn from_hex_for_0x1_a_is_26() {
assert_eq!(F::from_hex("0x1a").unwrap(), 26);
}
#[cfg(feature = "std")]
#[test]
fn to_hex_test_works_1() {
let num = F::from_hex("B").unwrap();
assert_eq!(F::to_hex(&num), "B");
}
#[cfg(feature = "std")]
#[test]
fn to_hex_test_works_2() {
let num = F::from_hex("0x1a").unwrap();
assert_eq!(F::to_hex(&num), "1A");
}
#[test]
fn bit_size_of_mod_13_field_is_4() {
assert_eq!(
<U64PrimeField<MODULUS> as crate::field::traits::IsPrimeField>::field_bit_size(),
4
);
}
#[test]
fn bit_size_of_big_mod_field_is_64() {
const MODULUS: u64 = 10000000000000000000;
assert_eq!(
<U64PrimeField<MODULUS> as crate::field::traits::IsPrimeField>::field_bit_size(),
64
);
}
#[test]
fn bit_size_of_63_bit_mod_field_is_63() {
const MODULUS: u64 = 9000000000000000000;
assert_eq!(
<U64PrimeField<MODULUS> as crate::field::traits::IsPrimeField>::field_bit_size(),
63
);
}
#[test]
fn two_plus_one_is_three() {
assert_eq!(FE::new(2) + FE::new(1), FE::new(3));
}
#[test]
fn max_order_plus_1_is_0() {
assert_eq!(FE::new(MODULUS - 1) + FE::new(1), FE::new(0));
}
#[test]
fn when_comparing_13_and_13_they_are_equal() {
let a: FE = FE::new(13);
let b: FE = FE::new(13);
assert_eq!(a, b);
}
#[test]
fn when_comparing_13_and_8_they_are_different() {
let a: FE = FE::new(13);
let b: FE = FE::new(8);
assert_ne!(a, b);
}
#[test]
fn mul_neutral_element() {
let a: FE = FE::new(1);
let b: FE = FE::new(2);
assert_eq!(a * b, FE::new(2));
}
#[test]
fn mul_2_3_is_6() {
let a: FE = FE::new(2);
let b: FE = FE::new(3);
assert_eq!(a * b, FE::new(6));
}
#[test]
fn mul_order_minus_1() {
let a: FE = FE::new(MODULUS - 1);
let b: FE = FE::new(MODULUS - 1);
assert_eq!(a * b, FE::new(1));
}
#[test]
fn inv_0_error() {
let result = FE::new(0).inv();
assert!(matches!(result, Err(FieldError::InvZeroError)));
}
#[test]
fn inv_2() {
let a: FE = FE::new(2);
assert_eq!(a * a.inv().unwrap(), FE::new(1));
}
#[test]
fn pow_2_3() {
assert_eq!(FE::new(2).pow(3_u64), FE::new(8))
}
#[test]
fn pow_p_minus_1() {
assert_eq!(FE::new(2).pow(MODULUS - 1), FE::new(1))
}
#[test]
fn div_1() {
assert_eq!(FE::new(2) / FE::new(1), FE::new(2))
}
#[test]
fn div_4_2() {
assert_eq!(FE::new(4) / FE::new(2), FE::new(2))
}
#[test]
fn div_4_3() {
assert_eq!(FE::new(4) / FE::new(3) * FE::new(3), FE::new(4))
}
#[test]
fn two_plus_its_additive_inv_is_0() {
let two = FE::new(2);
assert_eq!(two + (-two), FE::new(0))
}
#[test]
fn four_minus_three_is_1() {
let four = FE::new(4);
let three = FE::new(3);
assert_eq!(four - three, FE::new(1))
}
#[test]
fn zero_minus_1_is_order_minus_1() {
let zero = FE::new(0);
let one = FE::new(1);
assert_eq!(zero - one, FE::new(MODULUS - 1))
}
#[test]
fn neg_zero_is_zero() {
let zero = FE::new(0);
assert_eq!(-zero, zero);
}
#[test]
fn zero_constructor_returns_zero() {
assert_eq!(FE::new(0), FE::new(0));
}
#[test]
fn field_element_as_group_element_multiplication_by_scalar_works_as_multiplication_in_finite_fields(
) {
let a = FE::new(3);
let b = FE::new(12);
assert_eq!(a * b, a.operate_with_self(12_u16));
}
#[test]
#[cfg(feature = "alloc")]
fn to_bytes_from_bytes_be_is_the_identity() {
let x = FE::new(12345);
assert_eq!(FE::from_bytes_be(&x.to_bytes_be()).unwrap(), x);
}
#[test]
#[cfg(feature = "alloc")]
fn from_bytes_to_bytes_be_is_the_identity_for_one() {
let bytes = [0, 0, 0, 0, 0, 0, 0, 1];
assert_eq!(FE::from_bytes_be(&bytes).unwrap().to_bytes_be(), bytes);
}
#[test]
#[cfg(feature = "alloc")]
fn to_bytes_from_bytes_le_is_the_identity() {
let x = FE::new(12345);
assert_eq!(FE::from_bytes_le(&x.to_bytes_le()).unwrap(), x);
}
#[test]
#[cfg(feature = "alloc")]
fn from_bytes_to_bytes_le_is_the_identity_for_one() {
let bytes = [1, 0, 0, 0, 0, 0, 0, 0];
assert_eq!(FE::from_bytes_le(&bytes).unwrap().to_bytes_le(), bytes);
}
#[test]
fn creating_a_field_element_from_its_representative_returns_the_same_element_1() {
let change = 1;
let f1 = FE::new(MODULUS + change);
let f2 = FE::new(f1.representative());
assert_eq!(f1, f2);
}
#[test]
fn creating_a_field_element_from_its_representative_returns_the_same_element_2() {
let change = 8;
let f1 = FE::new(MODULUS + change);
let f2 = FE::new(f1.representative());
assert_eq!(f1, f2);
}
}