digest.rs (4099B)
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 provides common interface traits for digest/hashing functionality. 10 11 pub mod arrayref; 12 pub mod owned; 13 pub mod slice; 14 15 #[cfg(feature = "generic-tests")] 16 pub mod tests; 17 18 /// Error indicating that updating the digest state failed. 19 #[derive(Debug, PartialEq)] 20 pub enum UpdateError { 21 /// The length of the provided payload is invalid. 22 InvalidPayloadLength, 23 ///The maximum input length is exceeded. 24 MaximumLengthExceeded, 25 /// Unknown error. 26 Unknown, 27 } 28 29 impl core::fmt::Display for UpdateError { 30 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 31 let text = match self { 32 UpdateError::InvalidPayloadLength => "the length of the provided payload is invalid", 33 UpdateError::MaximumLengthExceeded => "the maximum input length is exceeded", 34 UpdateError::Unknown => "indicates an unknown error", 35 }; 36 37 f.write_str(text) 38 } 39 } 40 41 #[cfg(feature = "error-in-core")] 42 mod error_in_core { 43 44 impl core::error::Error for super::UpdateError {} 45 } 46 47 /// Base trait for incremental functionality. 48 /// 49 /// Traits that are built on top of this trait: 50 /// - [`slice::DigestIncremental`] 51 /// - [`arrayref::DigestIncremental`] 52 /// - [`owned::DigestIncremental`] 53 pub trait DigestIncrementalBase { 54 /// The digest state. 55 type IncrementalState; 56 /// Reset the digest state. 57 fn reset(state: &mut Self::IncrementalState); 58 /// Update the digest state with the `payload`. 59 fn update(state: &mut Self::IncrementalState, payload: &[u8]) -> Result<(), UpdateError>; 60 } 61 62 #[derive(Clone)] 63 /// A hasher that maintains the incremental digest state. 64 pub struct Hasher<const N: usize, D: DigestIncrementalBase> { 65 /// The digest state. 66 pub state: D::IncrementalState, 67 } 68 69 impl<const N: usize, D: arrayref::DigestIncremental<N>> Default for Hasher<N, D> 70 where 71 D::IncrementalState: Default, 72 { 73 fn default() -> Self { 74 Self { 75 state: Default::default(), 76 } 77 } 78 } 79 80 impl<const N: usize, D: DigestIncrementalBase + slice::Hash> Hasher<N, D> { 81 /// Oneshot API. Hash into a digest buffer, provided as a `&mut [u8]` slice. 82 pub fn hash_slice(digest: &mut [u8], payload: &[u8]) -> Result<usize, slice::HashError> { 83 D::hash(digest, payload) 84 } 85 } 86 87 impl<const N: usize, D: slice::DigestIncremental> Hasher<N, D> { 88 /// Finalize and write into a digest buffer, provided as a `&mut [u8]` slice. 89 pub fn finish_slice(&mut self, digest: &mut [u8]) -> Result<usize, slice::FinishError> { 90 D::finish(&mut self.state, digest) 91 } 92 } 93 94 impl<const N: usize, D: DigestIncrementalBase> Hasher<N, D> { 95 /// Update the digest state with the `payload`. 96 pub fn update(&mut self, payload: &[u8]) -> Result<(), UpdateError> { 97 D::update(&mut self.state, payload) 98 } 99 /// Reset the digest state. 100 pub fn reset(&mut self) { 101 D::reset(&mut self.state) 102 } 103 } 104 105 impl<const N: usize, D: arrayref::DigestIncremental<N>> Hasher<N, D> { 106 /// Finalize and write into a digest buffer, provided as a `&mut [u8; N]` array reference. 107 pub fn finish(&mut self, digest: &mut [u8; N]) { 108 D::finish(&mut self.state, digest) 109 } 110 /// owned version of `finish()` 111 pub fn finish_to_owned(&mut self) -> [u8; N] { 112 <D as owned::DigestIncremental<N>>::finish(&mut self.state) 113 } 114 } 115 116 impl<const N: usize, D: DigestIncrementalBase + arrayref::Hash<N>> Hasher<N, D> { 117 /// Oneshot API. Hash into a digest buffer, provided as a `&mut [u8; N]` array reference. 118 pub fn hash(digest: &mut [u8; N], payload: &[u8]) -> Result<(), arrayref::HashError> { 119 D::hash(digest, payload) 120 } 121 /// owned version of `hash()` 122 pub fn hash_to_owned(payload: &[u8]) -> Result<[u8; N], arrayref::HashError> { 123 <D as owned::Hash<N>>::hash(payload) 124 } 125 }