1use alloc::vec;
2use alloc::vec::Vec;
3use core::error::Error;
4use core::fmt::{Display, Formatter};
5
6use p3_field::{BasedVectorSpace, Field, 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 Self {
76 sponge_state: [F::default(); WIDTH],
77 input_buffer: vec![],
78 output_buffer: vec![],
79 permutation,
80 }
81 }
82
83 fn duplexing(&mut self) {
84 assert!(self.input_buffer.len() <= RATE);
85
86 for (i, val) in self.input_buffer.drain(..).enumerate() {
88 self.sponge_state[i] = val;
89 }
90
91 self.permutation.permute_mut(&mut self.sponge_state);
93
94 self.output_buffer.clear();
95 self.output_buffer.extend(&self.sponge_state[..RATE]);
96 }
97}
98
99impl<F, P, const WIDTH: usize, const RATE: usize> FieldChallenger<F>
100 for DuplexChallenger<F, P, WIDTH, RATE>
101where
102 F: PrimeField64,
103 P: CryptographicPermutation<[F; WIDTH]>,
104{
105}
106
107impl<F, P, const WIDTH: usize, const RATE: usize> CanObserve<F>
108 for DuplexChallenger<F, P, WIDTH, RATE>
109where
110 F: Copy,
111 P: CryptographicPermutation<[F; WIDTH]>,
112{
113 fn observe(&mut self, value: F) {
114 self.output_buffer.clear();
116
117 self.input_buffer.push(value);
118
119 if self.input_buffer.len() == RATE {
120 self.duplexing();
121 }
122 }
123}
124
125impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<[F; N]>
126 for DuplexChallenger<F, P, WIDTH, RATE>
127where
128 F: Copy,
129 P: CryptographicPermutation<[F; WIDTH]>,
130{
131 fn observe(&mut self, values: [F; N]) {
132 for value in values {
133 self.observe(value);
134 }
135 }
136}
137
138impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<Hash<F, F, N>>
139 for DuplexChallenger<F, P, WIDTH, RATE>
140where
141 F: Copy,
142 P: CryptographicPermutation<[F; WIDTH]>,
143{
144 fn observe(&mut self, values: Hash<F, F, N>) {
145 for value in values {
146 self.observe(value);
147 }
148 }
149}
150
151impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<&MerkleCap<F, [F; N]>>
152 for DuplexChallenger<F, P, WIDTH, RATE>
153where
154 F: Copy,
155 P: CryptographicPermutation<[F; WIDTH]>,
156{
157 fn observe(&mut self, cap: &MerkleCap<F, [F; N]>) {
158 for digest in cap.roots() {
159 for value in digest {
160 self.observe(*value);
161 }
162 }
163 }
164}
165
166impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<MerkleCap<F, [F; N]>>
167 for DuplexChallenger<F, P, WIDTH, RATE>
168where
169 F: Copy,
170 P: CryptographicPermutation<[F; WIDTH]>,
171{
172 fn observe(&mut self, cap: MerkleCap<F, [F; N]>) {
173 self.observe(&cap);
174 }
175}
176
177impl<F, P, const WIDTH: usize, const RATE: usize> CanObserve<Vec<Vec<F>>>
179 for DuplexChallenger<F, P, WIDTH, RATE>
180where
181 F: Copy,
182 P: CryptographicPermutation<[F; WIDTH]>,
183{
184 fn observe(&mut self, valuess: Vec<Vec<F>>) {
185 for values in valuess {
186 for value in values {
187 self.observe(value);
188 }
189 }
190 }
191}
192
193impl<F, EF, P, const WIDTH: usize, const RATE: usize> CanSample<EF>
194 for DuplexChallenger<F, P, WIDTH, RATE>
195where
196 F: Field,
197 EF: BasedVectorSpace<F>,
198 P: CryptographicPermutation<[F; WIDTH]>,
199{
200 fn sample(&mut self) -> EF {
201 EF::from_basis_coefficients_fn(|_| {
202 if !self.input_buffer.is_empty() || self.output_buffer.is_empty() {
205 self.duplexing();
206 }
207
208 self.output_buffer
209 .pop()
210 .expect("Output buffer should be non-empty")
211 })
212 }
213}
214
215impl<F, P, const WIDTH: usize, const RATE: usize> CanSampleBits<usize>
216 for DuplexChallenger<F, P, WIDTH, RATE>
217where
218 F: PrimeField64,
219 P: CryptographicPermutation<[F; WIDTH]>,
220{
221 fn sample_bits(&mut self, bits: usize) -> usize {
230 assert!(bits < (usize::BITS as usize));
231 assert!((1 << bits) < F::ORDER_U64);
232 let rand_f: F = self.sample();
233 let rand_usize = rand_f.as_canonical_u64() as usize;
234 rand_usize & ((1 << bits) - 1)
235 }
236}
237
238pub trait UniformSamplingField {
240 const MAX_SINGLE_SAMPLE_BITS: usize;
243 const SAMPLING_BITS_M: [u64; 64];
254}
255
256impl<MP> UniformSamplingField for MontyField31<MP>
260where
261 MP: UniformSamplingField + MontyParameters,
262{
263 const MAX_SINGLE_SAMPLE_BITS: usize = MP::MAX_SINGLE_SAMPLE_BITS;
264 const SAMPLING_BITS_M: [u64; 64] = MP::SAMPLING_BITS_M;
265}
266
267pub(super) struct ResampleOnRejection;
271pub(super) struct ErrorOnRejection;
273
274#[derive(Debug)]
277pub struct ResamplingError {
278 value: u64,
280 m: u64,
282}
283
284impl Display for ResamplingError {
285 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
286 write!(
287 f,
288 "Encountered value {0}, which requires resampling for uniform bits as it not smaller than {1}. But resampling is not enabled.",
289 self.value, self.m
290 )
291 }
292}
293
294impl Error for ResamplingError {}
295
296pub(super) trait BitSamplingStrategy<F, P, const W: usize, const R: usize>
298where
299 F: PrimeField64,
300 P: CryptographicPermutation<[F; W]>,
301{
302 const ERROR_ON_REJECTION: bool;
304
305 #[inline]
306 fn sample_value(
307 challenger: &mut DuplexChallenger<F, P, W, R>,
308 m: u64,
309 ) -> Result<F, ResamplingError> {
310 let mut result: F = challenger.sample();
311 if Self::ERROR_ON_REJECTION {
312 if result.as_canonical_u64() >= m {
313 return Err(ResamplingError {
314 value: result.as_canonical_u64(),
315 m,
316 });
317 }
318 } else {
319 while result.as_canonical_u64() >= m {
320 result = challenger.sample();
321 }
322 }
323 Ok(result)
324 }
325}
326
327impl<F, P, const W: usize, const R: usize> BitSamplingStrategy<F, P, W, R> for ResampleOnRejection
329where
330 F: PrimeField64,
331 P: CryptographicPermutation<[F; W]>,
332{
333 const ERROR_ON_REJECTION: bool = false;
334}
335
336impl<F, P, const W: usize, const R: usize> BitSamplingStrategy<F, P, W, R> for ErrorOnRejection
338where
339 F: PrimeField64,
340 P: CryptographicPermutation<[F; W]>,
341{
342 const ERROR_ON_REJECTION: bool = true;
343}
344
345impl<F, P, const WIDTH: usize, const RATE: usize> DuplexChallenger<F, P, WIDTH, RATE>
346where
347 F: UniformSamplingField + PrimeField64,
348 P: CryptographicPermutation<[F; WIDTH]>,
349{
350 #[inline]
352 fn sample_uniform_bits_with_strategy<S>(
353 &mut self,
354 bits: usize,
355 ) -> Result<usize, ResamplingError>
356 where
357 S: BitSamplingStrategy<F, P, WIDTH, RATE>,
358 {
359 if bits == 0 {
360 return Ok(0);
361 };
362 assert!(bits < usize::BITS as usize, "bit count must be valid");
363 assert!(
364 (1u64 << bits) < F::ORDER_U64,
365 "bit count exceeds field order"
366 );
367 let m = F::SAMPLING_BITS_M[bits];
368 if bits <= F::MAX_SINGLE_SAMPLE_BITS {
369 let rand_f = S::sample_value(self, m);
371 Ok(rand_f?.as_canonical_u64() as usize & ((1 << bits) - 1))
372 } else {
373 let half_bits1 = bits / 2;
376 let half_bits2 = bits - half_bits1;
377 let rand1 = S::sample_value(self, F::SAMPLING_BITS_M[half_bits1]);
379 let chunk1 = rand1?.as_canonical_u64() as usize & ((1 << half_bits1) - 1);
380 let rand2 = S::sample_value(self, F::SAMPLING_BITS_M[half_bits2]);
382 let chunk2 = rand2?.as_canonical_u64() as usize & ((1 << half_bits2) - 1);
383
384 Ok(chunk1 | (chunk2 << half_bits1))
386 }
387 }
388}
389
390impl<F, P, const WIDTH: usize, const RATE: usize> CanSampleUniformBits<F>
391 for DuplexChallenger<F, P, WIDTH, RATE>
392where
393 F: UniformSamplingField + PrimeField64,
394 P: CryptographicPermutation<[F; WIDTH]>,
395{
396 fn sample_uniform_bits<const RESAMPLE: bool>(
397 &mut self,
398 bits: usize,
399 ) -> Result<usize, ResamplingError> {
400 if RESAMPLE {
401 self.sample_uniform_bits_with_strategy::<ResampleOnRejection>(bits)
402 } else {
403 self.sample_uniform_bits_with_strategy::<ErrorOnRejection>(bits)
404 }
405 }
406}
407
408impl<F, P, const WIDTH: usize, const RATE: usize> CanFinalizeDigest
409 for DuplexChallenger<F, P, WIDTH, RATE>
410where
411 F: Copy,
412 P: CryptographicPermutation<[F; WIDTH]>,
413{
414 type Digest = [F; RATE];
415
416 fn finalize(mut self) -> [F; RATE] {
417 self.duplexing();
423 self.sponge_state[..RATE].try_into().unwrap()
424 }
425}
426
427#[cfg(test)]
428mod tests {
429 use core::iter;
430
431 use p3_baby_bear::BabyBear;
432 use p3_field::PrimeCharacteristicRing;
433 use p3_field::extension::BinomialExtensionField;
434 use p3_goldilocks::Goldilocks;
435 use p3_symmetric::Permutation;
436
437 use super::*;
438 use crate::grinding_challenger::GrindingChallenger;
439
440 const WIDTH: usize = 24;
441 const RATE: usize = 16;
442
443 type G = Goldilocks;
444 type EF2G = BinomialExtensionField<G, 2>;
445
446 type BB = BabyBear;
447
448 #[derive(Clone)]
449 struct TestPermutation {}
450
451 impl<F: Clone> Permutation<[F; WIDTH]> for TestPermutation {
452 fn permute_mut(&self, input: &mut [F; WIDTH]) {
453 input.reverse();
454 }
455 }
456
457 impl<F: Clone> CryptographicPermutation<[F; WIDTH]> for TestPermutation {}
458
459 #[test]
460 fn test_duplex_challenger() {
461 type Chal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
462 let permutation = TestPermutation {};
463 let mut duplex_challenger = DuplexChallenger::new(permutation);
464
465 (0..12).for_each(|element| duplex_challenger.observe(G::from_u8(element as u8)));
467
468 let state_after_duplexing: Vec<_> = iter::repeat_n(G::ZERO, 12)
469 .chain((0..12).map(G::from_u8).rev())
470 .collect();
471
472 let expected_samples: Vec<G> = state_after_duplexing[..16].iter().copied().rev().collect();
473 let samples = <Chal as CanSample<G>>::sample_vec(&mut duplex_challenger, 16);
474 assert_eq!(samples, expected_samples);
475 }
476
477 #[test]
478 #[should_panic]
479 fn test_duplex_challenger_sample_bits_security() {
480 type GoldilocksChal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
481 let permutation = TestPermutation {};
482 let mut duplex_challenger = GoldilocksChal::new(permutation);
483
484 for _ in 0..100 {
485 assert!(duplex_challenger.sample_bits(129) < 4);
486 }
487 }
488
489 #[test]
490 #[should_panic]
491 fn test_duplex_challenger_sample_bits_security_small_field() {
492 type BabyBearChal = DuplexChallenger<BB, TestPermutation, WIDTH, RATE>;
493 let permutation = TestPermutation {};
494 let mut duplex_challenger = BabyBearChal::new(permutation);
495
496 for _ in 0..100 {
497 assert!(duplex_challenger.sample_bits(40) < 1 << 31);
498 }
499 }
500
501 #[test]
502 #[should_panic]
503 fn test_duplex_challenger_grind_security() {
504 type GoldilocksChal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
505 let permutation = TestPermutation {};
506 let mut duplex_challenger = GoldilocksChal::new(permutation);
507
508 let too_many_bits = usize::BITS as usize;
513
514 let witness = duplex_challenger.grind(too_many_bits);
515 assert!(duplex_challenger.check_witness(too_many_bits, witness));
516 }
517
518 #[test]
519 fn test_observe_single_value() {
520 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
521 chal.observe(G::from_u8(42));
522 assert_eq!(chal.input_buffer, vec![G::from_u8(42)]);
523 assert!(chal.output_buffer.is_empty());
524 }
525
526 #[test]
527 fn test_observe_array_of_values() {
528 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
529 chal.observe([G::from_u8(1), G::from_u8(2), G::from_u8(3)]);
530 assert_eq!(
531 chal.input_buffer,
532 vec![G::from_u8(1), G::from_u8(2), G::from_u8(3)]
533 );
534 assert!(chal.output_buffer.is_empty());
535 }
536
537 #[test]
538 fn test_observe_hash_array() {
539 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
540 let hash = Hash::<G, G, 4>::from([G::from_u8(10); 4]);
541 chal.observe(hash);
542 assert_eq!(chal.input_buffer, vec![G::from_u8(10); 4]);
543 }
544
545 #[test]
546 fn test_observe_nested_vecs() {
547 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
548 chal.observe(vec![
549 vec![G::from_u8(1), G::from_u8(2)],
550 vec![G::from_u8(3)],
551 ]);
552 assert_eq!(
553 chal.input_buffer,
554 vec![G::from_u8(1), G::from_u8(2), G::from_u8(3)]
555 );
556 }
557
558 #[test]
559 fn test_sample_triggers_duplex() {
560 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
561 chal.observe(G::from_u8(5));
562 assert!(chal.output_buffer.is_empty());
563 let _sample: G = chal.sample();
564 assert!(!chal.output_buffer.is_empty());
565 }
566
567 #[test]
568 fn test_sample_multiple_extension_field() {
569 use p3_field::extension::BinomialExtensionField;
570 type EF = BinomialExtensionField<G, 2>;
571 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
572
573 chal.observe(G::from_u8(1));
574 chal.observe(G::from_u8(2));
575 let _: EF = chal.sample();
576 let _: EF = chal.sample();
577 }
578
579 #[test]
580 fn test_sample_bits_within_bounds() {
581 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
582 for i in 0..RATE {
583 chal.observe(G::from_u8(i as u8));
584 }
585
586 let bits = 3;
591 let value = chal.sample_bits(bits);
592 let expected = G::ZERO.as_canonical_u64() as usize & ((1 << bits) - 1);
593 assert_eq!(value, expected);
594 }
595
596 #[test]
597 fn test_sample_bits_trigger_duplex_when_empty() {
598 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
599 assert_eq!(chal.input_buffer.len(), 0);
601 assert_eq!(chal.output_buffer.len(), 0);
602
603 let bits = 2;
605 let sample = chal.sample_bits(bits);
606 let expected = G::ZERO.as_canonical_u64() as usize & ((1 << bits) - 1);
607 assert_eq!(sample, expected);
608 }
609
610 #[test]
611 fn test_output_buffer_pops_correctly() {
612 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
613
614 for i in 0..RATE {
616 chal.observe(G::from_u8(i as u8));
617 }
618
619 let expected = [
621 G::from_u8(0),
622 G::from_u8(0),
623 G::from_u8(0),
624 G::from_u8(0),
625 G::from_u8(0),
626 G::from_u8(0),
627 G::from_u8(0),
628 G::from_u8(0),
629 G::from_u8(15),
630 G::from_u8(14),
631 G::from_u8(13),
632 G::from_u8(12),
633 G::from_u8(11),
634 G::from_u8(10),
635 G::from_u8(9),
636 G::from_u8(8),
637 ]
638 .to_vec();
639
640 assert_eq!(chal.output_buffer, expected);
641
642 let first: G = chal.sample();
643 let second: G = chal.sample();
644
645 assert_eq!(first, G::from_u8(8));
647 assert_eq!(second, G::from_u8(9));
648 }
649
650 #[test]
651 fn test_duplexing_only_when_needed() {
652 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
653 chal.output_buffer = vec![G::from_u8(10), G::from_u8(20)];
654
655 let sample: G = chal.sample();
657 assert_eq!(sample, G::from_u8(20));
658 assert_eq!(chal.output_buffer, vec![G::from_u8(10)]);
659 }
660
661 #[test]
662 fn test_flush_when_input_full() {
663 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
664
665 for i in 0..RATE {
667 chal.observe(G::from_u8(i as u8));
668 }
669
670 let expected_output = [
672 G::from_u8(0),
673 G::from_u8(0),
674 G::from_u8(0),
675 G::from_u8(0),
676 G::from_u8(0),
677 G::from_u8(0),
678 G::from_u8(0),
679 G::from_u8(0),
680 G::from_u8(15),
681 G::from_u8(14),
682 G::from_u8(13),
683 G::from_u8(12),
684 G::from_u8(11),
685 G::from_u8(10),
686 G::from_u8(9),
687 G::from_u8(8),
688 ]
689 .to_vec();
690
691 assert!(chal.input_buffer.is_empty());
693
694 assert_eq!(chal.output_buffer, expected_output);
696 }
697
698 #[test]
699 fn test_observe_base_as_algebra_element_consistency_with_direct_observe() {
700 let mut chal1 =
702 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
703 let mut chal2 =
704 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
705
706 let base_val = G::from_u8(99);
707
708 chal1.observe_base_as_algebra_element::<EF2G>(base_val);
710
711 let ext_val = EF2G::from(base_val);
713 chal2.observe_algebra_element(ext_val);
714
715 assert_eq!(chal1.input_buffer, chal2.input_buffer);
717 assert_eq!(chal1.output_buffer, chal2.output_buffer);
718 assert_eq!(chal1.sponge_state, chal2.sponge_state);
719 }
720
721 #[test]
722 fn test_observe_base_as_algebra_element_stream_consistency() {
723 let mut chal1 =
725 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
726 let mut chal2 =
727 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
728
729 let base_values: Vec<_> = (0u8..25).map(G::from_u8).collect();
731
732 for &val in &base_values {
734 chal1.observe_base_as_algebra_element::<EF2G>(val);
735 }
736
737 for &val in &base_values {
739 let ext_val = EF2G::from(val);
740 chal2.observe_algebra_element(ext_val);
741 }
742
743 assert_eq!(chal1.input_buffer, chal2.input_buffer);
745 assert_eq!(chal1.output_buffer, chal2.output_buffer);
746 assert_eq!(chal1.sponge_state, chal2.sponge_state);
747
748 let sample1: EF2G = chal1.sample_algebra_element();
750 let sample2: EF2G = chal2.sample_algebra_element();
751 assert_eq!(sample1, sample2);
752
753 assert_eq!(chal1.input_buffer, chal2.input_buffer);
755 assert_eq!(chal1.output_buffer, chal2.output_buffer);
756 assert_eq!(chal1.sponge_state, chal2.sponge_state);
757 }
758
759 #[test]
760 fn test_observe_algebra_elements_equivalence() {
761 let mut chal1 =
765 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
766 let mut chal2 =
767 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
768
769 let ext_values: Vec<EF2G> = (0u8..10).map(|i| EF2G::from(G::from_u8(i))).collect();
771
772 chal1.observe_algebra_slice(&ext_values);
774
775 for ext_val in &ext_values {
777 chal2.observe_algebra_element(*ext_val);
778 }
779
780 assert_eq!(chal1.input_buffer, chal2.input_buffer);
782 assert_eq!(chal1.output_buffer, chal2.output_buffer);
783 assert_eq!(chal1.sponge_state, chal2.sponge_state);
784
785 let sample1: EF2G = chal1.sample_algebra_element();
787 let sample2: EF2G = chal2.sample_algebra_element();
788 assert_eq!(sample1, sample2);
789 }
790
791 #[test]
792 fn test_observe_algebra_elements_empty_slice() {
793 let mut chal1 =
795 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
796 let mut chal2 =
797 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
798
799 chal1.observe(G::from_u8(42));
801 chal2.observe(G::from_u8(42));
802
803 let empty: Vec<EF2G> = vec![];
805 chal1.observe_algebra_slice(&empty);
806
807 assert_eq!(chal1.input_buffer, chal2.input_buffer);
809 assert_eq!(chal1.output_buffer, chal2.output_buffer);
810 assert_eq!(chal1.sponge_state, chal2.sponge_state);
811 }
812
813 #[test]
814 fn test_observe_algebra_elements_triggers_duplexing() {
815 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
817
818 let ext_values: Vec<EF2G> = (0u8..8).map(|i| EF2G::from(G::from_u8(i))).collect();
822
823 assert!(chal.input_buffer.is_empty());
824 assert!(chal.output_buffer.is_empty());
825
826 chal.observe_algebra_slice(&ext_values);
827
828 assert!(chal.input_buffer.is_empty());
830 assert!(!chal.output_buffer.is_empty());
831 }
832
833 #[test]
834 fn test_finalize() {
835 let new_chal = || DuplexChallenger::<G, _, WIDTH, RATE>::new(TestPermutation {});
836
837 let mut c1 = new_chal();
839 let mut c2 = new_chal();
840 for i in 0..5u8 {
841 c1.observe(G::from_u8(i));
842 c2.observe(G::from_u8(i));
843 }
844 assert_eq!(c1.finalize(), c2.finalize());
845
846 let mut c1 = new_chal();
848 let mut c2 = new_chal();
849 for i in 0..10u8 {
850 c1.observe(G::from_u8(i));
851 c2.observe(G::from_u8(i + 1));
852 }
853 assert_ne!(c1.finalize(), c2.finalize());
854 }
855
856 #[test]
864 fn test_finalize_sample_interaction() {
865 let digest = |n_samples: usize| {
866 let mut c = DuplexChallenger::<G, _, WIDTH, RATE>::new(TestPermutation {});
867 for i in 0..5u8 {
868 c.observe(G::from_u8(i));
869 }
870 for _ in 0..n_samples {
871 let _: G = c.sample();
872 }
873 c.finalize()
874 };
875
876 assert_ne!(digest(0), digest(1));
880
881 assert_eq!(digest(1), digest(2));
885 assert_eq!(digest(1), digest(RATE));
886
887 assert_ne!(digest(RATE), digest(RATE + 1));
890
891 assert_eq!(digest(RATE + 1), digest(RATE + 2));
893 }
894}