//! Randomization of big integers use rand::distributions::uniform::{SampleUniform, UniformSampler}; use rand::prelude::*; use rand::AsByteSliceMut; use BigInt; use BigUint; use Sign::*; use big_digit::BigDigit; use bigint::{into_magnitude, magnitude}; use integer::Integer; use traits::Zero; /// A trait for sampling random big integers. /// /// The `rand` feature must be enabled to use this. See crate-level documentation for details. pub trait RandBigInt { /// Generate a random `BigUint` of the given bit size. fn gen_biguint(&mut self, bit_size: usize) -> BigUint; /// Generate a random BigInt of the given bit size. fn gen_bigint(&mut self, bit_size: usize) -> BigInt; /// Generate a random `BigUint` less than the given bound. Fails /// when the bound is zero. fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint; /// Generate a random `BigUint` within the given range. The lower /// bound is inclusive; the upper bound is exclusive. Fails when /// the upper bound is not greater than the lower bound. fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint; /// Generate a random `BigInt` within the given range. The lower /// bound is inclusive; the upper bound is exclusive. Fails when /// the upper bound is not greater than the lower bound. fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt; } impl RandBigInt for R { fn gen_biguint(&mut self, bit_size: usize) -> BigUint { use super::big_digit::BITS; let (digits, rem) = bit_size.div_rem(&BITS); let mut data = vec![BigDigit::default(); digits + (rem > 0) as usize]; // `fill_bytes` is faster than many `gen::` calls self.fill_bytes(data[..].as_byte_slice_mut()); // Swap bytes per the `Rng::fill` source. This might be // unnecessary if reproducibility across architectures is not // desired. data.to_le(); if rem > 0 { data[digits] >>= BITS - rem; } BigUint::new(data) } fn gen_bigint(&mut self, bit_size: usize) -> BigInt { loop { // Generate a random BigUint... let biguint = self.gen_biguint(bit_size); // ...and then randomly assign it a Sign... let sign = if biguint.is_zero() { // ...except that if the BigUint is zero, we need to try // again with probability 0.5. This is because otherwise, // the probability of generating a zero BigInt would be // double that of any other number. if self.gen() { continue; } else { NoSign } } else if self.gen() { Plus } else { Minus }; return BigInt::from_biguint(sign, biguint); } } fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint { assert!(!bound.is_zero()); let bits = bound.bits(); loop { let n = self.gen_biguint(bits); if n < *bound { return n; } } } fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint { assert!(*lbound < *ubound); if lbound.is_zero() { self.gen_biguint_below(ubound) } else { lbound + self.gen_biguint_below(&(ubound - lbound)) } } fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt { assert!(*lbound < *ubound); if lbound.is_zero() { BigInt::from(self.gen_biguint_below(magnitude(&ubound))) } else if ubound.is_zero() { lbound + BigInt::from(self.gen_biguint_below(magnitude(&lbound))) } else { let delta = ubound - lbound; lbound + BigInt::from(self.gen_biguint_below(magnitude(&delta))) } } } /// The back-end implementing rand's `UniformSampler` for `BigUint`. #[derive(Clone, Debug)] pub struct UniformBigUint { base: BigUint, len: BigUint, } impl UniformSampler for UniformBigUint { type X = BigUint; #[inline] fn new(low: Self::X, high: Self::X) -> Self { assert!(low < high); UniformBigUint { len: high - &low, base: low, } } #[inline] fn new_inclusive(low: Self::X, high: Self::X) -> Self { assert!(low <= high); Self::new(low, high + 1u32) } #[inline] fn sample(&self, rng: &mut R) -> Self::X { &self.base + rng.gen_biguint_below(&self.len) } #[inline] fn sample_single(low: Self::X, high: Self::X, rng: &mut R) -> Self::X { rng.gen_biguint_range(&low, &high) } } impl SampleUniform for BigUint { type Sampler = UniformBigUint; } /// The back-end implementing rand's `UniformSampler` for `BigInt`. #[derive(Clone, Debug)] pub struct UniformBigInt { base: BigInt, len: BigUint, } impl UniformSampler for UniformBigInt { type X = BigInt; #[inline] fn new(low: Self::X, high: Self::X) -> Self { assert!(low < high); UniformBigInt { len: into_magnitude(high - &low), base: low, } } #[inline] fn new_inclusive(low: Self::X, high: Self::X) -> Self { assert!(low <= high); Self::new(low, high + 1u32) } #[inline] fn sample(&self, rng: &mut R) -> Self::X { &self.base + BigInt::from(rng.gen_biguint_below(&self.len)) } #[inline] fn sample_single(low: Self::X, high: Self::X, rng: &mut R) -> Self::X { rng.gen_bigint_range(&low, &high) } } impl SampleUniform for BigInt { type Sampler = UniformBigInt; } /// A random distribution for `BigUint` and `BigInt` values of a particular bit size. /// /// The `rand` feature must be enabled to use this. See crate-level documentation for details. #[derive(Clone, Copy, Debug)] pub struct RandomBits { bits: usize, } impl RandomBits { #[inline] pub fn new(bits: usize) -> RandomBits { RandomBits { bits } } } impl Distribution for RandomBits { #[inline] fn sample(&self, rng: &mut R) -> BigUint { rng.gen_biguint(self.bits) } } impl Distribution for RandomBits { #[inline] fn sample(&self, rng: &mut R) -> BigInt { rng.gen_bigint(self.bits) } }