sp1_recursion_compiler/ir/
utils.rs1use p3_field::{AbstractExtensionField, AbstractField};
2use std::ops::{Add, Mul, MulAssign};
3
4use super::{Array, Builder, Config, DslIr, Ext, Felt, SymbolicExt, Usize, Var, Variable};
5
6impl<C: Config> Builder<C> {
7 pub fn generator(&mut self) -> Felt<C::F> {
11 self.eval(C::F::from_canonical_u32(31))
12 }
13
14 pub fn select_v(&mut self, cond: Var<C::N>, a: Var<C::N>, b: Var<C::N>) -> Var<C::N> {
16 let c = self.uninit();
17 self.push_op(DslIr::CircuitSelectV(cond, a, b, c));
18 c
19 }
20
21 pub fn select_f(&mut self, cond: Var<C::N>, a: Felt<C::F>, b: Felt<C::F>) -> Felt<C::F> {
23 let c = self.uninit();
24 self.push_op(DslIr::CircuitSelectF(cond, a, b, c));
25 c
26 }
27
28 pub fn select_ef(
30 &mut self,
31 cond: Var<C::N>,
32 a: Ext<C::F, C::EF>,
33 b: Ext<C::F, C::EF>,
34 ) -> Ext<C::F, C::EF> {
35 let c = self.uninit();
36 self.push_op(DslIr::CircuitSelectE(cond, a, b, c));
37 c
38 }
39
40 pub fn exp_power_of_2<V: Variable<C>, E: Into<V::Expression>>(
42 &mut self,
43 e: E,
44 power_log: usize,
45 ) -> V
46 where
47 V::Expression: MulAssign<V::Expression> + Clone,
48 {
49 let mut e = e.into();
50 for _ in 0..power_log {
51 e *= e.clone();
52 }
53 self.eval(e)
54 }
55
56 pub fn exp_bits<V>(&mut self, x: V, power_bits: &Array<C, Var<C::N>>) -> V
58 where
59 V::Expression: AbstractField,
60 V: Copy + Mul<Output = V::Expression> + Variable<C>,
61 {
62 let result = self.eval(V::Expression::one());
63 let power_f: V = self.eval(x);
64 self.range(0, power_bits.len()).for_each(|i, builder| {
65 let bit = builder.get(power_bits, i);
66 builder
67 .if_eq(bit, C::N::one())
68 .then(|builder| builder.assign(result, result * power_f));
69 builder.assign(power_f, power_f * power_f);
70 });
71 result
72 }
73
74 pub fn exp_f_bits(&mut self, x: Felt<C::F>, power_bits: Vec<Var<C::N>>) -> Felt<C::F> {
76 let mut result = self.eval(C::F::one());
77 let mut power_f: Felt<_> = self.eval(x);
78 for i in 0..power_bits.len() {
79 let bit = power_bits[i];
80 let tmp = self.eval(result * power_f);
81 result = self.select_f(bit, tmp, result);
82 power_f = self.eval(power_f * power_f);
83 }
84 result
85 }
86
87 pub fn exp_e_bits(
89 &mut self,
90 x: Ext<C::F, C::EF>,
91 power_bits: Vec<Var<C::N>>,
92 ) -> Ext<C::F, C::EF> {
93 let mut result = self.eval(SymbolicExt::from_f(C::EF::one()));
94 let mut power_f: Ext<_, _> = self.eval(x);
95 for i in 0..power_bits.len() {
96 let bit = power_bits[i];
97 let tmp = self.eval(result * power_f);
98 result = self.select_ef(bit, tmp, result);
99 power_f = self.eval(power_f * power_f);
100 }
101 result
102 }
103
104 pub fn exp_reverse_bits_len<V>(
108 &mut self,
109 x: V,
110 power_bits: &Array<C, Var<C::N>>,
111 bit_len: impl Into<Usize<C::N>>,
112 ) -> V
113 where
114 V::Expression: AbstractField,
115 V: Copy + Mul<Output = V::Expression> + Variable<C>,
116 {
117 let result = self.eval(V::Expression::one());
118 let power_f: V = self.eval(x);
119 let bit_len = bit_len.into().materialize(self);
120 let bit_len_plus_one: Var<_> = self.eval(bit_len + C::N::one());
121
122 self.range(1, bit_len_plus_one).for_each(|i, builder| {
123 let index: Var<C::N> = builder.eval(bit_len - i);
124 let bit = builder.get(power_bits, index);
125 builder
126 .if_eq(bit, C::N::one())
127 .then(|builder| builder.assign(result, result * power_f));
128 builder.assign(power_f, power_f * power_f);
129 });
130 result
131 }
132
133 pub fn exp_reverse_bits_len_fast(
135 &mut self,
136 x: Felt<C::F>,
137 power_bits: &Array<C, Var<C::N>>,
138 bit_len: impl Into<Usize<C::N>>,
139 ) -> Felt<C::F> {
140 let mut x_copy_arr: Array<C, Felt<C::F>> = self.dyn_array(1);
142 self.set(&mut x_copy_arr, 0, x);
143
144 let x_copy_arr_ptr = match x_copy_arr {
146 Array::Dyn(ptr, _) => ptr,
147 _ => panic!("Expected a dynamic array"),
148 };
149
150 let bit_len_var = bit_len.into().materialize(self);
152 let ptr = match power_bits {
154 Array::Dyn(ptr, _) => ptr,
155 _ => panic!("Expected a dynamic array"),
156 };
157
158 self.push_op(DslIr::ExpReverseBitsLen(x_copy_arr_ptr, ptr.address, bit_len_var));
161
162 self.get(&x_copy_arr, 0)
164 }
165
166 pub fn exp_power_of_2_v<V>(
168 &mut self,
169 base: impl Into<V::Expression>,
170 power_log: impl Into<Usize<C::N>>,
171 ) -> V
172 where
173 V: Variable<C> + Copy + Mul<Output = V::Expression>,
174 {
175 let mut result: V = self.eval(base);
176 let power_log: Usize<_> = power_log.into();
177 match power_log {
178 Usize::Var(power_log) => {
179 self.range(0, power_log)
180 .for_each(|_, builder| builder.assign(result, result * result));
181 }
182 Usize::Const(power_log) => {
183 for _ in 0..power_log {
184 result = self.eval(result * result);
185 }
186 }
187 }
188 result
189 }
190
191 pub fn exp_power_of_2_v_circuit<V>(
193 &mut self,
194 base: impl Into<V::Expression>,
195 power_log: usize,
196 ) -> V
197 where
198 V: Copy + Mul<Output = V::Expression> + Variable<C>,
199 {
200 let mut result: V = self.eval(base);
201 for _ in 0..power_log {
202 result = self.eval(result * result)
203 }
204 result
205 }
206
207 pub fn sll<V>(&mut self, base: impl Into<V::Expression>, shift: Usize<C::N>) -> V
209 where
210 V: Variable<C> + Copy + Add<Output = V::Expression>,
211 {
212 let result: V = self.eval(base);
213 self.range(0, shift).for_each(|_, builder| builder.assign(result, result + result));
214 result
215 }
216
217 pub fn ext_from_base_slice(&mut self, arr: &[Felt<C::F>]) -> Ext<C::F, C::EF> {
219 assert!(arr.len() <= <C::EF as AbstractExtensionField::<C::F>>::D);
220 let mut res = SymbolicExt::from_f(C::EF::zero());
221 for i in 0..arr.len() {
222 res += arr[i] * SymbolicExt::from_f(C::EF::monomial(i));
223 }
224 self.eval(res)
225 }
226
227 pub fn felts2ext(&mut self, felts: &[Felt<C::F>]) -> Ext<C::F, C::EF> {
228 assert_eq!(felts.len(), 4);
229 let out: Ext<C::F, C::EF> = self.uninit();
230 self.push_op(DslIr::CircuitFelts2Ext(felts.try_into().unwrap(), out));
231 out
232 }
233
234 pub fn ext2felt(&mut self, value: Ext<C::F, C::EF>) -> Array<C, Felt<C::F>> {
236 let result = self.dyn_array(4);
237 self.push_op(DslIr::HintExt2Felt(result.clone(), value));
238
239 let mut reconstructed_ext: Ext<C::F, C::EF> = self.constant(C::EF::zero());
241 for i in 0..4 {
242 let felt = self.get(&result, i);
243 let monomial: Ext<C::F, C::EF> = self.constant(C::EF::monomial(i));
244 reconstructed_ext = self.eval(reconstructed_ext + monomial * felt);
245 }
246
247 self.assert_ext_eq(reconstructed_ext, value);
248
249 result
250 }
251
252 pub fn ext2felt_circuit(&mut self, value: Ext<C::F, C::EF>) -> [Felt<C::F>; 4] {
254 let a = self.uninit();
255 let b = self.uninit();
256 let c = self.uninit();
257 let d = self.uninit();
258 self.push_op(DslIr::CircuitExt2Felt([a, b, c, d], value));
259 [a, b, c, d]
260 }
261}