Skip to main content

sp1_recursion_compiler/ir/
utils.rs

1use slop_algebra::{AbstractExtensionField, AbstractField};
2use sp1_primitives::{SP1ExtensionField, SP1Field};
3use std::ops::{Mul, MulAssign};
4
5use super::{Builder, Config, DslIr, Ext, Felt, SymbolicExt, Var, Variable};
6
7impl<C: Config> Builder<C> {
8    /// The generator for the field.
9    ///
10    /// Reference: [p3_koala_bear::KoalaBear]
11    pub fn generator(&mut self) -> Felt<SP1Field> {
12        self.eval(SP1Field::generator())
13    }
14
15    /// Select a variable based on a condition.
16    pub fn select_v(&mut self, cond: Var<C::N>, a: Var<C::N>, b: Var<C::N>) -> Var<C::N> {
17        let c = self.uninit();
18        self.push_op(DslIr::CircuitSelectV(cond, a, b, c));
19        c
20    }
21
22    /// Select a felt based on a condition.
23    pub fn select_f(
24        &mut self,
25        cond: Var<C::N>,
26        a: Felt<SP1Field>,
27        b: Felt<SP1Field>,
28    ) -> Felt<SP1Field> {
29        let c = self.uninit();
30        self.push_op(DslIr::CircuitSelectF(cond, a, b, c));
31        c
32    }
33
34    /// Select an extension based on a condition.
35    pub fn select_ef(
36        &mut self,
37        cond: Var<C::N>,
38        a: Ext<SP1Field, SP1ExtensionField>,
39        b: Ext<SP1Field, SP1ExtensionField>,
40    ) -> Ext<SP1Field, SP1ExtensionField> {
41        let c = self.uninit();
42        self.push_op(DslIr::CircuitSelectE(cond, a, b, c));
43        c
44    }
45
46    /// Exponentiates a variable to a power of two.
47    pub fn exp_power_of_2<V: Variable<C>, E: Into<V::Expression>>(
48        &mut self,
49        e: E,
50        power_log: usize,
51    ) -> V
52    where
53        V::Expression: MulAssign<V::Expression> + Clone,
54    {
55        let mut e = e.into();
56        for _ in 0..power_log {
57            e *= e.clone();
58        }
59        self.eval(e)
60    }
61
62    /// Exponentiates a felt to a list of bits in little endian.
63    pub fn exp_f_bits(&mut self, x: Felt<SP1Field>, power_bits: Vec<Var<C::N>>) -> Felt<SP1Field> {
64        let mut result = self.eval(SP1Field::one());
65        let mut power_f: Felt<_> = self.eval(x);
66        for i in 0..power_bits.len() {
67            let bit = power_bits[i];
68            let tmp = self.eval(result * power_f);
69            result = self.select_f(bit, tmp, result);
70            power_f = self.eval(power_f * power_f);
71        }
72        result
73    }
74
75    /// Exponentiates a extension to a list of bits in little endian.
76    pub fn exp_e_bits(
77        &mut self,
78        x: Ext<SP1Field, SP1ExtensionField>,
79        power_bits: Vec<Var<C::N>>,
80    ) -> Ext<SP1Field, SP1ExtensionField> {
81        let mut result = self.eval(SymbolicExt::from_f(SP1ExtensionField::one()));
82        let mut power_f: Ext<_, _> = self.eval(x);
83        for i in 0..power_bits.len() {
84            let bit = power_bits[i];
85            let tmp = self.eval(result * power_f);
86            result = self.select_ef(bit, tmp, result);
87            power_f = self.eval(power_f * power_f);
88        }
89        result
90    }
91
92    /// Exponentiates a variable to a list of bits in little endian inside a circuit.
93    pub fn exp_power_of_2_v_circuit<V>(
94        &mut self,
95        base: impl Into<V::Expression>,
96        power_log: usize,
97    ) -> V
98    where
99        V: Copy + Mul<Output = V::Expression> + Variable<C>,
100    {
101        let mut result: V = self.eval(base);
102        for _ in 0..power_log {
103            result = self.eval(result * result)
104        }
105        result
106    }
107
108    /// Creates an ext from a slice of felts.
109    pub fn ext_from_base_slice(
110        &mut self,
111        arr: &[Felt<SP1Field>],
112    ) -> Ext<SP1Field, SP1ExtensionField> {
113        assert!(arr.len() <= <SP1ExtensionField as AbstractExtensionField<SP1Field>>::D);
114        let mut res = SymbolicExt::from_f(SP1ExtensionField::zero());
115        for i in 0..arr.len() {
116            res += arr[i]
117                * SymbolicExt::from_f(
118                    <SP1ExtensionField as AbstractExtensionField<SP1Field>>::monomial(i),
119                );
120        }
121        self.eval(res)
122    }
123
124    pub fn felts2ext(&mut self, felts: &[Felt<SP1Field>]) -> Ext<SP1Field, SP1ExtensionField> {
125        assert_eq!(felts.len(), 4);
126        let out: Ext<SP1Field, SP1ExtensionField> = self.uninit();
127        self.push_op(DslIr::CircuitFelts2Ext(felts.try_into().unwrap(), out));
128        out
129    }
130
131    /// Converts an ext to a slice of felts inside a circuit.
132    pub fn ext2felt_circuit(
133        &mut self,
134        value: Ext<SP1Field, SP1ExtensionField>,
135    ) -> [Felt<SP1Field>; 4] {
136        let a = self.uninit();
137        let b = self.uninit();
138        let c = self.uninit();
139        let d = self.uninit();
140        self.push_op(DslIr::CircuitExt2Felt([a, b, c, d], value));
141        [a, b, c, d]
142    }
143}