summaryrefslogtreecommitdiffstats
path: root/vendor/crypto-bigint/src/uint.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/crypto-bigint/src/uint.rs')
-rw-r--r--vendor/crypto-bigint/src/uint.rs491
1 files changed, 491 insertions, 0 deletions
diff --git a/vendor/crypto-bigint/src/uint.rs b/vendor/crypto-bigint/src/uint.rs
new file mode 100644
index 0000000..a644496
--- /dev/null
+++ b/vendor/crypto-bigint/src/uint.rs
@@ -0,0 +1,491 @@
+//! Stack-allocated big unsigned integers.
+
+#![allow(clippy::needless_range_loop, clippy::many_single_char_names)]
+
+#[macro_use]
+mod macros;
+
+mod add;
+mod add_mod;
+mod bit_and;
+mod bit_not;
+mod bit_or;
+mod bit_xor;
+mod bits;
+mod cmp;
+mod concat;
+mod div;
+pub(crate) mod div_limb;
+mod encoding;
+mod from;
+mod inv_mod;
+mod mul;
+mod mul_mod;
+mod neg;
+mod neg_mod;
+mod resize;
+mod shl;
+mod shr;
+mod split;
+mod sqrt;
+mod sub;
+mod sub_mod;
+
+/// Implements modular arithmetic for constant moduli.
+pub mod modular;
+
+#[cfg(feature = "generic-array")]
+mod array;
+
+#[cfg(feature = "rand_core")]
+mod rand;
+
+use crate::{Bounded, Encoding, Integer, Limb, Word, Zero};
+use core::fmt;
+use subtle::{Choice, ConditionallySelectable};
+
+#[cfg(feature = "serde")]
+use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
+
+#[cfg(feature = "zeroize")]
+use zeroize::DefaultIsZeroes;
+
+/// Stack-allocated big unsigned integer.
+///
+/// Generic over the given number of `LIMBS`
+///
+/// # Encoding support
+/// This type supports many different types of encodings, either via the
+/// [`Encoding`][`crate::Encoding`] trait or various `const fn` decoding and
+/// encoding functions that can be used with [`Uint`] constants.
+///
+/// Optional crate features for encoding (off-by-default):
+/// - `generic-array`: enables [`ArrayEncoding`][`crate::ArrayEncoding`] trait which can be used to
+/// [`Uint`] as `GenericArray<u8, N>` and a [`ArrayDecoding`][`crate::ArrayDecoding`] trait which
+/// can be used to `GenericArray<u8, N>` as [`Uint`].
+/// - `rlp`: support for [Recursive Length Prefix (RLP)][RLP] encoding.
+///
+/// [RLP]: https://eth.wiki/fundamentals/rlp
+// TODO(tarcieri): make generic around a specified number of bits.
+// 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, Hash)]
+pub struct Uint<const LIMBS: usize> {
+ /// Inner limb array. Stored from least significant to most significant.
+ limbs: [Limb; LIMBS],
+}
+
+impl<const LIMBS: usize> Uint<LIMBS> {
+ /// The value `0`.
+ pub const ZERO: Self = Self::from_u8(0);
+
+ /// The value `1`.
+ pub const ONE: Self = Self::from_u8(1);
+
+ /// Maximum value this [`Uint`] can express.
+ pub const MAX: Self = Self {
+ limbs: [Limb::MAX; LIMBS],
+ };
+
+ /// Total size of the represented integer in bits.
+ pub const BITS: usize = LIMBS * Limb::BITS;
+
+ /// Bit size of `BITS`.
+ // Note: assumes the type of `BITS` is `usize`. Any way to assert that?
+ pub(crate) const LOG2_BITS: usize = (usize::BITS - Self::BITS.leading_zeros()) as usize;
+
+ /// Total size of the represented integer in bytes.
+ pub const BYTES: usize = LIMBS * Limb::BYTES;
+
+ /// The number of limbs used on this platform.
+ pub const LIMBS: usize = LIMBS;
+
+ /// Const-friendly [`Uint`] constructor.
+ pub const fn new(limbs: [Limb; LIMBS]) -> Self {
+ Self { limbs }
+ }
+
+ /// Create a [`Uint`] from an array of [`Word`]s (i.e. word-sized unsigned
+ /// integers).
+ #[inline]
+ pub const fn from_words(arr: [Word; LIMBS]) -> Self {
+ let mut limbs = [Limb::ZERO; LIMBS];
+ let mut i = 0;
+
+ while i < LIMBS {
+ limbs[i] = Limb(arr[i]);
+ i += 1;
+ }
+
+ Self { limbs }
+ }
+
+ /// Create an array of [`Word`]s (i.e. word-sized unsigned integers) from
+ /// a [`Uint`].
+ #[inline]
+ pub const fn to_words(self) -> [Word; LIMBS] {
+ let mut arr = [0; LIMBS];
+ let mut i = 0;
+
+ while i < LIMBS {
+ arr[i] = self.limbs[i].0;
+ i += 1;
+ }
+
+ arr
+ }
+
+ /// Borrow the inner limbs as an array of [`Word`]s.
+ pub const fn as_words(&self) -> &[Word; LIMBS] {
+ // SAFETY: `Limb` is a `repr(transparent)` newtype for `Word`
+ #[allow(trivial_casts, unsafe_code)]
+ unsafe {
+ &*((&self.limbs as *const _) as *const [Word; LIMBS])
+ }
+ }
+
+ /// Borrow the inner limbs as a mutable array of [`Word`]s.
+ pub fn as_words_mut(&mut self) -> &mut [Word; LIMBS] {
+ // SAFETY: `Limb` is a `repr(transparent)` newtype for `Word`
+ #[allow(trivial_casts, unsafe_code)]
+ unsafe {
+ &mut *((&mut self.limbs as *mut _) as *mut [Word; LIMBS])
+ }
+ }
+
+ /// Borrow the limbs of this [`Uint`].
+ pub const fn as_limbs(&self) -> &[Limb; LIMBS] {
+ &self.limbs
+ }
+
+ /// Borrow the limbs of this [`Uint`] mutably.
+ pub fn as_limbs_mut(&mut self) -> &mut [Limb; LIMBS] {
+ &mut self.limbs
+ }
+
+ /// Convert this [`Uint`] into its inner limbs.
+ pub const fn to_limbs(self) -> [Limb; LIMBS] {
+ self.limbs
+ }
+}
+
+impl<const LIMBS: usize> AsRef<[Word; LIMBS]> for Uint<LIMBS> {
+ fn as_ref(&self) -> &[Word; LIMBS] {
+ self.as_words()
+ }
+}
+
+impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Uint<LIMBS> {
+ fn as_mut(&mut self) -> &mut [Word; LIMBS] {
+ self.as_words_mut()
+ }
+}
+
+impl<const LIMBS: usize> AsRef<[Limb]> for Uint<LIMBS> {
+ fn as_ref(&self) -> &[Limb] {
+ self.as_limbs()
+ }
+}
+
+impl<const LIMBS: usize> AsMut<[Limb]> for Uint<LIMBS> {
+ fn as_mut(&mut self) -> &mut [Limb] {
+ self.as_limbs_mut()
+ }
+}
+
+impl<const LIMBS: usize> ConditionallySelectable for Uint<LIMBS> {
+ fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+ let mut limbs = [Limb::ZERO; LIMBS];
+
+ for i in 0..LIMBS {
+ limbs[i] = Limb::conditional_select(&a.limbs[i], &b.limbs[i], choice);
+ }
+
+ Self { limbs }
+ }
+}
+
+impl<const LIMBS: usize> Default for Uint<LIMBS> {
+ fn default() -> Self {
+ Self::ZERO
+ }
+}
+
+impl<const LIMBS: usize> Integer for Uint<LIMBS> {
+ const ONE: Self = Self::ONE;
+ const MAX: Self = Self::MAX;
+ const BITS: usize = Self::BITS;
+ const BYTES: usize = Self::BYTES;
+ const LIMBS: usize = Self::LIMBS;
+
+ fn is_odd(&self) -> Choice {
+ self.limbs
+ .first()
+ .map(|limb| limb.is_odd())
+ .unwrap_or_else(|| Choice::from(0))
+ }
+}
+
+impl<const LIMBS: usize> Zero for Uint<LIMBS> {
+ const ZERO: Self = Self::ZERO;
+}
+
+impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
+ const BITS: usize = Self::BITS;
+ const BYTES: usize = Self::BYTES;
+}
+
+impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Uint(0x{self:X})")
+ }
+}
+
+impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::UpperHex::fmt(self, f)
+ }
+}
+
+impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ for limb in self.limbs.iter().rev() {
+ fmt::LowerHex::fmt(limb, f)?;
+ }
+ Ok(())
+ }
+}
+
+impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ for limb in self.limbs.iter().rev() {
+ fmt::UpperHex::fmt(limb, f)?;
+ }
+ Ok(())
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<'de, const LIMBS: usize> Deserialize<'de> for Uint<LIMBS>
+where
+ Uint<LIMBS>: Encoding,
+{
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let mut buffer = Self::ZERO.to_le_bytes();
+ serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?;
+
+ Ok(Self::from_le_bytes(buffer))
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<const LIMBS: usize> Serialize for Uint<LIMBS>
+where
+ Uint<LIMBS>: Encoding,
+{
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
+ }
+}
+
+#[cfg(feature = "zeroize")]
+impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
+
+// TODO(tarcieri): use `generic_const_exprs` when stable to make generic around bits.
+impl_uint_aliases! {
+ (U64, 64, "64-bit"),
+ (U128, 128, "128-bit"),
+ (U192, 192, "192-bit"),
+ (U256, 256, "256-bit"),
+ (U320, 320, "320-bit"),
+ (U384, 384, "384-bit"),
+ (U448, 448, "448-bit"),
+ (U512, 512, "512-bit"),
+ (U576, 576, "576-bit"),
+ (U640, 640, "640-bit"),
+ (U704, 704, "704-bit"),
+ (U768, 768, "768-bit"),
+ (U832, 832, "832-bit"),
+ (U896, 896, "896-bit"),
+ (U960, 960, "960-bit"),
+ (U1024, 1024, "1024-bit"),
+ (U1280, 1280, "1280-bit"),
+ (U1536, 1536, "1536-bit"),
+ (U1792, 1792, "1792-bit"),
+ (U2048, 2048, "2048-bit"),
+ (U3072, 3072, "3072-bit"),
+ (U3584, 3584, "3584-bit"),
+ (U4096, 4096, "4096-bit"),
+ (U4224, 4224, "4224-bit"),
+ (U4352, 4352, "4352-bit"),
+ (U6144, 6144, "6144-bit"),
+ (U8192, 8192, "8192-bit"),
+ (U16384, 16384, "16384-bit"),
+ (U32768, 32768, "32768-bit")
+}
+
+#[cfg(target_pointer_width = "32")]
+impl_uint_aliases! {
+ (U224, 224, "224-bit"), // For NIST P-224
+ (U544, 544, "544-bit") // For NIST P-521
+}
+
+#[cfg(target_pointer_width = "32")]
+impl_uint_concat_split_even! {
+ U64,
+}
+
+// Implement concat and split for double-width Uint sizes: these should be
+// multiples of 128 bits.
+impl_uint_concat_split_even! {
+ U128,
+ U256,
+ U384,
+ U512,
+ U640,
+ U768,
+ U896,
+ U1024,
+ U1280,
+ U1536,
+ U1792,
+ U2048,
+ U3072,
+ U3584,
+ U4096,
+ U4224,
+ U4352,
+ U6144,
+ U8192,
+ U16384,
+}
+
+// Implement mixed concat and split for combinations not implemented by
+// impl_uint_concat_split_even. The numbers represent the size of each
+// component Uint in multiple of 64 bits. For example,
+// (U256, [1, 3]) will allow splitting U256 into (U64, U192) as well as
+// (U192, U64), while the (U128, U128) combination is already covered.
+impl_uint_concat_split_mixed! {
+ (U192, [1, 2]),
+ (U256, [1, 3]),
+ (U320, [1, 2, 3, 4]),
+ (U384, [1, 2, 4, 5]),
+ (U448, [1, 2, 3, 4, 5, 6]),
+ (U512, [1, 2, 3, 5, 6, 7]),
+ (U576, [1, 2, 3, 4, 5, 6, 7, 8]),
+ (U640, [1, 2, 3, 4, 6, 7, 8, 9]),
+ (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
+ (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
+ (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
+ (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
+ (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
+ (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
+}
+
+#[cfg(feature = "extra-sizes")]
+mod extra_sizes;
+#[cfg(feature = "extra-sizes")]
+pub use extra_sizes::*;
+
+#[cfg(test)]
+#[allow(clippy::unwrap_used)]
+mod tests {
+ use crate::{Encoding, U128};
+ use subtle::ConditionallySelectable;
+
+ #[cfg(feature = "alloc")]
+ use alloc::format;
+
+ #[cfg(feature = "serde")]
+ use crate::U64;
+
+ #[cfg(feature = "alloc")]
+ #[test]
+ fn debug() {
+ let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
+ let n = U128::from_be_hex(hex);
+
+ assert_eq!(
+ format!("{:?}", n),
+ "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)"
+ );
+ }
+
+ #[cfg(feature = "alloc")]
+ #[test]
+ fn display() {
+ let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD";
+ let n = U128::from_be_hex(hex);
+
+ use alloc::string::ToString;
+ assert_eq!(hex, n.to_string());
+
+ let hex = "AAAAAAAABBBBBBBB0000000000000000";
+ let n = U128::from_be_hex(hex);
+ assert_eq!(hex, n.to_string());
+
+ let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD";
+ let n = U128::from_be_hex(hex);
+ assert_eq!(hex, n.to_string());
+
+ let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD";
+ let n = U128::from_be_hex(hex);
+ assert_eq!(hex, n.to_string());
+ }
+
+ #[test]
+ fn from_bytes() {
+ let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD");
+
+ let be_bytes = a.to_be_bytes();
+ let le_bytes = a.to_le_bytes();
+ for i in 0..16 {
+ assert_eq!(le_bytes[i], be_bytes[15 - i]);
+ }
+
+ let a_from_be = U128::from_be_bytes(be_bytes);
+ let a_from_le = U128::from_le_bytes(le_bytes);
+ assert_eq!(a_from_be, a_from_le);
+ assert_eq!(a_from_be, a);
+ }
+
+ #[test]
+ fn conditional_select() {
+ let a = U128::from_be_hex("00002222444466668888AAAACCCCEEEE");
+ let b = U128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
+
+ let select_0 = U128::conditional_select(&a, &b, 0.into());
+ assert_eq!(a, select_0);
+
+ let select_1 = U128::conditional_select(&a, &b, 1.into());
+ assert_eq!(b, select_1);
+ }
+
+ #[cfg(feature = "serde")]
+ #[test]
+ fn serde() {
+ const TEST: U64 = U64::from_u64(0x0011223344556677);
+
+ let serialized = bincode::serialize(&TEST).unwrap();
+ let deserialized: U64 = bincode::deserialize(&serialized).unwrap();
+
+ assert_eq!(TEST, deserialized);
+ }
+
+ #[cfg(feature = "serde")]
+ #[test]
+ fn serde_owned() {
+ const TEST: U64 = U64::from_u64(0x0011223344556677);
+
+ let serialized = bincode::serialize(&TEST).unwrap();
+ let deserialized: U64 = bincode::deserialize_from(serialized.as_slice()).unwrap();
+
+ assert_eq!(TEST, deserialized);
+ }
+}