use crate::GenerateSecret;
use crate::Secret;
use crate::errors::UnknownCryptoError;
#[cfg(feature = "safe_api")]
use crate::generics::sealed::Data;
use crate::generics::sealed::Sealed;
use crate::generics::{ByteArrayData, TypeSpec};
use crate::hazardous::hash::blake3::internal::KEYED_HASH;
use crate::hazardous::hash::blake3::state::Blake3State;
#[cfg(feature = "serde")]
use alloc::vec::Vec;
pub const KEY_SIZE: usize = crate::hazardous::hash::blake3::internal::KEY_SIZE;
pub const TAG_SIZE: usize = 32;
pub type SecretKey = Secret<Blake3Key>;
pub type Tag = Secret<Blake3Tag>;
#[derive(Debug)]
pub struct Blake3Key {}
impl Sealed for Blake3Key {}
impl TypeSpec for Blake3Key {
const NAME: &'static str = stringify!(SecretKey);
type TypeData = ByteArrayData<KEY_SIZE>;
}
impl GenerateSecret for Blake3Key {
#[cfg(feature = "safe_api")]
#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
fn generate() -> Result<Secret<Blake3Key>, UnknownCryptoError> {
let mut data = Self::TypeData::new(KEY_SIZE)?;
crate::util::secure_rand_bytes(&mut data.bytes)?;
Ok(Secret::from_data(data))
}
}
impl From<[u8; KEY_SIZE]> for SecretKey {
fn from(value: [u8; KEY_SIZE]) -> Self {
Self::from_data(<Blake3Key as TypeSpec>::TypeData::from(value))
}
}
#[derive(Debug)]
pub struct Blake3Tag {}
impl Sealed for Blake3Tag {}
impl TypeSpec for Blake3Tag {
const NAME: &'static str = stringify!(Tag);
type TypeData = ByteArrayData<TAG_SIZE>;
}
impl From<[u8; TAG_SIZE]> for Tag {
fn from(value: [u8; TAG_SIZE]) -> Self {
Self::from_data(<Blake3Tag as TypeSpec>::TypeData::from(value))
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl serde::Serialize for Tag {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let bytes: &[u8] = self.data.as_ref();
bytes.serialize(serializer)
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de> serde::Deserialize<'de> for Tag {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let bytes = Vec::<u8>::deserialize(deserializer)?;
TryFrom::try_from(bytes.as_slice()).map_err(serde::de::Error::custom)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Blake3 {
internal: Blake3State,
is_finalized: bool,
}
impl Blake3 {
pub fn new(key: &SecretKey) -> Self {
Self {
internal: Blake3State::new(key, KEYED_HASH),
is_finalized: false,
}
}
pub fn reset(&mut self) {
self.internal.reset();
self.is_finalized = false;
}
pub fn update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
if self.is_finalized {
return Err(UnknownCryptoError);
}
self.internal.absorb(data, KEYED_HASH)
}
pub fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
if self.is_finalized {
return Err(UnknownCryptoError);
}
self.is_finalized = true;
let mut tag = Tag::from([0u8; TAG_SIZE]);
self.internal.squeeze(&mut tag.data.bytes, KEYED_HASH)?;
Ok(tag)
}
pub fn verify(
expected: &Tag,
secret_key: &SecretKey,
data: &[u8],
) -> Result<(), UnknownCryptoError> {
let mut ctx = Self::new(secret_key);
ctx.update(data)?;
if &ctx.finalize()? == expected {
Ok(())
} else {
Err(UnknownCryptoError)
}
}
}
#[cfg(test)]
mod keyed_streaming_interface {
use crate::hazardous::hash::blake3::internal::BLOCK_LEN;
use crate::hazardous::mac::blake3::*;
use crate::test_framework::incremental_interface::{
StreamingContextConsistencyTester, TestableStreamingContext,
};
#[test]
#[cfg(feature = "serde")]
fn test_serde_serialized_equivalence_to_bytes_fn() {
let bytes = [38u8; TAG_SIZE];
let secret_type = Tag::try_from(&bytes).unwrap();
let serialized_from_bytes = serde_json::to_value(bytes.as_slice()).unwrap();
let serialized_from_secret_type = serde_json::to_value(&secret_type).unwrap();
assert_eq!(serialized_from_bytes, serialized_from_secret_type);
}
#[test]
#[cfg(feature = "serde")]
fn test_serde_deserialized_equivalence_to_bytes_fn() {
let bytes = [38u8; TAG_SIZE];
let serialized_from_bytes = serde_json::to_value(bytes.as_slice()).unwrap();
let secret_type: Tag = serde_json::from_value(serialized_from_bytes).unwrap();
assert_eq!(secret_type.unprotected_as_ref(), bytes.as_slice());
}
impl TestableStreamingContext<Tag> for Blake3 {
fn reset(&mut self) -> Result<(), UnknownCryptoError> {
self.reset();
Ok(())
}
fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
self.update(input)
}
fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
self.finalize()
}
fn one_shot(input: &[u8]) -> Result<Tag, UnknownCryptoError> {
let secret_key = SecretKey::from([0x42; 32]);
let mut hasher = Blake3::new(&secret_key);
hasher.update(input)?;
hasher.finalize()
}
fn verify_result(expected: &Tag, input: &[u8]) -> Result<(), UnknownCryptoError> {
let actual = Self::one_shot(input)?;
if &actual == expected {
Ok(())
} else {
Err(UnknownCryptoError)
}
}
fn compare_states(state_1: &Self, state_2: &Self) {
assert_eq!(state_1, state_2)
}
}
#[test]
fn keyed_consistency_states() {
let secret_key = SecretKey::from([0x42; 32]);
let test_runner = StreamingContextConsistencyTester::<Tag, Blake3>::new(
Blake3::new(&secret_key),
BLOCK_LEN,
);
test_runner.run_all_tests();
}
#[quickcheck]
#[cfg(feature = "safe_api")]
fn prop_input_to_consistency(data: Vec<u8>) -> bool {
let secret_key = SecretKey::from([0x42; 32]);
let test_runner = StreamingContextConsistencyTester::<Tag, Blake3>::new(
Blake3::new(&secret_key),
BLOCK_LEN,
);
test_runner.run_all_tests_property(&data);
true
}
}