use crate::field::{polynomial::Polynomial, FiniteField, PrimeFiniteField};
use crate::ring::FiniteRing;
use crate::serialization::{BiggerThanModulus, CanonicalSerialize};
use generic_array::GenericArray;
use rand_core::RngCore;
use std::ops::{AddAssign, MulAssign, SubAssign};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
#[derive(Clone, Copy, Eq, Debug, Hash)]
pub struct F61p(u64);
const MODULUS: u64 = (1 << 61) - 1;
impl ConstantTimeEq for F61p {
#[inline]
fn ct_eq(&self, other: &Self) -> Choice {
self.0.ct_eq(&other.0)
}
}
impl ConditionallySelectable for F61p {
#[inline]
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
F61p(u64::conditional_select(&a.0, &b.0, choice))
}
}
impl FiniteRing for F61p {
#[inline]
fn from_uniform_bytes(x: &[u8; 16]) -> Self {
F61p(reduce(
u64::from_le_bytes(<[u8; 8]>::try_from(&x[0..8]).unwrap()) as u128,
))
}
#[inline]
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
F61p(reduce(rng.next_u64() as u128))
}
const ZERO: Self = F61p(0);
const ONE: Self = F61p(1);
}
impl CanonicalSerialize for F61p {
type Serializer = crate::serialization::ByteElementSerializer<Self>;
type Deserializer = crate::serialization::ByteElementDeserializer<Self>;
type ByteReprLen = generic_array::typenum::U8;
type FromBytesError = BiggerThanModulus;
#[inline]
fn from_bytes(
bytes: &GenericArray<u8, Self::ByteReprLen>,
) -> Result<Self, Self::FromBytesError> {
let buf = <[u8; 8]>::from(*bytes);
let raw = u64::from_le_bytes(buf);
if raw < MODULUS {
Ok(F61p(raw))
} else {
Err(BiggerThanModulus)
}
}
#[inline]
fn to_bytes(&self) -> GenericArray<u8, Self::ByteReprLen> {
self.0.to_le_bytes().into()
}
}
impl FiniteField for F61p {
type PrimeField = Self;
const GENERATOR: Self = F61p(37);
fn polynomial_modulus() -> Polynomial<Self::PrimeField> {
Polynomial::x()
}
type NumberOfBitsInBitDecomposition = generic_array::typenum::U61;
fn bit_decomposition(&self) -> GenericArray<bool, Self::NumberOfBitsInBitDecomposition> {
super::standard_bit_decomposition(u128::from(self.0))
}
fn inverse(&self) -> Self {
if *self == Self::ZERO {
panic!("Zero cannot be inverted");
}
self.pow_var_time(u128::from(MODULUS) - 2)
}
}
#[inline]
fn reduce(k: u128) -> u64 {
let i = (k & u128::from(MODULUS)) + (k >> 61);
let flag = (i < u128::from(MODULUS)) as u128;
let operand = flag.wrapping_sub(1) & u128::from(MODULUS);
(i - operand) as u64
}
impl AddAssign<&F61p> for F61p {
#[inline]
fn add_assign(&mut self, rhs: &Self) {
let a = self.0 as u128;
let b = rhs.0 as u128;
self.0 = reduce(a + b);
}
}
impl SubAssign<&F61p> for F61p {
#[inline]
fn sub_assign(&mut self, rhs: &Self) {
let a = u128::from(self.0) + u128::from(MODULUS);
let b = u128::from(rhs.0);
self.0 = reduce(a - b);
}
}
impl MulAssign<&F61p> for F61p {
#[inline]
fn mul_assign(&mut self, rhs: &Self) {
self.0 = reduce(u128::from(self.0) * u128::from(rhs.0));
}
}
impl std::iter::Sum for F61p {
#[inline]
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut out: u128 = 0;
for e in iter {
out += u128::from(e.0);
}
return F61p(reduce(out));
}
}
impl TryFrom<u128> for F61p {
type Error = BiggerThanModulus;
fn try_from(value: u128) -> Result<Self, Self::Error> {
if value < MODULUS.into() {
Ok(F61p(value.try_into().unwrap()))
} else {
Err(BiggerThanModulus)
}
}
}
impl PrimeFiniteField for F61p {}
field_ops!(F61p, SUM_ALREADY_DEFINED);
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
test_field!(test_field, crate::field::F61p);
#[cfg(test)]
proptest! {
#[test]
fn test_reduce(x in 0u128..((1 << (2 * 61))-1)) {
assert_eq!(u128::from(reduce(x)), x % u128::from(MODULUS));
}
}
#[test]
fn test_sum_overflow() {
let neg1 = F61p::ZERO - F61p::ONE;
let x = [neg1; 2];
assert_eq!(x.iter().map(|x| *x).sum::<F61p>(), neg1 + neg1);
}
}