use rand::Rng;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
pub trait FiniteRing:
'static
+ Clone
+ Copy
+ Send
+ Sync
+ Default
+ Debug
+ Eq
+ PartialEq
+ Hash
+ Sized
+ ConstantTimeEq
+ ConditionallySelectable
+ AddAssign<Self>
+ SubAssign<Self>
+ MulAssign<Self>
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Mul<Self, Output = Self>
+ Neg<Output = Self>
+ std::iter::Sum
+ std::iter::Product
+ num_traits::Zero
+ num_traits::One
+ CanonicalSerialize
{
fn from_uniform_bytes(x: &[u8; 16]) -> Self;
fn random<R: Rng + ?Sized>(rng: &mut R) -> Self;
fn random_nonzero<R: Rng + ?Sized>(rng: &mut R) -> Self {
loop {
let out = Self::random(rng);
if out != Self::ZERO {
return out;
}
}
}
const ZERO: Self;
const ONE: Self;
fn pow(&self, n: u128) -> Self {
self.pow_bounded(n, 128)
}
#[inline]
fn pow_bounded(&self, n: u128, bound: u16) -> Self {
debug_assert!(bound <= 128);
debug_assert_eq!(
if bound != 128 { n >> bound } else { 0 },
0
);
let mut r0 = Self::ONE;
let mut r1 = *self;
for i in (0..bound).rev() {
let bit_is_high = Choice::from((n & (1 << i) != 0) as u8);
let operand = Self::conditional_select(&r0, &r1, bit_is_high);
r0 *= operand;
r1 *= operand;
}
r0
}
fn pow_var_time(&self, n: u128) -> Self {
let mut acc = Self::ONE;
let mut b = *self;
let mut n = n;
while n != 0 {
if n & 0b1 == 0b1 {
acc = b * acc;
}
b = b * b;
n >>= 1;
}
acc
}
}
pub trait IsSubRingOf<R: FiniteRing>: FiniteRing + Mul<R, Output = R> + Into<R> {}
impl<R: FiniteRing> IsSubRingOf<R> for R {}
macro_rules! ring_ops {
($f:ident) => {
impl std::iter::Sum for $f {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold($f::ZERO, std::ops::Add::add)
}
}
crate::ring::ring_ops!($f, SUM_ALREADY_DEFINED);
};
( $f:ident, SUM_ALREADY_DEFINED) => {
impl PartialEq for $f {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl Default for $f {
fn default() -> Self {
Self::ZERO
}
}
impl std::iter::Product for $f {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold($f::ONE, std::ops::Mul::mul)
}
}
$crate::ops::binop!(Add, add, std::ops::AddAssign::add_assign, $f);
$crate::ops::binop!(Sub, sub, std::ops::SubAssign::sub_assign, $f);
$crate::ops::binop!(Mul, mul, std::ops::MulAssign::mul_assign, $f);
$crate::ops::assign_op!(AddAssign, add_assign, $f);
$crate::ops::assign_op!(SubAssign, sub_assign, $f);
$crate::ops::assign_op!(MulAssign, mul_assign, $f);
impl num_traits::Zero for $f {
#[inline]
fn zero() -> Self {
<$f as crate::field::FiniteRing>::ZERO
}
#[inline]
fn is_zero(&self) -> bool {
*self == <$f as crate::field::FiniteRing>::ZERO
}
}
impl num_traits::One for $f {
#[inline]
fn one() -> Self {
<$f as crate::field::FiniteRing>::ONE
}
#[inline]
fn is_one(&self) -> bool {
*self == <$f as crate::field::FiniteRing>::ONE
}
}
impl std::ops::Neg for $f {
type Output = $f;
fn neg(self) -> Self::Output {
$f::ZERO - self
}
}
impl rand::distributions::Distribution<$f> for rand::distributions::Standard {
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $f {
<$f>::random(rng)
}
}
$crate::serialization::serde_implementation!($f);
};
}
pub(crate) use ring_ops;
#[cfg(test)]
mod test_utils;
#[cfg(test)]
pub(crate) use test_utils::test_ring;
use crate::serialization::CanonicalSerialize;