sp1_recursion_circuit_v2/
challenger.rs

1use p3_field::{AbstractField, Field};
2use sp1_recursion_compiler::{
3    circuit::CircuitV2Builder,
4    ir::{DslIr, Var},
5    prelude::{Builder, Config, Ext, Felt},
6};
7use sp1_recursion_core_v2::{
8    air::ChallengerPublicValues,
9    runtime::{HASH_RATE, PERMUTATION_WIDTH},
10    NUM_BITS,
11};
12
13// Constants for the Multifield challenger.
14pub const SPONGE_SIZE: usize = 3;
15pub const DIGEST_SIZE: usize = 1;
16pub const RATE: usize = 16;
17
18// use crate::{DigestVariable, VerifyingKeyVariable};
19
20pub trait CanCopyChallenger<C: Config> {
21    fn copy(&self, builder: &mut Builder<C>) -> Self;
22}
23/// Reference: [p3_challenger::CanObserve].
24pub trait CanObserveVariable<C: Config, V> {
25    fn observe(&mut self, builder: &mut Builder<C>, value: V);
26
27    fn observe_slice(&mut self, builder: &mut Builder<C>, values: impl IntoIterator<Item = V>) {
28        for value in values {
29            self.observe(builder, value);
30        }
31    }
32}
33
34pub trait CanSampleVariable<C: Config, V> {
35    fn sample(&mut self, builder: &mut Builder<C>) -> V;
36}
37
38/// Reference: [p3_challenger::FieldChallenger].
39pub trait FieldChallengerVariable<C: Config, Bit>:
40    CanObserveVariable<C, Felt<C::F>> + CanSampleVariable<C, Felt<C::F>> + CanSampleBitsVariable<C, Bit>
41{
42    fn sample_ext(&mut self, builder: &mut Builder<C>) -> Ext<C::F, C::EF>;
43
44    fn check_witness(&mut self, builder: &mut Builder<C>, nb_bits: usize, witness: Felt<C::F>);
45
46    fn duplexing(&mut self, builder: &mut Builder<C>);
47}
48
49pub trait CanSampleBitsVariable<C: Config, V> {
50    fn sample_bits(&mut self, builder: &mut Builder<C>, nb_bits: usize) -> Vec<V>;
51}
52
53/// Reference: [p3_challenger::DuplexChallenger]
54#[derive(Clone)]
55pub struct DuplexChallengerVariable<C: Config> {
56    pub sponge_state: [Felt<C::F>; PERMUTATION_WIDTH],
57    pub input_buffer: Vec<Felt<C::F>>,
58    pub output_buffer: Vec<Felt<C::F>>,
59}
60
61impl<C: Config> DuplexChallengerVariable<C> {
62    /// Creates a new duplex challenger with the default state.
63    pub fn new(builder: &mut Builder<C>) -> Self {
64        DuplexChallengerVariable::<C> {
65            sponge_state: core::array::from_fn(|_| builder.eval(C::F::zero())),
66            input_buffer: vec![],
67            output_buffer: vec![],
68        }
69    }
70
71    /// Creates a new challenger with the same state as an existing challenger.
72    pub fn copy(&self, builder: &mut Builder<C>) -> Self {
73        let DuplexChallengerVariable { sponge_state, input_buffer, output_buffer } = self;
74        let sponge_state = sponge_state.map(|x| builder.eval(x));
75        let mut copy_vec = |v: &Vec<Felt<C::F>>| v.iter().map(|x| builder.eval(*x)).collect();
76        DuplexChallengerVariable::<C> {
77            sponge_state,
78            input_buffer: copy_vec(input_buffer),
79            output_buffer: copy_vec(output_buffer),
80        }
81    }
82
83    // /// Asserts that the state of this challenger is equal to the state of another challenger.
84    // fn assert_eq(&self, builder: &mut Builder<C>, other: &Self) {
85    //     zip(&self.sponge_state, &other.sponge_state)
86    //         .chain(zip(&self.input_buffer, &other.input_buffer))
87    //         .chain(zip(&self.output_buffer, &other.output_buffer))
88    //         .for_each(|(&element, &other_element)| {
89    //             builder.assert_felt_eq(element, other_element);
90    //         });
91    // }
92
93    // fn reset(&mut self, builder: &mut Builder<C>) {
94    //     self.sponge_state.fill(builder.eval(C::F::zero()));
95    //     self.input_buffer.clear();
96    //     self.output_buffer.clear();
97    // }
98
99    fn observe(&mut self, builder: &mut Builder<C>, value: Felt<C::F>) {
100        self.output_buffer.clear();
101
102        self.input_buffer.push(value);
103
104        if self.input_buffer.len() == HASH_RATE {
105            self.duplexing(builder);
106        }
107    }
108
109    // fn observe_commitment(&mut self, builder: &mut Builder<C>, commitment: DigestVariable<C>) {
110    //     for element in commitment {
111    //         self.observe(builder, element);
112    //     }
113    // }
114
115    fn sample(&mut self, builder: &mut Builder<C>) -> Felt<C::F> {
116        if !self.input_buffer.is_empty() || self.output_buffer.is_empty() {
117            self.duplexing(builder);
118        }
119
120        self.output_buffer.pop().expect("output buffer should be non-empty")
121    }
122
123    fn sample_bits(&mut self, builder: &mut Builder<C>, nb_bits: usize) -> Vec<Felt<C::F>> {
124        assert!(nb_bits <= NUM_BITS);
125        let rand_f = self.sample(builder);
126        let mut rand_f_bits = builder.num2bits_v2_f(rand_f, NUM_BITS);
127        rand_f_bits.truncate(nb_bits);
128        rand_f_bits
129    }
130
131    pub fn public_values(&self, builder: &mut Builder<C>) -> ChallengerPublicValues<Felt<C::F>> {
132        assert!(self.input_buffer.len() <= PERMUTATION_WIDTH);
133        assert!(self.output_buffer.len() <= PERMUTATION_WIDTH);
134
135        let sponge_state = self.sponge_state;
136        let num_inputs = builder.eval(C::F::from_canonical_usize(self.input_buffer.len()));
137        let num_outputs = builder.eval(C::F::from_canonical_usize(self.output_buffer.len()));
138
139        let input_buffer: [_; PERMUTATION_WIDTH] = self
140            .input_buffer
141            .iter()
142            .copied()
143            .chain((self.input_buffer.len()..PERMUTATION_WIDTH).map(|_| builder.eval(C::F::zero())))
144            .collect::<Vec<_>>()
145            .try_into()
146            .unwrap();
147
148        let output_buffer: [_; PERMUTATION_WIDTH] = self
149            .output_buffer
150            .iter()
151            .copied()
152            .chain(
153                (self.output_buffer.len()..PERMUTATION_WIDTH).map(|_| builder.eval(C::F::zero())),
154            )
155            .collect::<Vec<_>>()
156            .try_into()
157            .unwrap();
158
159        ChallengerPublicValues {
160            sponge_state,
161            num_inputs,
162            input_buffer,
163            num_outputs,
164            output_buffer,
165        }
166    }
167}
168
169impl<C: Config> CanCopyChallenger<C> for DuplexChallengerVariable<C> {
170    fn copy(&self, builder: &mut Builder<C>) -> Self {
171        DuplexChallengerVariable::copy(self, builder)
172    }
173}
174
175impl<C: Config> CanObserveVariable<C, Felt<C::F>> for DuplexChallengerVariable<C> {
176    fn observe(&mut self, builder: &mut Builder<C>, value: Felt<C::F>) {
177        DuplexChallengerVariable::observe(self, builder, value);
178    }
179
180    fn observe_slice(
181        &mut self,
182        builder: &mut Builder<C>,
183        values: impl IntoIterator<Item = Felt<C::F>>,
184    ) {
185        for value in values {
186            self.observe(builder, value);
187        }
188    }
189}
190
191impl<C: Config, const N: usize> CanObserveVariable<C, [Felt<C::F>; N]>
192    for DuplexChallengerVariable<C>
193{
194    fn observe(&mut self, builder: &mut Builder<C>, values: [Felt<C::F>; N]) {
195        for value in values {
196            self.observe(builder, value);
197        }
198    }
199}
200
201impl<C: Config> CanSampleVariable<C, Felt<C::F>> for DuplexChallengerVariable<C> {
202    fn sample(&mut self, builder: &mut Builder<C>) -> Felt<C::F> {
203        DuplexChallengerVariable::sample(self, builder)
204    }
205}
206
207impl<C: Config> CanSampleBitsVariable<C, Felt<C::F>> for DuplexChallengerVariable<C> {
208    fn sample_bits(&mut self, builder: &mut Builder<C>, nb_bits: usize) -> Vec<Felt<C::F>> {
209        DuplexChallengerVariable::sample_bits(self, builder, nb_bits)
210    }
211}
212
213impl<C: Config> FieldChallengerVariable<C, Felt<C::F>> for DuplexChallengerVariable<C> {
214    fn sample_ext(&mut self, builder: &mut Builder<C>) -> Ext<C::F, C::EF> {
215        let a = self.sample(builder);
216        let b = self.sample(builder);
217        let c = self.sample(builder);
218        let d = self.sample(builder);
219        builder.ext_from_base_slice(&[a, b, c, d])
220    }
221
222    fn check_witness(
223        &mut self,
224        builder: &mut Builder<C>,
225        nb_bits: usize,
226        witness: Felt<<C as Config>::F>,
227    ) {
228        self.observe(builder, witness);
229        let element_bits = self.sample_bits(builder, nb_bits);
230        for bit in element_bits {
231            builder.assert_felt_eq(bit, C::F::zero());
232        }
233    }
234
235    fn duplexing(&mut self, builder: &mut Builder<C>) {
236        assert!(self.input_buffer.len() <= HASH_RATE);
237
238        self.sponge_state[0..self.input_buffer.len()].copy_from_slice(self.input_buffer.as_slice());
239        self.input_buffer.clear();
240
241        self.sponge_state = builder.poseidon2_permute_v2(self.sponge_state);
242
243        self.output_buffer.clear();
244        self.output_buffer.extend_from_slice(&self.sponge_state);
245    }
246}
247
248#[derive(Clone)]
249pub struct MultiField32ChallengerVariable<C: Config> {
250    sponge_state: [Var<C::N>; 3],
251    input_buffer: Vec<Felt<C::F>>,
252    output_buffer: Vec<Felt<C::F>>,
253    num_f_elms: usize,
254}
255
256impl<C: Config> MultiField32ChallengerVariable<C> {
257    pub fn new(builder: &mut Builder<C>) -> Self {
258        MultiField32ChallengerVariable::<C> {
259            sponge_state: [
260                builder.eval(C::N::zero()),
261                builder.eval(C::N::zero()),
262                builder.eval(C::N::zero()),
263            ],
264            input_buffer: vec![],
265            output_buffer: vec![],
266            num_f_elms: C::N::bits() / 64,
267        }
268    }
269
270    pub fn duplexing(&mut self, builder: &mut Builder<C>) {
271        assert!(self.input_buffer.len() <= self.num_f_elms * SPONGE_SIZE);
272
273        for (i, f_chunk) in self.input_buffer.chunks(self.num_f_elms).enumerate() {
274            self.sponge_state[i] = reduce_32(builder, f_chunk);
275        }
276        self.input_buffer.clear();
277
278        // TODO make this a method for the builder.
279        builder.push(DslIr::CircuitPoseidon2Permute(self.sponge_state));
280
281        self.output_buffer.clear();
282        for &pf_val in self.sponge_state.iter() {
283            let f_vals = split_32(builder, pf_val, self.num_f_elms);
284            for f_val in f_vals {
285                self.output_buffer.push(f_val);
286            }
287        }
288    }
289
290    pub fn observe(&mut self, builder: &mut Builder<C>, value: Felt<C::F>) {
291        self.output_buffer.clear();
292
293        self.input_buffer.push(value);
294        if self.input_buffer.len() == self.num_f_elms * SPONGE_SIZE {
295            self.duplexing(builder);
296        }
297    }
298
299    pub fn observe_commitment(
300        &mut self,
301        builder: &mut Builder<C>,
302        value: [Var<C::N>; DIGEST_SIZE],
303    ) {
304        for val in value {
305            let f_vals: Vec<Felt<C::F>> = split_32(builder, val, self.num_f_elms);
306            for f_val in f_vals {
307                self.observe(builder, f_val);
308            }
309        }
310    }
311
312    pub fn sample(&mut self, builder: &mut Builder<C>) -> Felt<C::F> {
313        if !self.input_buffer.is_empty() || self.output_buffer.is_empty() {
314            self.duplexing(builder);
315        }
316
317        self.output_buffer.pop().expect("output buffer should be non-empty")
318    }
319
320    pub fn sample_ext(&mut self, builder: &mut Builder<C>) -> Ext<C::F, C::EF> {
321        let a = self.sample(builder);
322        let b = self.sample(builder);
323        let c = self.sample(builder);
324        let d = self.sample(builder);
325        builder.felts2ext(&[a, b, c, d])
326    }
327
328    pub fn sample_bits(&mut self, builder: &mut Builder<C>, bits: usize) -> Vec<Var<C::N>> {
329        let rand_f = self.sample(builder);
330        builder.num2bits_f_circuit(rand_f)[0..bits].to_vec()
331    }
332
333    pub fn check_witness(&mut self, builder: &mut Builder<C>, bits: usize, witness: Felt<C::F>) {
334        self.observe(builder, witness);
335        let element = self.sample_bits(builder, bits);
336        for bit in element {
337            builder.assert_var_eq(bit, C::N::from_canonical_usize(0));
338        }
339    }
340}
341
342impl<C: Config> CanCopyChallenger<C> for MultiField32ChallengerVariable<C> {
343    /// Creates a new challenger with the same state as an existing challenger.
344    fn copy(&self, builder: &mut Builder<C>) -> Self {
345        let MultiField32ChallengerVariable {
346            sponge_state,
347            input_buffer,
348            output_buffer,
349            num_f_elms,
350        } = self;
351        let sponge_state = sponge_state.map(|x| builder.eval(x));
352        let mut copy_vec = |v: &Vec<Felt<C::F>>| v.iter().map(|x| builder.eval(*x)).collect();
353        MultiField32ChallengerVariable::<C> {
354            sponge_state,
355            num_f_elms: *num_f_elms,
356            input_buffer: copy_vec(input_buffer),
357            output_buffer: copy_vec(output_buffer),
358        }
359    }
360}
361
362impl<C: Config> CanObserveVariable<C, Felt<C::F>> for MultiField32ChallengerVariable<C> {
363    fn observe(&mut self, builder: &mut Builder<C>, value: Felt<C::F>) {
364        MultiField32ChallengerVariable::observe(self, builder, value);
365    }
366}
367
368impl<C: Config> CanObserveVariable<C, [Var<C::N>; DIGEST_SIZE]>
369    for MultiField32ChallengerVariable<C>
370{
371    fn observe(&mut self, builder: &mut Builder<C>, value: [Var<C::N>; DIGEST_SIZE]) {
372        self.observe_commitment(builder, value)
373    }
374}
375
376impl<C: Config> CanObserveVariable<C, Var<C::N>> for MultiField32ChallengerVariable<C> {
377    fn observe(&mut self, builder: &mut Builder<C>, value: Var<C::N>) {
378        self.observe_commitment(builder, [value])
379    }
380}
381
382impl<C: Config> CanSampleVariable<C, Felt<C::F>> for MultiField32ChallengerVariable<C> {
383    fn sample(&mut self, builder: &mut Builder<C>) -> Felt<C::F> {
384        MultiField32ChallengerVariable::sample(self, builder)
385    }
386}
387
388impl<C: Config> CanSampleBitsVariable<C, Var<C::N>> for MultiField32ChallengerVariable<C> {
389    fn sample_bits(&mut self, builder: &mut Builder<C>, bits: usize) -> Vec<Var<C::N>> {
390        MultiField32ChallengerVariable::sample_bits(self, builder, bits)
391    }
392}
393
394impl<C: Config> FieldChallengerVariable<C, Var<C::N>> for MultiField32ChallengerVariable<C> {
395    fn sample_ext(&mut self, builder: &mut Builder<C>) -> Ext<C::F, C::EF> {
396        MultiField32ChallengerVariable::sample_ext(self, builder)
397    }
398
399    fn check_witness(&mut self, builder: &mut Builder<C>, bits: usize, witness: Felt<C::F>) {
400        MultiField32ChallengerVariable::check_witness(self, builder, bits, witness);
401    }
402
403    fn duplexing(&mut self, builder: &mut Builder<C>) {
404        MultiField32ChallengerVariable::duplexing(self, builder);
405    }
406}
407
408pub fn reduce_32<C: Config>(builder: &mut Builder<C>, vals: &[Felt<C::F>]) -> Var<C::N> {
409    let mut power = C::N::one();
410    let result: Var<C::N> = builder.eval(C::N::zero());
411    for val in vals.iter() {
412        let val = builder.felt2var_circuit(*val);
413        builder.assign(result, result + val * power);
414        power *= C::N::from_canonical_u64(1u64 << 32);
415    }
416    result
417}
418
419pub fn split_32<C: Config>(builder: &mut Builder<C>, val: Var<C::N>, n: usize) -> Vec<Felt<C::F>> {
420    let bits = builder.num2bits_v_circuit(val, 256);
421    let mut results = Vec::new();
422    for i in 0..n {
423        let result: Felt<C::F> = builder.eval(C::F::zero());
424        for j in 0..64 {
425            let bit = bits[i * 64 + j];
426            let t = builder.eval(result + C::F::from_wrapped_u64(1 << j));
427            let z = builder.select_f(bit, t, result);
428            builder.assign(result, z);
429        }
430        results.push(result);
431    }
432    results
433}
434
435#[cfg(test)]
436pub(crate) mod tests {
437    use std::iter::zip;
438
439    use crate::{
440        challenger::{CanCopyChallenger, MultiField32ChallengerVariable},
441        hash::{FieldHasherVariable, BN254_DIGEST_SIZE},
442        utils::tests::run_test_recursion,
443    };
444    use p3_baby_bear::BabyBear;
445    use p3_bn254_fr::Bn254Fr;
446    use p3_challenger::{CanObserve, CanSample, CanSampleBits, FieldChallenger};
447    use p3_field::AbstractField;
448    use p3_symmetric::{CryptographicHasher, Hash, PseudoCompressionFunction};
449    use sp1_recursion_compiler::{
450        asm::{AsmBuilder, AsmConfig},
451        config::OuterConfig,
452        constraints::ConstraintCompiler,
453        ir::{Builder, Config, Ext, ExtConst, Felt, Var},
454    };
455    use sp1_recursion_core_v2::stark::config::{
456        outer_perm, BabyBearPoseidon2Outer, OuterCompress, OuterHash,
457    };
458    use sp1_recursion_gnark_ffi::PlonkBn254Prover;
459    use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig};
460
461    use crate::{
462        challenger::{DuplexChallengerVariable, FieldChallengerVariable},
463        witness::OuterWitness,
464    };
465
466    type SC = BabyBearPoseidon2;
467    type C = OuterConfig;
468    type F = <SC as StarkGenericConfig>::Val;
469    type EF = <SC as StarkGenericConfig>::Challenge;
470
471    #[test]
472    fn test_compiler_challenger() {
473        let config = SC::default();
474        let mut challenger = config.challenger();
475        challenger.observe(F::one());
476        challenger.observe(F::two());
477        challenger.observe(F::two());
478        challenger.observe(F::two());
479        let result: F = challenger.sample();
480        println!("expected result: {}", result);
481        let result_ef: EF = challenger.sample_ext_element();
482        println!("expected result_ef: {}", result_ef);
483
484        let mut builder = AsmBuilder::<F, EF>::default();
485
486        let mut challenger = DuplexChallengerVariable::<AsmConfig<F, EF>> {
487            sponge_state: core::array::from_fn(|_| builder.eval(F::zero())),
488            input_buffer: vec![],
489            output_buffer: vec![],
490        };
491        let one: Felt<_> = builder.eval(F::one());
492        let two: Felt<_> = builder.eval(F::two());
493
494        challenger.observe(&mut builder, one);
495        challenger.observe(&mut builder, two);
496        challenger.observe(&mut builder, two);
497        challenger.observe(&mut builder, two);
498        let element = challenger.sample(&mut builder);
499        let element_ef = challenger.sample_ext(&mut builder);
500
501        let expected_result: Felt<_> = builder.eval(result);
502        let expected_result_ef: Ext<_, _> = builder.eval(result_ef.cons());
503        builder.print_f(element);
504        builder.assert_felt_eq(expected_result, element);
505        builder.print_e(element_ef);
506        builder.assert_ext_eq(expected_result_ef, element_ef);
507
508        run_test_recursion(builder.operations, None);
509    }
510
511    #[test]
512    fn test_challenger_outer() {
513        type SC = BabyBearPoseidon2Outer;
514        type F = <SC as StarkGenericConfig>::Val;
515        type EF = <SC as StarkGenericConfig>::Challenge;
516        type N = <C as Config>::N;
517
518        let config = SC::default();
519        let mut challenger = config.challenger();
520        challenger.observe(F::one());
521        challenger.observe(F::two());
522        challenger.observe(F::two());
523        challenger.observe(F::two());
524        let commit = Hash::from([N::two()]);
525        challenger.observe(commit);
526        let result: F = challenger.sample();
527        println!("expected result: {}", result);
528        let result_ef: EF = challenger.sample_ext_element();
529        println!("expected result_ef: {}", result_ef);
530        let mut bits = challenger.sample_bits(30);
531        let mut bits_vec = vec![];
532        for _ in 0..30 {
533            bits_vec.push(bits % 2);
534            bits >>= 1;
535        }
536        println!("expected bits: {:?}", bits_vec);
537
538        let mut builder = Builder::<C>::default();
539
540        // let width: Var<_> = builder.eval(F::from_canonical_usize(PERMUTATION_WIDTH));
541        let mut challenger = MultiField32ChallengerVariable::<C>::new(&mut builder);
542        let one: Felt<_> = builder.eval(F::one());
543        let two: Felt<_> = builder.eval(F::two());
544        let two_var: Var<_> = builder.eval(N::two());
545        // builder.halt();
546        challenger.observe(&mut builder, one);
547        challenger.observe(&mut builder, two);
548        challenger.observe(&mut builder, two);
549        challenger.observe(&mut builder, two);
550        challenger.observe_commitment(&mut builder, [two_var]);
551
552        // Check to make sure the copying works.
553        challenger = challenger.copy(&mut builder);
554        let element = challenger.sample(&mut builder);
555        let element_ef = challenger.sample_ext(&mut builder);
556        let bits = challenger.sample_bits(&mut builder, 31);
557
558        let expected_result: Felt<_> = builder.eval(result);
559        let expected_result_ef: Ext<_, _> = builder.eval(result_ef.cons());
560        builder.print_f(element);
561        builder.assert_felt_eq(expected_result, element);
562        builder.print_e(element_ef);
563        builder.assert_ext_eq(expected_result_ef, element_ef);
564        for (expected_bit, bit) in zip(bits_vec.iter(), bits.iter()) {
565            let expected_bit: Var<_> = builder.eval(N::from_canonical_usize(*expected_bit));
566            builder.print_v(*bit);
567            builder.assert_var_eq(expected_bit, *bit);
568        }
569
570        let mut backend = ConstraintCompiler::<C>::default();
571        let constraints = backend.emit(builder.operations);
572        let witness = OuterWitness::default();
573        PlonkBn254Prover::test::<C>(constraints, witness);
574    }
575
576    #[test]
577    fn test_select_chain_digest() {
578        type N = <C as Config>::N;
579
580        let mut builder = Builder::<C>::default();
581
582        let one: Var<_> = builder.eval(N::one());
583        let two: Var<_> = builder.eval(N::two());
584
585        let to_swap = [[one], [two]];
586        let result = BabyBearPoseidon2Outer::select_chain_digest(&mut builder, one, to_swap);
587
588        builder.assert_var_eq(result[0][0], two);
589        builder.assert_var_eq(result[1][0], one);
590
591        let mut backend = ConstraintCompiler::<C>::default();
592        let constraints = backend.emit(builder.operations);
593        let witness = OuterWitness::default();
594        PlonkBn254Prover::test::<C>(constraints, witness);
595    }
596
597    #[test]
598    fn test_p2_hash() {
599        let perm = outer_perm();
600        let hasher = OuterHash::new(perm.clone()).unwrap();
601
602        let input: [BabyBear; 7] = [
603            BabyBear::from_canonical_u32(0),
604            BabyBear::from_canonical_u32(1),
605            BabyBear::from_canonical_u32(2),
606            BabyBear::from_canonical_u32(2),
607            BabyBear::from_canonical_u32(2),
608            BabyBear::from_canonical_u32(2),
609            BabyBear::from_canonical_u32(2),
610        ];
611        let output = hasher.hash_iter(input);
612
613        let mut builder = Builder::<C>::default();
614        let a: Felt<_> = builder.eval(input[0]);
615        let b: Felt<_> = builder.eval(input[1]);
616        let c: Felt<_> = builder.eval(input[2]);
617        let d: Felt<_> = builder.eval(input[3]);
618        let e: Felt<_> = builder.eval(input[4]);
619        let f: Felt<_> = builder.eval(input[5]);
620        let g: Felt<_> = builder.eval(input[6]);
621        let result = BabyBearPoseidon2Outer::hash(&mut builder, &[a, b, c, d, e, f, g]);
622
623        builder.assert_var_eq(result[0], output[0]);
624
625        let mut backend = ConstraintCompiler::<C>::default();
626        let constraints = backend.emit(builder.operations);
627        PlonkBn254Prover::test::<C>(constraints.clone(), OuterWitness::default());
628    }
629
630    #[test]
631    fn test_p2_compress() {
632        type OuterDigestVariable = [Var<<C as Config>::N>; BN254_DIGEST_SIZE];
633        let perm = outer_perm();
634        let compressor = OuterCompress::new(perm.clone());
635
636        let a: [Bn254Fr; 1] = [Bn254Fr::two()];
637        let b: [Bn254Fr; 1] = [Bn254Fr::two()];
638        let gt = compressor.compress([a, b]);
639
640        let mut builder = Builder::<C>::default();
641        let a: OuterDigestVariable = [builder.eval(a[0])];
642        let b: OuterDigestVariable = [builder.eval(b[0])];
643        let result = BabyBearPoseidon2Outer::compress(&mut builder, [a, b]);
644        builder.assert_var_eq(result[0], gt[0]);
645
646        let mut backend = ConstraintCompiler::<C>::default();
647        let constraints = backend.emit(builder.operations);
648        PlonkBn254Prover::test::<C>(constraints.clone(), OuterWitness::default());
649    }
650}