Skip to main content

sp1_recursion_circuit/
challenger.rs

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