use core::{fmt::Debug, marker::PhantomData};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use crate::{Limb, Uint, Zero};
use super::{div_by_2::div_by_2, reduction::montgomery_reduction, Retrieve};
#[cfg(feature = "rand_core")]
use crate::{rand_core::CryptoRngCore, NonZero, Random, RandomMod};
#[cfg(feature = "serde")]
use {
crate::Encoding,
serdect::serde::de::Error,
serdect::serde::{Deserialize, Deserializer, Serialize, Serializer},
};
mod const_add;
mod const_inv;
mod const_mul;
mod const_neg;
mod const_pow;
mod const_sub;
#[macro_use]
mod macros;
pub use macros::*;
pub trait ResidueParams<const LIMBS: usize>:
Copy + Debug + Default + Eq + Send + Sync + 'static
{
const LIMBS: usize;
const MODULUS: Uint<LIMBS>;
const R: Uint<LIMBS>;
const R2: Uint<LIMBS>;
const R3: Uint<LIMBS>;
const MOD_NEG_INV: Limb;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Residue<MOD, const LIMBS: usize>
where
MOD: ResidueParams<LIMBS>,
{
montgomery_form: Uint<LIMBS>,
phantom: PhantomData<MOD>,
}
#[cfg(feature = "zeroize")]
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> zeroize::DefaultIsZeroes
for Residue<MOD, LIMBS>
{
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
pub const ZERO: Self = Self {
montgomery_form: Uint::<LIMBS>::ZERO,
phantom: PhantomData,
};
pub const ONE: Self = Self {
montgomery_form: MOD::R,
phantom: PhantomData,
};
pub const fn new(integer: &Uint<LIMBS>) -> Self {
let product = integer.mul_wide(&MOD::R2);
let montgomery_form =
montgomery_reduction::<LIMBS>(&product, &MOD::MODULUS, MOD::MOD_NEG_INV);
Self {
montgomery_form,
phantom: PhantomData,
}
}
pub const fn retrieve(&self) -> Uint<LIMBS> {
montgomery_reduction::<LIMBS>(
&(self.montgomery_form, Uint::ZERO),
&MOD::MODULUS,
MOD::MOD_NEG_INV,
)
}
pub fn div_by_2(&self) -> Self {
Self {
montgomery_form: div_by_2(&self.montgomery_form, &MOD::MODULUS),
phantom: PhantomData,
}
}
}
impl<MOD: ResidueParams<LIMBS> + Copy, const LIMBS: usize> ConditionallySelectable
for Residue<MOD, LIMBS>
{
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Residue {
montgomery_form: Uint::conditional_select(
&a.montgomery_form,
&b.montgomery_form,
choice,
),
phantom: PhantomData,
}
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> ConstantTimeEq for Residue<MOD, LIMBS> {
fn ct_eq(&self, other: &Self) -> Choice {
ConstantTimeEq::ct_eq(&self.montgomery_form, &other.montgomery_form)
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Default for Residue<MOD, LIMBS> {
fn default() -> Self {
Self::ZERO
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Zero for Residue<MOD, LIMBS> {
const ZERO: Self = Self::ZERO;
}
#[cfg(feature = "rand_core")]
impl<MOD, const LIMBS: usize> Random for Residue<MOD, LIMBS>
where
MOD: ResidueParams<LIMBS>,
{
#[inline]
fn random(rng: &mut impl CryptoRngCore) -> Self {
Self::new(&Uint::random_mod(rng, &NonZero::from_uint(MOD::MODULUS)))
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Retrieve for Residue<MOD, LIMBS> {
type Output = Uint<LIMBS>;
fn retrieve(&self) -> Self::Output {
self.retrieve()
}
}
#[cfg(feature = "serde")]
impl<'de, MOD, const LIMBS: usize> Deserialize<'de> for Residue<MOD, LIMBS>
where
MOD: ResidueParams<LIMBS>,
Uint<LIMBS>: Encoding,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Uint::<LIMBS>::deserialize(deserializer).and_then(|montgomery_form| {
if Uint::ct_lt(&montgomery_form, &MOD::MODULUS).into() {
Ok(Self {
montgomery_form,
phantom: PhantomData,
})
} else {
Err(D::Error::custom("montgomery form must be reduced"))
}
})
}
}
#[cfg(feature = "serde")]
impl<MOD, const LIMBS: usize> Serialize for Residue<MOD, LIMBS>
where
MOD: ResidueParams<LIMBS>,
Uint<LIMBS>: Encoding,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.montgomery_form.serialize(serializer)
}
}