1use std::marker::PhantomData;
2
3use crate::{Acceptable, Controlled, DefaultScope, Scope};
4use digest::array::Array;
5use digest::Digest;
6use digest::FixedOutputReset;
7use digest::Output;
8use digest::OutputSizeUser;
9use digest::Reset;
10
11pub struct ProtectedDigest<D, InputScope = DefaultScope>(D, PhantomData<InputScope>);
12
13impl<D: Digest, InputScope: Scope> ProtectedDigest<D, InputScope> {
16 pub fn new() -> Self {
17 Self(D::new(), PhantomData)
18 }
19
20 pub fn new_with_prefix<T>(data: &T) -> Self
21 where
22 T: Controlled + Acceptable<InputScope>,
23 T::Inner: AsRef<[u8]>,
24 {
25 Self(D::new_with_prefix(data.risky_ref()), PhantomData)
26 }
27
28 pub fn update<T>(&mut self, data: &T)
29 where
30 T: Controlled + Acceptable<InputScope>,
31 T::Inner: AsRef<[u8]>,
32 {
33 self.0.update(data.risky_ref())
34 }
35
36 pub fn finalize<T>(self) -> T
37 where
38 T: Controlled + From<Array<u8, <D as OutputSizeUser>::OutputSize>>,
39 {
40 let result = self.0.finalize();
41 result.into()
42 }
43
44 pub fn finalize_into<'m, T>(self, out: &'m mut T)
45 where
46 T: Controlled,
47 &'m mut Array<u8, <D as OutputSizeUser>::OutputSize>: From<&'m mut T::Inner>,
48 {
49 let target: &mut Output<D> = out.inner_mut().into();
50 self.0.finalize_into(target);
51 }
52
53 pub fn finalize_reset<T>(&mut self) -> T
54 where
55 D: FixedOutputReset,
56 T: Controlled + From<Array<u8, <D as OutputSizeUser>::OutputSize>>,
57 {
58 let result = self.0.finalize_reset();
59 result.into()
60 }
61
62 pub fn finalize_into_reset<'m, T>(&'m mut self, out: &'m mut T)
63 where
64 D: FixedOutputReset,
65 T: Controlled,
66 &'m mut Array<u8, <D as OutputSizeUser>::OutputSize>: From<&'m mut T::Inner>,
67 {
68 let target: &mut Output<D> = out.inner_mut().into();
69 Digest::finalize_into_reset(&mut self.0, target);
70 }
71
72 pub fn reset(&mut self)
73 where
74 D: Reset,
75 {
76 Digest::reset(&mut self.0);
77 }
78
79 pub fn output_size() -> usize {
80 <D as Digest>::output_size()
81 }
82
83 pub fn digest<T, O>(data: &T) -> O
84 where
85 T: Controlled + Acceptable<InputScope>,
86 T::Inner: AsRef<[u8]>,
87 O: Controlled + From<Array<u8, <D as OutputSizeUser>::OutputSize>>,
88 {
89 let mut hasher = Self::new();
90 hasher.update(data);
91 hasher.finalize()
92 }
93}
94
95impl<D: Digest, InputScope: Scope> Default for ProtectedDigest<D, InputScope> {
96 fn default() -> Self {
97 Self::new()
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::Protected;
105 use sha2::{Sha256, Sha384};
106
107 #[test]
108 fn test_digest_sha256_finalize() {
109 let mut digest: ProtectedDigest<Sha256> = ProtectedDigest::new();
110 digest.update(&Protected::new([0u8; 32]));
111 let result: Protected<[u8; 32]> = digest.finalize();
112 assert_eq!(
113 result.risky_unwrap(),
114 [
115 102, 104, 122, 173, 248, 98, 189, 119, 108, 143, 193, 139, 142, 159, 142, 32, 8,
116 151, 20, 133, 110, 226, 51, 179, 144, 42, 89, 29, 13, 95, 41, 37
117 ]
118 );
119 }
120
121 #[test]
122 fn test_digest_sha256_finalize_into() {
123 let mut digest: ProtectedDigest<Sha256> = ProtectedDigest::new();
124 digest.update(&Protected::new([0u8; 32]));
125 let mut result = Protected::new([0u8; 32]);
126 digest.finalize_into(&mut result);
127 assert_eq!(
128 result.risky_unwrap(),
129 [
130 102, 104, 122, 173, 248, 98, 189, 119, 108, 143, 193, 139, 142, 159, 142, 32, 8,
131 151, 20, 133, 110, 226, 51, 179, 144, 42, 89, 29, 13, 95, 41, 37
132 ]
133 );
134 }
135
136 #[test]
137 fn test_digest_sha384() {
138 let mut digest: ProtectedDigest<Sha384> = ProtectedDigest::new();
139 digest.update(&Protected::new([0u8; 32]));
140 let result: Protected<[u8; 48]> = digest.finalize();
141 assert_eq!(
142 result.risky_unwrap(),
143 [
144 163, 143, 255, 75, 162, 108, 21, 228, 172, 156, 222, 140, 3, 16, 58, 200, 144, 128,
145 253, 71, 84, 95, 222, 148, 70, 200, 241, 146, 114, 158, 171, 123, 208, 58, 77, 92,
146 49, 135, 247, 95, 226, 167, 27, 14, 229, 10, 74, 64,
147 ]
148 );
149 }
150}