mod add;
mod bits;
mod cmp;
mod ct;
mod div;
mod invert_mod;
mod mul;
mod shl;
mod shr;
mod slice;
mod sub;
use crate::{Choice, Limb, NonZero, Odd, Uint, Word};
use core::{
fmt,
ops::{Index, IndexMut},
ptr,
};
#[cfg(feature = "alloc")]
use {
crate::{BoxedUint, ToUnsigned},
alloc::borrow::ToOwned,
};
#[repr(transparent)]
#[derive(PartialEq, Eq)]
pub struct UintRef {
pub(crate) limbs: [Limb],
}
impl UintRef {
#[inline]
#[must_use]
pub const fn new(limbs: &[Limb]) -> &Self {
#[allow(unsafe_code)]
unsafe {
&*(ptr::from_ref(limbs) as *const UintRef)
}
}
#[inline]
pub const fn new_mut(limbs: &mut [Limb]) -> &mut Self {
#[allow(unsafe_code)]
unsafe {
&mut *(ptr::from_mut(limbs) as *mut UintRef)
}
}
pub const fn new_flattened_mut<const N: usize>(slice: &mut [[Limb; N]]) -> &mut Self {
let len = slice.len() * N;
#[allow(unsafe_code)]
let slice = unsafe { core::slice::from_raw_parts_mut(slice.as_mut_ptr().cast(), len) };
Self::new_mut(slice)
}
#[inline]
#[must_use]
pub const fn as_limbs(&self) -> &[Limb] {
&self.limbs
}
#[inline]
pub const fn as_mut_limbs(&mut self) -> &mut [Limb] {
&mut self.limbs
}
#[inline]
#[must_use]
pub const fn as_words(&self) -> &[Word] {
Limb::slice_as_words(&self.limbs)
}
#[inline]
pub const fn as_mut_words(&mut self) -> &mut [Word] {
Limb::slice_as_mut_words(&mut self.limbs)
}
#[inline]
#[must_use]
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &Limb> {
self.limbs.iter()
}
#[inline]
#[allow(dead_code)] pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Limb> {
self.limbs.iter_mut()
}
#[inline]
#[must_use]
pub const fn nlimbs(&self) -> usize {
self.limbs.len()
}
#[inline(always)]
pub const fn conditional_set_zero(&mut self, choice: Choice) {
let mut i = 0;
while i < self.nlimbs() {
self.limbs[i] = Limb::select(self.limbs[i], Limb::ZERO, choice);
i += 1;
}
}
#[inline(always)]
pub const fn conditional_set_one(&mut self, choice: Choice) {
self.limbs[0] = Limb::select(self.limbs[0], Limb::ONE, choice);
self.trailing_mut(1).conditional_set_zero(choice);
}
#[inline]
pub const fn conditional_set_max(&mut self, choice: Choice) {
let mut i = 0;
while i < self.nlimbs() {
self.limbs[i] = Limb::select(self.limbs[i], Limb::MAX, choice);
i += 1;
}
}
#[must_use]
pub const fn to_uint_resize<const LIMBS: usize>(&self) -> Uint<LIMBS> {
let mut out = Uint::ZERO;
let len = if self.nlimbs() > LIMBS {
LIMBS
} else {
self.nlimbs()
};
let mut i = 0;
while i < len {
out.limbs[i] = self.limbs[i];
i += 1;
}
out
}
#[inline]
#[must_use]
pub const fn as_nz_vartime(&self) -> Option<&NonZero<Self>> {
if self.is_zero_vartime() {
return None;
}
Some(NonZero::new_ref_unchecked(self))
}
#[inline]
#[must_use]
pub const fn as_odd_vartime(&self) -> Option<&Odd<Self>> {
if !self.is_odd().to_bool_vartime() {
return None;
}
Some(Odd::new_ref_unchecked(self))
}
cpubits::cpubits! {
32 => {
#[inline(always)]
pub(crate) const fn lowest_u64(&self) -> u64 {
debug_assert!(self.nlimbs() >= 1);
let mut ret = self.limbs[0].0 as u64;
if self.nlimbs() >= 2 {
ret |= (self.limbs[1].0 as u64) << 32;
}
ret
}
}
64 => {
#[inline(always)]
pub(crate) const fn lowest_u64(&self) -> u64 {
self.limbs[0].0
}
}
}
#[cfg(feature = "alloc")]
#[inline(always)]
pub(crate) fn fold_limbs<F>(&mut self, lhs: &Self, rhs: &Self, mut carry: Limb, f: F) -> Limb
where
F: Fn(Limb, Limb, Limb) -> (Limb, Limb),
{
for i in 0..self.nlimbs() {
let &a = lhs.limbs.get(i).unwrap_or(&Limb::ZERO);
let &b = rhs.limbs.get(i).unwrap_or(&Limb::ZERO);
(self.limbs[i], carry) = f(a, b, carry);
}
carry
}
#[cfg(feature = "alloc")]
#[inline(always)]
pub(crate) fn fold_limbs_assign<F>(&mut self, rhs: &UintRef, mut carry: Limb, f: F) -> Limb
where
F: Fn(Limb, Limb, Limb) -> (Limb, Limb),
{
for i in 0..self.nlimbs() {
let &b = rhs.limbs.get(i).unwrap_or(&Limb::ZERO);
(self.limbs[i], carry) = f(self.limbs[i], b, carry);
}
carry
}
}
impl AsRef<[Limb]> for UintRef {
#[inline]
fn as_ref(&self) -> &[Limb] {
self.as_limbs()
}
}
impl AsRef<UintRef> for UintRef {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl AsMut<[Limb]> for UintRef {
#[inline]
fn as_mut(&mut self) -> &mut [Limb] {
self.as_mut_limbs()
}
}
impl AsMut<UintRef> for UintRef {
#[inline]
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl Index<usize> for UintRef {
type Output = Limb;
#[inline]
fn index(&self, index: usize) -> &Limb {
self.limbs.index(index)
}
}
impl IndexMut<usize> for UintRef {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Limb {
self.limbs.index_mut(index)
}
}
#[cfg(feature = "alloc")]
impl ToOwned for UintRef {
type Owned = BoxedUint;
fn to_owned(&self) -> BoxedUint {
BoxedUint::from(self)
}
}
#[cfg(feature = "alloc")]
impl ToUnsigned for UintRef {
type Unsigned = BoxedUint;
fn to_unsigned(&self) -> Self::Unsigned {
BoxedUint::from(self)
}
fn to_unsigned_zero(&self) -> Self::Unsigned {
BoxedUint::zero_with_precision(self.bits_precision())
}
}
impl fmt::Debug for UintRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UintRef(0x{self:X})")
}
}
impl fmt::Binary for UintRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "0b")?;
}
for limb in self.iter().rev() {
write!(f, "{:0width$b}", &limb.0, width = Limb::BITS as usize)?;
}
Ok(())
}
}
impl fmt::Display for UintRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(self, f)
}
}
impl fmt::LowerHex for UintRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "0x")?;
}
for limb in self.iter().rev() {
write!(f, "{:0width$x}", &limb.0, width = Limb::BYTES * 2)?;
}
Ok(())
}
}
impl fmt::UpperHex for UintRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "0x")?;
}
for limb in self.iter().rev() {
write!(f, "{:0width$X}", &limb.0, width = Limb::BYTES * 2)?;
}
Ok(())
}
}