177 lines
4.1 KiB
Rust
177 lines
4.1 KiB
Rust
//! Big integers are represented as an array of smaller CPU word-size integers
|
|
//! called "limbs".
|
|
|
|
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, Zero};
|
|
use core::fmt;
|
|
use subtle::{Choice, ConditionallySelectable};
|
|
|
|
#[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");
|
|
|
|
//
|
|
// 32-bit definitions
|
|
//
|
|
|
|
/// Inner integer type that the [`Limb`] newtype wraps.
|
|
#[cfg(target_pointer_width = "32")]
|
|
pub type Word = u32;
|
|
|
|
/// Unsigned wide integer type: double the width of [`Word`].
|
|
#[cfg(target_pointer_width = "32")]
|
|
pub type WideWord = u64;
|
|
|
|
//
|
|
// 64-bit definitions
|
|
//
|
|
|
|
/// Unsigned integer type that the [`Limb`] newtype wraps.
|
|
#[cfg(target_pointer_width = "64")]
|
|
pub type Word = u64;
|
|
|
|
/// Wide integer type: double the width of [`Word`].
|
|
#[cfg(target_pointer_width = "64")]
|
|
pub type WideWord = u128;
|
|
|
|
/// Highest bit in a [`Limb`].
|
|
pub(crate) const HI_BIT: usize = Limb::BITS - 1;
|
|
|
|
/// Big integers are represented as an array of smaller CPU word-size integers
|
|
/// called "limbs".
|
|
// Our PartialEq impl only differs from the default one by being constant-time, so this is safe
|
|
#[allow(clippy::derived_hash_with_manual_eq)]
|
|
#[derive(Copy, Clone, Default, Hash)]
|
|
#[repr(transparent)]
|
|
pub struct Limb(pub Word);
|
|
|
|
impl Limb {
|
|
/// The value `0`.
|
|
pub const ZERO: Self = Limb(0);
|
|
|
|
/// The value `1`.
|
|
pub const ONE: Self = Limb(1);
|
|
|
|
/// Maximum value this [`Limb`] can express.
|
|
pub const MAX: Self = Limb(Word::MAX);
|
|
|
|
// 32-bit
|
|
|
|
/// Size of the inner integer in bits.
|
|
#[cfg(target_pointer_width = "32")]
|
|
pub const BITS: usize = 32;
|
|
/// Size of the inner integer in bytes.
|
|
#[cfg(target_pointer_width = "32")]
|
|
pub const BYTES: usize = 4;
|
|
|
|
// 64-bit
|
|
|
|
/// Size of the inner integer in bits.
|
|
#[cfg(target_pointer_width = "64")]
|
|
pub const BITS: usize = 64;
|
|
/// Size of the inner integer in bytes.
|
|
#[cfg(target_pointer_width = "64")]
|
|
pub const BYTES: usize = 8;
|
|
}
|
|
|
|
impl Bounded for Limb {
|
|
const BITS: usize = Self::BITS;
|
|
const BYTES: usize = Self::BYTES;
|
|
}
|
|
|
|
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 Zero for Limb {
|
|
const ZERO: Self = Self::ZERO;
|
|
}
|
|
|
|
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::LowerHex for Limb {
|
|
#[inline]
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
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 {
|
|
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)");
|
|
}
|
|
}
|