#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(not(feature = "std"))]
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "std")]
use std::vec::Vec;
use crate::error::{validate, Error, Result};
#[cfg(feature = "alloc")]
pub mod shake;
#[cfg(feature = "alloc")]
pub mod blake3;
#[cfg(feature = "alloc")]
pub use shake::{ShakeXof128, ShakeXof256};
#[cfg(feature = "alloc")]
pub use blake3::Blake3Xof;
#[cfg(feature = "alloc")]
pub type Xof = Vec<u8>;
pub trait ExtendableOutputFunction {
fn new() -> Self;
fn update(&mut self, data: &[u8]) -> Result<()>;
fn finalize(&mut self) -> Result<()>;
fn squeeze(&mut self, output: &mut [u8]) -> Result<()>;
#[cfg(feature = "alloc")]
fn squeeze_into_vec(&mut self, len: usize) -> Result<Vec<u8>>;
fn reset(&mut self) -> Result<()>;
fn security_level() -> usize;
#[cfg(feature = "alloc")]
fn generate(data: &[u8], len: usize) -> Result<Vec<u8>>
where
Self: Sized,
{
validate::parameter(
len > 0,
"output_length",
"XOF output length must be greater than 0",
)?;
let mut xof = Self::new();
xof.update(data)?;
xof.squeeze_into_vec(len)
}
}
pub trait XofAlgorithm {
const SECURITY_LEVEL: usize;
const MIN_OUTPUT_SIZE: usize;
const MAX_OUTPUT_SIZE: Option<usize>;
const ALGORITHM_ID: &'static str;
fn name() -> &'static str {
Self::ALGORITHM_ID
}
fn validate_output_length(len: usize) -> Result<()> {
validate::parameter(
len >= Self::MIN_OUTPUT_SIZE,
"output_length",
"Output length below minimum recommended size",
)?;
if let Some(max) = Self::MAX_OUTPUT_SIZE {
validate::max_length("XOF output", len, max)?;
}
Ok(())
}
}
pub enum Shake128Algorithm {}
impl XofAlgorithm for Shake128Algorithm {
const SECURITY_LEVEL: usize = 128;
const MIN_OUTPUT_SIZE: usize = 16; const MAX_OUTPUT_SIZE: Option<usize> = None; const ALGORITHM_ID: &'static str = "SHAKE-128";
}
pub enum Shake256Algorithm {}
impl XofAlgorithm for Shake256Algorithm {
const SECURITY_LEVEL: usize = 256;
const MIN_OUTPUT_SIZE: usize = 32; const MAX_OUTPUT_SIZE: Option<usize> = None; const ALGORITHM_ID: &'static str = "SHAKE-256";
}
pub enum Blake3Algorithm {}
impl XofAlgorithm for Blake3Algorithm {
const SECURITY_LEVEL: usize = 256;
const MIN_OUTPUT_SIZE: usize = 32; const MAX_OUTPUT_SIZE: Option<usize> = None; const ALGORITHM_ID: &'static str = "BLAKE3-XOF";
}
pub trait KeyedXof: ExtendableOutputFunction {
fn with_key(key: &[u8]) -> Result<Self>
where
Self: Sized;
#[cfg(feature = "alloc")]
fn keyed_generate(key: &[u8], data: &[u8], len: usize) -> Result<Vec<u8>>
where
Self: Sized,
{
validate::parameter(
len > 0,
"output_length",
"XOF output length must be greater than 0",
)?;
let mut xof = Self::with_key(key)?;
xof.update(data)?;
xof.squeeze_into_vec(len)
}
}
pub trait DeriveKeyXof: ExtendableOutputFunction {
fn for_derive_key(context: &[u8]) -> Result<Self>
where
Self: Sized;
#[cfg(feature = "alloc")]
fn derive_key(context: &[u8], data: &[u8], len: usize) -> Result<Vec<u8>>
where
Self: Sized,
{
validate::parameter(
len > 0,
"output_length",
"Key derivation output length must be greater than 0",
)?;
let mut xof = Self::for_derive_key(context)?;
xof.update(data)?;
xof.squeeze_into_vec(len)
}
}
impl Error {
pub(crate) fn xof_finalized() -> Self {
Error::Processing {
operation: "XOF",
details: "Cannot update after finalization",
}
}
pub(crate) fn xof_squeezing() -> Self {
Error::Processing {
operation: "XOF",
details: "Cannot update after squeezing has begun",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_xof_algorithm_validation() {
assert!(Shake128Algorithm::validate_output_length(16).is_ok());
assert!(Shake128Algorithm::validate_output_length(15).is_err());
assert!(Shake256Algorithm::validate_output_length(32).is_ok());
assert!(Shake256Algorithm::validate_output_length(31).is_err());
assert!(Blake3Algorithm::validate_output_length(32).is_ok());
assert!(Blake3Algorithm::validate_output_length(31).is_err());
}
}