use serde::{de::Visitor, Deserializer, Serializer};
use serde::{Deserialize, Serialize};
use smallvec::{smallvec, SmallVec};
use zeroize::Zeroize;
use core::{convert::TryFrom, fmt, ops::Deref};
const BUFFER_SIZE: usize = 256;
#[derive(Clone)]
pub struct SensitiveData(SmallVec<[u8; BUFFER_SIZE]>);
impl SensitiveData {
pub(crate) fn zeros(len: usize) -> Self {
SensitiveData(smallvec![0; len])
}
pub(crate) fn bytes_mut(&mut self) -> &mut [u8] {
&mut *self.0
}
}
impl fmt::Debug for SensitiveData {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_tuple("SensitiveData").field(&"_").finish()
}
}
impl Deref for SensitiveData {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl Drop for SensitiveData {
fn drop(&mut self) {
Zeroize::zeroize(self.0.as_mut_slice());
}
}
struct LogNTransform;
impl LogNTransform {
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn serialize<S: Serializer>(value: &u8, serializer: S) -> Result<S::Ok, S::Error> {
assert!(*value < 32, "too large value to serialize: {}", value);
serializer.serialize_u64(1 << u64::from(*value))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<u8, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error as DeError;
struct Log2Visitor;
impl<'de> Visitor<'de> for Log2Visitor {
type Value = u8;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a power of two")
}
fn visit_u64<E: DeError>(self, value: u64) -> Result<Self::Value, E> {
if !value.is_power_of_two() {
return Err(E::custom("not a power of two"));
}
Ok(63 - u8::try_from(value.leading_zeros()).unwrap())
}
}
deserializer.deserialize_u64(Log2Visitor)
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct ScryptParams {
#[serde(rename = "n", with = "LogNTransform")]
pub(crate) log_n: u8,
pub(crate) r: u32,
pub(crate) p: u32,
}
impl Default for ScryptParams {
fn default() -> Self {
ScryptParams {
log_n: 14,
r: 8,
p: 1,
}
}
}
impl ScryptParams {
pub const fn light() -> Self {
ScryptParams {
log_n: 12,
r: 8,
p: 6,
}
}
pub const fn custom(log_n: u8, p: u32) -> Self {
ScryptParams { log_n, p, r: 8 }
}
}
#[test]
fn log2_transform() {
use serde::{Deserialize, Serialize};
use serde_json::{self, Value};
#[derive(Serialize, Deserialize)]
struct Test {
#[serde(rename = "n", with = "LogNTransform")]
log_n: u8,
}
let json = r#"{ "n": 65536 }"#;
let value: Test = serde_json::from_str(json).unwrap();
assert_eq!(value.log_n, 16);
assert_eq!(
serde_json::to_value(value).unwrap(),
serde_json::from_str::<Value>(json).unwrap(),
);
}