mod add;
mod bit_and;
mod bit_not;
mod bit_or;
mod bit_xor;
mod bits;
mod cmp;
mod encoding;
mod from;
mod mul;
mod neg;
mod shl;
mod shr;
mod sub;
#[cfg(feature = "rand_core")]
mod rand;
use crate::{Bounded, ConstCtOption, ConstOne, ConstZero, Constants, NonZero, One, Zero};
use core::fmt;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
#[cfg(feature = "serde")]
use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
compile_error!("this crate builds on 32-bit and 64-bit platforms only");
#[cfg(target_pointer_width = "32")]
pub type Word = u32;
#[cfg(target_pointer_width = "32")]
pub type WideWord = u64;
#[cfg(target_pointer_width = "64")]
pub type Word = u64;
#[cfg(target_pointer_width = "64")]
pub type WideWord = u128;
#[allow(clippy::derived_hash_with_manual_eq)]
#[derive(Copy, Clone, Default, Hash)]
#[repr(transparent)]
pub struct Limb(pub Word);
impl Limb {
pub const ZERO: Self = Limb(0);
pub const ONE: Self = Limb(1);
pub const MAX: Self = Limb(Word::MAX);
pub(crate) const HI_BIT: u32 = Limb::BITS - 1;
#[cfg(target_pointer_width = "32")]
pub const BITS: u32 = 32;
#[cfg(target_pointer_width = "32")]
pub const BYTES: usize = 4;
#[cfg(target_pointer_width = "64")]
pub const BITS: u32 = 64;
#[cfg(target_pointer_width = "64")]
pub const BYTES: usize = 8;
pub const LOG2_BITS: u32 = u32::BITS - (Self::BITS - 1).leading_zeros();
pub const fn to_nz(self) -> ConstCtOption<NonZero<Self>> {
ConstCtOption::new(NonZero(self), self.is_nonzero())
}
}
impl Bounded for Limb {
const BITS: u32 = Self::BITS;
const BYTES: usize = Self::BYTES;
}
impl Constants for Limb {
const MAX: Self = Self::MAX;
}
impl ConditionallySelectable for Limb {
#[inline]
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self(Word::conditional_select(&a.0, &b.0, choice))
}
}
impl ConstZero for Limb {
const ZERO: Self = Self::ZERO;
}
impl ConstOne for Limb {
const ONE: Self = Self::ONE;
}
impl Zero for Limb {
#[inline(always)]
fn zero() -> Self {
Self::ZERO
}
}
impl One for Limb {
#[inline(always)]
fn one() -> Self {
Self::ONE
}
}
impl num_traits::Zero for Limb {
fn zero() -> Self {
Self::ZERO
}
fn is_zero(&self) -> bool {
self.ct_eq(&Self::ZERO).into()
}
}
impl num_traits::One for Limb {
fn one() -> Self {
Self::ONE
}
fn is_one(&self) -> bool {
self.ct_eq(&Self::ONE).into()
}
}
impl fmt::Debug for Limb {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Limb(0x{self:X})")
}
}
impl fmt::Display for Limb {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(self, f)
}
}
impl fmt::Binary for Limb {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "0b")?;
}
write!(f, "{:0width$b}", &self.0, width = Self::BITS as usize)
}
}
impl fmt::LowerHex for Limb {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "0x")?;
}
write!(f, "{:0width$x}", &self.0, width = Self::BYTES * 2)
}
}
impl fmt::UpperHex for Limb {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "0x")?;
}
write!(f, "{:0width$X}", &self.0, width = Self::BYTES * 2)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Limb {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(Word::deserialize(deserializer)?))
}
}
#[cfg(feature = "serde")]
impl Serialize for Limb {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
#[cfg(feature = "zeroize")]
impl zeroize::DefaultIsZeroes for Limb {}
#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
use {super::Limb, alloc::format};
#[cfg(feature = "alloc")]
#[test]
fn debug() {
#[cfg(target_pointer_width = "32")]
assert_eq!(format!("{:?}", Limb(42)), "Limb(0x0000002A)");
#[cfg(target_pointer_width = "64")]
assert_eq!(format!("{:?}", Limb(42)), "Limb(0x000000000000002A)");
}
}