use crate::prelude_internal::*;
use num_bigint::BigUint;
#[cfg(feature = "openssl")]
use openssl::bn::BigNum;
pub trait ExtractInteger {
fn extract_int_to_be_slice(&self, max: &[u8], out: &mut [u8]) -> Result<()>;
fn extract_int_to_be_vec(&self, max: &[u8]) -> Result<Vec<u8>> {
let mut ret = max.to_vec();
self.extract_int_to_be_slice(max, &mut ret)?;
Ok(ret)
}
fn extract_u64(&self, max: u64) -> Result<u64> {
let max = max.to_be_bytes();
let mut ret = max;
self.extract_int_to_be_slice(&max, &mut ret)?;
Ok(u64::from_be_bytes(ret))
}
fn extract_usize(&self, max: usize) -> Result<usize> {
let max = max.to_be_bytes();
let mut ret = max;
self.extract_int_to_be_slice(&max, &mut ret)?;
Ok(usize::from_be_bytes(ret))
}
fn extract_u32(&self, max: u32) -> Result<u32> {
Ok(self.extract_usize(max as usize)?.try_into().unwrap())
}
fn extract_bool(&self) -> Result<bool> {
Ok(self.extract_u32(1)? == 1)
}
fn extract_big_uint(&self, max: &BigUint) -> Result<BigUint> {
Ok(BigUint::from_bytes_be(
&self.extract_int_to_be_vec(&max.to_bytes_be())?,
))
}
#[cfg(feature = "openssl")]
fn extract_big_num(&self, max: &BigNum) -> Result<BigNum> {
Ok(BigNum::from_slice(
&self.extract_int_to_be_vec(&max.to_vec())?,
)?)
}
}
impl ExtractInteger for Secret {
fn extract_int_to_be_slice(&self, mut max: &[u8], mut out: &mut [u8]) -> Result<()> {
if max.len() != out.len() {
bail!("slices must be the same size");
}
let mut secret = self.clone();
while max.first() == Some(&0) {
out[0] = 0;
out = &mut out[1..];
max = &max[1..];
}
if max.is_empty() {
return Ok(());
}
fn enclosing_mask_u8(mut x: u8) -> u8 {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x
}
let enclosing_mask = enclosing_mask_u8(max[0]);
loop {
secret.mutate_with_salt(max)?;
secret.extract_bytes_into(out)?;
out[0] &= enclosing_mask;
if (out as &[u8]) <= max {
return Ok(());
}
}
}
}