1use std::marker::PhantomData;
4
5use binius_field::{
6 as_packed_field::{PackScalar, PackedType},
7 make_aes_to_binary_packed_transformer, make_binary_to_aes_packed_transformer,
8 packed::set_packed_slice,
9 underlier::{Divisible, WithUnderlier},
10 AESTowerField32b, AesToBinaryTransformation, BinaryField, BinaryField32b, BinaryField8b,
11 BinaryToAesTransformation, ExtensionField, Field, PackedAESBinaryField8x32b,
12 PackedBinaryField8x32b, PackedExtension, PackedExtensionIndexable, PackedField,
13 PackedFieldIndexable,
14};
15use lazy_static::lazy_static;
16
17use super::permutation::PERMUTATION;
18use crate::{permutation::Permutation, FixedLenHasher, HashError};
19
20const RATE_AS_U32: usize = 16;
21const RATE_AS_U8: usize = RATE_AS_U32 * std::mem::size_of::<u32>();
22
23const PADDING_START: u8 = 0x01;
24const PADDING_END: u8 = 0x80;
25
26lazy_static! {
27 static ref TRANS_AES_TO_CANONICAL: AesToBinaryTransformation<PackedAESBinaryField8x32b, PackedBinaryField8x32b> =
28 make_aes_to_binary_packed_transformer::<PackedAESBinaryField8x32b, PackedBinaryField8x32b>();
29 static ref TRANS_CANONICAL_TO_AES: BinaryToAesTransformation<PackedBinaryField8x32b, PackedAESBinaryField8x32b> =
30 make_binary_to_aes_packed_transformer::<PackedBinaryField8x32b, PackedAESBinaryField8x32b>();
31
32 static ref PADDING_BLOCK: [u8; RATE_AS_U8] = {
34 let mut block = [0; RATE_AS_U8];
35 block[0] = PADDING_START;
36 block[RATE_AS_U8 - 1] |= PADDING_END;
37 block
38 };
39}
40
41pub type Vision32b<P> = VisionHasher<BinaryField32b, P>;
43
44#[derive(Clone)]
47pub struct VisionHasher<F, P> {
48 state: [PackedAESBinaryField8x32b; 3],
50 committed_len: u64,
52 current_len: u64,
54 _p_marker: PhantomData<P>,
55 _f_marker: PhantomData<F>,
56}
57
58impl<U, F, P> FixedLenHasher<P> for VisionHasher<F, P>
59where
60 U: PackScalar<F> + Divisible<u32>,
61 F: BinaryField + From<AESTowerField32b> + Into<AESTowerField32b>,
62 P: PackedExtension<F, PackedSubfield: PackedFieldIndexable>,
63 PackedAESBinaryField8x32b: WithUnderlier<Underlier = U>,
64{
65 type Digest = PackedType<U, F>;
66
67 fn new(msg_len: u64) -> Self {
68 let mut this = Self {
69 state: [PackedAESBinaryField8x32b::zero(); 3],
70 committed_len: msg_len,
71 current_len: 0,
72 _p_marker: PhantomData,
73 _f_marker: PhantomData,
74 };
75 this.reset();
76 this
77 }
78
79 fn update(&mut self, msg: impl AsRef<[P]>) {
80 let msg = msg.as_ref();
81 if msg.is_empty() {
82 return;
83 }
84
85 let msg_scalars = P::unpack_base_scalars(msg).iter().copied().map(Into::into);
86
87 let cur_block = (self.current_len as usize * P::WIDTH * P::Scalar::DEGREE) % RATE_AS_U32;
88 for (i, x) in msg_scalars.enumerate() {
89 let block_idx = (cur_block + i) % RATE_AS_U32;
90 let next_block = PackedAESBinaryField8x32b::unpack_scalars_mut(&mut self.state);
91 next_block[block_idx] = x;
92 if block_idx == RATE_AS_U32 - 1 {
93 self.state = PERMUTATION.permute(self.state);
94 }
95 }
96
97 self.current_len = self
98 .current_len
99 .checked_add(msg.len() as u64)
100 .expect("Overflow on message length");
101 }
102
103 fn chain_update(mut self, msg: impl AsRef<[P]>) -> Self {
104 self.update(msg);
105 self
106 }
107
108 fn finalize(mut self) -> Result<Self::Digest, HashError> {
109 if self.current_len < self.committed_len {
111 return Err(HashError::NotEnoughData {
112 committed: self.committed_len,
113 hashed: self.current_len,
114 });
115 }
116
117 if self.current_len > self.committed_len {
118 return Err(HashError::TooMuchData {
119 committed: self.committed_len,
120 received: self.current_len,
121 });
122 }
123
124 let cur_block = (self.current_len as usize * P::WIDTH * P::Scalar::DEGREE) % RATE_AS_U32;
125 if cur_block != 0 {
126 let next_block = PackedFieldIndexable::unpack_scalars_mut(&mut self.state[..2]);
128 next_block[cur_block..].fill(AESTowerField32b::ZERO);
129 self.state = PERMUTATION.permute(self.state);
130 }
131
132 let out_native = self.state[0];
133 Ok(Self::Digest::from_fn(|i| F::from(out_native.get(i))))
134 }
135
136 fn reset(&mut self) {
137 self.state.fill(PackedAESBinaryField8x32b::zero());
138
139 let bytes_per_elem = P::WIDTH
141 * P::Scalar::DEGREE
142 * <BinaryField32b as ExtensionField<BinaryField8b>>::DEGREE;
143 let msg_len_bytes = self
144 .committed_len
145 .checked_mul(bytes_per_elem as u64)
146 .expect("Overflow on message length");
147 let msg_len_bytes_enc = msg_len_bytes.to_le_bytes();
148 set_packed_slice(
149 &mut self.state,
150 RATE_AS_U32,
151 AESTowerField32b::from(BinaryField32b::new(u32::from_le_bytes(
152 msg_len_bytes_enc[0..4].try_into().unwrap(),
153 ))),
154 );
155 set_packed_slice(
156 &mut self.state,
157 RATE_AS_U32 + 1,
158 AESTowerField32b::from(BinaryField32b::new(u32::from_le_bytes(
159 msg_len_bytes_enc[4..8].try_into().unwrap(),
160 ))),
161 );
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use std::array;
168
169 use binius_field::{
170 linear_transformation::Transformation, make_aes_to_binary_packed_transformer,
171 make_binary_to_aes_packed_transformer, BinaryField64b, PackedAESBinaryField4x64b,
172 PackedBinaryField4x64b, PackedBinaryField8x32b,
173 };
174 use hex_literal::hex;
175 use rand::thread_rng;
176
177 use super::*;
178 use crate::{FixedLenHasherDigest, HashDigest};
179
180 fn from_bytes_to_packed_256(elements: &[u8; 32]) -> PackedBinaryField8x32b {
181 PackedBinaryField8x32b::from_fn(|i| {
182 BinaryField32b::new(u32::from_le_bytes(elements[i * 4..i * 4 + 4].try_into().unwrap()))
183 })
184 }
185
186 #[test]
187 fn test_fixed_length_too_much_data() {
188 let mut hasher = Vision32b::new(20);
189 let data = [BinaryField32b::zero(); 30];
190 hasher.update(data);
191 let successful_failure = matches!(
192 hasher.finalize().err().unwrap(),
193 HashError::TooMuchData {
194 committed: 20,
195 received: 30,
196 }
197 );
198 assert!(successful_failure);
199 }
200
201 #[test]
202 fn test_fixed_length_not_enough_data() {
203 let mut hasher = Vision32b::new(20);
204 let data = [BinaryField32b::zero(); 3];
205 hasher.update(data);
206 let successful_failure = matches!(
207 hasher.finalize().err().unwrap(),
208 HashError::NotEnoughData {
209 committed: 20,
210 hashed: 3,
211 }
212 );
213 assert!(successful_failure);
214 }
215
216 #[test]
217 fn test_empty_input_error() {
218 let hasher = Vision32b::<BinaryField32b>::new(0);
219 assert_eq!(hasher.finalize().unwrap(), PackedBinaryField8x32b::zero());
220
221 let hasher: Vision32b<BinaryField32b> = Vision32b::new(25);
222 let successful_failure = matches!(
223 hasher.chain_update([]).finalize().err().unwrap(),
224 HashError::NotEnoughData {
225 committed: 25,
226 hashed: 0
227 }
228 );
229 assert!(successful_failure);
230
231 let hasher: Vision32b<BinaryField32b> = Vision32b::new(25);
232 let successful_failure = matches!(
233 hasher.finalize().err().unwrap(),
234 HashError::NotEnoughData {
235 committed: 25,
236 hashed: 0,
237 }
238 );
239 assert!(successful_failure);
240 }
241
242 #[test]
243 fn test_simple_hash() {
244 let mut hasher: Vision32b<BinaryField32b> = Vision32b::new(1);
245 hasher.update([BinaryField32b::new(u32::from_le_bytes([
246 0xde, 0xad, 0xbe, 0xef,
247 ]))]);
248 let out = hasher.finalize().unwrap();
249 let expected = from_bytes_to_packed_256(&hex!(
251 "69e1764144099730124ab8ef1414570895ae9de0b74dedf364c72d118851cf65"
252 ));
253 assert_eq!(expected, out);
254 }
255
256 fn from_bytes_to_b32s(inp: &[u8]) -> Vec<BinaryField32b> {
257 inp.chunks_exact(4)
258 .map(|x| BinaryField32b::new(u32::from_le_bytes(x.try_into().unwrap())))
259 .collect::<Vec<_>>()
260 }
261
262 #[test]
263 fn test_multi_block_aligned() {
264 let mut hasher: Vision32b<BinaryField32b> = Vision32b::new(64);
265 let input = "One part of the mysterious existence of Captain Nemo had been unveiled and, if his identity had not been recognised, at least, the nations united against him were no longer hunting a chimerical creature, but a man who had vowed a deadly hatred against them";
266 hasher.update(from_bytes_to_b32s(input.as_bytes()));
267 let out = hasher.finalize().unwrap();
268
269 let expected = from_bytes_to_packed_256(&hex!(
270 "6ade8ba2a45a070a3abaff6f1bf9483686c78d4afca2d0d8d3c7897fdfe2df91"
271 ));
272 assert_eq!(expected, out);
273
274 let mut hasher = Vision32b::new(64);
275 let input_as_b = from_bytes_to_b32s(input.as_bytes());
276 hasher.update(&input_as_b[0..29]);
277 hasher.update(&input_as_b[29..31]);
278 hasher.update(&input_as_b[31..57]);
279 hasher.update(&input_as_b[57..]);
280
281 assert_eq!(expected, hasher.finalize().unwrap());
282 }
283
284 #[test]
285 fn test_extensions_and_packings() {
286 let mut rng = thread_rng();
287 let data_to_hash: [BinaryField32b; 200] =
288 array::from_fn(|_| <BinaryField32b as Field>::random(&mut rng));
289 let expected = FixedLenHasherDigest::<_, Vision32b<_>>::hash(data_to_hash);
290
291 let data_as_u64 = data_to_hash
292 .chunks_exact(2)
293 .map(|x| BinaryField64b::from_bases(x).unwrap())
294 .collect::<Vec<_>>();
295 assert_eq!(FixedLenHasherDigest::<_, Vision32b<_>>::hash(&data_as_u64), expected);
296
297 let l = data_as_u64.len();
298 let data_as_packedu64 = (0..(l / 4))
299 .map(|j| PackedBinaryField4x64b::from_fn(|i| data_as_u64[j * 4 + i]))
300 .collect::<Vec<_>>();
301 assert_eq!(FixedLenHasherDigest::<_, Vision32b<_>>::hash(data_as_packedu64), expected);
302 }
303
304 #[test]
305 fn test_multi_block_unaligned() {
306 let mut hasher = Vision32b::new(23);
307 let input = "You can prove anything you want by coldly logical reason--if you pick the proper postulates.";
308 hasher.update(from_bytes_to_b32s(input.as_bytes()));
309
310 let expected = from_bytes_to_packed_256(&hex!(
311 "2819814fd9da83ab358533900adaf87f4c9e0f88657f572a9a6e83d95b88a9ea"
312 ));
313 let out = hasher.finalize().unwrap();
314 assert_eq!(expected, out);
315 }
316
317 #[test]
318 fn test_aes_to_binary_hash() {
319 let mut rng = thread_rng();
320
321 let aes_transformer_1 = make_binary_to_aes_packed_transformer::<
322 PackedBinaryField4x64b,
323 PackedAESBinaryField4x64b,
324 >();
325 let aes_transformer_2 = make_aes_to_binary_packed_transformer::<
326 PackedAESBinaryField8x32b,
327 PackedBinaryField8x32b,
328 >();
329
330 let data_bin: [PackedBinaryField4x64b; 100] =
331 array::from_fn(|_| PackedBinaryField4x64b::random(&mut rng));
332 let data_aes: [PackedAESBinaryField4x64b; 100] =
333 array::from_fn(|i| aes_transformer_1.transform(&data_bin[i]));
334
335 let hasher_32b = Vision32b::new(100);
336 let hasher_aes32b = VisionHasher::<AESTowerField32b, _>::new(100);
337
338 let digest_as_bin = hasher_32b.chain_update(data_bin).finalize().unwrap();
339 let digest_as_aes = hasher_aes32b.chain_update(data_aes).finalize().unwrap();
340
341 assert_eq!(digest_as_bin, aes_transformer_2.transform(&digest_as_aes));
342 }
343}