sp1_recursion_circuit_v2/
lib.rs1use std::{
4 iter::{repeat, zip},
5 ops::{Add, Mul},
6};
7
8use challenger::{
9 CanCopyChallenger, CanObserveVariable, DuplexChallengerVariable, FieldChallengerVariable,
10 MultiField32ChallengerVariable,
11};
12use hash::FieldHasherVariable;
13use p3_bn254_fr::Bn254Fr;
14use p3_field::AbstractField;
15use p3_matrix::dense::RowMajorMatrix;
16use sp1_recursion_compiler::{
17 circuit::CircuitV2Builder,
18 config::{InnerConfig, OuterConfig},
19 ir::{Builder, Config, DslIr, Ext, Felt, Var, Variable},
20};
21
22mod types;
23
24pub mod build_wrap_v2;
25pub mod challenger;
26pub mod constraints;
27pub mod domain;
28pub mod fri;
29pub mod hash;
30pub mod machine;
31pub mod stark;
32pub(crate) mod utils;
33pub mod witness;
34
35use sp1_stark::{
36 baby_bear_poseidon2::{BabyBearPoseidon2, ValMmcs},
37 StarkGenericConfig,
38};
39pub use types::*;
40
41use p3_challenger::{CanObserve, CanSample, FieldChallenger, GrindingChallenger};
42use p3_commit::{ExtensionMmcs, Mmcs};
43use p3_dft::Radix2DitParallel;
44use p3_fri::{FriConfig, TwoAdicFriPcs};
45use sp1_recursion_core_v2::{
46 stark::config::{BabyBearPoseidon2Outer, OuterValMmcs},
47 D,
48};
49
50use p3_baby_bear::BabyBear;
51
52type EF = <BabyBearPoseidon2 as StarkGenericConfig>::Challenge;
53
54pub type PcsConfig<C> = FriConfig<
55 ExtensionMmcs<
56 <C as StarkGenericConfig>::Val,
57 <C as StarkGenericConfig>::Challenge,
58 <C as BabyBearFriConfig>::ValMmcs,
59 >,
60>;
61
62pub type Digest<C, SC> = <SC as FieldHasherVariable<C>>::Digest;
63
64pub type FriMmcs<C> = ExtensionMmcs<BabyBear, EF, <C as BabyBearFriConfig>::ValMmcs>;
65
66pub trait BabyBearFriConfig:
67 StarkGenericConfig<
68 Val = BabyBear,
69 Challenge = EF,
70 Challenger = Self::FriChallenger,
71 Pcs = TwoAdicFriPcs<
72 BabyBear,
73 Radix2DitParallel,
74 Self::ValMmcs,
75 ExtensionMmcs<BabyBear, EF, Self::ValMmcs>,
76 >,
77>
78{
79 type ValMmcs: Mmcs<BabyBear, ProverData<RowMajorMatrix<BabyBear>> = Self::RowMajorProverData>
80 + Send
81 + Sync;
82 type RowMajorProverData: Clone + Send + Sync;
83 type FriChallenger: CanObserve<<Self::ValMmcs as Mmcs<BabyBear>>::Commitment>
84 + CanSample<EF>
85 + GrindingChallenger<Witness = BabyBear>
86 + FieldChallenger<BabyBear>;
87
88 fn fri_config(&self) -> &FriConfig<FriMmcs<Self>>;
89}
90
91pub trait BabyBearFriConfigVariable<C: CircuitConfig<F = BabyBear>>:
92 BabyBearFriConfig + FieldHasherVariable<C>
93{
94 type FriChallengerVariable: FieldChallengerVariable<C, <C as CircuitConfig>::Bit>
95 + CanObserveVariable<C, <Self as FieldHasherVariable<C>>::Digest>
96 + CanCopyChallenger<C>;
97
98 fn challenger_variable(&self, builder: &mut Builder<C>) -> Self::FriChallengerVariable;
100}
101
102pub trait CircuitConfig: Config {
103 type Bit: Clone + Variable<Self>;
104
105 fn read_bit(builder: &mut Builder<Self>) -> Self::Bit;
106
107 fn read_felt(builder: &mut Builder<Self>) -> Felt<Self::F>;
108
109 fn read_ext(builder: &mut Builder<Self>) -> Ext<Self::F, Self::EF>;
110
111 fn ext2felt(
112 builder: &mut Builder<Self>,
113 ext: Ext<<Self as Config>::F, <Self as Config>::EF>,
114 ) -> [Felt<<Self as Config>::F>; D];
115
116 fn exp_reverse_bits(
117 builder: &mut Builder<Self>,
118 input: Felt<<Self as Config>::F>,
119 power_bits: Vec<Self::Bit>,
120 ) -> Felt<<Self as Config>::F>;
121
122 fn num2bits(
123 builder: &mut Builder<Self>,
124 num: Felt<<Self as Config>::F>,
125 num_bits: usize,
126 ) -> Vec<Self::Bit>;
127
128 fn bits2num(
129 builder: &mut Builder<Self>,
130 bits: impl IntoIterator<Item = Self::Bit>,
131 ) -> Felt<<Self as Config>::F>;
132
133 #[allow(clippy::type_complexity)]
134 fn select_chain_ef(
135 builder: &mut Builder<Self>,
136 should_swap: Self::Bit,
137 first: impl IntoIterator<Item = Ext<<Self as Config>::F, <Self as Config>::EF>> + Clone,
138 second: impl IntoIterator<Item = Ext<<Self as Config>::F, <Self as Config>::EF>> + Clone,
139 ) -> Vec<Ext<<Self as Config>::F, <Self as Config>::EF>>;
140}
141
142impl CircuitConfig for InnerConfig {
143 type Bit = Felt<<Self as Config>::F>;
144
145 fn read_bit(builder: &mut Builder<Self>) -> Self::Bit {
146 builder.hint_felt_v2()
147 }
148
149 fn read_felt(builder: &mut Builder<Self>) -> Felt<Self::F> {
150 builder.hint_felt_v2()
151 }
152
153 fn read_ext(builder: &mut Builder<Self>) -> Ext<Self::F, Self::EF> {
154 builder.hint_ext_v2()
155 }
156
157 fn ext2felt(
158 builder: &mut Builder<Self>,
159 ext: Ext<<Self as Config>::F, <Self as Config>::EF>,
160 ) -> [Felt<<Self as Config>::F>; D] {
161 builder.ext2felt_v2(ext)
162 }
163
164 fn exp_reverse_bits(
165 builder: &mut Builder<Self>,
166 input: Felt<<Self as Config>::F>,
167 power_bits: Vec<Felt<<Self as Config>::F>>,
168 ) -> Felt<<Self as Config>::F> {
169 builder.exp_reverse_bits_v2(input, power_bits)
170 }
171
172 fn num2bits(
173 builder: &mut Builder<Self>,
174 num: Felt<<Self as Config>::F>,
175 num_bits: usize,
176 ) -> Vec<Felt<<Self as Config>::F>> {
177 builder.num2bits_v2_f(num, num_bits)
178 }
179
180 fn bits2num(
181 builder: &mut Builder<Self>,
182 bits: impl IntoIterator<Item = Felt<<Self as Config>::F>>,
183 ) -> Felt<<Self as Config>::F> {
184 builder.bits2num_v2_f(bits)
185 }
186
187 fn select_chain_ef(
188 builder: &mut Builder<Self>,
189 should_swap: Self::Bit,
190 first: impl IntoIterator<Item = Ext<<Self as Config>::F, <Self as Config>::EF>> + Clone,
191 second: impl IntoIterator<Item = Ext<<Self as Config>::F, <Self as Config>::EF>> + Clone,
192 ) -> Vec<Ext<<Self as Config>::F, <Self as Config>::EF>> {
193 let one: Felt<_> = builder.constant(Self::F::one());
194 let shouldnt_swap: Felt<_> = builder.eval(one - should_swap);
195
196 let id_branch = first.clone().into_iter().chain(second.clone());
197 let swap_branch = second.into_iter().chain(first);
198 zip(zip(id_branch, swap_branch), zip(repeat(shouldnt_swap), repeat(should_swap)))
199 .map(|((id_v, sw_v), (id_c, sw_c))| builder.eval(id_v * id_c + sw_v * sw_c))
200 .collect()
201 }
202}
203
204impl CircuitConfig for OuterConfig {
205 type Bit = Var<<Self as Config>::N>;
206
207 fn read_bit(builder: &mut Builder<Self>) -> Self::Bit {
208 builder.witness_var()
209 }
210
211 fn read_felt(builder: &mut Builder<Self>) -> Felt<Self::F> {
212 builder.witness_felt()
213 }
214
215 fn read_ext(builder: &mut Builder<Self>) -> Ext<Self::F, Self::EF> {
216 builder.witness_ext()
217 }
218
219 fn ext2felt(
220 builder: &mut Builder<Self>,
221 ext: Ext<<Self as Config>::F, <Self as Config>::EF>,
222 ) -> [Felt<<Self as Config>::F>; D] {
223 let felts = core::array::from_fn(|_| builder.uninit());
224 builder.operations.push(DslIr::CircuitExt2Felt(felts, ext));
225 felts
226 }
227
228 fn exp_reverse_bits(
229 builder: &mut Builder<Self>,
230 input: Felt<<Self as Config>::F>,
231 power_bits: Vec<Var<<Self as Config>::N>>,
232 ) -> Felt<<Self as Config>::F> {
233 let mut result = builder.constant(Self::F::one());
234 let power_f = input;
235 let bit_len = power_bits.len();
236
237 for i in 1..=bit_len {
238 let index = bit_len - i;
239 let bit = power_bits[index];
240 let prod = builder.eval(result * power_f);
241 result = builder.select_f(bit, prod, result);
242 builder.assign(power_f, power_f * power_f);
243 }
244 result
245 }
246
247 fn num2bits(
248 builder: &mut Builder<Self>,
249 num: Felt<<Self as Config>::F>,
250 num_bits: usize,
251 ) -> Vec<Var<<Self as Config>::N>> {
252 builder.num2bits_f_circuit(num)[..num_bits].to_vec()
253 }
254
255 fn bits2num(
256 builder: &mut Builder<Self>,
257 bits: impl IntoIterator<Item = Var<<Self as Config>::N>>,
258 ) -> Felt<<Self as Config>::F> {
259 let result = builder.eval(Self::F::zero());
260 for (i, bit) in bits.into_iter().enumerate() {
261 let to_add: Felt<_> = builder.uninit();
262 let pow2 = builder.constant(Self::F::from_canonical_u32(1 << i));
263 let zero = builder.constant(Self::F::zero());
264 builder.operations.push(DslIr::CircuitSelectF(bit, pow2, zero, to_add));
265 builder.assign(result, result + to_add);
266 }
267 result
268 }
269
270 fn select_chain_ef(
271 builder: &mut Builder<Self>,
272 should_swap: Self::Bit,
273 first: impl IntoIterator<Item = Ext<<Self as Config>::F, <Self as Config>::EF>> + Clone,
274 second: impl IntoIterator<Item = Ext<<Self as Config>::F, <Self as Config>::EF>> + Clone,
275 ) -> Vec<Ext<<Self as Config>::F, <Self as Config>::EF>> {
276 let id_branch = first.clone().into_iter().chain(second.clone());
277 let swap_branch = second.into_iter().chain(first);
278 zip(id_branch, swap_branch)
279 .map(|(id_v, sw_v): (Ext<_, _>, Ext<_, _>)| -> Ext<_, _> {
280 let result: Ext<_, _> = builder.uninit();
281 builder.operations.push(DslIr::CircuitSelectE(should_swap, sw_v, id_v, result));
282 result
283 })
284 .collect()
285 }
286}
287
288impl BabyBearFriConfig for BabyBearPoseidon2 {
289 type ValMmcs = ValMmcs;
290 type FriChallenger = <Self as StarkGenericConfig>::Challenger;
291 type RowMajorProverData = <ValMmcs as Mmcs<BabyBear>>::ProverData<RowMajorMatrix<BabyBear>>;
292
293 fn fri_config(&self) -> &FriConfig<FriMmcs<Self>> {
294 self.pcs().fri_config()
295 }
296}
297
298impl BabyBearFriConfig for BabyBearPoseidon2Outer {
299 type ValMmcs = OuterValMmcs;
300 type FriChallenger = <Self as StarkGenericConfig>::Challenger;
301
302 type RowMajorProverData =
303 <OuterValMmcs as Mmcs<BabyBear>>::ProverData<RowMajorMatrix<BabyBear>>;
304
305 fn fri_config(&self) -> &FriConfig<FriMmcs<Self>> {
306 self.pcs().fri_config()
307 }
308}
309
310impl<C: CircuitConfig<F = BabyBear, Bit = Felt<BabyBear>>> BabyBearFriConfigVariable<C>
311 for BabyBearPoseidon2
312{
313 type FriChallengerVariable = DuplexChallengerVariable<C>;
314
315 fn challenger_variable(&self, builder: &mut Builder<C>) -> Self::FriChallengerVariable {
316 DuplexChallengerVariable::new(builder)
317 }
318}
319
320impl<C: CircuitConfig<F = BabyBear, N = Bn254Fr, Bit = Var<Bn254Fr>>> BabyBearFriConfigVariable<C>
321 for BabyBearPoseidon2Outer
322{
323 type FriChallengerVariable = MultiField32ChallengerVariable<C>;
324
325 fn challenger_variable(&self, builder: &mut Builder<C>) -> Self::FriChallengerVariable {
326 MultiField32ChallengerVariable::new(builder)
327 }
328}
329
330pub fn select_chain<'a, C, R, S>(
331 builder: &'a mut Builder<C>,
332 should_swap: R,
333 first: impl IntoIterator<Item = S> + Clone + 'a,
334 second: impl IntoIterator<Item = S> + Clone + 'a,
335) -> impl Iterator<Item = S> + 'a
336where
337 C: Config,
338 R: Variable<C> + 'a,
339 S: Variable<C> + 'a,
340 <R as Variable<C>>::Expression: AbstractField
341 + Mul<<S as Variable<C>>::Expression, Output = <S as Variable<C>>::Expression>,
342 <S as Variable<C>>::Expression: Add<Output = <S as Variable<C>>::Expression>,
343{
344 let should_swap: <R as Variable<C>>::Expression = should_swap.into();
345 let one = <R as Variable<C>>::Expression::one();
346 let shouldnt_swap = one - should_swap.clone();
347
348 let id_branch =
349 first.clone().into_iter().chain(second.clone()).map(<S as Variable<C>>::Expression::from);
350 let swap_branch = second.into_iter().chain(first).map(<S as Variable<C>>::Expression::from);
351 zip(zip(id_branch, swap_branch), zip(repeat(shouldnt_swap), repeat(should_swap)))
352 .map(|((id_v, sw_v), (id_c, sw_c))| builder.eval(id_c * id_v + sw_c * sw_v))
353}