use crate::crypto::hash::Digest;
use crate::crypto::profiles::CryptoProvider;
use crate::transport::handshake::error::HandshakeError;
pub const TRANSCRIPT_HASH_LEN: usize = 32;
pub(crate) fn digest_output_to_array(bytes: &[u8]) -> Result<[u8; TRANSCRIPT_HASH_LEN], HandshakeError> {
if bytes.len() < TRANSCRIPT_HASH_LEN {
return Err(HandshakeError::TranscriptDigestLength { expected: TRANSCRIPT_HASH_LEN, received: bytes.len() });
}
let mut out = [0u8; TRANSCRIPT_HASH_LEN];
out.copy_from_slice(&bytes[..TRANSCRIPT_HASH_LEN]);
Ok(out)
}
pub fn transcript_hash<P: CryptoProvider>(messages: &[&[u8]]) -> Result<[u8; TRANSCRIPT_HASH_LEN], HandshakeError> {
let mut hasher = P::Digest::default();
for message in messages {
hasher.update(message);
}
digest_output_to_array(&hasher.finalize())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::crypto::profiles::DefaultCryptoProvider;
#[test]
fn test_transcript_hash_single_message() -> Result<(), HandshakeError> {
let msg = b"Hello, World!";
let hash = transcript_hash::<DefaultCryptoProvider>(&[msg])?;
assert_eq!(hash.len(), 32);
Ok(())
}
#[test]
fn test_transcript_hash_multiple_messages() -> Result<(), HandshakeError> {
let msg1 = b"Message 1";
let msg2 = b"Message 2";
let msg3 = b"Message 3";
let hash = transcript_hash::<DefaultCryptoProvider>(&[msg1, msg2, msg3])?;
assert_eq!(hash.len(), 32);
Ok(())
}
#[test]
fn test_transcript_hash_deterministic() -> Result<(), HandshakeError> {
let msg1 = b"Test";
let msg2 = b"Data";
let hash1 = transcript_hash::<DefaultCryptoProvider>(&[msg1, msg2])?;
let hash2 = transcript_hash::<DefaultCryptoProvider>(&[msg1, msg2])?;
assert_eq!(hash1, hash2);
Ok(())
}
#[test]
fn test_transcript_hash_order_matters() -> Result<(), HandshakeError> {
let msg1 = b"First";
let msg2 = b"Second";
let hash_forward = transcript_hash::<DefaultCryptoProvider>(&[msg1, msg2])?;
let hash_reverse = transcript_hash::<DefaultCryptoProvider>(&[msg2, msg1])?;
assert_ne!(hash_forward, hash_reverse);
Ok(())
}
#[test]
fn test_digest_output_narrow_rejected_wide_truncated() -> Result<(), HandshakeError> {
let narrow = [0u8; 28];
assert!(matches!(
digest_output_to_array(&narrow),
Err(HandshakeError::TranscriptDigestLength { expected: 32, received: 28 })
));
let mut wide = [0u8; 64];
for (i, byte) in wide.iter_mut().enumerate() {
*byte = i as u8;
}
let truncated = digest_output_to_array(&wide)?;
assert_eq!(truncated, wide[..32]);
Ok(())
}
}