use std::ops::RangeInclusive;
use bc_rand::{
RandomNumberGenerator, SecureRandomNumberGenerator,
rng_next_in_closed_range, rng_random_data,
};
use bc_ur::prelude::*;
use crate::{Error, Result, tags};
#[derive(Clone, Eq, PartialEq)]
pub struct Salt(Vec<u8>);
impl Salt {
pub fn len(&self) -> usize { self.0.len() }
pub fn is_empty(&self) -> bool { self.0.is_empty() }
pub fn from_data(data: impl AsRef<[u8]>) -> Self {
Self(data.as_ref().to_vec())
}
pub fn as_bytes(&self) -> &[u8] { self.as_ref() }
pub fn new_with_len(count: usize) -> Result<Self> {
let mut rng = SecureRandomNumberGenerator;
Self::new_with_len_using(count, &mut rng)
}
pub fn new_with_len_using(
count: usize,
rng: &mut impl RandomNumberGenerator,
) -> Result<Self> {
if count < 8 {
return Err(Error::data_too_short("salt", 8, count));
}
Ok(Self::from_data(rng_random_data(rng, count)))
}
pub fn new_in_range(range: RangeInclusive<usize>) -> Result<Self> {
if range.start() < &8 {
return Err(Error::data_too_short("salt", 8, *range.start()));
}
let mut rng = SecureRandomNumberGenerator;
Self::new_in_range_using(&range, &mut rng)
}
pub fn new_in_range_using(
range: &RangeInclusive<usize>,
rng: &mut impl RandomNumberGenerator,
) -> Result<Self> {
if range.start() < &8 {
return Err(Error::data_too_short("salt", 8, *range.start()));
}
let count = rng_next_in_closed_range(rng, range);
Self::new_with_len_using(count, rng)
}
pub fn new_for_size(size: usize) -> Self {
let mut rng = SecureRandomNumberGenerator;
Self::new_for_size_using(size, &mut rng)
}
pub fn new_for_size_using(
size: usize,
rng: &mut impl RandomNumberGenerator,
) -> Self {
let count = size as f64;
let min_size = std::cmp::max(8, (count * 0.05).ceil() as usize);
let max_size =
std::cmp::max(min_size + 8, (count * 0.25).ceil() as usize);
Self::new_in_range_using(&(min_size..=max_size), rng).unwrap()
}
pub fn from_hex(hex: impl AsRef<str>) -> Self {
Self::from_data(hex::decode(hex.as_ref()).unwrap())
}
pub fn hex(&self) -> String { hex::encode(self.as_bytes()) }
}
impl<'a> From<&'a Salt> for &'a [u8] {
fn from(value: &'a Salt) -> Self { value.as_bytes() }
}
impl AsRef<[u8]> for Salt {
fn as_ref(&self) -> &[u8] { &self.0 }
}
impl AsRef<Salt> for Salt {
fn as_ref(&self) -> &Salt { self }
}
impl CBORTagged for Salt {
fn cbor_tags() -> Vec<Tag> { tags_for_values(&[tags::TAG_SALT]) }
}
impl From<Salt> for CBOR {
fn from(value: Salt) -> Self { value.tagged_cbor() }
}
impl CBORTaggedEncodable for Salt {
fn untagged_cbor(&self) -> CBOR { CBOR::to_byte_string(self.as_bytes()) }
}
impl TryFrom<CBOR> for Salt {
type Error = dcbor::Error;
fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
Self::from_tagged_cbor(cbor)
}
}
impl CBORTaggedDecodable for Salt {
fn from_untagged_cbor(untagged_cbor: CBOR) -> dcbor::Result<Self> {
let data = CBOR::try_into_byte_string(untagged_cbor)?;
let instance = Self::from_data(data);
Ok(instance)
}
}
impl std::fmt::Debug for Salt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Salt({})", self.len())
}
}
impl From<&Salt> for Salt {
fn from(salt: &Salt) -> Self { salt.clone() }
}
impl From<Salt> for Vec<u8> {
fn from(salt: Salt) -> Self { salt.0.to_vec() }
}
impl From<&Salt> for Vec<u8> {
fn from(salt: &Salt) -> Self { salt.0.to_vec() }
}