1use alloc::vec;
2use alloc::vec::Vec;
3use core::error::Error;
4use core::fmt::{Display, Formatter};
5
6use p3_field::{BasedVectorSpace, Field, PrimeField, PrimeField64};
7use p3_monty_31::{MontyField31, MontyParameters};
8use p3_symmetric::{CryptographicPermutation, Hash, MerkleCap};
9
10use crate::{
11 CanFinalizeDigest, CanObserve, CanSample, CanSampleBits, CanSampleUniformBits, FieldChallenger,
12};
13
14#[derive(Clone, Debug)]
31pub struct DuplexChallenger<F, P, const WIDTH: usize, const RATE: usize>
32where
33 F: Clone,
34 P: CryptographicPermutation<[F; WIDTH]>,
35{
36 pub sponge_state: [F; WIDTH],
43
44 pub input_buffer: Vec<F>,
50
51 pub output_buffer: Vec<F>,
57
58 pub permutation: P,
64}
65
66impl<F, P, const WIDTH: usize, const RATE: usize> DuplexChallenger<F, P, WIDTH, RATE>
67where
68 F: Copy,
69 P: CryptographicPermutation<[F; WIDTH]>,
70{
71 pub fn new(permutation: P) -> Self
72 where
73 F: Default,
74 {
75 const {
76 assert!(RATE > 0 && RATE < WIDTH);
77 }
78 Self {
79 sponge_state: [F::default(); WIDTH],
80 input_buffer: vec![],
81 output_buffer: vec![],
82 permutation,
83 }
84 }
85
86 pub(crate) fn duplexing(&mut self) {
87 assert!(self.input_buffer.len() <= RATE);
88
89 for (i, val) in self.input_buffer.drain(..).enumerate() {
91 self.sponge_state[i] = val;
92 }
93
94 self.permutation.permute_mut(&mut self.sponge_state);
96
97 self.output_buffer.clear();
98 self.output_buffer.extend(&self.sponge_state[..RATE]);
99 }
100}
101
102impl<F, P, const WIDTH: usize, const RATE: usize> DuplexChallenger<F, P, WIDTH, RATE>
103where
104 F: Copy + Default + PrimeField,
105 P: CryptographicPermutation<[F; WIDTH]>,
106{
107 pub fn absorb_rate_padded_with_tag(&mut self, values: &[F], length_tag: u8) {
114 const {
115 assert!(
116 RATE < WIDTH,
117 "RATE must be less than WIDTH for capacity length slot"
118 );
119 }
120 assert!(values.len() <= RATE);
121 self.input_buffer.clear();
122 self.output_buffer.clear();
123 for (i, &v) in values.iter().enumerate() {
124 self.sponge_state[i] = v;
125 }
126 self.sponge_state[values.len()..RATE].fill(F::ZERO);
127 self.sponge_state[RATE] += F::from_u8(length_tag);
128 self.permutation.permute_mut(&mut self.sponge_state);
129 self.output_buffer
130 .extend_from_slice(&self.sponge_state[..RATE]);
131 }
132}
133
134impl<F, P, const WIDTH: usize, const RATE: usize> FieldChallenger<F>
135 for DuplexChallenger<F, P, WIDTH, RATE>
136where
137 F: PrimeField64,
138 P: CryptographicPermutation<[F; WIDTH]>,
139{
140}
141
142impl<F, P, const WIDTH: usize, const RATE: usize> CanObserve<F>
143 for DuplexChallenger<F, P, WIDTH, RATE>
144where
145 F: Copy,
146 P: CryptographicPermutation<[F; WIDTH]>,
147{
148 fn observe(&mut self, value: F) {
149 self.output_buffer.clear();
151
152 self.input_buffer.push(value);
153
154 if self.input_buffer.len() == RATE {
155 self.duplexing();
156 }
157 }
158}
159
160impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<[F; N]>
161 for DuplexChallenger<F, P, WIDTH, RATE>
162where
163 F: Copy,
164 P: CryptographicPermutation<[F; WIDTH]>,
165{
166 fn observe(&mut self, values: [F; N]) {
167 for value in values {
168 self.observe(value);
169 }
170 }
171}
172
173impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<Hash<F, F, N>>
174 for DuplexChallenger<F, P, WIDTH, RATE>
175where
176 F: Copy,
177 P: CryptographicPermutation<[F; WIDTH]>,
178{
179 fn observe(&mut self, values: Hash<F, F, N>) {
180 for value in values {
181 self.observe(value);
182 }
183 }
184}
185
186impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<&MerkleCap<F, [F; N]>>
187 for DuplexChallenger<F, P, WIDTH, RATE>
188where
189 F: Copy,
190 P: CryptographicPermutation<[F; WIDTH]>,
191{
192 fn observe(&mut self, cap: &MerkleCap<F, [F; N]>) {
193 for digest in cap.roots() {
194 for value in digest {
195 self.observe(*value);
196 }
197 }
198 }
199}
200
201impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<MerkleCap<F, [F; N]>>
202 for DuplexChallenger<F, P, WIDTH, RATE>
203where
204 F: Copy,
205 P: CryptographicPermutation<[F; WIDTH]>,
206{
207 fn observe(&mut self, cap: MerkleCap<F, [F; N]>) {
208 self.observe(&cap);
209 }
210}
211
212impl<F, P, const WIDTH: usize, const RATE: usize> CanObserve<Vec<Vec<F>>>
214 for DuplexChallenger<F, P, WIDTH, RATE>
215where
216 F: Copy,
217 P: CryptographicPermutation<[F; WIDTH]>,
218{
219 fn observe(&mut self, valuess: Vec<Vec<F>>) {
220 for values in valuess {
221 for value in values {
222 self.observe(value);
223 }
224 }
225 }
226}
227
228impl<F, EF, P, const WIDTH: usize, const RATE: usize> CanSample<EF>
229 for DuplexChallenger<F, P, WIDTH, RATE>
230where
231 F: Field,
232 EF: BasedVectorSpace<F>,
233 P: CryptographicPermutation<[F; WIDTH]>,
234{
235 fn sample(&mut self) -> EF {
236 EF::from_basis_coefficients_fn(|_| {
237 if !self.input_buffer.is_empty() || self.output_buffer.is_empty() {
240 self.duplexing();
241 }
242
243 self.output_buffer
244 .pop()
245 .expect("Output buffer should be non-empty")
246 })
247 }
248}
249
250impl<F, P, const WIDTH: usize, const RATE: usize> CanSampleBits<usize>
251 for DuplexChallenger<F, P, WIDTH, RATE>
252where
253 F: PrimeField64,
254 P: CryptographicPermutation<[F; WIDTH]>,
255{
256 fn sample_bits(&mut self, bits: usize) -> usize {
265 assert!(bits < (usize::BITS as usize));
266 assert!((1 << bits) < F::ORDER_U64);
267 let rand_f: F = self.sample();
268 let rand_usize = rand_f.as_canonical_u64() as usize;
269 rand_usize & ((1 << bits) - 1)
270 }
271}
272
273pub trait UniformSamplingField {
275 const MAX_SINGLE_SAMPLE_BITS: usize;
278 const SAMPLING_BITS_M: [u64; 64];
289}
290
291impl<MP> UniformSamplingField for MontyField31<MP>
295where
296 MP: UniformSamplingField + MontyParameters,
297{
298 const MAX_SINGLE_SAMPLE_BITS: usize = MP::MAX_SINGLE_SAMPLE_BITS;
299 const SAMPLING_BITS_M: [u64; 64] = MP::SAMPLING_BITS_M;
300}
301
302pub(super) struct ResampleOnRejection;
306pub(super) struct ErrorOnRejection;
308
309#[derive(Debug)]
312pub struct ResamplingError {
313 value: u64,
315 m: u64,
317}
318
319impl Display for ResamplingError {
320 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
321 write!(
322 f,
323 "Encountered value {0}, which requires resampling for uniform bits as it not smaller than {1}. But resampling is not enabled.",
324 self.value, self.m
325 )
326 }
327}
328
329impl Error for ResamplingError {}
330
331pub(super) trait BitSamplingStrategy<F, P, const W: usize, const R: usize>
333where
334 F: PrimeField64,
335 P: CryptographicPermutation<[F; W]>,
336{
337 const ERROR_ON_REJECTION: bool;
339
340 #[inline]
341 fn sample_value(
342 challenger: &mut DuplexChallenger<F, P, W, R>,
343 m: u64,
344 ) -> Result<F, ResamplingError> {
345 let mut result: F = challenger.sample();
346 if Self::ERROR_ON_REJECTION {
347 if result.as_canonical_u64() >= m {
348 return Err(ResamplingError {
349 value: result.as_canonical_u64(),
350 m,
351 });
352 }
353 } else {
354 while result.as_canonical_u64() >= m {
355 result = challenger.sample();
356 }
357 }
358 Ok(result)
359 }
360}
361
362impl<F, P, const W: usize, const R: usize> BitSamplingStrategy<F, P, W, R> for ResampleOnRejection
364where
365 F: PrimeField64,
366 P: CryptographicPermutation<[F; W]>,
367{
368 const ERROR_ON_REJECTION: bool = false;
369}
370
371impl<F, P, const W: usize, const R: usize> BitSamplingStrategy<F, P, W, R> for ErrorOnRejection
373where
374 F: PrimeField64,
375 P: CryptographicPermutation<[F; W]>,
376{
377 const ERROR_ON_REJECTION: bool = true;
378}
379
380impl<F, P, const WIDTH: usize, const RATE: usize> DuplexChallenger<F, P, WIDTH, RATE>
381where
382 F: UniformSamplingField + PrimeField64,
383 P: CryptographicPermutation<[F; WIDTH]>,
384{
385 #[inline]
387 fn sample_uniform_bits_with_strategy<S>(
388 &mut self,
389 bits: usize,
390 ) -> Result<usize, ResamplingError>
391 where
392 S: BitSamplingStrategy<F, P, WIDTH, RATE>,
393 {
394 if bits == 0 {
395 return Ok(0);
396 };
397 assert!(bits < usize::BITS as usize, "bit count must be valid");
398 assert!(
399 (1u64 << bits) < F::ORDER_U64,
400 "bit count exceeds field order"
401 );
402 let m = F::SAMPLING_BITS_M[bits];
403 if bits <= F::MAX_SINGLE_SAMPLE_BITS {
404 let rand_f = S::sample_value(self, m);
406 Ok(rand_f?.as_canonical_u64() as usize & ((1 << bits) - 1))
407 } else {
408 let half_bits1 = bits / 2;
411 let half_bits2 = bits - half_bits1;
412 let rand1 = S::sample_value(self, F::SAMPLING_BITS_M[half_bits1]);
414 let chunk1 = rand1?.as_canonical_u64() as usize & ((1 << half_bits1) - 1);
415 let rand2 = S::sample_value(self, F::SAMPLING_BITS_M[half_bits2]);
417 let chunk2 = rand2?.as_canonical_u64() as usize & ((1 << half_bits2) - 1);
418
419 Ok(chunk1 | (chunk2 << half_bits1))
421 }
422 }
423}
424
425impl<F, P, const WIDTH: usize, const RATE: usize> CanSampleUniformBits<F>
426 for DuplexChallenger<F, P, WIDTH, RATE>
427where
428 F: UniformSamplingField + PrimeField64,
429 P: CryptographicPermutation<[F; WIDTH]>,
430{
431 fn sample_uniform_bits<const RESAMPLE: bool>(
432 &mut self,
433 bits: usize,
434 ) -> Result<usize, ResamplingError> {
435 if RESAMPLE {
436 self.sample_uniform_bits_with_strategy::<ResampleOnRejection>(bits)
437 } else {
438 self.sample_uniform_bits_with_strategy::<ErrorOnRejection>(bits)
439 }
440 }
441}
442
443impl<F, P, const WIDTH: usize, const RATE: usize> CanFinalizeDigest
444 for DuplexChallenger<F, P, WIDTH, RATE>
445where
446 F: Copy,
447 P: CryptographicPermutation<[F; WIDTH]>,
448{
449 type Digest = [F; RATE];
450
451 fn finalize(mut self) -> [F; RATE] {
452 self.duplexing();
458 self.sponge_state[..RATE].try_into().unwrap()
459 }
460}
461
462#[cfg(test)]
463mod tests {
464 use core::iter;
465
466 use p3_baby_bear::BabyBear;
467 use p3_field::PrimeCharacteristicRing;
468 use p3_field::extension::BinomialExtensionField;
469 use p3_goldilocks::Goldilocks;
470 use p3_symmetric::Permutation;
471
472 use super::*;
473 use crate::grinding_challenger::GrindingChallenger;
474
475 const WIDTH: usize = 24;
476 const RATE: usize = 16;
477
478 type G = Goldilocks;
479 type EF2G = BinomialExtensionField<G, 2>;
480
481 type BB = BabyBear;
482
483 #[derive(Clone)]
484 struct TestPermutation {}
485
486 impl<F: Clone> Permutation<[F; WIDTH]> for TestPermutation {
487 fn permute_mut(&self, input: &mut [F; WIDTH]) {
488 input.reverse();
489 }
490 }
491
492 impl<F: Clone> CryptographicPermutation<[F; WIDTH]> for TestPermutation {}
493
494 #[test]
495 fn test_duplex_challenger() {
496 type Chal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
497 let permutation = TestPermutation {};
498 let mut duplex_challenger = DuplexChallenger::new(permutation);
499
500 (0..12).for_each(|element| duplex_challenger.observe(G::from_u8(element as u8)));
502
503 let state_after_duplexing: Vec<_> = iter::repeat_n(G::ZERO, 12)
504 .chain((0..12).map(G::from_u8).rev())
505 .collect();
506
507 let expected_samples: Vec<G> = state_after_duplexing[..16].iter().copied().rev().collect();
508 let samples = <Chal as CanSample<G>>::sample_vec(&mut duplex_challenger, 16);
509 assert_eq!(samples, expected_samples);
510 }
511
512 #[test]
513 #[should_panic]
514 fn test_duplex_challenger_sample_bits_security() {
515 type GoldilocksChal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
516 let permutation = TestPermutation {};
517 let mut duplex_challenger = GoldilocksChal::new(permutation);
518
519 for _ in 0..100 {
520 assert!(duplex_challenger.sample_bits(129) < 4);
521 }
522 }
523
524 #[test]
525 #[should_panic]
526 fn test_duplex_challenger_sample_bits_security_small_field() {
527 type BabyBearChal = DuplexChallenger<BB, TestPermutation, WIDTH, RATE>;
528 let permutation = TestPermutation {};
529 let mut duplex_challenger = BabyBearChal::new(permutation);
530
531 for _ in 0..100 {
532 assert!(duplex_challenger.sample_bits(40) < 1 << 31);
533 }
534 }
535
536 #[test]
537 #[should_panic]
538 fn test_duplex_challenger_grind_security() {
539 type GoldilocksChal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
540 let permutation = TestPermutation {};
541 let mut duplex_challenger = GoldilocksChal::new(permutation);
542
543 let too_many_bits = usize::BITS as usize;
548
549 let witness = duplex_challenger.grind(too_many_bits);
550 assert!(duplex_challenger.check_witness(too_many_bits, witness));
551 }
552
553 #[test]
554 fn test_observe_single_value() {
555 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
556 chal.observe(G::from_u8(42));
557 assert_eq!(chal.input_buffer, vec![G::from_u8(42)]);
558 assert!(chal.output_buffer.is_empty());
559 }
560
561 #[test]
562 fn test_observe_array_of_values() {
563 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
564 chal.observe([G::from_u8(1), G::from_u8(2), G::from_u8(3)]);
565 assert_eq!(
566 chal.input_buffer,
567 vec![G::from_u8(1), G::from_u8(2), G::from_u8(3)]
568 );
569 assert!(chal.output_buffer.is_empty());
570 }
571
572 #[test]
573 fn test_observe_hash_array() {
574 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
575 let hash = Hash::<G, G, 4>::from([G::from_u8(10); 4]);
576 chal.observe(hash);
577 assert_eq!(chal.input_buffer, vec![G::from_u8(10); 4]);
578 }
579
580 #[test]
581 fn test_observe_nested_vecs() {
582 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
583 chal.observe(vec![
584 vec![G::from_u8(1), G::from_u8(2)],
585 vec![G::from_u8(3)],
586 ]);
587 assert_eq!(
588 chal.input_buffer,
589 vec![G::from_u8(1), G::from_u8(2), G::from_u8(3)]
590 );
591 }
592
593 #[test]
594 fn test_sample_triggers_duplex() {
595 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
596 chal.observe(G::from_u8(5));
597 assert!(chal.output_buffer.is_empty());
598 let _sample: G = chal.sample();
599 assert!(!chal.output_buffer.is_empty());
600 }
601
602 #[test]
603 fn test_sample_multiple_extension_field() {
604 use p3_field::extension::BinomialExtensionField;
605 type EF = BinomialExtensionField<G, 2>;
606 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
607
608 chal.observe(G::from_u8(1));
609 chal.observe(G::from_u8(2));
610 let _: EF = chal.sample();
611 let _: EF = chal.sample();
612 }
613
614 #[test]
615 fn test_sample_bits_within_bounds() {
616 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
617 for i in 0..RATE {
618 chal.observe(G::from_u8(i as u8));
619 }
620
621 let bits = 3;
626 let value = chal.sample_bits(bits);
627 let expected = G::ZERO.as_canonical_u64() as usize & ((1 << bits) - 1);
628 assert_eq!(value, expected);
629 }
630
631 #[test]
632 fn test_sample_bits_trigger_duplex_when_empty() {
633 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
634 assert_eq!(chal.input_buffer.len(), 0);
636 assert_eq!(chal.output_buffer.len(), 0);
637
638 let bits = 2;
640 let sample = chal.sample_bits(bits);
641 let expected = G::ZERO.as_canonical_u64() as usize & ((1 << bits) - 1);
642 assert_eq!(sample, expected);
643 }
644
645 #[test]
646 fn test_output_buffer_pops_correctly() {
647 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
648
649 for i in 0..RATE {
651 chal.observe(G::from_u8(i as u8));
652 }
653
654 let expected = [
656 G::from_u8(0),
657 G::from_u8(0),
658 G::from_u8(0),
659 G::from_u8(0),
660 G::from_u8(0),
661 G::from_u8(0),
662 G::from_u8(0),
663 G::from_u8(0),
664 G::from_u8(15),
665 G::from_u8(14),
666 G::from_u8(13),
667 G::from_u8(12),
668 G::from_u8(11),
669 G::from_u8(10),
670 G::from_u8(9),
671 G::from_u8(8),
672 ]
673 .to_vec();
674
675 assert_eq!(chal.output_buffer, expected);
676
677 let first: G = chal.sample();
678 let second: G = chal.sample();
679
680 assert_eq!(first, G::from_u8(8));
682 assert_eq!(second, G::from_u8(9));
683 }
684
685 #[test]
686 fn test_duplexing_only_when_needed() {
687 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
688 chal.output_buffer = vec![G::from_u8(10), G::from_u8(20)];
689
690 let sample: G = chal.sample();
692 assert_eq!(sample, G::from_u8(20));
693 assert_eq!(chal.output_buffer, vec![G::from_u8(10)]);
694 }
695
696 #[test]
697 fn test_flush_when_input_full() {
698 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
699
700 for i in 0..RATE {
702 chal.observe(G::from_u8(i as u8));
703 }
704
705 let expected_output = [
707 G::from_u8(0),
708 G::from_u8(0),
709 G::from_u8(0),
710 G::from_u8(0),
711 G::from_u8(0),
712 G::from_u8(0),
713 G::from_u8(0),
714 G::from_u8(0),
715 G::from_u8(15),
716 G::from_u8(14),
717 G::from_u8(13),
718 G::from_u8(12),
719 G::from_u8(11),
720 G::from_u8(10),
721 G::from_u8(9),
722 G::from_u8(8),
723 ]
724 .to_vec();
725
726 assert!(chal.input_buffer.is_empty());
728
729 assert_eq!(chal.output_buffer, expected_output);
731 }
732
733 #[test]
734 fn test_observe_base_as_algebra_element_consistency_with_direct_observe() {
735 let mut chal1 =
737 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
738 let mut chal2 =
739 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
740
741 let base_val = G::from_u8(99);
742
743 chal1.observe_base_as_algebra_element::<EF2G>(base_val);
745
746 let ext_val = EF2G::from(base_val);
748 chal2.observe_algebra_element(ext_val);
749
750 assert_eq!(chal1.input_buffer, chal2.input_buffer);
752 assert_eq!(chal1.output_buffer, chal2.output_buffer);
753 assert_eq!(chal1.sponge_state, chal2.sponge_state);
754 }
755
756 #[test]
757 fn test_observe_base_as_algebra_element_stream_consistency() {
758 let mut chal1 =
760 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
761 let mut chal2 =
762 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
763
764 let base_values: Vec<_> = (0u8..25).map(G::from_u8).collect();
766
767 for &val in &base_values {
769 chal1.observe_base_as_algebra_element::<EF2G>(val);
770 }
771
772 for &val in &base_values {
774 let ext_val = EF2G::from(val);
775 chal2.observe_algebra_element(ext_val);
776 }
777
778 assert_eq!(chal1.input_buffer, chal2.input_buffer);
780 assert_eq!(chal1.output_buffer, chal2.output_buffer);
781 assert_eq!(chal1.sponge_state, chal2.sponge_state);
782
783 let sample1: EF2G = chal1.sample_algebra_element();
785 let sample2: EF2G = chal2.sample_algebra_element();
786 assert_eq!(sample1, sample2);
787
788 assert_eq!(chal1.input_buffer, chal2.input_buffer);
790 assert_eq!(chal1.output_buffer, chal2.output_buffer);
791 assert_eq!(chal1.sponge_state, chal2.sponge_state);
792 }
793
794 #[test]
795 fn test_observe_algebra_elements_equivalence() {
796 let mut chal1 =
800 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
801 let mut chal2 =
802 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
803
804 let ext_values: Vec<EF2G> = (0u8..10).map(|i| EF2G::from(G::from_u8(i))).collect();
806
807 chal1.observe_algebra_slice(&ext_values);
809
810 for ext_val in &ext_values {
812 chal2.observe_algebra_element(*ext_val);
813 }
814
815 assert_eq!(chal1.input_buffer, chal2.input_buffer);
817 assert_eq!(chal1.output_buffer, chal2.output_buffer);
818 assert_eq!(chal1.sponge_state, chal2.sponge_state);
819
820 let sample1: EF2G = chal1.sample_algebra_element();
822 let sample2: EF2G = chal2.sample_algebra_element();
823 assert_eq!(sample1, sample2);
824 }
825
826 #[test]
827 fn test_observe_algebra_elements_empty_slice() {
828 let mut chal1 =
830 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
831 let mut chal2 =
832 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
833
834 chal1.observe(G::from_u8(42));
836 chal2.observe(G::from_u8(42));
837
838 let empty: Vec<EF2G> = vec![];
840 chal1.observe_algebra_slice(&empty);
841
842 assert_eq!(chal1.input_buffer, chal2.input_buffer);
844 assert_eq!(chal1.output_buffer, chal2.output_buffer);
845 assert_eq!(chal1.sponge_state, chal2.sponge_state);
846 }
847
848 #[test]
849 fn test_observe_algebra_elements_triggers_duplexing() {
850 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
852
853 let ext_values: Vec<EF2G> = (0u8..8).map(|i| EF2G::from(G::from_u8(i))).collect();
857
858 assert!(chal.input_buffer.is_empty());
859 assert!(chal.output_buffer.is_empty());
860
861 chal.observe_algebra_slice(&ext_values);
862
863 assert!(chal.input_buffer.is_empty());
865 assert!(!chal.output_buffer.is_empty());
866 }
867
868 #[test]
869 fn test_finalize() {
870 let new_chal = || DuplexChallenger::<G, _, WIDTH, RATE>::new(TestPermutation {});
871
872 let mut c1 = new_chal();
874 let mut c2 = new_chal();
875 for i in 0..5u8 {
876 c1.observe(G::from_u8(i));
877 c2.observe(G::from_u8(i));
878 }
879 assert_eq!(c1.finalize(), c2.finalize());
880
881 let mut c1 = new_chal();
883 let mut c2 = new_chal();
884 for i in 0..10u8 {
885 c1.observe(G::from_u8(i));
886 c2.observe(G::from_u8(i + 1));
887 }
888 assert_ne!(c1.finalize(), c2.finalize());
889 }
890
891 #[test]
899 fn test_finalize_sample_interaction() {
900 let digest = |n_samples: usize| {
901 let mut c = DuplexChallenger::<G, _, WIDTH, RATE>::new(TestPermutation {});
902 for i in 0..5u8 {
903 c.observe(G::from_u8(i));
904 }
905 for _ in 0..n_samples {
906 let _: G = c.sample();
907 }
908 c.finalize()
909 };
910
911 assert_ne!(digest(0), digest(1));
915
916 assert_eq!(digest(1), digest(2));
920 assert_eq!(digest(1), digest(RATE));
921
922 assert_ne!(digest(RATE), digest(RATE + 1));
925
926 assert_eq!(digest(RATE + 1), digest(RATE + 2));
928 }
929}