Skip to main content

sp1_recursion_compiler/ir/
builder.rs

1use std::{cell::UnsafeCell, ptr};
2
3use slop_algebra::AbstractField;
4use sp1_primitives::{types::RecursionProgramType, SP1ExtensionField, SP1Field};
5
6use super::{
7    Config, DslIr, DslIrBlock, Ext, ExtHandle, ExtOperations, Felt, FeltHandle, FeltOperations,
8    FromConstant, SymbolicExt, SymbolicFelt, SymbolicVar, Var, VarHandle, VarOperations, Variable,
9};
10
11#[derive(Debug, Clone)]
12pub(crate) struct InnerBuilder<C: Config> {
13    pub(crate) variable_count: u32,
14    pub operations: Vec<DslIr<C>>,
15}
16
17/// A builder for the DSL.
18///
19/// Can compile to both assembly and a set of constraints.
20#[derive(Debug)]
21pub struct Builder<C: Config> {
22    pub(crate) inner: Box<UnsafeCell<InnerBuilder<C>>>,
23    pub(crate) nb_public_values: Option<Var<C::N>>,
24    pub(crate) witness_var_count: u32,
25    pub(crate) witness_felt_count: u32,
26    pub(crate) witness_ext_count: u32,
27    pub(crate) var_handle: Box<VarHandle<C::N>>,
28    pub(crate) felt_handle: Box<FeltHandle<SP1Field>>,
29    pub(crate) ext_handle: Box<ExtHandle<SP1Field, SP1ExtensionField>>,
30    pub(crate) p2_hash_num: Var<C::N>,
31    pub(crate) debug: bool,
32    pub(crate) is_sub_builder: bool,
33    pub poseidon2_constants: Vec<Ext<SP1Field, SP1ExtensionField>>,
34    pub program_type: RecursionProgramType,
35}
36
37impl<C: Config> Default for Builder<C> {
38    fn default() -> Self {
39        let mut builder = Self::new(RecursionProgramType::Core);
40        C::initialize(&mut builder);
41        builder
42    }
43}
44
45impl<C: Config> Builder<C> {
46    pub fn new(program_type: RecursionProgramType) -> Self {
47        // We need to create a temporary placeholder for the p2_hash_num variable.
48        let placeholder_p2_hash_num = Var::new(0, ptr::null_mut());
49
50        let mut inner = Box::new(UnsafeCell::new(InnerBuilder {
51            variable_count: 0,
52            operations: Default::default(),
53        }));
54
55        let var_handle = Box::new(VarOperations::var_handle(&mut inner));
56        let mut ext_handle = Box::new(ExtOperations::ext_handle(&mut inner));
57        let felt_handle = Box::new(FeltOperations::felt_handle(
58            &mut inner,
59            ext_handle.as_mut() as *mut _ as *mut (),
60        ));
61
62        let mut new_builder = Self {
63            inner,
64            witness_var_count: 0,
65            witness_felt_count: 0,
66            witness_ext_count: 0,
67            nb_public_values: None,
68            var_handle,
69            felt_handle,
70            ext_handle,
71            p2_hash_num: placeholder_p2_hash_num,
72            debug: false,
73            is_sub_builder: false,
74            poseidon2_constants: vec![],
75            program_type,
76        };
77
78        new_builder.p2_hash_num = new_builder.uninit();
79        new_builder
80    }
81
82    /// Creates a new builder with a given number of counts for each type.
83    pub fn new_sub_builder(
84        variable_count: u32,
85        nb_public_values: Option<Var<C::N>>,
86        p2_hash_num: Var<C::N>,
87        debug: bool,
88        program_type: RecursionProgramType,
89    ) -> Self {
90        let mut builder = Self::new(program_type);
91        builder.inner.get_mut().variable_count = variable_count;
92        builder.nb_public_values = nb_public_values;
93        builder.p2_hash_num = p2_hash_num;
94        builder.debug = debug;
95
96        builder
97    }
98
99    /// Convenience function for creating a new sub builder.
100    pub fn sub_builder(&self) -> Self {
101        Builder::<C>::new_sub_builder(
102            self.variable_count(),
103            self.nb_public_values,
104            self.p2_hash_num,
105            self.debug,
106            self.program_type,
107        )
108    }
109
110    /// Pushes an operation to the builder.
111    #[inline(always)]
112    pub fn push_op(&mut self, op: DslIr<C>) {
113        self.inner.get_mut().operations.push(op);
114    }
115
116    pub fn extend_ops(&mut self, ops: impl IntoIterator<Item = DslIr<C>>) {
117        self.inner.get_mut().operations.extend(ops);
118    }
119
120    #[inline(always)]
121    // Record a trace if the "debug" feature is enabled.
122    pub fn push_backtrace(&mut self) {
123        #[cfg(feature = "debug")]
124        self.push_op(DslIr::DebugBacktrace(backtrace::Backtrace::new_unresolved()));
125    }
126
127    /// Pushes an operation to the builder and records a trace if the "debug" feature is enabled.
128    #[inline(always)]
129    pub fn push_traced_op(&mut self, op: DslIr<C>) {
130        self.push_backtrace();
131        self.push_op(op);
132    }
133
134    pub fn variable_count(&self) -> u32 {
135        unsafe { (*self.inner.get()).variable_count }
136    }
137
138    pub fn into_operations(self) -> Vec<DslIr<C>> {
139        self.inner.into_inner().operations
140    }
141
142    pub fn into_root_block(self) -> DslIrBlock<C> {
143        let addrs_written = 0..self.variable_count();
144        DslIrBlock { ops: self.inner.into_inner().operations, addrs_written }
145    }
146
147    /// Get a mutable reference to the list of operations.
148    /// Can be used for adjusting evaluation order using the utility functions from [`std::mem`].
149    ///
150    /// One use case is to move "lazy" evaluation out of a parallel context.
151    pub fn get_mut_operations(&mut self) -> &mut Vec<DslIr<C>> {
152        &mut self.inner.get_mut().operations
153    }
154
155    /// Creates an uninitialized variable.
156    pub fn uninit<V: Variable<C>>(&mut self) -> V {
157        V::uninit(self)
158    }
159
160    /// Evaluates an expression and returns a variable.
161    pub fn eval<V: Variable<C>, E: Into<V::Expression>>(&mut self, expr: E) -> V {
162        let dst = V::uninit(self);
163        dst.assign(expr.into(), self);
164        dst
165    }
166
167    /// Evaluates a constant expression and returns a variable.
168    pub fn constant<V: FromConstant<C>>(&mut self, value: V::Constant) -> V {
169        V::constant(value, self)
170    }
171
172    /// Assigns an expression to a variable.
173    pub fn assign<V: Variable<C>, E: Into<V::Expression>>(&mut self, dst: V, expr: E) {
174        dst.assign(expr.into(), self);
175    }
176
177    /// Asserts that two expressions are equal.
178    pub fn assert_eq<V: Variable<C>>(
179        &mut self,
180        lhs: impl Into<V::Expression>,
181        rhs: impl Into<V::Expression>,
182    ) {
183        V::assert_eq(lhs, rhs, self);
184    }
185
186    /// Asserts that two expressions are not equal.
187    pub fn assert_ne<V: Variable<C>>(
188        &mut self,
189        lhs: impl Into<V::Expression>,
190        rhs: impl Into<V::Expression>,
191    ) {
192        V::assert_ne(lhs, rhs, self);
193    }
194
195    /// Assert that two vars are equal.
196    pub fn assert_var_eq<LhsExpr: Into<SymbolicVar<C::N>>, RhsExpr: Into<SymbolicVar<C::N>>>(
197        &mut self,
198        lhs: LhsExpr,
199        rhs: RhsExpr,
200    ) {
201        self.assert_eq::<Var<C::N>>(lhs, rhs);
202    }
203
204    /// Assert that two vars are not equal.
205    pub fn assert_var_ne<LhsExpr: Into<SymbolicVar<C::N>>, RhsExpr: Into<SymbolicVar<C::N>>>(
206        &mut self,
207        lhs: LhsExpr,
208        rhs: RhsExpr,
209    ) {
210        self.assert_ne::<Var<C::N>>(lhs, rhs);
211    }
212
213    /// Assert that two felts are equal.
214    pub fn assert_felt_eq<
215        LhsExpr: Into<SymbolicFelt<SP1Field>>,
216        RhsExpr: Into<SymbolicFelt<SP1Field>>,
217    >(
218        &mut self,
219        lhs: LhsExpr,
220        rhs: RhsExpr,
221    ) {
222        self.assert_eq::<Felt<SP1Field>>(lhs, rhs);
223    }
224
225    /// Assert that two felts are not equal.
226    pub fn assert_felt_ne<
227        LhsExpr: Into<SymbolicFelt<SP1Field>>,
228        RhsExpr: Into<SymbolicFelt<SP1Field>>,
229    >(
230        &mut self,
231        lhs: LhsExpr,
232        rhs: RhsExpr,
233    ) {
234        self.assert_ne::<Felt<SP1Field>>(lhs, rhs);
235    }
236
237    /// Assert that two exts are equal.
238    pub fn assert_ext_eq<
239        LhsExpr: Into<SymbolicExt<SP1Field, SP1ExtensionField>>,
240        RhsExpr: Into<SymbolicExt<SP1Field, SP1ExtensionField>>,
241    >(
242        &mut self,
243        lhs: LhsExpr,
244        rhs: RhsExpr,
245    ) {
246        self.assert_eq::<Ext<SP1Field, SP1ExtensionField>>(lhs, rhs);
247    }
248
249    /// Assert that two exts are not equal.
250    pub fn assert_ext_ne<
251        LhsExpr: Into<SymbolicExt<SP1Field, SP1ExtensionField>>,
252        RhsExpr: Into<SymbolicExt<SP1Field, SP1ExtensionField>>,
253    >(
254        &mut self,
255        lhs: LhsExpr,
256        rhs: RhsExpr,
257    ) {
258        self.assert_ne::<Ext<SP1Field, SP1ExtensionField>>(lhs, rhs);
259    }
260
261    pub fn print_debug(&mut self, val: usize) {
262        let constant = self.eval(C::N::from_canonical_usize(val));
263        self.print_v(constant);
264    }
265
266    /// Print a variable.
267    pub fn print_v(&mut self, dst: Var<C::N>) {
268        self.push_op(DslIr::PrintV(dst));
269    }
270
271    /// Print a felt.
272    pub fn print_f(&mut self, dst: Felt<SP1Field>) {
273        self.push_op(DslIr::PrintF(dst));
274    }
275
276    /// Print an ext.
277    pub fn print_e(&mut self, dst: Ext<SP1Field, SP1ExtensionField>) {
278        self.push_op(DslIr::PrintE(dst));
279    }
280
281    pub fn witness_var(&mut self) -> Var<C::N> {
282        assert!(!self.is_sub_builder, "Cannot create a witness var with a sub builder");
283        let witness = self.uninit();
284        self.push_op(DslIr::WitnessVar(witness, self.witness_var_count));
285        self.witness_var_count += 1;
286        witness
287    }
288
289    pub fn witness_felt(&mut self) -> Felt<SP1Field> {
290        assert!(!self.is_sub_builder, "Cannot create a witness felt with a sub builder");
291        let witness = self.uninit();
292        self.push_op(DslIr::WitnessFelt(witness, self.witness_felt_count));
293        self.witness_felt_count += 1;
294        witness
295    }
296
297    pub fn witness_ext(&mut self) -> Ext<SP1Field, SP1ExtensionField> {
298        assert!(!self.is_sub_builder, "Cannot create a witness ext with a sub builder");
299        let witness = self.uninit();
300        self.push_op(DslIr::WitnessExt(witness, self.witness_ext_count));
301        self.witness_ext_count += 1;
302        witness
303    }
304
305    /// Throws an error.
306    pub fn error(&mut self) {
307        self.push_traced_op(DslIr::Error());
308    }
309
310    /// Register and commits a felt as public value.  This value will be constrained when verified.
311    pub fn commit_public_value(&mut self, val: Felt<SP1Field>) {
312        assert!(!self.is_sub_builder, "Cannot commit to a public value with a sub builder");
313        if self.nb_public_values.is_none() {
314            self.nb_public_values = Some(self.eval(C::N::zero()));
315        }
316        let nb_public_values = *self.nb_public_values.as_ref().unwrap();
317
318        self.push_op(DslIr::Commit(val, nb_public_values));
319        self.assign(nb_public_values, nb_public_values + C::N::one());
320    }
321
322    pub fn commit_vkey_hash_circuit(&mut self, var: Var<C::N>) {
323        self.push_op(DslIr::CircuitCommitVkeyHash(var));
324    }
325
326    pub fn commit_committed_values_digest_circuit(&mut self, var: Var<C::N>) {
327        self.push_op(DslIr::CircuitCommitCommittedValuesDigest(var));
328    }
329
330    pub fn commit_exit_code_circuit(&mut self, var: Var<C::N>) {
331        self.push_op(DslIr::CircuitCommitExitCode(var));
332    }
333
334    pub fn commit_proof_nonce_circuit(&mut self, var: Var<C::N>) {
335        self.push_op(DslIr::CircuitCommitProofNonce(var));
336    }
337
338    pub fn commit_vk_root_circuit(&mut self, var: Var<C::N>) {
339        self.push_op(DslIr::CircuitCommitVkRoot(var));
340    }
341
342    pub fn reduce_e(&mut self, ext: Ext<SP1Field, SP1ExtensionField>) {
343        self.push_op(DslIr::ReduceE(ext));
344    }
345
346    pub fn felt2var_circuit(&mut self, felt: Felt<SP1Field>) -> Var<C::N> {
347        let var = self.uninit();
348        self.push_op(DslIr::CircuitFelt2Var(felt, var));
349        var
350    }
351}