#[macro_export]
macro_rules! fiat_monty_field_arithmetic {
(
name: $fe:tt,
params: $params:ty,
uint: $uint:ty,
non_mont: $non_mont_type:expr,
mont: $mont_type:expr,
from_mont: $from_mont:ident,
to_mont: $to_mont:ident,
add: $add:ident,
sub: $sub:ident,
mul: $mul:ident,
neg: $neg:ident,
square: $square:ident,
divstep_precomp: $divstep_precomp:ident,
divstep: $divstep:ident,
msat: $msat:ident,
selectnz: $selectznz:ident
) => {
impl $fe {
#[doc = stringify!($fe)]
#[doc = stringify!($uint)]
#[inline]
pub(crate) const fn from_uint_unchecked(w: $uint) -> Self {
let mut out = $mont_type([0; <$uint>::LIMBS]);
$to_mont(&mut out, &$non_mont_type(w.to_words()));
Self(
$crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
out.0,
),
)
}
#[doc = stringify!($fe)]
#[doc = stringify!($uint)]
#[inline]
pub const fn to_canonical(self) -> $uint {
let mut out = $non_mont_type([0; <$uint>::LIMBS]);
$from_mont(&mut out, &$mont_type(self.0.to_montgomery_words()));
<$uint>::from_words(out.0)
}
#[inline]
pub const fn add(&self, rhs: &Self) -> Self {
let mut out = $mont_type([0; <$uint>::LIMBS]);
$add(
&mut out,
&$mont_type(self.0.to_montgomery_words()),
&$mont_type(rhs.0.to_montgomery_words()),
);
Self(
$crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
out.0,
),
)
}
#[inline]
#[must_use]
pub const fn double(&self) -> Self {
self.add(self)
}
#[inline]
pub const fn sub(&self, rhs: &Self) -> Self {
let mut out = $mont_type([0; <$uint>::LIMBS]);
$sub(
&mut out,
&$mont_type(self.0.to_montgomery_words()),
&$mont_type(rhs.0.to_montgomery_words()),
);
Self(
$crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
out.0,
),
)
}
#[inline]
pub const fn multiply(&self, rhs: &Self) -> Self {
let mut out = $mont_type([0; <$uint>::LIMBS]);
$mul(
&mut out,
&$mont_type(self.0.to_montgomery_words()),
&$mont_type(rhs.0.to_montgomery_words()),
);
Self(
$crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
out.0,
),
)
}
#[inline]
pub const fn neg(&self) -> Self {
let mut out = $mont_type([0; <$uint>::LIMBS]);
$neg(&mut out, &$mont_type(self.0.to_montgomery_words()));
Self(
$crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
out.0,
),
)
}
#[inline]
#[must_use]
pub const fn square(&self) -> Self {
let mut out = $mont_type([0; <$uint>::LIMBS]);
$square(&mut out, &$mont_type(self.0.to_montgomery_words()));
Self(
$crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
out.0,
),
)
}
#[doc = stringify!($fe)]
#[inline]
pub fn invert(&self) -> $crate::subtle::CtOption<Self> {
$crate::subtle::CtOption::new(self.invert_unchecked(), !self.is_zero())
}
pub const fn const_invert(&self) -> Self {
assert!(
!self.0.as_montgomery().cmp_vartime(&<$uint>::ZERO).is_eq(),
"input to invert should be non-zero"
);
self.invert_unchecked()
}
const fn invert_unchecked(&self) -> Self {
let words = $crate::fiat_bernstein_yang_invert!(
a: &$mont_type(self.0.to_montgomery_words()),
one: &$mont_type(Self::ONE.0.to_montgomery_words()),
d: <$fe as $crate::ff::PrimeField>::NUM_BITS as usize,
nlimbs: <$uint>::LIMBS,
word: $crate::bigint::Word,
non_mont: $non_mont_type,
mont: $mont_type,
from_mont: $from_mont,
mul: $mul,
neg: $neg,
divstep_precomp: $divstep_precomp,
divstep: $divstep,
msat: $msat,
selectnz: $selectznz
);
Self(
$crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
words,
),
)
}
}
};
}
#[macro_export]
macro_rules! fiat_bernstein_yang_invert {
(
a: $a:expr,
one: $one:expr,
d: $d:expr,
nlimbs: $nlimbs:expr,
word: $word:ty,
non_mont: $non_mont_type: expr,
mont: $mont_type: expr,
from_mont: $from_mont:ident,
mul: $mul:ident,
neg: $neg:ident,
divstep_precomp: $divstep_precomp:ident,
divstep: $divstep:ident,
msat: $msat:ident,
selectnz: $selectznz:ident
) => {{
const ITERATIONS: usize = (49 * $d + 57) / 17;
let mut a = $non_mont_type([0; $nlimbs]);
$from_mont(&mut a, $a);
let mut d = 1;
let mut f = [0; $nlimbs + 1];
$msat(&mut f);
let mut g = [0; $nlimbs + 1];
let mut v = [0; $nlimbs];
let mut r = $one.0;
let mut i = 0;
let mut j = 0;
while j < $nlimbs {
g[j] = a.0[j];
j += 1;
}
while i < ITERATIONS - ITERATIONS % 2 {
let mut out1 = 0;
let mut out2 = [0; $nlimbs + 1];
let mut out3 = [0; $nlimbs + 1];
let mut out4 = [0; $nlimbs];
let mut out5 = [0; $nlimbs];
$divstep(
&mut out1, &mut out2, &mut out3, &mut out4, &mut out5, d, &f, &g, &v, &r,
);
$divstep(
&mut d, &mut f, &mut g, &mut v, &mut r, out1, &out2, &out3, &out4, &out5,
);
i += 2;
}
if ITERATIONS % 2 != 0 {
let mut out1 = 0;
let mut out2 = [0; $nlimbs + 1];
let mut out3 = [0; $nlimbs + 1];
let mut out4 = [0; $nlimbs];
let mut out5 = [0; $nlimbs];
$divstep(
&mut out1, &mut out2, &mut out3, &mut out4, &mut out5, d, &f, &g, &v, &r,
);
f = out2;
v = out4;
}
let s = ((f[f.len() - 1] >> <$word>::BITS - 1) & 1) as u8;
let mut neg_v = $mont_type([0; $nlimbs]);
$neg(&mut neg_v, &$mont_type(v));
let mut v2 = $mont_type([0; $nlimbs]);
$selectznz(&mut v2.0, s, &v, &neg_v.0);
let mut precomp = $mont_type([0; $nlimbs]);
$divstep_precomp(&mut precomp.0);
let mut out = $mont_type([0; $nlimbs]);
$mul(&mut out, &v2, &precomp);
out.0
}};
}
#[macro_export]
macro_rules! test_fiat_monty_field_arithmetic {
(
name: $fe:tt,
params: $params:ty,
uint: $uint:ty,
non_mont: $non_mont_type:expr,
mont: $mont_type:expr,
to_mont: $to_mont:ident,
msat: $msat:ident
) => {
use $crate::bigint::modular::ConstMontyParams as _;
#[test]
fn fiat_montgomery_r_constant() {
let mut one = $non_mont_type([0; <$uint>::LIMBS]);
one[0] = 1;
let mut R = $mont_type([0; <$uint>::LIMBS]);
$to_mont(&mut R, &one);
assert_eq!(<$params>::PARAMS.one().as_words(), &R.0)
}
#[test]
fn fiat_msat_constant() {
use $crate::bigint::Word;
let mut out = [0 as Word; <$uint>::LIMBS + 1];
$msat(&mut out);
assert_eq!(out[<$uint>::LIMBS], 0);
assert_eq!(
<$params>::PARAMS.modulus().as_words(),
&out[..<$uint>::LIMBS]
);
}
};
}