#![deny(warnings)]
#![allow(clippy::upper_case_acronyms)]
use crate::{fs::File, io::Write, path::PathBuf, prelude::*, rand::SeedableRng};
use base64::engine::fast_portable::{FastPortable, FastPortableConfig};
use digest::generic_array::typenum::U64;
use digest::Digest;
use rand_chacha::ChaCha20Rng;
const BASE64_PADDING_CONFIG: FastPortableConfig = FastPortableConfig::new()
.with_decode_padding_mode(base64::engine::DecodePaddingMode::Indifferent);
const BASE64_ENGINE: FastPortable =
FastPortable::from(&base64::alphabet::URL_SAFE, BASE64_PADDING_CONFIG);
pub fn u8_be_slice_to_u64(slice: &[u8]) -> u64 {
let mut a = [0u8; 8];
a.copy_from_slice(slice);
u64::from_be_bytes(a)
}
pub fn u8_le_slice_to_u64(slice: &[u8]) -> u64 {
let mut a = [0u8; 8];
a.copy_from_slice(slice);
u64::from_le_bytes(a)
}
pub fn u8_be_slice_to_u32(slice: &[u8]) -> u32 {
let mut a = [0u8; 4];
a.copy_from_slice(slice);
u32::from_be_bytes(a)
}
pub fn u8_le_slice_to_u32(slice: &[u8]) -> u32 {
let mut a = [0u8; 4];
a.copy_from_slice(slice);
u32::from_le_bytes(a)
}
pub fn min_greater_equal_power_of_two(n: u32) -> u32 {
2.0f64.powi((n as f64).log2().ceil() as i32) as u32
}
pub fn u64_to_u32_pair(x: u64) -> (u32, u32) {
((x & 0xFFFF_FFFF) as u32, (x >> 32) as u32)
}
pub fn b64enc<T: ?Sized + AsRef<[u8]>>(input: &T) -> String {
base64::encode_engine(input, &BASE64_ENGINE)
}
pub fn b64dec<T: ?Sized + AsRef<[u8]>>(input: &T) -> Result<Vec<u8>> {
base64::decode_engine(input, &BASE64_ENGINE).c(d!())
}
pub fn derive_prng_from_hash<D>(hash: D) -> ChaCha20Rng
where
D: Digest<OutputSize = U64> + Default,
{
const SEED_SIZE: usize = 32;
let mut seed: [u8; SEED_SIZE] = [0; SEED_SIZE];
let result = hash.finalize();
seed.copy_from_slice(&result[0..SEED_SIZE]);
ChaCha20Rng::from_seed(seed)
}
pub fn shift_u8_vec(r: &mut Vec<u8>) {
let mut next = 0u8;
for e in r.iter_mut().rev() {
let prev = *e;
*e = (*e >> 1) | next;
next = (prev % 2) << 7;
}
if *r.last().unwrap() == 0 && r.len() > 1 {
r.pop();
}
}
pub fn u64_lsf_to_bytes(slice: &[u64]) -> Vec<u8> {
let mut bytes = vec![];
for a in slice {
bytes.extend(&a.to_le_bytes()[..])
}
while let Some(b) = bytes.last() {
if *b != 0 {
break;
}
bytes.pop();
}
bytes
}
pub fn u64_limbs_from_bytes(slice: &[u8]) -> Vec<u64> {
let mut r: Vec<u64> = vec![];
let n = slice.len() / 8;
for i in 0..n {
let mut u64_bytes = [0u8; 8];
u64_bytes.copy_from_slice(&slice[i * 8..(i + 1) * 8]);
r.push(u64::from_le_bytes(u64_bytes));
}
if slice.len() % 8 != 0 {
let bytes = &slice[n * 8..];
let mut u64_bytes = [0u8; 8];
u64_bytes[..bytes.len()].copy_from_slice(bytes);
r.push(u64::from_le_bytes(u64_bytes));
}
r
}
pub fn save_to_file(params_ser: &[u8], out_filename: PathBuf) {
let filename = out_filename.to_str().unwrap();
let mut f = File::create(&filename).expect("Unable to create file");
f.write_all(params_ser).expect("Unable to write data");
println!("Public parameters written in file {}.", filename);
}
#[macro_export]
macro_rules! not_matches {
($expression:expr, $( $pattern:pat_param )|+ $( if $guard: expr )?) => {
match $expression {
$( $pattern )|+ $( if $guard )? => false,
_ => true
}
}
}
#[cfg(test)]
mod test {
#[test]
fn test_shift_u8_vec() {
let mut v = vec![0];
super::shift_u8_vec(&mut v);
assert_eq!(v, vec![0]);
let mut v = vec![1];
super::shift_u8_vec(&mut v);
assert_eq!(v, vec![0]);
let mut v = vec![2];
super::shift_u8_vec(&mut v);
assert_eq!(v, vec![1]);
let mut v = vec![255];
super::shift_u8_vec(&mut v);
assert_eq!(v, vec![127]);
let mut v = vec![0, 1];
super::shift_u8_vec(&mut v);
assert_eq!(v, vec![128]);
let mut v = vec![0, 0, 1];
super::shift_u8_vec(&mut v);
assert_eq!(v, vec![0, 128]);
}
#[test]
fn test_u8_be_slice_to_u32() {
let array = [0xFA_u8, 0x01, 0xC6, 0x73];
let n = super::u8_be_slice_to_u32(&array);
assert_eq!(0xFA01C673, n);
}
#[test]
fn u8_be_slice_to_u64() {
let array = [0xFA_u8, 0x01, 0xC6, 0x73, 0x22, 0xE4, 0x98, 0xA2];
let n = super::u8_be_slice_to_u64(&array);
assert_eq!(0xFA01C67322E498A2, n);
}
#[test]
fn u64_lsf_to_bytes() {
let n = vec![1, 2, 3, 4, 5];
let bytes = super::u64_lsf_to_bytes(&n);
assert!(bytes.len() < n.len() * 8);
let nn = super::u64_limbs_from_bytes(&bytes);
assert_eq!(n, nn);
}
#[test]
fn min_greater_equal_power_of_two() {
assert_eq!(16, super::min_greater_equal_power_of_two(16));
assert_eq!(16, super::min_greater_equal_power_of_two(15));
assert_eq!(16, super::min_greater_equal_power_of_two(9));
assert_eq!(8, super::min_greater_equal_power_of_two(8));
assert_eq!(8, super::min_greater_equal_power_of_two(6));
assert_eq!(8, super::min_greater_equal_power_of_two(5));
assert_eq!(4, super::min_greater_equal_power_of_two(4));
assert_eq!(4, super::min_greater_equal_power_of_two(3));
assert_eq!(2, super::min_greater_equal_power_of_two(2));
assert_eq!(1, super::min_greater_equal_power_of_two(1));
assert_eq!(0, super::min_greater_equal_power_of_two(0));
}
#[test]
fn u64_to_u32_pair() {
assert_eq!((32, 0), super::u64_to_u32_pair(32u64));
assert_eq!(
(0xFFFFFFFF, 0xFFFFFFFF),
super::u64_to_u32_pair(0xFFFFFFFFFFFFFFFFu64)
);
assert_eq!(
(0, 0xFFFFFFFF),
super::u64_to_u32_pair(0xFFFFFFFF00000000u64)
);
}
#[test]
fn test_not_matches_macro() {
let foofoo = 'g';
assert!(not_matches!(foofoo, 'a'..='f'));
let barbar = Some(4);
assert!(not_matches!(barbar, Some(x) if x < 2));
}
}