1use std::hash::Hasher;
7
8use arbitrary::Arbitrary;
9use get_size2::GetSize;
10use itertools::Itertools;
11use num_traits::ConstOne;
12use num_traits::ConstZero;
13use serde::Deserialize;
14use serde::Serialize;
15
16use crate::math::x_field_element::EXTENSION_DEGREE;
17use crate::prelude::BFieldCodec;
18use crate::prelude::BFieldElement;
19use crate::prelude::XFieldElement;
20use crate::util_types::sponge::Domain;
21use crate::util_types::sponge::Sponge;
22pub use digest::Digest;
23
24pub const STATE_SIZE: usize = 16;
25pub const NUM_SPLIT_AND_LOOKUP: usize = 4;
26pub const LOG2_STATE_SIZE: usize = 4;
27pub const CAPACITY: usize = 6;
28pub const RATE: usize = 10;
29pub const NUM_ROUNDS: usize = 5;
30
31pub mod digest;
32
33pub const LOOKUP_TABLE: [u8; 256] = [
36 0, 7, 26, 63, 124, 215, 85, 254, 214, 228, 45, 185, 140, 173, 33, 240, 29, 177, 176, 32, 8,
37 110, 87, 202, 204, 99, 150, 106, 230, 14, 235, 128, 213, 239, 212, 138, 23, 130, 208, 6, 44,
38 71, 93, 116, 146, 189, 251, 81, 199, 97, 38, 28, 73, 179, 95, 84, 152, 48, 35, 119, 49, 88,
39 242, 3, 148, 169, 72, 120, 62, 161, 166, 83, 175, 191, 137, 19, 100, 129, 112, 55, 221, 102,
40 218, 61, 151, 237, 68, 164, 17, 147, 46, 234, 203, 216, 22, 141, 65, 57, 123, 12, 244, 54, 219,
41 231, 96, 77, 180, 154, 5, 253, 133, 165, 98, 195, 205, 134, 245, 30, 9, 188, 59, 142, 186, 197,
42 181, 144, 92, 31, 224, 163, 111, 74, 58, 69, 113, 196, 67, 246, 225, 10, 121, 50, 60, 157, 90,
43 122, 2, 250, 101, 75, 178, 159, 24, 36, 201, 11, 243, 132, 198, 190, 114, 233, 39, 52, 21, 209,
44 108, 238, 91, 187, 18, 104, 194, 37, 153, 34, 200, 143, 126, 155, 236, 118, 64, 80, 172, 89,
45 94, 193, 135, 183, 86, 107, 252, 13, 167, 206, 136, 220, 207, 103, 171, 160, 76, 182, 227, 217,
46 158, 56, 174, 4, 66, 109, 139, 162, 184, 211, 249, 47, 125, 232, 117, 43, 16, 42, 127, 20, 241,
47 25, 149, 105, 156, 51, 53, 168, 145, 247, 223, 79, 78, 226, 15, 222, 82, 115, 70, 210, 27, 41,
48 1, 170, 40, 131, 192, 229, 248, 255,
49];
50
51pub const ROUND_CONSTANTS: [BFieldElement; NUM_ROUNDS * STATE_SIZE] = [
54 BFieldElement::new(13630775303355457758),
55 BFieldElement::new(16896927574093233874),
56 BFieldElement::new(10379449653650130495),
57 BFieldElement::new(1965408364413093495),
58 BFieldElement::new(15232538947090185111),
59 BFieldElement::new(15892634398091747074),
60 BFieldElement::new(3989134140024871768),
61 BFieldElement::new(2851411912127730865),
62 BFieldElement::new(8709136439293758776),
63 BFieldElement::new(3694858669662939734),
64 BFieldElement::new(12692440244315327141),
65 BFieldElement::new(10722316166358076749),
66 BFieldElement::new(12745429320441639448),
67 BFieldElement::new(17932424223723990421),
68 BFieldElement::new(7558102534867937463),
69 BFieldElement::new(15551047435855531404),
70 BFieldElement::new(17532528648579384106),
71 BFieldElement::new(5216785850422679555),
72 BFieldElement::new(15418071332095031847),
73 BFieldElement::new(11921929762955146258),
74 BFieldElement::new(9738718993677019874),
75 BFieldElement::new(3464580399432997147),
76 BFieldElement::new(13408434769117164050),
77 BFieldElement::new(264428218649616431),
78 BFieldElement::new(4436247869008081381),
79 BFieldElement::new(4063129435850804221),
80 BFieldElement::new(2865073155741120117),
81 BFieldElement::new(5749834437609765994),
82 BFieldElement::new(6804196764189408435),
83 BFieldElement::new(17060469201292988508),
84 BFieldElement::new(9475383556737206708),
85 BFieldElement::new(12876344085611465020),
86 BFieldElement::new(13835756199368269249),
87 BFieldElement::new(1648753455944344172),
88 BFieldElement::new(9836124473569258483),
89 BFieldElement::new(12867641597107932229),
90 BFieldElement::new(11254152636692960595),
91 BFieldElement::new(16550832737139861108),
92 BFieldElement::new(11861573970480733262),
93 BFieldElement::new(1256660473588673495),
94 BFieldElement::new(13879506000676455136),
95 BFieldElement::new(10564103842682358721),
96 BFieldElement::new(16142842524796397521),
97 BFieldElement::new(3287098591948630584),
98 BFieldElement::new(685911471061284805),
99 BFieldElement::new(5285298776918878023),
100 BFieldElement::new(18310953571768047354),
101 BFieldElement::new(3142266350630002035),
102 BFieldElement::new(549990724933663297),
103 BFieldElement::new(4901984846118077401),
104 BFieldElement::new(11458643033696775769),
105 BFieldElement::new(8706785264119212710),
106 BFieldElement::new(12521758138015724072),
107 BFieldElement::new(11877914062416978196),
108 BFieldElement::new(11333318251134523752),
109 BFieldElement::new(3933899631278608623),
110 BFieldElement::new(16635128972021157924),
111 BFieldElement::new(10291337173108950450),
112 BFieldElement::new(4142107155024199350),
113 BFieldElement::new(16973934533787743537),
114 BFieldElement::new(11068111539125175221),
115 BFieldElement::new(17546769694830203606),
116 BFieldElement::new(5315217744825068993),
117 BFieldElement::new(4609594252909613081),
118 BFieldElement::new(3350107164315270407),
119 BFieldElement::new(17715942834299349177),
120 BFieldElement::new(9600609149219873996),
121 BFieldElement::new(12894357635820003949),
122 BFieldElement::new(4597649658040514631),
123 BFieldElement::new(7735563950920491847),
124 BFieldElement::new(1663379455870887181),
125 BFieldElement::new(13889298103638829706),
126 BFieldElement::new(7375530351220884434),
127 BFieldElement::new(3502022433285269151),
128 BFieldElement::new(9231805330431056952),
129 BFieldElement::new(9252272755288523725),
130 BFieldElement::new(10014268662326746219),
131 BFieldElement::new(15565031632950843234),
132 BFieldElement::new(1209725273521819323),
133 BFieldElement::new(6024642864597845108),
134];
135
136pub const MDS_MATRIX_FIRST_COLUMN: [i64; STATE_SIZE] = [
140 61402, 1108, 28750, 33823, 7454, 43244, 53865, 12034, 56951, 27521, 41351, 40901, 12021, 59689,
141 26798, 17845,
142];
143
144#[derive(
145 Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, GetSize, BFieldCodec, Arbitrary,
146)]
147pub struct Tip5 {
148 pub state: [BFieldElement; STATE_SIZE],
149}
150
151impl Tip5 {
152 #[inline]
153 pub const fn new(domain: Domain) -> Self {
154 use Domain::*;
155
156 let mut state = [BFieldElement::ZERO; STATE_SIZE];
157
158 match domain {
159 VariableLength => (),
160 FixedLength => {
161 let mut i = RATE;
162 while i < STATE_SIZE {
163 state[i] = BFieldElement::ONE;
164 i += 1;
165 }
166 }
167 }
168
169 Self { state }
170 }
171
172 #[inline]
173 fn split_and_lookup(element: &mut BFieldElement) {
174 let mut bytes = element.raw_bytes();
176
177 for i in 0..8 {
178 bytes[i] = LOOKUP_TABLE[bytes[i] as usize];
180 }
181
182 *element = BFieldElement::from_raw_bytes(&bytes);
183 }
184
185 #[inline(always)]
186 fn mds_generated(&mut self) {
187 let mut lo: [u64; STATE_SIZE] = [0; STATE_SIZE];
188 let mut hi: [u64; STATE_SIZE] = [0; STATE_SIZE];
189 for i in 0..STATE_SIZE {
190 let b = self.state[i].raw_u64();
191 hi[i] = b >> 32;
192 lo[i] = b & 0xffffffffu64;
193 }
194
195 lo = Self::generated_function(lo);
196 hi = Self::generated_function(hi);
197
198 for r in 0..STATE_SIZE {
199 let s = (lo[r] >> 4) as u128 + ((hi[r] as u128) << 28);
200
201 let s_hi = (s >> 64) as u64;
202 let s_lo = s as u64;
203
204 let (res, over) = s_lo.overflowing_add(s_hi * 0xffffffffu64);
205
206 self.state[r] =
207 BFieldElement::from_raw_u64(if over { res + 0xffffffffu64 } else { res });
208 }
209 }
210
211 #[inline(always)]
212 fn generated_function(input: [u64; STATE_SIZE]) -> [u64; STATE_SIZE] {
213 let node_34 = input[0].wrapping_add(input[8]);
214 let node_38 = input[4].wrapping_add(input[12]);
215 let node_36 = input[2].wrapping_add(input[10]);
216 let node_40 = input[6].wrapping_add(input[14]);
217 let node_35 = input[1].wrapping_add(input[9]);
218 let node_39 = input[5].wrapping_add(input[13]);
219 let node_37 = input[3].wrapping_add(input[11]);
220 let node_41 = input[7].wrapping_add(input[15]);
221 let node_50 = node_34.wrapping_add(node_38);
222 let node_52 = node_36.wrapping_add(node_40);
223 let node_51 = node_35.wrapping_add(node_39);
224 let node_53 = node_37.wrapping_add(node_41);
225 let node_160 = input[0].wrapping_sub(input[8]);
226 let node_161 = input[1].wrapping_sub(input[9]);
227 let node_165 = input[5].wrapping_sub(input[13]);
228 let node_163 = input[3].wrapping_sub(input[11]);
229 let node_167 = input[7].wrapping_sub(input[15]);
230 let node_162 = input[2].wrapping_sub(input[10]);
231 let node_166 = input[6].wrapping_sub(input[14]);
232 let node_164 = input[4].wrapping_sub(input[12]);
233 let node_58 = node_50.wrapping_add(node_52);
234 let node_59 = node_51.wrapping_add(node_53);
235 let node_90 = node_34.wrapping_sub(node_38);
236 let node_91 = node_35.wrapping_sub(node_39);
237 let node_93 = node_37.wrapping_sub(node_41);
238 let node_92 = node_36.wrapping_sub(node_40);
239 let node_64 = node_58.wrapping_add(node_59).wrapping_mul(524757);
240 let node_67 = node_58.wrapping_sub(node_59).wrapping_mul(52427);
241 let node_71 = node_50.wrapping_sub(node_52);
242 let node_72 = node_51.wrapping_sub(node_53);
243 let node_177 = node_161.wrapping_add(node_165);
244 let node_179 = node_163.wrapping_add(node_167);
245 let node_178 = node_162.wrapping_add(node_166);
246 let node_176 = node_160.wrapping_add(node_164);
247 let node_69 = node_64.wrapping_add(node_67);
248 let node_397 = node_71
249 .wrapping_mul(18446744073709525744)
250 .wrapping_sub(node_72.wrapping_mul(53918));
251 let node_1857 = node_90.wrapping_mul(395512);
252 let node_99 = node_91.wrapping_add(node_93);
253 let node_1865 = node_91.wrapping_mul(18446744073709254400);
254 let node_1869 = node_93.wrapping_mul(179380);
255 let node_1873 = node_92.wrapping_mul(18446744073709509368);
256 let node_1879 = node_160.wrapping_mul(35608);
257 let node_185 = node_161.wrapping_add(node_163);
258 let node_1915 = node_161.wrapping_mul(18446744073709340312);
259 let node_1921 = node_163.wrapping_mul(18446744073709494992);
260 let node_1927 = node_162.wrapping_mul(18446744073709450808);
261 let node_228 = node_165.wrapping_add(node_167);
262 let node_1939 = node_165.wrapping_mul(18446744073709420056);
263 let node_1945 = node_167.wrapping_mul(18446744073709505128);
264 let node_1951 = node_166.wrapping_mul(216536);
265 let node_1957 = node_164.wrapping_mul(18446744073709515080);
266 let node_70 = node_64.wrapping_sub(node_67);
267 let node_702 = node_71
268 .wrapping_mul(53918)
269 .wrapping_add(node_72.wrapping_mul(18446744073709525744));
270 let node_1961 = node_90.wrapping_mul(18446744073709254400);
271 let node_1963 = node_91.wrapping_mul(395512);
272 let node_1965 = node_92.wrapping_mul(179380);
273 let node_1967 = node_93.wrapping_mul(18446744073709509368);
274 let node_1970 = node_160.wrapping_mul(18446744073709340312);
275 let node_1973 = node_161.wrapping_mul(35608);
276 let node_1982 = node_162.wrapping_mul(18446744073709494992);
277 let node_1985 = node_163.wrapping_mul(18446744073709450808);
278 let node_1988 = node_166.wrapping_mul(18446744073709505128);
279 let node_1991 = node_167.wrapping_mul(216536);
280 let node_1994 = node_164.wrapping_mul(18446744073709420056);
281 let node_1997 = node_165.wrapping_mul(18446744073709515080);
282 let node_98 = node_90.wrapping_add(node_92);
283 let node_184 = node_160.wrapping_add(node_162);
284 let node_227 = node_164.wrapping_add(node_166);
285 let node_86 = node_69.wrapping_add(node_397);
286 let node_403 = node_1857.wrapping_sub(
287 node_99
288 .wrapping_mul(18446744073709433780)
289 .wrapping_sub(node_1865)
290 .wrapping_sub(node_1869)
291 .wrapping_add(node_1873),
292 );
293 let node_271 = node_177.wrapping_add(node_179);
294 let node_1891 = node_177.wrapping_mul(18446744073709208752);
295 let node_1897 = node_179.wrapping_mul(18446744073709448504);
296 let node_1903 = node_178.wrapping_mul(115728);
297 let node_1909 = node_185.wrapping_mul(18446744073709283688);
298 let node_1933 = node_228.wrapping_mul(18446744073709373568);
299 let node_88 = node_70.wrapping_add(node_702);
300 let node_708 = node_1961
301 .wrapping_add(node_1963)
302 .wrapping_sub(node_1965.wrapping_add(node_1967));
303 let node_1976 = node_178.wrapping_mul(18446744073709448504);
304 let node_1979 = node_179.wrapping_mul(115728);
305 let node_87 = node_69.wrapping_sub(node_397);
306 let node_897 = node_1865
307 .wrapping_add(node_98.wrapping_mul(353264))
308 .wrapping_sub(node_1857)
309 .wrapping_sub(node_1873)
310 .wrapping_sub(node_1869);
311 let node_2007 = node_184.wrapping_mul(18446744073709486416);
312 let node_2013 = node_227.wrapping_mul(180000);
313 let node_89 = node_70.wrapping_sub(node_702);
314 let node_1077 = node_98
315 .wrapping_mul(18446744073709433780)
316 .wrapping_add(node_99.wrapping_mul(353264))
317 .wrapping_sub(node_1961.wrapping_add(node_1963))
318 .wrapping_sub(node_1965.wrapping_add(node_1967));
319 let node_2020 = node_184.wrapping_mul(18446744073709283688);
320 let node_2023 = node_185.wrapping_mul(18446744073709486416);
321 let node_2026 = node_227.wrapping_mul(18446744073709373568);
322 let node_2029 = node_228.wrapping_mul(180000);
323 let node_2035 = node_176.wrapping_mul(18446744073709550688);
324 let node_2038 = node_176.wrapping_mul(18446744073709208752);
325 let node_2041 = node_177.wrapping_mul(18446744073709550688);
326 let node_270 = node_176.wrapping_add(node_178);
327 let node_152 = node_86.wrapping_add(node_403);
328 let node_412 = node_1879.wrapping_sub(
329 node_271
330 .wrapping_mul(18446744073709105640)
331 .wrapping_sub(node_1891)
332 .wrapping_sub(node_1897)
333 .wrapping_add(node_1903)
334 .wrapping_sub(
335 node_1909
336 .wrapping_sub(node_1915)
337 .wrapping_sub(node_1921)
338 .wrapping_add(node_1927),
339 )
340 .wrapping_sub(
341 node_1933
342 .wrapping_sub(node_1939)
343 .wrapping_sub(node_1945)
344 .wrapping_add(node_1951),
345 )
346 .wrapping_add(node_1957),
347 );
348 let node_154 = node_88.wrapping_add(node_708);
349 let node_717 = node_1970.wrapping_add(node_1973).wrapping_sub(
350 node_1976
351 .wrapping_add(node_1979)
352 .wrapping_sub(node_1982.wrapping_add(node_1985))
353 .wrapping_sub(node_1988.wrapping_add(node_1991))
354 .wrapping_add(node_1994.wrapping_add(node_1997)),
355 );
356 let node_156 = node_87.wrapping_add(node_897);
357 let node_906 = node_1915
358 .wrapping_add(node_2007)
359 .wrapping_sub(node_1879)
360 .wrapping_sub(node_1927)
361 .wrapping_sub(
362 node_1897
363 .wrapping_sub(node_1921)
364 .wrapping_sub(node_1945)
365 .wrapping_add(
366 node_1939
367 .wrapping_add(node_2013)
368 .wrapping_sub(node_1957)
369 .wrapping_sub(node_1951),
370 ),
371 );
372 let node_158 = node_89.wrapping_add(node_1077);
373 let node_1086 = node_2020
374 .wrapping_add(node_2023)
375 .wrapping_sub(node_1970.wrapping_add(node_1973))
376 .wrapping_sub(node_1982.wrapping_add(node_1985))
377 .wrapping_sub(
378 node_2026
379 .wrapping_add(node_2029)
380 .wrapping_sub(node_1994.wrapping_add(node_1997))
381 .wrapping_sub(node_1988.wrapping_add(node_1991)),
382 );
383 let node_153 = node_86.wrapping_sub(node_403);
384 let node_1237 = node_1909
385 .wrapping_sub(node_1915)
386 .wrapping_sub(node_1921)
387 .wrapping_add(node_1927)
388 .wrapping_add(node_2035)
389 .wrapping_sub(node_1879)
390 .wrapping_sub(node_1957)
391 .wrapping_sub(
392 node_1933
393 .wrapping_sub(node_1939)
394 .wrapping_sub(node_1945)
395 .wrapping_add(node_1951),
396 );
397 let node_155 = node_88.wrapping_sub(node_708);
398 let node_1375 = node_1982
399 .wrapping_add(node_1985)
400 .wrapping_add(node_2038.wrapping_add(node_2041))
401 .wrapping_sub(node_1970.wrapping_add(node_1973))
402 .wrapping_sub(node_1994.wrapping_add(node_1997))
403 .wrapping_sub(node_1988.wrapping_add(node_1991));
404 let node_157 = node_87.wrapping_sub(node_897);
405 let node_1492 = node_1921
406 .wrapping_add(
407 node_1891
408 .wrapping_add(node_270.wrapping_mul(114800))
409 .wrapping_sub(node_2035)
410 .wrapping_sub(node_1903),
411 )
412 .wrapping_sub(
413 node_1915
414 .wrapping_add(node_2007)
415 .wrapping_sub(node_1879)
416 .wrapping_sub(node_1927),
417 )
418 .wrapping_sub(
419 node_1939
420 .wrapping_add(node_2013)
421 .wrapping_sub(node_1957)
422 .wrapping_sub(node_1951),
423 )
424 .wrapping_sub(node_1945);
425 let node_159 = node_89.wrapping_sub(node_1077);
426 let node_1657 = node_270
427 .wrapping_mul(18446744073709105640)
428 .wrapping_add(node_271.wrapping_mul(114800))
429 .wrapping_sub(node_2038.wrapping_add(node_2041))
430 .wrapping_sub(node_1976.wrapping_add(node_1979))
431 .wrapping_sub(
432 node_2020
433 .wrapping_add(node_2023)
434 .wrapping_sub(node_1970.wrapping_add(node_1973))
435 .wrapping_sub(node_1982.wrapping_add(node_1985)),
436 )
437 .wrapping_sub(
438 node_2026
439 .wrapping_add(node_2029)
440 .wrapping_sub(node_1994.wrapping_add(node_1997))
441 .wrapping_sub(node_1988.wrapping_add(node_1991)),
442 );
443
444 [
445 node_152.wrapping_add(node_412),
446 node_154.wrapping_add(node_717),
447 node_156.wrapping_add(node_906),
448 node_158.wrapping_add(node_1086),
449 node_153.wrapping_add(node_1237),
450 node_155.wrapping_add(node_1375),
451 node_157.wrapping_add(node_1492),
452 node_159.wrapping_add(node_1657),
453 node_152.wrapping_sub(node_412),
454 node_154.wrapping_sub(node_717),
455 node_156.wrapping_sub(node_906),
456 node_158.wrapping_sub(node_1086),
457 node_153.wrapping_sub(node_1237),
458 node_155.wrapping_sub(node_1375),
459 node_157.wrapping_sub(node_1492),
460 node_159.wrapping_sub(node_1657),
461 ]
462 }
463
464 #[inline(always)]
465 fn sbox_layer(&mut self) {
466 for i in 0..NUM_SPLIT_AND_LOOKUP {
467 Self::split_and_lookup(&mut self.state[i]);
468 }
469
470 for i in NUM_SPLIT_AND_LOOKUP..STATE_SIZE {
471 let sq = self.state[i] * self.state[i];
472 let qu = sq * sq;
473 self.state[i] *= sq * qu;
474 }
475 }
476
477 #[inline(always)]
478 fn round(&mut self, round_index: usize) {
479 self.sbox_layer();
480 self.mds_generated();
481 for i in 0..STATE_SIZE {
482 self.state[i] += ROUND_CONSTANTS[round_index * STATE_SIZE + i];
483 }
484 }
485
486 #[inline(always)]
487 pub fn permutation(&mut self) {
488 for i in 0..NUM_ROUNDS {
489 self.round(i);
490 }
491 }
492
493 pub fn trace(&mut self) -> [[BFieldElement; STATE_SIZE]; 1 + NUM_ROUNDS] {
497 let mut trace = [[BFieldElement::ZERO; STATE_SIZE]; 1 + NUM_ROUNDS];
498
499 trace[0] = self.state;
500 for i in 0..NUM_ROUNDS {
501 self.round(i);
502 trace[1 + i] = self.state;
503 }
504
505 trace
506 }
507
508 pub fn hash_10(input: &[BFieldElement; 10]) -> [BFieldElement; Digest::LEN] {
518 let mut sponge = Self::new(Domain::FixedLength);
519
520 sponge.state[..10].copy_from_slice(input);
522
523 sponge.permutation();
524
525 sponge.state[..Digest::LEN].try_into().unwrap()
527 }
528
529 pub fn hash_pair(left: Digest, right: Digest) -> Digest {
536 let mut sponge = Self::new(Domain::FixedLength);
537 sponge.state[..Digest::LEN].copy_from_slice(&left.values());
538 sponge.state[Digest::LEN..2 * Digest::LEN].copy_from_slice(&right.values());
539
540 sponge.permutation();
541
542 let digest_values = sponge.state[..Digest::LEN].try_into().unwrap();
543 Digest::new(digest_values)
544 }
545
546 pub fn hash<T: BFieldCodec>(value: &T) -> Digest {
552 Self::hash_varlen(&value.encode())
553 }
554
555 pub fn hash_varlen(input: &[BFieldElement]) -> Digest {
576 let mut sponge = Self::init();
577 sponge.pad_and_absorb_all(input);
578 let produce: [BFieldElement; Digest::LEN] =
579 (&sponge.state[..Digest::LEN]).try_into().unwrap();
580
581 Digest::new(produce)
582 }
583
584 pub fn sample_indices(&mut self, upper_bound: u32, num_indices: usize) -> Vec<u32> {
592 debug_assert!(upper_bound.is_power_of_two());
593 let mut indices = vec![];
594 let mut squeezed_elements = vec![];
595 while indices.len() != num_indices {
596 if squeezed_elements.is_empty() {
597 squeezed_elements = self.squeeze().into_iter().rev().collect_vec();
598 }
599 let element = squeezed_elements.pop().unwrap();
600 if element != BFieldElement::new(BFieldElement::MAX) {
601 indices.push(element.value() as u32 % upper_bound);
602 }
603 }
604 indices
605 }
606
607 pub fn sample_scalars(&mut self, num_elements: usize) -> Vec<XFieldElement> {
614 let num_squeezes = (num_elements * EXTENSION_DEGREE).div_ceil(Self::RATE);
615 debug_assert!(
616 num_elements * EXTENSION_DEGREE <= num_squeezes * Self::RATE,
617 "need {} elements but getting {}",
618 num_elements * EXTENSION_DEGREE,
619 num_squeezes * Self::RATE
620 );
621 (0..num_squeezes)
622 .flat_map(|_| self.squeeze())
623 .collect_vec()
624 .chunks(3)
625 .take(num_elements)
626 .map(|elem| XFieldElement::new([elem[0], elem[1], elem[2]]))
627 .collect()
628 }
629}
630
631impl Sponge for Tip5 {
632 const RATE: usize = RATE;
633
634 fn init() -> Self {
635 Self::new(Domain::VariableLength)
636 }
637
638 fn absorb(&mut self, input: [BFieldElement; RATE]) {
639 self.state[..RATE]
640 .iter_mut()
641 .zip_eq(&input)
642 .for_each(|(a, &b)| *a = b);
643
644 self.permutation();
645 }
646
647 fn squeeze(&mut self) -> [BFieldElement; RATE] {
648 let produce: [BFieldElement; RATE] = (&self.state[..RATE]).try_into().unwrap();
649 self.permutation();
650
651 produce
652 }
653}
654
655impl Hasher for Tip5 {
656 fn finish(&self) -> u64 {
657 self.state[0].value()
658 }
659
660 fn write(&mut self, bytes: &[u8]) {
661 let bfield_elements = bytes.chunks(BFieldElement::BYTES).map(|chunk| {
662 let mut buffer = [0u8; BFieldElement::BYTES];
663 buffer[..chunk.len()].copy_from_slice(chunk);
664 BFieldElement::new(u64::from_le_bytes(buffer))
665 });
666
667 for chunk in bfield_elements.chunks(Tip5::RATE).into_iter() {
668 let mut buffer = [BFieldElement::ZERO; Tip5::RATE];
669 for (buffer_elem, chunk_elem) in buffer.iter_mut().zip(chunk) {
670 *buffer_elem = chunk_elem;
671 }
672 self.absorb(buffer)
673 }
674 }
675}
676
677#[cfg(test)]
678#[cfg_attr(coverage_nightly, coverage(off))]
679pub(crate) mod tests {
680 use std::hash::Hash;
681 use std::ops::Mul;
682
683 use prop::sample::size_range;
684 use proptest::prelude::*;
685 use proptest_arbitrary_interop::arb;
686 use rand::Rng;
687 use rand::RngCore;
688 use rayon::prelude::IntoParallelIterator;
689 use rayon::prelude::ParallelIterator;
690 use test_strategy::proptest;
691
692 use super::*;
693 use crate::math::other::random_elements;
694 use crate::math::x_field_element::XFieldElement;
695
696 impl Tip5 {
697 pub(crate) fn randomly_seeded() -> Self {
698 let mut sponge = Self::init();
699 let mut rng = rand::rng();
700 sponge.absorb(rng.random());
701 sponge
702 }
703
704 fn mds_cyclomul(&mut self) {
705 let mut result = [BFieldElement::ZERO; STATE_SIZE];
706
707 let mut lo: [i64; STATE_SIZE] = [0; STATE_SIZE];
708 let mut hi: [i64; STATE_SIZE] = [0; STATE_SIZE];
709 for (i, b) in self.state.iter().enumerate() {
710 hi[i] = (b.raw_u64() >> 32) as i64;
711 lo[i] = (b.raw_u64() as u32) as i64;
712 }
713
714 lo = Self::fast_cyclomul16(lo, MDS_MATRIX_FIRST_COLUMN);
715 hi = Self::fast_cyclomul16(hi, MDS_MATRIX_FIRST_COLUMN);
716
717 for r in 0..STATE_SIZE {
718 let s = lo[r] as u128 + ((hi[r] as u128) << 32);
719 let s_hi = (s >> 64) as u64;
720 let s_lo = s as u64;
721 let z = (s_hi << 32) - s_hi;
722 let (res, over) = s_lo.overflowing_add(z);
723
724 result[r] = BFieldElement::from_raw_u64(
725 res.wrapping_add(0u32.wrapping_sub(over as u32) as u64),
726 );
727 }
728 self.state = result;
729 }
730
731 fn fast_cyclomul16(f: [i64; 16], g: [i64; 16]) -> [i64; 16] {
732 const N: usize = 8;
733 let mut ff_lo = [0i64; N];
734 let mut gg_lo = [0i64; N];
735 let mut ff_hi = [0i64; N];
736 let mut gg_hi = [0i64; N];
737 for i in 0..N {
738 ff_lo[i] = f[i] + f[i + N];
739 ff_hi[i] = f[i] - f[i + N];
740 gg_lo[i] = g[i] + g[i + N];
741 gg_hi[i] = g[i] - g[i + N];
742 }
743
744 let hh_lo = Self::fast_cyclomul8(ff_lo, gg_lo);
745 let hh_hi = Self::complex_negacyclomul8(ff_hi, gg_hi);
746
747 let mut hh = [0i64; 2 * N];
748 for i in 0..N {
749 hh[i] = (hh_lo[i] + hh_hi[i]) >> 1;
750 hh[i + N] = (hh_lo[i] - hh_hi[i]) >> 1;
751 }
752
753 hh
754 }
755
756 fn fast_cyclomul8(f: [i64; 8], g: [i64; 8]) -> [i64; 8] {
757 const N: usize = 4;
758 let mut ff_lo = [0i64; N];
759 let mut gg_lo = [0i64; N];
760 let mut ff_hi = [0i64; N];
761 let mut gg_hi = [0i64; N];
762 for i in 0..N {
763 ff_lo[i] = f[i] + f[i + N];
764 ff_hi[i] = f[i] - f[i + N];
765 gg_lo[i] = g[i] + g[i + N];
766 gg_hi[i] = g[i] - g[i + N];
767 }
768
769 let hh_lo = Self::fast_cyclomul4(ff_lo, gg_lo);
770 let hh_hi = Self::complex_negacyclomul4(ff_hi, gg_hi);
771
772 let mut hh = [0i64; 2 * N];
773 for i in 0..N {
774 hh[i] = (hh_lo[i] + hh_hi[i]) >> 1;
775 hh[i + N] = (hh_lo[i] - hh_hi[i]) >> 1;
776 }
777
778 hh
779 }
780
781 fn fast_cyclomul4(f: [i64; 4], g: [i64; 4]) -> [i64; 4] {
782 const N: usize = 2;
783 let mut ff_lo = [0i64; N];
784 let mut gg_lo = [0i64; N];
785 let mut ff_hi = [0i64; N];
786 let mut gg_hi = [0i64; N];
787 for i in 0..N {
788 ff_lo[i] = f[i] + f[i + N];
789 ff_hi[i] = f[i] - f[i + N];
790 gg_lo[i] = g[i] + g[i + N];
791 gg_hi[i] = g[i] - g[i + N];
792 }
793
794 let hh_lo = Self::fast_cyclomul2(ff_lo, gg_lo);
795 let hh_hi = Self::complex_negacyclomul2(ff_hi, gg_hi);
796
797 let mut hh = [0i64; 2 * N];
798 for i in 0..N {
799 hh[i] = (hh_lo[i] + hh_hi[i]) >> 1;
800 hh[i + N] = (hh_lo[i] - hh_hi[i]) >> 1;
801 }
802
803 hh
804 }
805
806 fn fast_cyclomul2(f: [i64; 2], g: [i64; 2]) -> [i64; 2] {
807 let ff_lo = f[0] + f[1];
808 let ff_hi = f[0] - f[1];
809 let gg_lo = g[0] + g[1];
810 let gg_hi = g[0] - g[1];
811
812 let hh_lo = ff_lo * gg_lo;
813 let hh_hi = ff_hi * gg_hi;
814
815 let mut hh = [0i64; 2];
816 hh[0] = (hh_lo + hh_hi) >> 1;
817 hh[1] = (hh_lo - hh_hi) >> 1;
818
819 hh
820 }
821
822 fn complex_negacyclomul8(f: [i64; 8], g: [i64; 8]) -> [i64; 8] {
823 const N: usize = 4;
824
825 let mut f0 = [(0i64, 0i64); N];
826 let mut g0 = [(0i64, 0i64); N];
827
828 for i in 0..N {
829 f0[i] = (f[i], -f[N + i]);
830 g0[i] = (g[i], -g[N + i]);
831 }
832
833 let h0 = Self::complex_karatsuba4(f0, g0);
834
835 let mut h = [0i64; 3 * N - 1];
836 for i in 0..(2 * N - 1) {
837 h[i] += h0[i].0;
838 h[i + N] -= h0[i].1;
839 }
840
841 let mut hh = [0i64; 2 * N];
842 for i in 0..(2 * N) {
843 hh[i] += h[i];
844 }
845 for i in (2 * N)..(3 * N - 1) {
846 hh[i - 2 * N] -= h[i];
847 }
848
849 hh
850 }
851
852 fn complex_negacyclomul4(f: [i64; 4], g: [i64; 4]) -> [i64; 4] {
853 const N: usize = 2;
854
855 let mut f0 = [(0i64, 0i64); N];
856 let mut g0 = [(0i64, 0i64); N];
857
858 for i in 0..N {
859 f0[i] = (f[i], -f[N + i]);
860 g0[i] = (g[i], -g[N + i]);
861 }
862
863 let h0 = Self::complex_karatsuba2(f0, g0);
864
865 let mut h = [0i64; 4 * N - 1];
866 for i in 0..(2 * N - 1) {
867 h[i] += h0[i].0;
868 h[i + N] -= h0[i].1;
869 }
870
871 let mut hh = [0i64; 2 * N];
872 for i in 0..(2 * N) {
873 hh[i] += h[i];
874 }
875 for i in (2 * N)..(4 * N - 1) {
876 hh[i - 2 * N] -= h[i];
877 }
878
879 hh
880 }
881
882 fn complex_negacyclomul2(f: [i64; 2], g: [i64; 2]) -> [i64; 2] {
883 let f0 = (f[0], -f[1]);
884 let g0 = (g[0], -g[1]);
885
886 let h0 = Self::complex_product(f0, g0);
887
888 [h0.0, -h0.1]
889 }
890
891 #[inline(always)]
892 fn complex_karatsuba4(f: [(i64, i64); 4], g: [(i64, i64); 4]) -> [(i64, i64); 7] {
893 const N: usize = 2;
894
895 let ff = Self::complex_sum::<2>(f[..N].try_into().unwrap(), f[N..].try_into().unwrap());
896 let gg = Self::complex_sum::<2>(g[..N].try_into().unwrap(), g[N..].try_into().unwrap());
897
898 let lo =
899 Self::complex_karatsuba2(f[..N].try_into().unwrap(), g[..N].try_into().unwrap());
900 let hi =
901 Self::complex_karatsuba2(f[N..].try_into().unwrap(), g[N..].try_into().unwrap());
902
903 let li = Self::complex_diff::<3>(
904 Self::complex_karatsuba2(ff, gg),
905 Self::complex_sum::<3>(lo, hi),
906 );
907
908 let mut result = [(0i64, 0i64); 4 * N - 1];
909 for i in 0..(2 * N - 1) {
910 result[i].0 = lo[i].0;
911 result[i].1 = lo[i].1;
912 }
913 for i in 0..(2 * N - 1) {
914 result[N + i].0 += li[i].0;
915 result[N + i].1 += li[i].1;
916 }
917 for i in 0..(2 * N - 1) {
918 result[2 * N + i].0 += hi[i].0;
919 result[2 * N + i].1 += hi[i].1;
920 }
921
922 result
923 }
924
925 fn complex_karatsuba2(f: [(i64, i64); 2], g: [(i64, i64); 2]) -> [(i64, i64); 3] {
926 const N: usize = 1;
927
928 let ff = (f[0].0 + f[1].0, f[0].1 + f[1].1);
929 let gg = (g[0].0 + g[1].0, g[0].1 + g[1].1);
930
931 let lo = Self::complex_product(f[0], g[0]);
932 let hi = Self::complex_product(f[1], g[1]);
933
934 let ff_times_gg = Self::complex_product(ff, gg);
935 let lo_plus_hi = (lo.0 + hi.0, lo.1 + hi.1);
936
937 let li = (ff_times_gg.0 - lo_plus_hi.0, ff_times_gg.1 - lo_plus_hi.1);
938
939 let mut result = [(0i64, 0i64); 4 * N - 1];
940 result[0].0 += lo.0;
941 result[0].1 += lo.1;
942 result[N].0 += li.0;
943 result[N].1 += li.1;
944 result[2 * N].0 += hi.0;
945 result[2 * N].1 += hi.1;
946
947 result
948 }
949
950 fn complex_product(f: (i64, i64), g: (i64, i64)) -> (i64, i64) {
951 (f.0 * g.0 - f.1 * g.1, f.0 * g.1 + f.1 * g.0)
953 }
954
955 fn complex_sum<const N: usize>(f: [(i64, i64); N], g: [(i64, i64); N]) -> [(i64, i64); N] {
956 let mut h = [(0i64, 0i64); N];
957 for i in 0..N {
958 h[i].0 = f[i].0 + g[i].0;
959 h[i].1 = f[i].1 + g[i].1;
960 }
961 h
962 }
963
964 fn complex_diff<const N: usize>(f: [(i64, i64); N], g: [(i64, i64); N]) -> [(i64, i64); N] {
965 let mut h = [(0i64, 0i64); N];
966 for i in 0..N {
967 h[i].0 = f[i].0 - g[i].0;
968 h[i].1 = f[i].1 - g[i].1;
969 }
970 h
971 }
972
973 fn offset_fermat_cube_map(x: u16) -> u16 {
974 let xx = (x + 1) as u64;
975 let xxx = xx * xx * xx;
976 ((xxx + 256) % 257) as u16
977 }
978 }
979
980 #[test]
981 fn get_size_test() {
982 assert_eq!(
983 STATE_SIZE * BFieldElement::ZERO.get_size(),
984 Tip5::randomly_seeded().get_size()
985 );
986 }
987
988 #[test]
989 fn lookup_table_is_correct() {
990 let table: [u8; 256] = (0..256)
991 .map(|t| Tip5::offset_fermat_cube_map(t as u16) as u8)
992 .collect_vec()
993 .try_into()
994 .unwrap();
995
996 println!(
997 "Entire lookup table:\n{}",
998 table.iter().map(|t| format!("{t:02x}")).join(", ")
999 );
1000
1001 (0_usize..256).for_each(|i| {
1002 assert_eq!(
1003 LOOKUP_TABLE[i], table[i],
1004 "Lookup tables must agree at every index, including index {i}."
1005 )
1006 });
1007 }
1008
1009 #[test]
1010 fn round_constants_are_correct() {
1011 let to_int = |bytes: &[u8]| {
1012 bytes
1013 .iter()
1014 .take(16)
1015 .enumerate()
1016 .map(|(i, b)| (*b as u128) << (8 * i))
1017 .sum::<u128>()
1018 };
1019 let round_constants = (0..NUM_ROUNDS * STATE_SIZE)
1020 .map(|i| ["Tip5".to_string().as_bytes(), &[i as u8]].concat())
1021 .map(|bytes| blake3::hash(&bytes))
1022 .map(|hash| *hash.as_bytes())
1023 .map(|bytes| to_int(&bytes))
1024 .map(|i| (i % BFieldElement::P as u128) as u64)
1025 .map(BFieldElement::from_raw_u64)
1026 .collect_vec();
1027
1028 println!(
1029 "In case you changed something, here are all round constants:\n{}",
1030 round_constants.iter().map(|c| format!("{c}")).join(", ")
1031 );
1032
1033 (0_usize..NUM_ROUNDS * STATE_SIZE).for_each(|i| {
1034 assert_eq!(
1035 ROUND_CONSTANTS[i], round_constants[i],
1036 "Round constants must agree at every index, including index {i}."
1037 )
1038 });
1039 }
1040
1041 #[test]
1042 fn test_fermat_cube_map_is_permutation() {
1043 let mut touched = [false; 256];
1044 for i in 0..256 {
1045 touched[Tip5::offset_fermat_cube_map(i) as usize] = true;
1046 }
1047 assert!(touched.iter().all(|t| *t));
1048 assert_eq!(Tip5::offset_fermat_cube_map(0), 0);
1049 assert_eq!(Tip5::offset_fermat_cube_map(255), 255);
1050 }
1051
1052 #[test]
1053 fn calculate_differential_uniformity() {
1054 let count_satisfiers_fermat = |a, b| {
1057 (0..(1 << 8))
1058 .map(|x| {
1059 u16::from(
1060 (256 + Tip5::offset_fermat_cube_map((x + a) & 0xff)
1061 - Tip5::offset_fermat_cube_map(x))
1062 & 0xff
1063 == b,
1064 )
1065 })
1066 .sum()
1067 };
1068 let du_fermat: u16 = (1..256)
1069 .into_par_iter()
1070 .map(|a| {
1071 (1..256)
1072 .map(|b| count_satisfiers_fermat(a, b))
1073 .max()
1074 .unwrap()
1075 })
1076 .max()
1077 .unwrap();
1078 println!("additive differential uniformity for fermat cube map: {du_fermat}");
1079
1080 let count_satisfiers_fermat_bitwise = |a: u16, b: u16| {
1082 (0..(1 << 8))
1083 .map(|x| {
1084 u16::from(
1085 (Tip5::offset_fermat_cube_map(x ^ a) ^ Tip5::offset_fermat_cube_map(x))
1086 == b,
1087 )
1088 })
1089 .sum::<u16>()
1090 };
1091 for a in 1..256 {
1092 for b in 1..256 {
1093 let num_satisfiers = count_satisfiers_fermat_bitwise(a, b);
1094 if num_satisfiers == 256 {
1095 println!("a: {a}, b: {b} -> 256 satisfiers");
1096 }
1097 }
1098 }
1099 let du_fermat_bitwise: u16 = (1..256)
1100 .into_par_iter()
1101 .map(|a| {
1102 (1..256)
1103 .map(|b| count_satisfiers_fermat_bitwise(a, b))
1104 .max()
1105 .unwrap()
1106 })
1107 .max()
1108 .unwrap();
1109 println!("bitwise differential uniformity for fermat cube map: {du_fermat_bitwise}");
1110 }
1111
1112 #[test]
1113 fn calculate_approximation_quality() {
1114 let mut fermat_cubed = [0u16; 65536];
1115 let mut bfield_cubed = [0u16; 65536];
1116 for i in 0..65536 {
1117 let cubed = (i as u64) * (i as u64) * (i as u64);
1118 fermat_cubed[i] = (cubed % 65537) as u16;
1119 bfield_cubed[i] = (cubed & 0xffff) as u16;
1120 }
1121 let equal_count = fermat_cubed
1122 .iter()
1123 .zip(bfield_cubed.iter())
1124 .filter(|(a, b)| a == b)
1125 .count();
1126 println!("agreement with low-degree function: {equal_count}");
1127 }
1128
1129 #[test]
1130 fn hash10_test_vectors() {
1131 let mut preimage = [BFieldElement::ZERO; RATE];
1132 let mut digest: [BFieldElement; Digest::LEN];
1133 for i in 0..6 {
1134 digest = Tip5::hash_10(&preimage);
1135 println!(
1136 "{:?} -> {:?}",
1137 preimage.iter().map(|b| b.value()).collect_vec(),
1138 digest.iter().map(|b| b.value()).collect_vec()
1139 );
1140 preimage[i..Digest::LEN + i].copy_from_slice(&digest);
1141 }
1142 digest = Tip5::hash_10(&preimage);
1143 println!(
1144 "{:?} -> {:?}",
1145 preimage.iter().map(|b| b.value()).collect_vec(),
1146 digest.iter().map(|b| b.value()).collect_vec()
1147 );
1148 let final_digest = [
1149 10869784347448351760,
1150 1853783032222938415,
1151 6856460589287344822,
1152 17178399545409290325,
1153 7650660984651717733,
1154 ]
1155 .map(BFieldElement::new);
1156 assert_eq!(
1157 digest,
1158 final_digest,
1159 "expected: {:?}\nbut got: {:?}",
1160 final_digest.map(|d| d.value()),
1161 digest.map(|d| d.value()),
1162 )
1163 }
1164
1165 #[test]
1166 fn hash_varlen_test_vectors() {
1167 let mut digest_sum = [BFieldElement::ZERO; Digest::LEN];
1168 for i in 0..20 {
1169 let preimage = (0..i).map(BFieldElement::new).collect_vec();
1170 let digest = Tip5::hash_varlen(&preimage);
1171 println!(
1172 "{:?} -> {:?}",
1173 preimage.iter().map(|b| b.value()).collect_vec(),
1174 digest.values().iter().map(|b| b.value()).collect_vec()
1175 );
1176 digest_sum
1177 .iter_mut()
1178 .zip(digest.values().iter())
1179 .for_each(|(s, d)| *s += *d);
1180 }
1181 println!(
1182 "sum of digests: {:?}",
1183 digest_sum.iter().map(|b| b.value()).collect_vec()
1184 );
1185 let expected_sum = [
1186 7610004073009036015,
1187 5725198067541094245,
1188 4721320565792709122,
1189 1732504843634706218,
1190 259800783350288362,
1191 ]
1192 .map(BFieldElement::new);
1193 assert_eq!(
1194 expected_sum,
1195 digest_sum,
1196 "expected: {:?}\nbut got: {:?}",
1197 expected_sum.map(|s| s.value()),
1198 digest_sum.map(|s| s.value())
1199 );
1200 }
1201
1202 fn manual_hash_varlen(preimage: &[BFieldElement]) -> Digest {
1203 let mut sponge = Tip5::init();
1204 sponge.pad_and_absorb_all(preimage);
1205 let squeeze_result = sponge.squeeze();
1206
1207 Digest::new((&squeeze_result[..Digest::LEN]).try_into().unwrap())
1208 }
1209
1210 #[test]
1211 fn hash_var_len_equivalence_corner_cases() {
1212 for preimage_length in 0..=11 {
1213 let preimage = vec![BFieldElement::new(42); preimage_length];
1214 let hash_varlen_digest = Tip5::hash_varlen(&preimage);
1215
1216 let digest_through_pad_squeeze_absorb = manual_hash_varlen(&preimage);
1217 assert_eq!(digest_through_pad_squeeze_absorb, hash_varlen_digest);
1218 }
1219 }
1220
1221 #[proptest]
1222 fn hash_var_len_equivalence(#[strategy(arb())] preimage: Vec<BFieldElement>) {
1223 let hash_varlen_digest = Tip5::hash_varlen(&preimage);
1224 let digest_through_pad_squeeze_absorb = manual_hash_varlen(&preimage);
1225 prop_assert_eq!(digest_through_pad_squeeze_absorb, hash_varlen_digest);
1226 }
1227
1228 #[test]
1229 fn test_linearity_of_mds() {
1230 type SpongeState = [BFieldElement; STATE_SIZE];
1231
1232 let mds_procedure = |state| {
1233 let mut sponge = Tip5 { state };
1234 sponge.mds_cyclomul();
1235 sponge.state
1236 };
1237
1238 let a: BFieldElement = random_elements(1)[0];
1239 let b: BFieldElement = random_elements(1)[0];
1240
1241 let mul_procedure = |u: SpongeState, v: SpongeState| -> SpongeState {
1242 let mul_result = u.iter().zip(&v).map(|(&uu, &vv)| a * uu + b * vv);
1243 mul_result.collect_vec().try_into().unwrap()
1244 };
1245
1246 let u: SpongeState = random_elements(STATE_SIZE).try_into().unwrap();
1247 let v: SpongeState = random_elements(STATE_SIZE).try_into().unwrap();
1248 let w = mul_procedure(u, v);
1249
1250 let u = mds_procedure(u);
1251 let v = mds_procedure(v);
1252 let w = mds_procedure(w);
1253
1254 let w_ = mul_procedure(u, v);
1255
1256 assert_eq!(w, w_);
1257 }
1258
1259 #[test]
1260 fn test_mds_circulancy() {
1261 let mut sponge = Tip5::init();
1262 sponge.state = [BFieldElement::ZERO; STATE_SIZE];
1263 sponge.state[0] = BFieldElement::ONE;
1264
1265 sponge.mds_generated();
1266
1267 let mut mat_first_row = [BFieldElement::ZERO; STATE_SIZE];
1268 mat_first_row[0] = sponge.state[0];
1269 for (i, first_row_elem) in mat_first_row.iter_mut().enumerate().skip(1) {
1270 *first_row_elem = sponge.state[STATE_SIZE - i];
1271 }
1272
1273 println!(
1274 "mds matrix first row: {:?}",
1275 mat_first_row.map(|b| b.value())
1276 );
1277
1278 let initial_state: [BFieldElement; STATE_SIZE] =
1279 random_elements(STATE_SIZE).try_into().unwrap();
1280
1281 let mut mv = [BFieldElement::ZERO; STATE_SIZE];
1282 for i in 0..STATE_SIZE {
1283 for j in 0..STATE_SIZE {
1284 mv[i] += mat_first_row[(STATE_SIZE - i + j) % STATE_SIZE] * initial_state[j];
1285 }
1286 }
1287
1288 let mut sponge_2 = Tip5::init();
1289 sponge_2.state = initial_state;
1290 sponge_2.mds_generated();
1291
1292 assert_eq!(sponge_2.state, mv);
1293 }
1294
1295 #[test]
1296 fn test_complex_karatsuba() {
1297 const N: usize = 4;
1298 let mut f = [(0i64, 0i64); N];
1299 let mut g = [(0i64, 0i64); N];
1300 for i in 0..N {
1301 f[i].0 = i as i64;
1302 g[i].0 = 1;
1303 f[i].1 = 1;
1304 g[i].1 = i as i64;
1305 }
1306
1307 let h0 = Tip5::complex_karatsuba4(f, g);
1308 let h1 = [(0, 1), (0, 2), (0, 4), (0, 8), (0, 13), (0, 14), (0, 10)];
1309
1310 assert_eq!(h0, h1);
1311 }
1312
1313 #[test]
1314 fn test_complex_product() {
1315 let mut rng = rand::rng();
1316 let mut random_small_i64 = || (rng.next_u32() % (1 << 16)) as i64;
1317 for _ in 0..1000 {
1318 let f = (random_small_i64(), random_small_i64());
1319 let g = (random_small_i64(), random_small_i64());
1320 let h0 = Tip5::complex_product(f, g);
1321 let h1 = (f.0 * g.0 - f.1 * g.1, f.0 * g.1 + f.1 * g.0);
1322 assert_eq!(h1, h0);
1323 }
1324 }
1325
1326 #[test]
1327 fn sample_scalars_test() {
1328 let mut sponge = Tip5::randomly_seeded();
1329 let mut product = XFieldElement::ONE;
1330 for amount in 0..=4 {
1331 let scalars = sponge.sample_scalars(amount);
1332 assert_eq!(amount, scalars.len());
1333 product *= scalars
1334 .into_iter()
1335 .fold(XFieldElement::ONE, XFieldElement::mul);
1336 }
1337 assert_ne!(product, XFieldElement::ZERO); }
1339
1340 #[test]
1341 fn test_mds_agree() {
1342 let mut rng = rand::rng();
1343 let initial_state: [BFieldElement; STATE_SIZE] = (0..STATE_SIZE)
1344 .map(|_| BFieldElement::new(rng.random_range(0..10)))
1345 .collect_vec()
1346 .try_into()
1347 .unwrap();
1348
1349 let mut sponge_cyclomut = Tip5 {
1350 state: initial_state,
1351 };
1352 let mut sponge_generated = Tip5 {
1353 state: initial_state,
1354 };
1355
1356 sponge_cyclomut.mds_cyclomul();
1357 sponge_generated.mds_generated();
1358
1359 assert_eq!(
1360 sponge_cyclomut,
1361 sponge_generated,
1362 "cyclomul =/= generated\n{}\n{}",
1363 sponge_cyclomut.state.into_iter().join(","),
1364 sponge_generated.state.into_iter().join(",")
1365 );
1366 }
1367
1368 #[test]
1369 fn tip5_hasher_trait_snapshot_test() {
1370 let mut hasher = Tip5::init();
1371 let data = b"hello world";
1372 hasher.write(data);
1373 assert_eq!(hasher.finish(), 2267905471610932299);
1374 }
1375
1376 #[proptest]
1377 fn tip5_hasher_consumes_small_data(#[filter(!#bytes.is_empty())] bytes: Vec<u8>) {
1378 let mut hasher = Tip5::init();
1379 bytes.hash(&mut hasher);
1380
1381 prop_assert_ne!(Tip5::init().finish(), hasher.finish());
1382 }
1383
1384 #[proptest]
1385 fn appending_small_data_to_big_data_changes_tip5_hash(
1386 #[any(size_range(2_000..8_000).lift())] big_data: Vec<u8>,
1387 #[filter(!#small_data.is_empty())] small_data: Vec<u8>,
1388 ) {
1389 let mut hasher = Tip5::init();
1390 big_data.hash(&mut hasher);
1391 let big_data_hash = hasher.finish();
1392
1393 small_data.hash(&mut hasher);
1395 let all_data_hash = hasher.finish();
1396
1397 prop_assert_ne!(big_data_hash, all_data_hash);
1398 }
1399
1400 #[proptest]
1401 fn tip5_trace_starts_with_initial_state_and_is_equivalent_to_permutation(
1402 #[strategy(arb())] mut tip5: Tip5,
1403 ) {
1404 let [first, .., last] = tip5.clone().trace();
1405 prop_assert_eq!(first, tip5.state);
1406
1407 tip5.permutation();
1408 prop_assert_eq!(last, tip5.state);
1409 }
1410}