1use alloc::vec;
2use alloc::vec::Vec;
3use core::error::Error;
4use core::fmt::{Display, Formatter};
5
6use p3_field::{BasedVectorSpace, Field, PrimeCharacteristicRing, 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 where
88 F: PrimeCharacteristicRing,
89 {
90 let num_absorbed = self.input_buffer.len();
91 assert!(num_absorbed <= RATE);
92
93 for (i, val) in self.input_buffer.drain(..).enumerate() {
95 self.sponge_state[i] = val;
96 }
97
98 if num_absorbed > 0 {
101 self.sponge_state[num_absorbed..RATE].fill(F::ZERO);
103 self.sponge_state[RATE] += F::from_u8(num_absorbed as u8);
105 }
106
107 self.permutation.permute_mut(&mut self.sponge_state);
109
110 self.output_buffer.clear();
111 self.output_buffer.extend(&self.sponge_state[..RATE]);
112 }
113}
114
115impl<F, P, const WIDTH: usize, const RATE: usize> DuplexChallenger<F, P, WIDTH, RATE>
116where
117 F: Copy + Default + PrimeField,
118 P: CryptographicPermutation<[F; WIDTH]>,
119{
120 pub fn absorb_rate_padded_with_tag(&mut self, values: &[F], length_tag: u8) {
132 const {
133 assert!(
134 RATE < WIDTH,
135 "RATE must be less than WIDTH for capacity length slot"
136 );
137 }
138 assert!(values.len() <= RATE);
139 self.input_buffer.clear();
140 self.output_buffer.clear();
141 for (i, &v) in values.iter().enumerate() {
142 self.sponge_state[i] = v;
143 }
144 self.sponge_state[values.len()..RATE].fill(F::ZERO);
145 self.sponge_state[RATE] += F::from_u8(length_tag);
146 self.permutation.permute_mut(&mut self.sponge_state);
147 self.output_buffer
148 .extend_from_slice(&self.sponge_state[..RATE]);
149 }
150}
151
152impl<F, P, const WIDTH: usize, const RATE: usize> FieldChallenger<F>
153 for DuplexChallenger<F, P, WIDTH, RATE>
154where
155 F: PrimeField64,
156 P: CryptographicPermutation<[F; WIDTH]>,
157{
158}
159
160impl<F, P, const WIDTH: usize, const RATE: usize> CanObserve<F>
161 for DuplexChallenger<F, P, WIDTH, RATE>
162where
163 F: Copy + PrimeCharacteristicRing,
164 P: CryptographicPermutation<[F; WIDTH]>,
165{
166 fn observe(&mut self, value: F) {
167 self.output_buffer.clear();
169
170 self.input_buffer.push(value);
171
172 if self.input_buffer.len() == RATE {
173 self.duplexing();
174 }
175 }
176}
177
178impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<[F; N]>
179 for DuplexChallenger<F, P, WIDTH, RATE>
180where
181 F: Copy + PrimeCharacteristicRing,
182 P: CryptographicPermutation<[F; WIDTH]>,
183{
184 fn observe(&mut self, values: [F; N]) {
185 for value in values {
186 self.observe(value);
187 }
188 }
189}
190
191impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<Hash<F, F, N>>
192 for DuplexChallenger<F, P, WIDTH, RATE>
193where
194 F: Copy + PrimeCharacteristicRing,
195 P: CryptographicPermutation<[F; WIDTH]>,
196{
197 fn observe(&mut self, values: Hash<F, F, N>) {
198 for value in values {
199 self.observe(value);
200 }
201 }
202}
203
204impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<&MerkleCap<F, [F; N]>>
205 for DuplexChallenger<F, P, WIDTH, RATE>
206where
207 F: Copy + PrimeCharacteristicRing,
208 P: CryptographicPermutation<[F; WIDTH]>,
209{
210 fn observe(&mut self, cap: &MerkleCap<F, [F; N]>) {
211 for digest in cap.roots() {
212 for value in digest {
213 self.observe(*value);
214 }
215 }
216 }
217}
218
219impl<F, P, const N: usize, const WIDTH: usize, const RATE: usize> CanObserve<MerkleCap<F, [F; N]>>
220 for DuplexChallenger<F, P, WIDTH, RATE>
221where
222 F: Copy + PrimeCharacteristicRing,
223 P: CryptographicPermutation<[F; WIDTH]>,
224{
225 fn observe(&mut self, cap: MerkleCap<F, [F; N]>) {
226 self.observe(&cap);
227 }
228}
229
230impl<F, P, const WIDTH: usize, const RATE: usize> CanObserve<Vec<Vec<F>>>
232 for DuplexChallenger<F, P, WIDTH, RATE>
233where
234 F: Copy + PrimeCharacteristicRing,
235 P: CryptographicPermutation<[F; WIDTH]>,
236{
237 fn observe(&mut self, valuess: Vec<Vec<F>>) {
238 for values in valuess {
239 for value in values {
240 self.observe(value);
241 }
242 }
243 }
244}
245
246impl<F, EF, P, const WIDTH: usize, const RATE: usize> CanSample<EF>
247 for DuplexChallenger<F, P, WIDTH, RATE>
248where
249 F: Field,
250 EF: BasedVectorSpace<F>,
251 P: CryptographicPermutation<[F; WIDTH]>,
252{
253 fn sample(&mut self) -> EF {
254 EF::from_basis_coefficients_fn(|_| {
255 if !self.input_buffer.is_empty() || self.output_buffer.is_empty() {
258 self.duplexing();
259 }
260
261 self.output_buffer
262 .pop()
263 .expect("Output buffer should be non-empty")
264 })
265 }
266}
267
268impl<F, P, const WIDTH: usize, const RATE: usize> CanSampleBits<usize>
269 for DuplexChallenger<F, P, WIDTH, RATE>
270where
271 F: PrimeField64,
272 P: CryptographicPermutation<[F; WIDTH]>,
273{
274 fn sample_bits(&mut self, bits: usize) -> usize {
283 assert!(bits < (usize::BITS as usize));
284 assert!((1 << bits) < F::ORDER_U64);
285 let rand_f: F = self.sample();
286 let rand_usize = rand_f.as_canonical_u64() as usize;
287 rand_usize & ((1 << bits) - 1)
288 }
289}
290
291pub trait UniformSamplingField {
293 const MAX_SINGLE_SAMPLE_BITS: usize;
296 const SAMPLING_BITS_M: [u64; 64];
307}
308
309impl<MP> UniformSamplingField for MontyField31<MP>
313where
314 MP: UniformSamplingField + MontyParameters,
315{
316 const MAX_SINGLE_SAMPLE_BITS: usize = MP::MAX_SINGLE_SAMPLE_BITS;
317 const SAMPLING_BITS_M: [u64; 64] = MP::SAMPLING_BITS_M;
318}
319
320pub(super) struct ResampleOnRejection;
324pub(super) struct ErrorOnRejection;
326
327#[derive(Debug)]
330pub struct ResamplingError {
331 value: u64,
333 m: u64,
335}
336
337impl Display for ResamplingError {
338 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
339 write!(
340 f,
341 "Encountered value {0}, which requires resampling for uniform bits as it not smaller than {1}. But resampling is not enabled.",
342 self.value, self.m
343 )
344 }
345}
346
347impl Error for ResamplingError {}
348
349pub(super) trait BitSamplingStrategy<F, P, const W: usize, const R: usize>
351where
352 F: PrimeField64,
353 P: CryptographicPermutation<[F; W]>,
354{
355 const ERROR_ON_REJECTION: bool;
357
358 #[inline]
359 fn sample_value(
360 challenger: &mut DuplexChallenger<F, P, W, R>,
361 m: u64,
362 ) -> Result<F, ResamplingError> {
363 let mut result: F = challenger.sample();
364 if Self::ERROR_ON_REJECTION {
365 if result.as_canonical_u64() >= m {
366 return Err(ResamplingError {
367 value: result.as_canonical_u64(),
368 m,
369 });
370 }
371 } else {
372 while result.as_canonical_u64() >= m {
373 result = challenger.sample();
374 }
375 }
376 Ok(result)
377 }
378}
379
380impl<F, P, const W: usize, const R: usize> BitSamplingStrategy<F, P, W, R> for ResampleOnRejection
382where
383 F: PrimeField64,
384 P: CryptographicPermutation<[F; W]>,
385{
386 const ERROR_ON_REJECTION: bool = false;
387}
388
389impl<F, P, const W: usize, const R: usize> BitSamplingStrategy<F, P, W, R> for ErrorOnRejection
391where
392 F: PrimeField64,
393 P: CryptographicPermutation<[F; W]>,
394{
395 const ERROR_ON_REJECTION: bool = true;
396}
397
398impl<F, P, const WIDTH: usize, const RATE: usize> DuplexChallenger<F, P, WIDTH, RATE>
399where
400 F: UniformSamplingField + PrimeField64,
401 P: CryptographicPermutation<[F; WIDTH]>,
402{
403 #[inline]
405 fn sample_uniform_bits_with_strategy<S>(
406 &mut self,
407 bits: usize,
408 ) -> Result<usize, ResamplingError>
409 where
410 S: BitSamplingStrategy<F, P, WIDTH, RATE>,
411 {
412 if bits == 0 {
413 return Ok(0);
414 };
415 assert!(bits < usize::BITS as usize, "bit count must be valid");
416 assert!(
417 (1u64 << bits) < F::ORDER_U64,
418 "bit count exceeds field order"
419 );
420 let m = F::SAMPLING_BITS_M[bits];
421 if bits <= F::MAX_SINGLE_SAMPLE_BITS {
422 let rand_f = S::sample_value(self, m);
424 Ok(rand_f?.as_canonical_u64() as usize & ((1 << bits) - 1))
425 } else {
426 let half_bits1 = bits / 2;
429 let half_bits2 = bits - half_bits1;
430 let rand1 = S::sample_value(self, F::SAMPLING_BITS_M[half_bits1]);
432 let chunk1 = rand1?.as_canonical_u64() as usize & ((1 << half_bits1) - 1);
433 let rand2 = S::sample_value(self, F::SAMPLING_BITS_M[half_bits2]);
435 let chunk2 = rand2?.as_canonical_u64() as usize & ((1 << half_bits2) - 1);
436
437 Ok(chunk1 | (chunk2 << half_bits1))
439 }
440 }
441}
442
443impl<F, P, const WIDTH: usize, const RATE: usize> CanSampleUniformBits<F>
444 for DuplexChallenger<F, P, WIDTH, RATE>
445where
446 F: UniformSamplingField + PrimeField64,
447 P: CryptographicPermutation<[F; WIDTH]>,
448{
449 fn sample_uniform_bits<const RESAMPLE: bool>(
450 &mut self,
451 bits: usize,
452 ) -> Result<usize, ResamplingError> {
453 if RESAMPLE {
454 self.sample_uniform_bits_with_strategy::<ResampleOnRejection>(bits)
455 } else {
456 self.sample_uniform_bits_with_strategy::<ErrorOnRejection>(bits)
457 }
458 }
459}
460
461impl<F, P, const WIDTH: usize, const RATE: usize> CanFinalizeDigest
462 for DuplexChallenger<F, P, WIDTH, RATE>
463where
464 F: Copy + PrimeCharacteristicRing,
465 P: CryptographicPermutation<[F; WIDTH]>,
466{
467 type Digest = [F; RATE];
468
469 fn finalize(mut self) -> [F; RATE] {
470 self.duplexing();
476 self.sponge_state[..RATE].try_into().unwrap()
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use p3_baby_bear::BabyBear;
483 use p3_field::PrimeCharacteristicRing;
484 use p3_field::extension::BinomialExtensionField;
485 use p3_goldilocks::Goldilocks;
486 use p3_symmetric::Permutation;
487
488 use super::*;
489 use crate::grinding_challenger::GrindingChallenger;
490
491 const WIDTH: usize = 24;
492 const RATE: usize = 16;
493
494 type G = Goldilocks;
495 type EF2G = BinomialExtensionField<G, 2>;
496
497 type BB = BabyBear;
498
499 #[derive(Clone)]
500 struct TestPermutation {}
501
502 impl<F: Clone> Permutation<[F; WIDTH]> for TestPermutation {
503 fn permute_mut(&self, input: &mut [F; WIDTH]) {
504 input.reverse();
505 }
506 }
507
508 impl<F: Clone> CryptographicPermutation<[F; WIDTH]> for TestPermutation {}
509
510 #[test]
511 fn test_duplex_challenger() {
512 type Chal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
513 let permutation = TestPermutation {};
514 let mut duplex_challenger = DuplexChallenger::new(permutation);
515
516 (0..12).for_each(|element| duplex_challenger.observe(G::from_u8(element as u8)));
518
519 let mut pre_permute = [G::ZERO; WIDTH];
521 (0..12).for_each(|i| pre_permute[i] = G::from_u8(i as u8));
522 pre_permute[RATE] = G::from_u8(12);
524
525 let mut state_after_duplexing = pre_permute;
527 state_after_duplexing.reverse();
528 let expected_samples: Vec<G> = state_after_duplexing[..RATE]
530 .iter()
531 .copied()
532 .rev()
533 .collect();
534
535 let samples = <Chal as CanSample<G>>::sample_vec(&mut duplex_challenger, 16);
536 assert_eq!(samples, expected_samples);
537 }
538
539 #[test]
540 fn test_absorb_is_length_binding() {
541 type Chal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
542
543 let mut chal_a = Chal::new(TestPermutation {});
554 let mut chal_b = Chal::new(TestPermutation {});
555
556 chal_a.observe(G::from_u8(5));
558 chal_a.observe(G::from_u8(7));
559
560 chal_b.observe(G::from_u8(5));
562 chal_b.observe(G::from_u8(7));
563 chal_b.observe(G::ZERO);
564 chal_b.observe(G::ZERO);
565
566 let samples_a = <Chal as CanSample<G>>::sample_vec(&mut chal_a, RATE);
569 let samples_b = <Chal as CanSample<G>>::sample_vec(&mut chal_b, RATE);
570 assert_ne!(samples_a, samples_b);
571 }
572
573 #[test]
574 #[should_panic]
575 fn test_duplex_challenger_sample_bits_security() {
576 type GoldilocksChal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
577 let permutation = TestPermutation {};
578 let mut duplex_challenger = GoldilocksChal::new(permutation);
579
580 for _ in 0..100 {
581 assert!(duplex_challenger.sample_bits(129) < 4);
582 }
583 }
584
585 #[test]
586 #[should_panic]
587 fn test_duplex_challenger_sample_bits_security_small_field() {
588 type BabyBearChal = DuplexChallenger<BB, TestPermutation, WIDTH, RATE>;
589 let permutation = TestPermutation {};
590 let mut duplex_challenger = BabyBearChal::new(permutation);
591
592 for _ in 0..100 {
593 assert!(duplex_challenger.sample_bits(40) < 1 << 31);
594 }
595 }
596
597 #[test]
598 #[should_panic]
599 fn test_duplex_challenger_grind_security() {
600 type GoldilocksChal = DuplexChallenger<G, TestPermutation, WIDTH, RATE>;
601 let permutation = TestPermutation {};
602 let mut duplex_challenger = GoldilocksChal::new(permutation);
603
604 let too_many_bits = usize::BITS as usize;
609
610 let witness = duplex_challenger.grind(too_many_bits);
611 assert!(duplex_challenger.check_witness(too_many_bits, witness));
612 }
613
614 #[test]
615 fn test_observe_single_value() {
616 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
617 chal.observe(G::from_u8(42));
618 assert_eq!(chal.input_buffer, vec![G::from_u8(42)]);
619 assert!(chal.output_buffer.is_empty());
620 }
621
622 #[test]
623 fn test_observe_array_of_values() {
624 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
625 chal.observe([G::from_u8(1), G::from_u8(2), G::from_u8(3)]);
626 assert_eq!(
627 chal.input_buffer,
628 vec![G::from_u8(1), G::from_u8(2), G::from_u8(3)]
629 );
630 assert!(chal.output_buffer.is_empty());
631 }
632
633 #[test]
634 fn test_observe_hash_array() {
635 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
636 let hash = Hash::<G, G, 4>::from([G::from_u8(10); 4]);
637 chal.observe(hash);
638 assert_eq!(chal.input_buffer, vec![G::from_u8(10); 4]);
639 }
640
641 #[test]
642 fn test_observe_nested_vecs() {
643 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
644 chal.observe(vec![
645 vec![G::from_u8(1), G::from_u8(2)],
646 vec![G::from_u8(3)],
647 ]);
648 assert_eq!(
649 chal.input_buffer,
650 vec![G::from_u8(1), G::from_u8(2), G::from_u8(3)]
651 );
652 }
653
654 #[test]
655 fn test_sample_triggers_duplex() {
656 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
657 chal.observe(G::from_u8(5));
658 assert!(chal.output_buffer.is_empty());
659 let _sample: G = chal.sample();
660 assert!(!chal.output_buffer.is_empty());
661 }
662
663 #[test]
664 fn test_sample_multiple_extension_field() {
665 use p3_field::extension::BinomialExtensionField;
666 type EF = BinomialExtensionField<G, 2>;
667 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
668
669 chal.observe(G::from_u8(1));
670 chal.observe(G::from_u8(2));
671 let _: EF = chal.sample();
672 let _: EF = chal.sample();
673 }
674
675 #[test]
676 fn test_sample_bits_within_bounds() {
677 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
678 for i in 0..RATE {
679 chal.observe(G::from_u8(i as u8));
680 }
681
682 let bits = 3;
687 let value = chal.sample_bits(bits);
688 let expected = G::ZERO.as_canonical_u64() as usize & ((1 << bits) - 1);
689 assert_eq!(value, expected);
690 }
691
692 #[test]
693 fn test_sample_bits_trigger_duplex_when_empty() {
694 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
695 assert_eq!(chal.input_buffer.len(), 0);
697 assert_eq!(chal.output_buffer.len(), 0);
698
699 let bits = 2;
701 let sample = chal.sample_bits(bits);
702 let expected = G::ZERO.as_canonical_u64() as usize & ((1 << bits) - 1);
703 assert_eq!(sample, expected);
704 }
705
706 #[test]
707 fn test_output_buffer_pops_correctly() {
708 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
709
710 for i in 0..RATE {
712 chal.observe(G::from_u8(i as u8));
713 }
714
715 let expected = [
718 G::from_u8(0),
719 G::from_u8(0),
720 G::from_u8(0),
721 G::from_u8(0),
722 G::from_u8(0),
723 G::from_u8(0),
724 G::from_u8(0),
725 G::from_u8(RATE as u8),
726 G::from_u8(15),
727 G::from_u8(14),
728 G::from_u8(13),
729 G::from_u8(12),
730 G::from_u8(11),
731 G::from_u8(10),
732 G::from_u8(9),
733 G::from_u8(8),
734 ]
735 .to_vec();
736
737 assert_eq!(chal.output_buffer, expected);
738
739 let first: G = chal.sample();
740 let second: G = chal.sample();
741
742 assert_eq!(first, G::from_u8(8));
744 assert_eq!(second, G::from_u8(9));
745 }
746
747 #[test]
748 fn test_duplexing_only_when_needed() {
749 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
750 chal.output_buffer = vec![G::from_u8(10), G::from_u8(20)];
751
752 let sample: G = chal.sample();
754 assert_eq!(sample, G::from_u8(20));
755 assert_eq!(chal.output_buffer, vec![G::from_u8(10)]);
756 }
757
758 #[test]
759 fn test_flush_when_input_full() {
760 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
761
762 for i in 0..RATE {
764 chal.observe(G::from_u8(i as u8));
765 }
766
767 let expected_output = [
770 G::from_u8(0),
771 G::from_u8(0),
772 G::from_u8(0),
773 G::from_u8(0),
774 G::from_u8(0),
775 G::from_u8(0),
776 G::from_u8(0),
777 G::from_u8(RATE as u8),
778 G::from_u8(15),
779 G::from_u8(14),
780 G::from_u8(13),
781 G::from_u8(12),
782 G::from_u8(11),
783 G::from_u8(10),
784 G::from_u8(9),
785 G::from_u8(8),
786 ]
787 .to_vec();
788
789 assert!(chal.input_buffer.is_empty());
791
792 assert_eq!(chal.output_buffer, expected_output);
794 }
795
796 #[test]
797 fn test_observe_base_as_algebra_element_consistency_with_direct_observe() {
798 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 base_val = G::from_u8(99);
805
806 chal1.observe_base_as_algebra_element::<EF2G>(base_val);
808
809 let ext_val = EF2G::from(base_val);
811 chal2.observe_algebra_element(ext_val);
812
813 assert_eq!(chal1.input_buffer, chal2.input_buffer);
815 assert_eq!(chal1.output_buffer, chal2.output_buffer);
816 assert_eq!(chal1.sponge_state, chal2.sponge_state);
817 }
818
819 #[test]
820 fn test_observe_base_as_algebra_element_stream_consistency() {
821 let mut chal1 =
823 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
824 let mut chal2 =
825 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
826
827 let base_values: Vec<_> = (0u8..25).map(G::from_u8).collect();
829
830 for &val in &base_values {
832 chal1.observe_base_as_algebra_element::<EF2G>(val);
833 }
834
835 for &val in &base_values {
837 let ext_val = EF2G::from(val);
838 chal2.observe_algebra_element(ext_val);
839 }
840
841 assert_eq!(chal1.input_buffer, chal2.input_buffer);
843 assert_eq!(chal1.output_buffer, chal2.output_buffer);
844 assert_eq!(chal1.sponge_state, chal2.sponge_state);
845
846 let sample1: EF2G = chal1.sample_algebra_element();
848 let sample2: EF2G = chal2.sample_algebra_element();
849 assert_eq!(sample1, sample2);
850
851 assert_eq!(chal1.input_buffer, chal2.input_buffer);
853 assert_eq!(chal1.output_buffer, chal2.output_buffer);
854 assert_eq!(chal1.sponge_state, chal2.sponge_state);
855 }
856
857 #[test]
858 fn test_observe_algebra_elements_equivalence() {
859 let mut chal1 =
863 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
864 let mut chal2 =
865 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
866
867 let ext_values: Vec<EF2G> = (0u8..10).map(|i| EF2G::from(G::from_u8(i))).collect();
869
870 chal1.observe_algebra_slice(&ext_values);
872
873 for ext_val in &ext_values {
875 chal2.observe_algebra_element(*ext_val);
876 }
877
878 assert_eq!(chal1.input_buffer, chal2.input_buffer);
880 assert_eq!(chal1.output_buffer, chal2.output_buffer);
881 assert_eq!(chal1.sponge_state, chal2.sponge_state);
882
883 let sample1: EF2G = chal1.sample_algebra_element();
885 let sample2: EF2G = chal2.sample_algebra_element();
886 assert_eq!(sample1, sample2);
887 }
888
889 #[test]
890 fn test_observe_algebra_elements_empty_slice() {
891 let mut chal1 =
893 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
894 let mut chal2 =
895 DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
896
897 chal1.observe(G::from_u8(42));
899 chal2.observe(G::from_u8(42));
900
901 let empty: Vec<EF2G> = vec![];
903 chal1.observe_algebra_slice(&empty);
904
905 assert_eq!(chal1.input_buffer, chal2.input_buffer);
907 assert_eq!(chal1.output_buffer, chal2.output_buffer);
908 assert_eq!(chal1.sponge_state, chal2.sponge_state);
909 }
910
911 #[test]
912 fn test_observe_algebra_elements_triggers_duplexing() {
913 let mut chal = DuplexChallenger::<G, TestPermutation, WIDTH, RATE>::new(TestPermutation {});
915
916 let ext_values: Vec<EF2G> = (0u8..8).map(|i| EF2G::from(G::from_u8(i))).collect();
920
921 assert!(chal.input_buffer.is_empty());
922 assert!(chal.output_buffer.is_empty());
923
924 chal.observe_algebra_slice(&ext_values);
925
926 assert!(chal.input_buffer.is_empty());
928 assert!(!chal.output_buffer.is_empty());
929 }
930
931 #[test]
932 fn test_finalize() {
933 let new_chal = || DuplexChallenger::<G, _, WIDTH, RATE>::new(TestPermutation {});
934
935 let mut c1 = new_chal();
937 let mut c2 = new_chal();
938 for i in 0..5u8 {
939 c1.observe(G::from_u8(i));
940 c2.observe(G::from_u8(i));
941 }
942 assert_eq!(c1.finalize(), c2.finalize());
943
944 let mut c1 = new_chal();
946 let mut c2 = new_chal();
947 for i in 0..10u8 {
948 c1.observe(G::from_u8(i));
949 c2.observe(G::from_u8(i + 1));
950 }
951 assert_ne!(c1.finalize(), c2.finalize());
952 }
953
954 #[test]
962 fn test_finalize_sample_interaction() {
963 let digest = |n_samples: usize| {
964 let mut c = DuplexChallenger::<G, _, WIDTH, RATE>::new(TestPermutation {});
965 for i in 0..5u8 {
966 c.observe(G::from_u8(i));
967 }
968 for _ in 0..n_samples {
969 let _: G = c.sample();
970 }
971 c.finalize()
972 };
973
974 assert_ne!(digest(0), digest(1));
978
979 assert_eq!(digest(1), digest(2));
983 assert_eq!(digest(1), digest(RATE));
984
985 assert_ne!(digest(RATE), digest(RATE + 1));
988
989 assert_eq!(digest(RATE + 1), digest(RATE + 2));
991 }
992}