#![allow(clippy::duplicate_mod)]
use super::Rng;
use crate::Sign::*;
use crate::{BigInt, BigUint};
use crate::big_digit::BigDigit;
use crate::biguint::biguint_from_vec;
use core::mem::size_of;
use num_integer::Integer;
use num_traits::Zero;
pub trait BigRng: Rng {
fn random_biguint(&mut self, bit_size: u64) -> BigUint;
fn random_bigint(&mut self, bit_size: u64) -> BigInt;
fn random_biguint_below(&mut self, bound: &BigUint) -> BigUint;
fn random_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint;
fn random_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
#[deprecated(since = "0.5.0", note = "Renamed to `random_biguint`")]
fn gen_biguint(&mut self, bit_size: u64) -> BigUint {
self.random_biguint(bit_size)
}
#[deprecated(since = "0.5.0", note = "Renamed to `random_bigint`")]
fn gen_bigint(&mut self, bit_size: u64) -> BigInt {
self.random_bigint(bit_size)
}
#[deprecated(since = "0.5.0", note = "Renamed to `random_biguint_below`")]
fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint {
self.random_biguint_below(bound)
}
#[deprecated(since = "0.5.0", note = "Renamed to `random_biguint_range`")]
fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint {
self.random_biguint_range(lbound, ubound)
}
#[deprecated(since = "0.5.0", note = "Renamed to `random_bigint_range`")]
fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt {
self.random_bigint_range(lbound, ubound)
}
}
impl<R: Rng + ?Sized> BigRng for R {
fn random_biguint(&mut self, bit_size: u64) -> BigUint {
let mask = (1 << (bit_size % 8)) - 1;
let bytes = Integer::div_ceil(&bit_size, &8);
let bytes = usize::try_from(bytes).expect("capacity overflow");
let digits = Integer::div_ceil(&bit_size, &BigDigit::BITS.into());
let digits = usize::try_from(digits).unwrap();
debug_assert_eq!(digits, Integer::div_ceil(&bytes, &size_of::<BigDigit>()));
let mut data = vec![0 as BigDigit; digits];
{
let ptr = data.as_mut_ptr().cast::<u8>();
let slice = unsafe { core::slice::from_raw_parts_mut(ptr, bytes) };
self.fill_bytes(slice);
if mask != 0 {
slice[bytes - 1] &= mask;
}
}
#[cfg(not(target_endian = "little"))]
for digit in &mut data {
*digit = BigDigit::from_le(*digit);
}
biguint_from_vec(data)
}
fn random_bigint(&mut self, bit_size: u64) -> BigInt {
loop {
let biguint = self.random_biguint(bit_size);
let negative = (self.next_u32() as i32) < 0;
let sign = if biguint.is_zero() {
if negative {
continue;
}
NoSign
} else if negative {
Minus
} else {
Plus
};
return BigInt::from_biguint(sign, biguint);
}
}
fn random_biguint_below(&mut self, bound: &BigUint) -> BigUint {
assert!(!bound.is_zero());
let bits = bound.bits();
if bound.trailing_zeros() == Some(bits - 1) {
return self.random_biguint(bits - 1);
}
loop {
let n = self.random_biguint(bits);
if n < *bound {
return n;
}
}
}
fn random_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint {
assert!(*lbound < *ubound);
if lbound.is_zero() {
self.random_biguint_below(ubound)
} else {
lbound + self.random_biguint_below(&(ubound - lbound))
}
}
fn random_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt {
assert!(*lbound < *ubound);
if lbound.is_zero() {
BigInt::from(self.random_biguint_below(ubound.magnitude()))
} else if ubound.is_zero() {
lbound + BigInt::from(self.random_biguint_below(lbound.magnitude()))
} else {
let delta = ubound - lbound;
lbound + BigInt::from(self.random_biguint_below(delta.magnitude()))
}
}
}