pub use core::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
};
pub use ctutils::{CtAssign, CtEq, CtGt, CtLt, CtNeg, CtSelect};
pub use num_traits::{
ConstOne, ConstZero, WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr,
WrappingSub,
};
use crate::{
Choice, CtOption, Limb, NonZero, Odd, Reciprocal, UintRef,
modular::{MontyParams, Retrieve},
primitives::u32_bits,
};
use core::fmt::{self, Debug};
#[cfg(feature = "rand_core")]
use rand_core::{Rng, TryRng};
pub trait Bounded {
const BITS: u32;
const BYTES: usize;
}
pub trait Integer:
'static
+ sealed::Sealed
+ Add<Output = Self>
+ for<'a> Add<&'a Self, Output = Self>
+ AddAssign<Self>
+ for<'a> AddAssign<&'a Self>
+ AsRef<[Limb]>
+ AsMut<[Limb]>
+ BitAnd<Output = Self>
+ for<'a> BitAnd<&'a Self, Output = Self>
+ BitAndAssign
+ for<'a> BitAndAssign<&'a Self>
+ BitOr<Output = Self>
+ for<'a> BitOr<&'a Self, Output = Self>
+ BitOrAssign
+ for<'a> BitOrAssign<&'a Self>
+ BitXor<Output = Self>
+ for<'a> BitXor<&'a Self, Output = Self>
+ BitXorAssign
+ for<'a> BitXorAssign<&'a Self>
+ CheckedAdd
+ CheckedSub
+ CheckedMul
+ CheckedDiv
+ CheckedSquareRoot<Output = Self>
+ Clone
+ CtAssign
+ CtEq
+ CtGt
+ CtLt
+ CtSelect
+ Debug
+ Default
+ DivAssign<NonZero<Self>>
+ for<'a> DivAssign<&'a NonZero<Self>>
+ Eq
+ fmt::LowerHex
+ fmt::UpperHex
+ fmt::Binary
+ Mul<Output = Self>
+ for<'a> Mul<&'a Self, Output = Self>
+ MulAssign<Self>
+ for<'a> MulAssign<&'a Self>
+ Not<Output = Self>
+ One
+ Ord
+ Rem<NonZero<Self>, Output = Self>
+ for<'a> Rem<&'a NonZero<Self>, Output = Self>
+ RemAssign<NonZero<Self>>
+ for<'a> RemAssign<&'a NonZero<Self>>
+ Send
+ Sized
+ Shl<u32, Output = Self>
+ ShlAssign<u32>
+ ShlVartime
+ Shr<u32, Output = Self>
+ ShrAssign<u32>
+ ShrVartime
+ Sub<Output = Self>
+ for<'a> Sub<&'a Self, Output = Self>
+ SubAssign<Self>
+ for<'a> SubAssign<&'a Self>
+ Sync
+ WrappingAdd
+ WrappingSub
+ WrappingMul
+ WrappingNeg
+ WrappingShl
+ WrappingShr
+ Zero
{
#[must_use]
fn as_limbs(&self) -> &[Limb];
#[must_use]
fn as_mut_limbs(&mut self) -> &mut [Limb];
#[must_use]
fn nlimbs(&self) -> usize;
#[must_use]
fn is_odd(&self) -> Choice {
self.as_ref()
.first()
.copied()
.map_or(Choice::FALSE, Limb::is_odd)
}
#[must_use]
fn is_even(&self) -> Choice {
!self.is_odd()
}
}
pub trait Signed:
Div<NonZero<Self>, Output = CtOption<Self>>
+ for<'a> Div<&'a NonZero<Self>, Output = CtOption<Self>>
+ From<i8>
+ From<i16>
+ From<i32>
+ From<i64>
+ Gcd<Output = Self::Unsigned>
+ Integer {
type Unsigned: Unsigned;
#[must_use]
fn abs_sign(&self) -> (Self::Unsigned, Choice);
#[must_use]
fn abs(&self) -> Self::Unsigned {
self.abs_sign().0
}
#[must_use]
fn is_negative(&self) -> Choice;
#[must_use]
fn is_positive(&self) -> Choice;
}
pub trait Unsigned:
AsRef<UintRef>
+ AsMut<UintRef>
+ AddMod<Output = Self>
+ BitOps
+ Div<NonZero<Self>, Output = Self>
+ for<'a> Div<&'a NonZero<Self>, Output = Self>
+ DivRemLimb
+ FloorSquareRoot<Output = Self>
+ From<u8>
+ From<u16>
+ From<u32>
+ From<u64>
+ From<Limb>
+ Gcd<Output = Self>
+ Integer
+ MulMod<Output = Self>
+ NegMod<Output = Self>
+ RemLimb
+ SquareMod<Output = Self>
+ SubMod<Output = Self>
{
#[must_use]
fn as_uint_ref(&self) -> &UintRef;
fn as_mut_uint_ref(&mut self) -> &mut UintRef;
#[must_use]
fn from_limb_like(limb: Limb, other: &Self) -> Self;
}
pub trait UnsignedWithMontyForm: Unsigned {
type MontyForm: MontyForm<Integer = Self>;
}
pub trait ToUnsigned: AsRef<UintRef> + AsMut<UintRef> {
type Unsigned: Unsigned;
fn to_unsigned(&self) -> Self::Unsigned;
fn to_unsigned_zero(&self) -> Self::Unsigned {
let mut res = self.to_unsigned();
res.set_zero();
res
}
}
impl<T: Unsigned> ToUnsigned for T {
type Unsigned = T;
fn to_unsigned(&self) -> Self::Unsigned {
self.clone()
}
fn to_unsigned_zero(&self) -> Self::Unsigned {
T::zero_like(self)
}
}
pub trait Zero: CtEq + Sized {
#[must_use]
fn zero() -> Self;
#[inline]
#[must_use]
fn is_zero(&self) -> Choice {
self.ct_eq(&Self::zero())
}
#[inline]
fn set_zero(&mut self) {
*self = Zero::zero();
}
#[must_use]
fn zero_like(other: &Self) -> Self
where
Self: Clone,
{
let mut ret = other.clone();
ret.set_zero();
ret
}
}
pub trait One: CtEq + Sized {
#[must_use]
fn one() -> Self;
#[inline]
#[must_use]
fn is_one(&self) -> Choice {
self.ct_eq(&Self::one())
}
#[inline]
fn set_one(&mut self) {
*self = One::one();
}
#[must_use]
fn one_like(_other: &Self) -> Self {
One::one()
}
}
pub trait Constants: ConstZero + ConstOne {
const MAX: Self;
}
pub trait FixedInteger: Bounded + Constants + Copy + Integer {
const LIMBS: usize;
}
pub trait Gcd<Rhs = Self>: Sized {
type Output;
#[must_use]
fn gcd(&self, rhs: &Rhs) -> Self::Output;
#[must_use]
fn gcd_vartime(&self, rhs: &Rhs) -> Self::Output;
}
pub trait Xgcd<Rhs = Self>: Sized {
type Output;
#[must_use]
fn xgcd(&self, rhs: &Rhs) -> Self::Output;
#[must_use]
fn xgcd_vartime(&self, rhs: &Rhs) -> Self::Output;
}
#[cfg(feature = "rand_core")]
pub trait Random: Sized {
fn try_random_from_rng<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error>;
#[must_use]
fn random_from_rng<R: Rng + ?Sized>(rng: &mut R) -> Self {
let Ok(out) = Self::try_random_from_rng(rng);
out
}
#[cfg(feature = "getrandom")]
fn try_random() -> Result<Self, getrandom::Error> {
Self::try_random_from_rng(&mut getrandom::SysRng)
}
#[cfg(feature = "getrandom")]
#[must_use]
fn random() -> Self {
Self::try_random().expect("RNG failure")
}
}
#[cfg(feature = "rand_core")]
#[derive(Debug)]
pub enum RandomBitsError<T> {
RandCore(T),
BitsPrecisionMismatch {
bits_precision: u32,
integer_bits: u32,
},
BitLengthTooLarge {
bit_length: u32,
bits_precision: u32,
},
}
#[cfg(feature = "rand_core")]
impl<T> fmt::Display for RandomBitsError<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::RandCore(err) => write!(f, "{err}"),
Self::BitsPrecisionMismatch {
bits_precision,
integer_bits,
} => write!(
f,
concat![
"The requested `bits_precision` ({}) does not match ",
"the size of the integer corresponding to the type ({})"
],
bits_precision, integer_bits
),
Self::BitLengthTooLarge {
bit_length,
bits_precision,
} => write!(
f,
"The requested `bit_length` ({bit_length}) is larger than `bits_precision` ({bits_precision}).",
),
}
}
}
#[cfg(feature = "rand_core")]
impl<T> core::error::Error for RandomBitsError<T> where T: Debug + fmt::Display {}
#[cfg(feature = "rand_core")]
pub trait RandomBits: Sized {
#[must_use]
fn random_bits<R: TryRng + ?Sized>(rng: &mut R, bit_length: u32) -> Self {
Self::try_random_bits(rng, bit_length).expect("try_random_bits() failed")
}
fn try_random_bits<R: TryRng + ?Sized>(
rng: &mut R,
bit_length: u32,
) -> Result<Self, RandomBitsError<R::Error>>;
#[must_use]
#[track_caller]
fn random_bits_with_precision<R: TryRng + ?Sized>(
rng: &mut R,
bit_length: u32,
bits_precision: u32,
) -> Self {
Self::try_random_bits_with_precision(rng, bit_length, bits_precision)
.expect("try_random_bits_with_precision() failed")
}
fn try_random_bits_with_precision<R: TryRng + ?Sized>(
rng: &mut R,
bit_length: u32,
bits_precision: u32,
) -> Result<Self, RandomBitsError<R::Error>>;
}
#[cfg(feature = "rand_core")]
pub trait RandomMod: Sized + Zero {
#[must_use]
fn random_mod_vartime<R: Rng + ?Sized>(rng: &mut R, modulus: &NonZero<Self>) -> Self {
let Ok(out) = Self::try_random_mod_vartime(rng, modulus);
out
}
fn try_random_mod_vartime<R: TryRng + ?Sized>(
rng: &mut R,
modulus: &NonZero<Self>,
) -> Result<Self, R::Error>;
#[deprecated(since = "0.7.0", note = "please use `random_mod_vartime` instead")]
#[must_use]
fn random_mod<R: Rng + ?Sized>(rng: &mut R, modulus: &NonZero<Self>) -> Self {
Self::random_mod_vartime(rng, modulus)
}
#[deprecated(since = "0.7.0", note = "please use `try_random_mod_vartime` instead")]
fn try_random_mod<R: TryRng + ?Sized>(
rng: &mut R,
modulus: &NonZero<Self>,
) -> Result<Self, R::Error> {
Self::try_random_mod_vartime(rng, modulus)
}
}
pub trait AddMod<Rhs = Self, Mod = NonZero<Self>> {
type Output;
#[must_use]
fn add_mod(&self, rhs: &Rhs, p: &Mod) -> Self::Output;
}
pub trait SubMod<Rhs = Self, Mod = NonZero<Self>> {
type Output;
#[must_use]
fn sub_mod(&self, rhs: &Rhs, p: &Mod) -> Self::Output;
}
pub trait NegMod<Mod = NonZero<Self>> {
type Output;
#[must_use]
fn neg_mod(&self, p: &Mod) -> Self::Output;
}
pub trait MulMod<Rhs = Self, Mod = NonZero<Self>> {
type Output;
#[must_use]
fn mul_mod(&self, rhs: &Rhs, p: &Mod) -> Self::Output;
}
pub trait SquareMod<Mod = NonZero<Self>> {
type Output;
#[must_use]
fn square_mod(&self, p: &Mod) -> Self::Output;
}
#[deprecated(since = "0.7.0", note = "please use `InvertMod` instead")]
pub trait InvMod<Rhs = Self>: Sized {
type Output;
#[must_use]
fn inv_mod(&self, p: &Rhs) -> CtOption<Self::Output>;
}
#[allow(deprecated)]
impl<T, Rhs> InvMod<Rhs> for T
where
T: InvertMod<Rhs>,
{
type Output = <T as InvertMod<Rhs>>::Output;
fn inv_mod(&self, p: &Rhs) -> CtOption<Self::Output> {
self.invert_mod(p)
}
}
pub trait InvertMod<Mod = NonZero<Self>>: Sized {
type Output;
#[must_use]
fn invert_mod(&self, p: &Mod) -> CtOption<Self::Output>;
}
pub trait CheckedAdd<Rhs = Self>: Sized {
#[must_use]
fn checked_add(&self, rhs: &Rhs) -> CtOption<Self>;
}
pub trait CheckedDiv<Rhs = Self>: Sized {
#[must_use]
fn checked_div(&self, rhs: &Rhs) -> CtOption<Self>;
}
pub trait CheckedMul<Rhs = Self>: Sized {
#[must_use]
fn checked_mul(&self, rhs: &Rhs) -> CtOption<Self>;
}
pub trait CheckedSub<Rhs = Self>: Sized {
#[must_use]
fn checked_sub(&self, rhs: &Rhs) -> CtOption<Self>;
}
pub trait Concat<const HI: usize> {
type Output: Integer;
}
pub trait Split<const LO: usize> {
type Output: Integer;
}
pub trait SplitEven {
type Output: Integer;
}
pub trait Encoding: Sized {
type Repr: AsRef<[u8]>
+ AsMut<[u8]>
+ Clone
+ Sized
+ for<'a> TryFrom<&'a [u8], Error: core::error::Error>;
#[must_use]
fn from_be_bytes(bytes: Self::Repr) -> Self;
#[must_use]
fn from_le_bytes(bytes: Self::Repr) -> Self;
#[must_use]
fn to_be_bytes(&self) -> Self::Repr;
#[must_use]
fn to_le_bytes(&self) -> Self::Repr;
}
pub trait EncodedSize {
type Target;
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DecodeError {
Empty,
InvalidDigit,
InputSize,
Precision,
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => write!(f, "empty value provided"),
Self::InvalidDigit => {
write!(f, "invalid digit character")
}
Self::InputSize => write!(f, "input size is too small to fit in the given precision"),
Self::Precision => write!(
f,
"the deserialized number is larger than the given precision"
),
}
}
}
impl core::error::Error for DecodeError {}
pub trait Square {
#[must_use]
fn square(&self) -> Self;
}
pub trait SquareAssign {
fn square_assign(&mut self);
}
pub trait CheckedSquareRoot: Sized {
type Output;
#[must_use]
fn checked_sqrt(&self) -> CtOption<Self::Output>;
#[must_use]
fn checked_sqrt_vartime(&self) -> Option<Self::Output>;
}
pub trait FloorSquareRoot: CheckedSquareRoot {
#[must_use]
fn floor_sqrt(&self) -> Self::Output;
#[must_use]
fn floor_sqrt_vartime(&self) -> Self::Output;
}
pub trait DivRemLimb: Sized {
#[must_use]
fn div_rem_limb(&self, rhs: NonZero<Limb>) -> (Self, Limb) {
self.div_rem_limb_with_reciprocal(&Reciprocal::new(rhs))
}
#[must_use]
fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb);
}
pub trait RemMixed<Reductor>: Sized {
#[must_use]
fn rem_mixed(&self, reductor: &NonZero<Reductor>) -> Reductor;
}
pub trait Reduce<T>: Sized {
#[must_use]
fn reduce(value: &T) -> Self;
}
pub trait DivVartime: Sized {
#[must_use]
fn div_vartime(&self, rhs: &NonZero<Self>) -> Self;
}
pub trait RemLimb: Sized {
#[must_use]
fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
self.rem_limb_with_reciprocal(&Reciprocal::new(rhs))
}
#[must_use]
fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb;
}
pub trait BitOps {
#[must_use]
fn bits_precision(&self) -> u32;
#[must_use]
fn log2_bits(&self) -> u32 {
u32_bits(self.bits_precision()) - 1
}
#[must_use]
fn bytes_precision(&self) -> usize;
#[must_use]
fn bit(&self, index: u32) -> Choice;
fn set_bit(&mut self, index: u32, bit_value: Choice);
#[must_use]
fn bits(&self) -> u32 {
self.bits_precision() - self.leading_zeros()
}
#[must_use]
fn trailing_zeros(&self) -> u32;
#[must_use]
fn trailing_ones(&self) -> u32;
#[must_use]
fn leading_zeros(&self) -> u32;
#[must_use]
fn bit_vartime(&self, index: u32) -> bool;
#[must_use]
fn bits_vartime(&self) -> u32 {
self.bits()
}
fn set_bit_vartime(&mut self, index: u32, bit_value: bool);
#[must_use]
fn leading_zeros_vartime(&self) -> u32 {
self.bits_precision() - self.bits_vartime()
}
#[must_use]
fn trailing_zeros_vartime(&self) -> u32 {
self.trailing_zeros()
}
#[must_use]
fn trailing_ones_vartime(&self) -> u32 {
self.trailing_ones()
}
}
pub trait Pow<Exponent> {
#[must_use]
fn pow(&self, exponent: &Exponent) -> Self;
}
impl<T: PowBoundedExp<Exponent>, Exponent: Unsigned> Pow<Exponent> for T {
fn pow(&self, exponent: &Exponent) -> Self {
self.pow_bounded_exp(exponent, exponent.bits_precision())
}
}
pub trait PowBoundedExp<Exponent> {
#[must_use]
fn pow_bounded_exp(&self, exponent: &Exponent, exponent_bits: u32) -> Self;
}
pub trait MultiExponentiate<Exponent, BasesAndExponents>: Pow<Exponent> + Sized
where
BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized,
{
#[must_use]
fn multi_exponentiate(bases_and_exponents: &BasesAndExponents) -> Self;
}
impl<T, Exponent, BasesAndExponents> MultiExponentiate<Exponent, BasesAndExponents> for T
where
T: MultiExponentiateBoundedExp<Exponent, BasesAndExponents>,
Exponent: Bounded,
BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized,
{
fn multi_exponentiate(bases_and_exponents: &BasesAndExponents) -> Self {
Self::multi_exponentiate_bounded_exp(bases_and_exponents, Exponent::BITS)
}
}
pub trait MultiExponentiateBoundedExp<Exponent, BasesAndExponents>: Pow<Exponent> + Sized
where
BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized,
{
#[must_use]
fn multi_exponentiate_bounded_exp(
bases_and_exponents: &BasesAndExponents,
exponent_bits: u32,
) -> Self;
}
pub trait Invert {
type Output;
fn invert(&self) -> Self::Output;
fn invert_vartime(&self) -> Self::Output {
self.invert()
}
}
pub trait ConcatenatingMul<Rhs = Self>: Sized {
type Output: Integer;
#[must_use]
fn concatenating_mul(&self, rhs: Rhs) -> Self::Output;
}
pub trait ConcatenatingSquare: Sized {
type Output: Integer;
#[must_use]
fn concatenating_square(&self) -> Self::Output;
}
#[deprecated(since = "0.7.0", note = "please use `ConcatenatingMul` instead")]
pub trait WideningMul<Rhs = Self>: Sized {
type Output: Integer;
#[must_use]
fn widening_mul(&self, rhs: Rhs) -> Self::Output;
}
#[allow(deprecated)]
impl<T, Rhs> WideningMul<Rhs> for T
where
T: ConcatenatingMul<Rhs>,
{
type Output = <T as ConcatenatingMul<Rhs>>::Output;
fn widening_mul(&self, rhs: Rhs) -> Self::Output {
self.concatenating_mul(rhs)
}
}
pub trait ShlVartime: Sized {
fn overflowing_shl_vartime(&self, shift: u32) -> Option<Self>;
#[must_use]
fn unbounded_shl_vartime(&self, shift: u32) -> Self;
#[must_use]
fn wrapping_shl_vartime(&self, shift: u32) -> Self;
}
pub trait ShrVartime: Sized {
fn overflowing_shr_vartime(&self, shift: u32) -> Option<Self>;
#[must_use]
fn unbounded_shr_vartime(&self, shift: u32) -> Self;
#[must_use]
fn wrapping_shr_vartime(&self, shift: u32) -> Self;
}
pub trait Resize: Sized {
type Output;
#[must_use]
fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output;
fn try_resize(self, at_least_bits_precision: u32) -> Option<Self::Output>;
#[must_use]
#[track_caller]
fn resize(self, at_least_bits_precision: u32) -> Self::Output {
self.try_resize(at_least_bits_precision).unwrap_or_else(|| {
panic!("The bit size of `self` is larger than `at_least_bits_precision`")
})
}
}
pub trait MontyForm:
'static
+ sealed::Sealed
+ Clone
+ CtEq
+ CtSelect
+ Debug
+ Eq
+ Invert<Output = CtOption<Self>>
+ Sized
+ Send
+ Sync
+ Add<Output = Self>
+ for<'a> Add<&'a Self, Output = Self>
+ AddAssign
+ for<'a> AddAssign<&'a Self>
+ Sub<Output = Self>
+ for<'a> Sub<&'a Self, Output = Self>
+ SubAssign
+ for<'a> SubAssign<&'a Self>
+ Mul<Output = Self>
+ for<'a> Mul<&'a Self, Output = Self>
+ MulAssign
+ for<'a> MulAssign<&'a Self>
+ Neg<Output = Self>
+ PowBoundedExp<Self::Integer>
+ Retrieve<Output = Self::Integer>
+ Square
+ SquareAssign
{
type Integer: UnsignedWithMontyForm<MontyForm = Self>;
type Multiplier<'a>: Debug + Clone + MontyMultiplier<'a, Monty = Self>;
type Params: 'static
+ AsRef<MontyParams<Self::Integer>>
+ From<MontyParams<Self::Integer>>
+ Clone
+ Debug
+ Eq
+ Sized
+ Send
+ Sync;
#[must_use]
fn new_params_vartime(modulus: Odd<Self::Integer>) -> Self::Params;
#[must_use]
fn new(value: Self::Integer, params: &Self::Params) -> Self;
#[must_use]
fn zero(params: &Self::Params) -> Self;
#[must_use]
fn is_zero(&self) -> Choice {
self.as_montgomery().is_zero()
}
#[must_use]
fn one(params: &Self::Params) -> Self;
#[must_use]
fn is_one(&self) -> Choice {
self.as_montgomery().ct_eq(self.params().as_ref().one())
}
#[must_use]
fn params(&self) -> &Self::Params;
#[must_use]
fn as_montgomery(&self) -> &Self::Integer;
fn copy_montgomery_from(&mut self, other: &Self);
#[must_use]
fn from_montgomery(integer: Self::Integer, params: &Self::Params) -> Self;
#[must_use]
fn into_montgomery(self) -> Self::Integer;
#[must_use]
fn double(&self) -> Self;
#[must_use]
fn div_by_2(&self) -> Self;
fn div_by_2_assign(&mut self) {
*self = self.div_by_2();
}
#[must_use]
fn lincomb_vartime(products: &[(&Self, &Self)]) -> Self;
}
pub trait MontyMultiplier<'a>: From<&'a <Self::Monty as MontyForm>::Params> {
type Monty: MontyForm;
fn mul_assign(&mut self, lhs: &mut Self::Monty, rhs: &Self::Monty);
fn square_assign(&mut self, lhs: &mut Self::Monty);
}
pub(crate) trait AmmMultiplier<'a>: MontyMultiplier<'a> {
fn mul_amm_assign(
&mut self,
a: &mut <Self::Monty as MontyForm>::Integer,
b: &<Self::Monty as MontyForm>::Integer,
);
fn square_amm_assign(&mut self, a: &mut <Self::Monty as MontyForm>::Integer);
}
pub(crate) mod sealed {
pub trait Sealed {}
}
#[cfg(test)]
pub(crate) mod tests {
use super::{
Integer, Invert, MontyForm, Retrieve, Signed, Square, SquareAssign, ToUnsigned, Unsigned,
UnsignedWithMontyForm,
};
use crate::{Choice, CtEq, CtSelect, Limb, NonZero, Odd, One, Reciprocal, Zero};
pub fn test_integer<T: Integer>(min: T, max: T) {
let zero = T::zero_like(&min);
let one = T::one_like(&min);
let two = one.clone() + &one;
let inputs = &[zero.clone(), one.clone(), max.clone()];
let nz_one = NonZero::new(one.clone()).expect("must be non-zero");
let nz_two = NonZero::new(two.clone()).expect("must be non-zero");
let pairs = &[
(zero.clone(), zero.clone()),
(zero.clone(), one.clone()),
(zero.clone(), max.clone()),
(one.clone(), zero.clone()),
(one.clone(), one.clone()),
(one.clone(), max.clone()),
(max.clone(), zero.clone()),
(max.clone(), one.clone()),
(max.clone(), max.clone()),
];
#[cfg(feature = "alloc")]
for a in inputs {
let _ = format!("{a:?}");
let _ = format!("{a:#?}");
let _ = format!("{a:b}");
let _ = format!("{a:x}");
let _ = format!("{a:X}");
}
assert_eq!(T::default(), zero);
assert_eq!(zero, T::zero());
assert_eq!(one, T::one());
assert_ne!(zero, one);
assert_ne!(zero, max);
assert_ne!(min, max);
assert!(zero.is_even().to_bool());
assert!(!zero.is_odd().to_bool());
assert!(!one.is_even().to_bool());
assert!(one.is_odd().to_bool());
assert!(two.is_even().to_bool());
assert!(!two.is_odd().to_bool());
for (a, b) in pairs {
assert_eq!(a.nlimbs(), a.as_limbs().len());
assert_eq!(a.as_limbs(), a.as_ref());
assert_eq!(a.clone().as_mut_limbs(), a.clone().as_mut());
assert_eq!(&*a.clone().as_mut_limbs(), a.as_limbs());
assert_eq!(
a.ct_eq(b).to_bool(),
a.as_limbs().ct_eq(b.as_limbs()).to_bool()
);
assert_ne!(a.ct_eq(b).to_bool(), a.ct_ne(b).to_bool());
if a == b {
assert!(!a.ct_lt(b).to_bool());
assert!(!a.ct_gt(b).to_bool());
} else {
assert_ne!(a.ct_lt(b).to_bool(), a.ct_gt(b).to_bool());
}
assert_eq!(a.ct_lt(b).to_bool(), a < b);
assert_eq!(a.ct_gt(b).to_bool(), a > b);
}
for (a, b) in pairs {
let mut c = a.clone();
c.ct_assign(b, Choice::FALSE);
assert_eq!(&c, a);
c.ct_assign(b, Choice::TRUE);
assert_eq!(&c, b);
assert_eq!(&CtSelect::ct_select(a, b, Choice::FALSE), a);
assert_eq!(&CtSelect::ct_select(a, b, Choice::TRUE), b);
let (mut c, mut d) = (a.clone(), b.clone());
CtSelect::ct_swap(&mut c, &mut d, Choice::FALSE);
assert_eq!((&c, &d), (a, b));
CtSelect::ct_swap(&mut c, &mut d, Choice::TRUE);
assert_eq!((&c, &d), (b, a));
}
for a in inputs {
assert_eq!(a.clone().bitand(zero.clone()), zero);
assert_eq!(a.clone().bitand(&zero), zero);
assert_eq!(&a.clone().bitand(a), a);
assert_eq!(zero.clone().bitand(a), zero);
assert_eq!(a.clone().not().bitand(a), zero);
let mut b = a.clone();
b &= a.clone();
assert_eq!(a, &b);
let mut b = a.clone();
b &= a;
assert_eq!(a, &b);
}
for a in inputs {
assert_eq!(&a.clone().bitor(zero.clone()), a);
assert_eq!(&a.clone().bitor(&zero), a);
assert_eq!(&a.clone().bitor(a), a);
assert_eq!(&zero.clone().bitor(a), a);
let mut b = a.clone();
b |= a;
assert_eq!(a, &b);
let mut b = a.clone();
b |= a.clone();
assert_eq!(a, &b);
}
for a in inputs {
assert_eq!(&a.clone().bitxor(zero.clone()), a);
assert_eq!(&a.clone().bitor(&zero), a);
assert_eq!(a.clone().bitxor(a), zero);
assert_eq!(&zero.clone().bitxor(a), a);
let mut b = a.clone();
b ^= a;
assert_eq!(T::zero(), b);
let mut b = a.clone();
b ^= a.clone();
assert_eq!(T::zero(), b);
}
assert_eq!(zero.clone().shr(1u32), zero);
assert_eq!(one.clone().shr(1u32), zero);
assert_eq!(zero.clone().shl(1u32), zero);
assert_eq!(one.clone().shl(1u32), two);
assert_eq!(two.clone().shr(1u32), one);
assert_ne!(max.clone().shr(1u32), max);
let mut expect = one.clone();
expect.shl_assign(1);
assert_eq!(expect, two);
expect.shr_assign(1);
assert_eq!(expect, one);
for a in inputs {
assert_eq!(&a.clone().add(zero.clone()), a);
assert_eq!(&a.clone().add(&zero), a);
assert_eq!(&zero.clone().add(a), a);
let mut b = a.clone();
b += &zero;
assert_eq!(a, &b);
let mut b = a.clone();
b += zero.clone();
assert_eq!(a, &b);
}
for a in inputs {
assert_eq!(&a.clone().sub(zero.clone()), a);
assert_eq!(&a.clone().sub(&zero), a);
assert_eq!(a.clone().sub(a), zero);
let mut b = a.clone();
b -= a;
assert_eq!(zero, b);
let mut b = a.clone();
b -= a.clone();
assert_eq!(zero, b);
}
for a in inputs {
assert_eq!(a.clone().mul(zero.clone()), zero);
assert_eq!(a.clone().mul(&zero), zero);
assert_eq!(&a.clone().mul(&one), a);
assert_eq!(zero.clone().mul(a), zero);
assert_eq!(&one.clone().mul(a), a);
let mut b = a.clone();
b *= &one;
assert_eq!(a, &b);
let mut b = a.clone();
b *= one.clone();
assert_eq!(a, &b);
}
let mut a = one.clone();
a /= &nz_one;
assert_eq!(a, one);
let mut a = one.clone();
a /= nz_one.clone();
assert_eq!(a, one);
assert_eq!(zero.clone().rem(&nz_one), zero);
assert_eq!(zero.clone().rem(nz_one.clone()), zero);
assert_eq!(one.clone().rem(&nz_one), zero);
assert_eq!(one.clone().rem(&nz_two), one);
let mut a = one.clone();
a %= &nz_one;
assert_eq!(a, zero);
let mut a = one.clone();
a %= nz_one.clone();
assert_eq!(a, zero);
assert_eq!(
zero.clone().checked_add(&zero).into_option(),
Some(zero.clone())
);
assert_eq!(
zero.clone().checked_add(&one).into_option(),
Some(one.clone())
);
assert_eq!(
zero.clone().checked_add(&max).into_option(),
Some(max.clone())
);
assert_eq!(max.checked_add(&one).into_option(), None);
assert_eq!(max.checked_add(&max).into_option(), None);
assert_eq!(
zero.clone().checked_sub(&zero).into_option(),
Some(zero.clone())
);
assert_eq!(min.checked_sub(&zero).into_option(), Some(min.clone()));
assert_eq!(min.checked_sub(&one).into_option(), None);
assert_eq!(min.checked_sub(&max).into_option(), None);
assert_eq!(max.checked_sub(&zero).into_option(), Some(max.clone()));
assert_eq!(max.checked_sub(&max).into_option(), Some(zero.clone()));
assert_eq!(
zero.clone().checked_mul(&zero).into_option(),
Some(zero.clone())
);
assert_eq!(
zero.clone().checked_mul(&one).into_option(),
Some(zero.clone())
);
assert_eq!(
one.clone().checked_mul(&max).into_option(),
Some(max.clone())
);
assert_eq!(max.checked_mul(&max).into_option(), None);
assert_eq!(zero.clone().checked_div(&zero).into_option(), None);
assert_eq!(one.clone().checked_div(&zero).into_option(), None);
assert_eq!(
one.clone().checked_div(&one).into_option(),
Some(one.clone())
);
assert_eq!(max.checked_div(&max).into_option(), Some(one.clone()));
assert_eq!(zero.checked_sqrt().into_option(), Some(zero.clone()));
assert_eq!(zero.checked_sqrt_vartime(), Some(zero.clone()));
assert_eq!(one.checked_sqrt().into_option(), Some(one.clone()));
assert_eq!(one.checked_sqrt_vartime(), Some(one.clone()));
assert_eq!(two.checked_sqrt().into_option(), None);
assert_eq!(two.checked_sqrt_vartime(), None);
assert_eq!(zero.clone().wrapping_add(&zero), zero);
assert_eq!(zero.clone().wrapping_add(&one), one);
assert_eq!(one.clone().wrapping_add(&zero), one);
assert_eq!(one.clone().wrapping_add(&one), two);
assert_eq!(one.clone().wrapping_add(&max), min);
assert_eq!(max.wrapping_add(&one), min);
assert_eq!(zero.clone().wrapping_sub(&zero), zero);
assert_eq!(one.clone().wrapping_sub(&zero), one);
assert_eq!(two.wrapping_sub(&one), one);
assert_eq!(min.wrapping_sub(&one), max);
assert_eq!(min.wrapping_sub(&min), zero);
assert_eq!(zero.clone().wrapping_mul(&zero), zero);
assert_eq!(zero.clone().wrapping_mul(&one), zero);
assert_eq!(one.clone().wrapping_mul(&zero), zero);
assert_eq!(one.clone().wrapping_mul(&one), one);
assert_eq!(one.clone().wrapping_mul(&max), max);
assert_eq!(max.wrapping_mul(&zero), zero);
assert_eq!(max.wrapping_mul(&one), max);
assert_eq!(max.wrapping_mul(&two), max.clone().shl(1u32));
assert_eq!(zero.clone().wrapping_neg(), zero);
for a in inputs {
assert_eq!(a.wrapping_add(&a.wrapping_neg()), zero);
assert_eq!(zero.wrapping_sub(a), a.wrapping_neg());
}
assert_eq!(zero.clone().wrapping_shr(1u32), zero);
assert_eq!(one.clone().wrapping_shr(1u32), zero);
assert_eq!(zero.clone().wrapping_shl(1u32), zero);
assert_eq!(one.clone().wrapping_shl(1u32), two);
assert_eq!(two.clone().wrapping_shr(1u32), one);
assert_ne!(max.clone().wrapping_shr(1u32), max);
}
pub fn test_unsigned<T: Unsigned>(min: T, max: T) {
let zero = T::zero_like(&min);
let one = T::one_like(&min);
let two = one.clone() + &one;
let nz_one = NonZero::new(one.clone()).expect("must be non-zero");
let nz_two = NonZero::new(two.clone()).expect("must be non-zero");
let nz_limb_one = NonZero::new(Limb::ONE).expect("must be non-zero");
let nz_limb_two = NonZero::new(Limb::from(2u8)).expect("must be non-zero");
let inputs = &[zero.clone(), one.clone(), max.clone()];
test_integer(min.clone(), max.clone());
for a in inputs {
assert_eq!(a.as_uint_ref(), a.as_ref());
assert_eq!(a.clone().as_mut_uint_ref(), a.clone().as_mut());
assert_eq!(T::from_limb_like(Limb::ZERO, &one), zero);
assert_eq!(T::from_limb_like(Limb::ONE, &one), one);
}
assert!(zero.is_zero().to_bool());
assert!(!one.is_zero().to_bool());
let mut a = one.clone();
a.set_zero();
assert_eq!(a, zero);
assert!(!zero.is_one().to_bool());
assert!(one.is_one().to_bool());
let mut a = zero.clone();
a.set_one();
assert_eq!(a, one);
assert_eq!(T::from(0u8), T::zero());
assert_eq!(T::from(1u8), T::one());
assert_eq!(T::from(1u16), T::one());
assert_eq!(T::from(1u32), T::one());
assert_eq!(T::from(1u64), T::one());
assert_eq!(T::from(Limb::ONE), T::one());
assert_eq!(one.to_unsigned(), one);
assert_eq!(one.to_unsigned_zero(), zero);
assert_eq!(zero.floor_sqrt(), zero);
assert_eq!(zero.floor_sqrt_vartime(), zero);
assert_eq!(one.floor_sqrt(), one);
assert_eq!(one.floor_sqrt_vartime(), one);
assert_eq!(two.floor_sqrt(), one);
assert_eq!(two.floor_sqrt_vartime(), one);
assert_eq!(zero.gcd(&zero), zero);
assert_eq!(zero.gcd_vartime(&zero), zero);
assert_eq!(one.gcd(&one), one);
assert_eq!(one.gcd_vartime(&one), one);
assert_eq!(two.gcd(&one), one);
assert_eq!(two.gcd_vartime(&one), one);
assert_eq!(zero.clone().div(&nz_one), zero);
assert_eq!(zero.clone().div(&nz_two), zero);
assert_eq!(one.clone().div(&nz_one), one);
assert_eq!(one.clone().div(&nz_two), zero);
assert_eq!(zero.clone().div(nz_one.clone()), zero);
assert_eq!(zero.clone().div(nz_two.clone()), zero);
assert_eq!(one.clone().div(nz_one.clone()), one);
assert_eq!(one.clone().div(nz_two.clone()), zero);
assert_eq!(zero.div_rem_limb(nz_limb_one), (zero.clone(), Limb::ZERO));
assert_eq!(zero.div_rem_limb(nz_limb_two), (zero.clone(), Limb::ZERO));
assert_eq!(one.div_rem_limb(nz_limb_one), (one.clone(), Limb::ZERO));
assert_eq!(one.div_rem_limb(nz_limb_two), (zero.clone(), Limb::ONE));
assert_eq!(
zero.div_rem_limb_with_reciprocal(&Reciprocal::new(nz_limb_one)),
(zero.clone(), Limb::ZERO)
);
assert_eq!(
one.div_rem_limb_with_reciprocal(&Reciprocal::new(nz_limb_one)),
(one.clone(), Limb::ZERO)
);
assert_eq!(
one.div_rem_limb_with_reciprocal(&Reciprocal::new(nz_limb_two)),
(zero.clone(), Limb::ONE)
);
assert_eq!(zero.rem_limb(nz_limb_one), Limb::ZERO);
assert_eq!(zero.rem_limb(nz_limb_two), Limb::ZERO);
assert_eq!(one.rem_limb(nz_limb_one), Limb::ZERO);
assert_eq!(one.rem_limb(nz_limb_two), Limb::ONE);
assert_eq!(
zero.rem_limb_with_reciprocal(&Reciprocal::new(nz_limb_one)),
Limb::ZERO
);
assert_eq!(
one.rem_limb_with_reciprocal(&Reciprocal::new(nz_limb_one)),
Limb::ZERO
);
assert_eq!(
one.rem_limb_with_reciprocal(&Reciprocal::new(nz_limb_two)),
Limb::ONE
);
assert_eq!(zero.bits(), 0);
assert_eq!(one.bits(), 1);
assert_eq!(one.bits_vartime(), 1);
assert_eq!(one.bits_precision() as usize, one.bytes_precision() * 8);
assert_eq!(one.bits_precision(), 1 << one.log2_bits());
assert_eq!(zero.leading_zeros(), zero.bits_precision());
assert_eq!(zero.leading_zeros_vartime(), zero.bits_precision());
assert_eq!(zero.trailing_zeros(), zero.bits_precision());
assert_eq!(zero.trailing_zeros_vartime(), zero.bits_precision());
assert_eq!(zero.trailing_ones(), 0);
assert_eq!(zero.trailing_ones_vartime(), 0);
assert_eq!(one.leading_zeros(), one.bits_precision() - 1);
assert_eq!(one.leading_zeros_vartime(), one.bits_precision() - 1);
assert_eq!(one.trailing_zeros(), 0);
assert_eq!(one.trailing_zeros_vartime(), 0);
assert_eq!(one.trailing_ones(), 1);
assert_eq!(one.trailing_ones_vartime(), 1);
assert!(!zero.bit(0).to_bool());
assert!(!zero.bit_vartime(0));
assert!(one.bit(0).to_bool());
assert!(one.bit_vartime(0));
assert!(!one.bit(1).to_bool());
assert!(!one.bit_vartime(1));
let mut a = zero.clone();
a.set_bit(0, Choice::TRUE);
assert_eq!(a, one);
let mut a = zero.clone();
a.set_bit_vartime(0, true);
assert_eq!(a, one);
let mut a = one.clone();
a.set_bit(0, Choice::FALSE);
assert_eq!(a, zero);
let mut a = one.clone();
a.set_bit_vartime(0, false);
assert_eq!(a, zero);
assert_eq!(zero.add_mod(&zero, &nz_two), zero);
assert_eq!(zero.add_mod(&one, &nz_two), one);
assert_eq!(one.add_mod(&zero, &nz_two), one);
assert_eq!(one.add_mod(&one, &nz_two), zero);
assert_eq!(zero.sub_mod(&zero, &nz_two), zero);
assert_eq!(zero.sub_mod(&one, &nz_two), one);
assert_eq!(one.sub_mod(&zero, &nz_two), one);
assert_eq!(one.sub_mod(&one, &nz_two), zero);
assert_eq!(zero.mul_mod(&zero, &nz_two), zero);
assert_eq!(zero.mul_mod(&one, &nz_two), zero);
assert_eq!(one.mul_mod(&zero, &nz_two), zero);
assert_eq!(one.mul_mod(&one, &nz_two), one);
assert_eq!(zero.square_mod(&nz_two), zero);
assert_eq!(one.square_mod(&nz_two), one);
assert_eq!(zero.neg_mod(&nz_two), zero);
assert_eq!(one.neg_mod(&nz_two), one);
}
pub fn test_signed<T: Signed>(min: T, max: T) {
let zero = T::zero_like(&min);
let one = T::one_like(&min);
let two = one.clone() + &one;
let zero_unsigned = T::Unsigned::zero();
let one_unsigned = T::Unsigned::one();
let minus_one = T::from(-1i8);
let nz_one = NonZero::new(one.clone()).expect("must be non-zero");
let nz_minus_one = NonZero::new(minus_one.clone()).expect("must be non-zero");
let nz_two = NonZero::new(two.clone()).expect("must be non-zero");
test_integer(min.clone(), max.clone());
assert!(!zero.is_positive().to_bool());
assert!(!zero.is_negative().to_bool());
assert!(one.is_positive().to_bool());
assert!(!one.is_negative().to_bool());
assert!(!minus_one.is_positive().to_bool());
assert!(minus_one.is_negative().to_bool());
assert_eq!(zero.abs(), zero_unsigned);
assert_eq!(one.abs(), one_unsigned);
assert_eq!(minus_one.abs(), one_unsigned);
let (check, check_sign) = zero.abs_sign();
assert_eq!(
(check, check_sign.to_bool()),
(zero_unsigned.clone(), false)
);
let (check, check_sign) = one.abs_sign();
assert_eq!((check, check_sign.to_bool()), (one_unsigned.clone(), false));
let (check, check_sign) = minus_one.abs_sign();
assert_eq!((check, check_sign.to_bool()), (one_unsigned.clone(), true));
assert_eq!(T::from(0i8), T::zero());
assert_eq!(T::from(1i8), T::one());
assert_eq!(T::from(1i16), T::one());
assert_eq!(T::from(1i32), T::one());
assert_eq!(T::from(1i64), T::one());
assert_eq!(T::from(-1i64), T::zero() - T::one());
assert_eq!(zero.gcd(&zero), T::Unsigned::zero());
assert_eq!(zero.gcd_vartime(&zero), T::Unsigned::zero());
assert_eq!(one.gcd(&one), T::Unsigned::one());
assert_eq!(one.gcd_vartime(&one), T::Unsigned::one());
assert_eq!(two.gcd(&one), T::Unsigned::one());
assert_eq!(two.gcd_vartime(&one), T::Unsigned::one());
assert_eq!(minus_one.gcd(&one), T::Unsigned::one());
assert_eq!(minus_one.gcd_vartime(&one), T::Unsigned::one());
assert_eq!(zero.clone().div(&nz_one).into_option(), Some(zero.clone()));
assert_eq!(
zero.clone().div(&nz_minus_one).into_option(),
Some(zero.clone())
);
assert_eq!(zero.clone().div(&nz_two).into_option(), Some(zero.clone()));
assert_eq!(one.clone().div(&nz_one).into_option(), Some(one.clone()));
assert_eq!(
one.clone().div(&nz_minus_one).into_option(),
Some(minus_one.clone())
);
assert_eq!(one.clone().div(&nz_two).into_option(), Some(zero.clone()));
assert_eq!(
zero.clone().div(nz_one.clone()).into_option(),
Some(zero.clone())
);
assert_eq!(
zero.clone().div(nz_minus_one.clone()).into_option(),
Some(zero.clone())
);
assert_eq!(
zero.clone().div(nz_two.clone()).into_option(),
Some(zero.clone())
);
assert_eq!(
one.clone().div(nz_one.clone()).into_option(),
Some(one.clone())
);
assert_eq!(
one.clone().div(nz_minus_one.clone()).into_option(),
Some(minus_one.clone())
);
assert_eq!(
one.clone().div(nz_two.clone()).into_option(),
Some(zero.clone())
);
}
pub fn test_unsigned_monty_form<T: UnsignedWithMontyForm>() {
let modulus = Odd::new(T::from(17863u32)).unwrap();
let params = T::MontyForm::new_params_vartime(modulus);
assert_eq!(
<T::MontyForm as MontyForm>::Params::from(params.as_ref().clone()),
params,
);
assert_eq!(params, params.clone());
let zero = T::MontyForm::zero(¶ms);
assert!(zero.is_zero().to_bool_vartime());
assert!(!zero.is_one().to_bool_vartime());
let one = T::MontyForm::one(¶ms);
assert!(!one.is_zero().to_bool_vartime());
assert!(one.is_one().to_bool_vartime());
assert_eq!(zero.as_montgomery(), &T::zero());
assert_eq!(one.as_montgomery(), params.as_ref().one());
let mut z2 = one.clone();
z2.copy_montgomery_from(&zero);
assert_eq!(z2, zero);
let one2 =
<T::MontyForm as MontyForm>::from_montgomery(params.as_ref().one().clone(), ¶ms);
assert_eq!(one2, one);
assert_eq!(&one2.into_montgomery(), params.as_ref().one());
assert_eq!(zero.double(), zero);
assert_ne!(one.double(), one);
assert_eq!(one.double().div_by_2(), one);
let mut half = one.clone();
half.div_by_2_assign();
assert_ne!(half, one);
assert_eq!(half.double(), one);
assert_eq!(
<T::MontyForm as MontyForm>::lincomb_vartime(&[(&zero, &zero)]),
zero
);
assert_eq!(
<T::MontyForm as MontyForm>::lincomb_vartime(&[(&one, &one)]),
one
);
assert_eq!(
<T::MontyForm as MontyForm>::lincomb_vartime(&[(&one, &one), (&one, &one)]),
one.double()
);
assert_eq!(zero.ct_select(&one, Choice::FALSE), zero);
assert_eq!(zero.ct_select(&one, Choice::TRUE), one);
assert!(zero.invert().is_none().to_bool_vartime());
assert!(zero.invert_vartime().is_none().to_bool_vartime());
assert!(
one.invert()
.expect("inversion error")
.is_one()
.to_bool_vartime()
);
assert!(
one.invert_vartime()
.expect("inversion error")
.is_one()
.to_bool_vartime()
);
assert_eq!(one.clone() + one.clone(), one.double());
assert_eq!(one.clone() + &one, one.double());
let mut two = one.clone();
two += one.clone();
assert_eq!(two, one.double());
let mut two = one.clone();
two += &one;
assert_eq!(two, one.double());
assert_eq!(one.clone() - one.clone(), zero);
assert_eq!(one.clone() - &one, zero);
let mut check = one.double();
check -= one.clone();
assert_eq!(check, one);
let mut check = one.double();
check -= &one;
assert_eq!(check, one);
assert_eq!(zero.clone() * &zero, zero);
assert_eq!(zero.clone() * &one, zero);
assert_eq!(one.clone() * one.clone(), one);
let mut check = one.clone();
check *= one.clone();
assert_eq!(check, one);
let mut check = one.clone();
check *= &zero;
assert_eq!(check, zero);
assert_eq!(-zero.clone(), zero);
assert_ne!(-one.clone(), one);
assert_eq!(-(-one.clone()), one);
assert_eq!(zero.retrieve(), T::zero());
assert_eq!(one.retrieve(), T::one());
assert_eq!(zero.square(), zero);
assert_eq!(one.square(), one);
let mut check = one.double();
check.square_assign();
assert_eq!(check, one.double().double());
}
}