crypto_bigint/uint/
boxed.rsmod add;
mod add_mod;
mod bit_and;
mod bit_not;
mod bit_or;
mod bit_xor;
mod bits;
mod cmp;
mod ct;
pub(crate) mod div;
mod div_limb;
pub(crate) mod encoding;
mod from;
mod gcd;
mod inv_mod;
mod mul;
mod mul_mod;
mod neg;
mod neg_mod;
mod shl;
mod shr;
mod sqrt;
mod sub;
mod sub_mod;
#[cfg(feature = "rand_core")]
mod rand;
use crate::{modular::BoxedMontyForm, Integer, Limb, NonZero, Odd, Word, Zero};
use alloc::{boxed::Box, vec, vec::Vec};
use core::fmt;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
#[allow(clippy::derived_hash_with_manual_eq)]
#[derive(Clone, Hash)]
pub struct BoxedUint {
pub(crate) limbs: Box<[Limb]>,
}
impl BoxedUint {
fn limbs_for_precision(at_least_bits_precision: u32) -> usize {
((at_least_bits_precision + Limb::BITS - 1) / Limb::BITS) as usize
}
pub fn zero() -> Self {
Self {
limbs: vec![Limb::ZERO; 1].into(),
}
}
pub fn zero_with_precision(at_least_bits_precision: u32) -> Self {
vec![Limb::ZERO; Self::limbs_for_precision(at_least_bits_precision)].into()
}
pub fn one() -> Self {
Self {
limbs: vec![Limb::ONE; 1].into(),
}
}
pub fn one_with_precision(at_least_bits_precision: u32) -> Self {
let mut ret = Self::zero_with_precision(at_least_bits_precision);
ret.limbs[0] = Limb::ONE;
ret
}
pub fn is_zero(&self) -> Choice {
self.limbs
.iter()
.fold(Choice::from(1), |acc, limb| acc & limb.is_zero())
}
#[inline]
pub fn is_nonzero(&self) -> Choice {
!self.is_zero()
}
pub fn is_one(&self) -> Choice {
let mut iter = self.limbs.iter();
let choice = iter.next().copied().unwrap_or(Limb::ZERO).ct_eq(&Limb::ONE);
iter.fold(choice, |acc, limb| acc & limb.is_zero())
}
pub fn max(at_least_bits_precision: u32) -> Self {
vec![Limb::MAX; Self::limbs_for_precision(at_least_bits_precision)].into()
}
#[inline]
pub fn from_words(words: impl IntoIterator<Item = Word>) -> Self {
Self {
limbs: words.into_iter().map(Into::into).collect(),
}
}
#[inline]
pub fn to_words(&self) -> Box<[Word]> {
self.limbs.iter().copied().map(Into::into).collect()
}
pub fn as_words(&self) -> &[Word] {
#[allow(trivial_casts, unsafe_code)]
unsafe {
&*((&*self.limbs as *const [Limb]) as *const [Word])
}
}
pub fn as_words_mut(&mut self) -> &mut [Word] {
#[allow(trivial_casts, unsafe_code)]
unsafe {
&mut *((&mut *self.limbs as *mut [Limb]) as *mut [Word])
}
}
pub fn as_limbs(&self) -> &[Limb] {
self.limbs.as_ref()
}
pub fn as_limbs_mut(&mut self) -> &mut [Limb] {
self.limbs.as_mut()
}
pub fn to_limbs(&self) -> Box<[Limb]> {
self.limbs.clone()
}
pub fn into_limbs(self) -> Box<[Limb]> {
self.limbs
}
pub fn nlimbs(&self) -> usize {
self.limbs.len()
}
pub fn to_odd(&self) -> CtOption<Odd<Self>> {
let is_odd = self.is_odd();
CtOption::new(Odd(self.clone()), is_odd)
}
#[must_use]
pub fn widen(&self, at_least_bits_precision: u32) -> BoxedUint {
assert!(at_least_bits_precision >= self.bits_precision());
let mut ret = BoxedUint::zero_with_precision(at_least_bits_precision);
ret.limbs[..self.nlimbs()].copy_from_slice(&self.limbs);
ret
}
#[must_use]
pub fn shorten(&self, at_least_bits_precision: u32) -> BoxedUint {
assert!(at_least_bits_precision <= self.bits_precision());
let mut ret = BoxedUint::zero_with_precision(at_least_bits_precision);
let nlimbs = ret.nlimbs();
ret.limbs.copy_from_slice(&self.limbs[..nlimbs]);
ret
}
#[inline]
fn fold_limbs<F>(lhs: &Self, rhs: &Self, mut carry: Limb, f: F) -> (Self, Limb)
where
F: Fn(Limb, Limb, Limb) -> (Limb, Limb),
{
let nlimbs = cmp::max(lhs.nlimbs(), rhs.nlimbs());
let mut limbs = Vec::with_capacity(nlimbs);
for i in 0..nlimbs {
let &a = lhs.limbs.get(i).unwrap_or(&Limb::ZERO);
let &b = rhs.limbs.get(i).unwrap_or(&Limb::ZERO);
let (limb, c) = f(a, b, carry);
limbs.push(limb);
carry = c;
}
(limbs.into(), carry)
}
#[inline]
fn map_limbs<F>(lhs: &Self, rhs: &Self, f: F) -> Self
where
F: Fn(Limb, Limb) -> Limb,
{
let nlimbs = cmp::max(lhs.nlimbs(), rhs.nlimbs());
let mut limbs = Vec::with_capacity(nlimbs);
for i in 0..nlimbs {
let &a = lhs.limbs.get(i).unwrap_or(&Limb::ZERO);
let &b = rhs.limbs.get(i).unwrap_or(&Limb::ZERO);
limbs.push(f(a, b));
}
limbs.into()
}
pub(crate) fn conditional_set_zero(&mut self, choice: Choice) {
let nlimbs = self.nlimbs();
let limbs = self.limbs.as_mut();
for i in 0..nlimbs {
limbs[i] = Limb::conditional_select(&limbs[i], &Limb::ZERO, choice);
}
}
}
impl NonZero<BoxedUint> {
pub fn widen(&self, bits_precision: u32) -> Self {
NonZero(self.0.widen(bits_precision))
}
}
impl AsRef<[Word]> for BoxedUint {
fn as_ref(&self) -> &[Word] {
self.as_words()
}
}
impl AsMut<[Word]> for BoxedUint {
fn as_mut(&mut self) -> &mut [Word] {
self.as_words_mut()
}
}
impl AsRef<[Limb]> for BoxedUint {
fn as_ref(&self) -> &[Limb] {
self.as_limbs()
}
}
impl AsMut<[Limb]> for BoxedUint {
fn as_mut(&mut self) -> &mut [Limb] {
self.as_limbs_mut()
}
}
impl Default for BoxedUint {
fn default() -> Self {
Self::zero()
}
}
impl Integer for BoxedUint {
type Monty = BoxedMontyForm;
fn one() -> Self {
Self::one()
}
fn from_limb_like(limb: Limb, other: &Self) -> Self {
let mut ret = Self::zero_with_precision(other.bits_precision());
ret.limbs[0] = limb;
ret
}
fn nlimbs(&self) -> usize {
self.nlimbs()
}
}
impl Zero for BoxedUint {
fn zero() -> Self {
Self::zero()
}
fn is_zero(&self) -> Choice {
self.is_zero()
}
fn set_zero(&mut self) {
self.limbs.as_mut().fill(Limb::ZERO)
}
}
impl num_traits::Zero for BoxedUint {
fn zero() -> Self {
Self::zero()
}
fn is_zero(&self) -> bool {
self.is_zero().into()
}
}
impl num_traits::One for BoxedUint {
fn one() -> Self {
Self::one()
}
fn is_one(&self) -> bool {
self.is_one().into()
}
}
#[cfg(feature = "zeroize")]
impl Zeroize for BoxedUint {
fn zeroize(&mut self) {
self.limbs.zeroize();
}
}
impl fmt::Debug for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BoxedUint(0x{self:X})")
}
}
impl fmt::Display for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(self, f)
}
}
impl fmt::Binary for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.limbs.is_empty() {
return fmt::Binary::fmt(&Limb::ZERO, f);
}
for limb in self.limbs.iter().rev() {
fmt::Binary::fmt(limb, f)?;
}
Ok(())
}
}
impl fmt::LowerHex for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.limbs.is_empty() {
return fmt::LowerHex::fmt(&Limb::ZERO, f);
}
for limb in self.limbs.iter().rev() {
fmt::LowerHex::fmt(limb, f)?;
}
Ok(())
}
}
impl fmt::UpperHex for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.limbs.is_empty() {
return fmt::LowerHex::fmt(&Limb::ZERO, f);
}
for limb in self.limbs.iter().rev() {
fmt::UpperHex::fmt(limb, f)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::BoxedUint;
use crate::Word;
use alloc::vec::Vec;
#[test]
fn from_word_vec() {
let words: &[Word] = &[0, 1, 2, 3];
let uint = BoxedUint::from(Vec::from(words));
assert_eq!(uint.nlimbs(), 4);
assert_eq!(uint.as_words(), words);
}
}