slice.rs (4311B)
1 // Copyright 2023 Cryspen Sarl 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 9 //! This module contains the trait and related errors for hashers that take slices as 10 //! arguments and write the results to mutable slices. 11 12 use super::arrayref; 13 14 /// A trait for oneshot hashing, where the output is written to a provided slice. 15 pub trait Hash { 16 /// Writes the digest for the given input byte slice, into `digest` in immediate mode. 17 fn hash(digest: &mut [u8], payload: &[u8]) -> Result<usize, HashError>; 18 } 19 20 /// A trait for incremental hashing, where the output is written to a provided slice. 21 pub trait DigestIncremental: super::DigestIncrementalBase { 22 /// Writes the digest into `digest`. 23 /// 24 /// Note that the digest state can be continued to be used, to extend the digest. 25 fn finish(state: &mut Self::IncrementalState, digest: &mut [u8]) -> Result<usize, FinishError>; 26 } 27 28 /// Error indicating that finalizing failed. 29 #[derive(Debug, PartialEq)] 30 pub enum FinishError { 31 /// The length of the provided digest buffer is invalid. 32 InvalidDigestLength, 33 /// Unknown error. 34 Unknown, 35 } 36 37 impl core::fmt::Display for FinishError { 38 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 39 let text = match self { 40 FinishError::InvalidDigestLength => { 41 "the length of the provided digest buffer is invalid" 42 } 43 FinishError::Unknown => "indicates an unknown error", 44 }; 45 46 f.write_str(text) 47 } 48 } 49 50 /// Error indicating that hashing failed. 51 #[derive(Debug, PartialEq)] 52 pub enum HashError { 53 /// The length of the provided digest buffer is invalid. 54 InvalidDigestLength, 55 /// The length of the provided payload is invalid. 56 InvalidPayloadLength, 57 } 58 59 impl core::fmt::Display for HashError { 60 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 61 let text = match self { 62 HashError::InvalidDigestLength => "the length of the provided digest buffer is invalid", 63 HashError::InvalidPayloadLength => "the length of the provided payload is invalid", 64 }; 65 66 f.write_str(text) 67 } 68 } 69 70 #[cfg(feature = "error-in-core")] 71 mod error_in_core { 72 73 impl core::error::Error for super::HashError {} 74 impl core::error::Error for super::FinishError {} 75 } 76 77 impl From<arrayref::HashError> for HashError { 78 fn from(e: arrayref::HashError) -> Self { 79 match e { 80 arrayref::HashError::InvalidPayloadLength => Self::InvalidPayloadLength, 81 } 82 } 83 } 84 85 #[macro_export] 86 /// Implements [`Hash`] for any [`arrayref::Hash`]. 87 macro_rules! impl_hash_trait { 88 ($type:ty => $len:expr) => { 89 impl $crate::digest::slice::Hash for $type { 90 fn hash( 91 digest: &mut [u8], 92 payload: &[u8], 93 ) -> Result<usize, $crate::digest::slice::HashError> { 94 let digest: &mut [u8; $len] = digest 95 .try_into() 96 .map_err(|_| $crate::digest::slice::HashError::InvalidDigestLength)?; 97 <Self as $crate::digest::arrayref::Hash<$len>>::hash(digest, payload) 98 .map(|_| $len) 99 .map_err($crate::digest::slice::HashError::from) 100 } 101 } 102 }; 103 } 104 105 #[macro_export] 106 /// Implements [`DigestIncremental`] for any [`arrayref::DigestIncremental`]. 107 macro_rules! impl_digest_incremental_trait { 108 ($type:ty => $incremental_state:ty, $len:expr) => { 109 impl $crate::digest::slice::DigestIncremental for $type { 110 fn finish( 111 state: &mut Self::IncrementalState, 112 digest: &mut [u8], 113 ) -> Result<usize, $crate::digest::slice::FinishError> { 114 let digest: &mut [u8; $len] = digest 115 .try_into() 116 .map_err(|_| $crate::digest::slice::FinishError::InvalidDigestLength)?; 117 <Self as $crate::digest::arrayref::DigestIncremental<$len>>::finish(state, digest); 118 119 Ok($len) 120 } 121 } 122 }; 123 } 124 125 pub use impl_digest_incremental_trait; 126 pub use impl_hash_trait;