rsnark_core/
api.rs

1use crate::{Variable, variable::CircuitVariable};
2
3/// The main API trait for building arithmetic circuits in zero-knowledge proof systems.
4///
5/// This trait provides a comprehensive set of operations for constructing arithmetic circuits,
6/// including basic arithmetic operations, logical operations, assertions, and utility functions.
7/// All operations work with variables that implement the `Variable` trait, enabling flexible
8/// circuit construction with different variable types.
9pub trait API {
10    /// Performs addition of two variables: res = x1 + x2
11    ///
12    /// This is a convenience method that calls `add_multi` with no additional variables.
13    ///
14    /// # Arguments
15    /// * `x1` - First operand
16    /// * `x2` - Second operand
17    ///
18    /// # Returns
19    /// A new local variable containing the sum
20    fn add(&mut self, x1: &impl Variable, x2: &impl Variable) -> CircuitVariable {
21        self.add_multi(x1, x2, &[])
22    }
23
24    /// Performs addition of multiple variables: res = x1 + x2 + ... + xn
25    ///
26    /// # Arguments
27    /// * `x1` - First operand
28    /// * `x2` - Second operand  
29    /// * `xn` - Additional operands to sum
30    ///
31    /// # Returns
32    /// A new local variable containing the sum of all operands
33    fn add_multi(
34        &mut self,
35        x1: &impl Variable,
36        x2: &impl Variable,
37        xn: &[&dyn Variable],
38    ) -> CircuitVariable;
39
40    /// Performs multiply-accumulate operation: res = a + (b * c)
41    ///
42    /// This is an optimized operation that combines multiplication and addition
43    /// in a single constraint, which can be more efficient than separate operations.
44    ///
45    /// # Arguments
46    /// * `a` - The accumulator value
47    /// * `b` - First multiplicand
48    /// * `c` - Second multiplicand
49    ///
50    /// # Returns
51    /// A new local variable containing the result a + (b * c)
52    fn mul_acc(
53        &mut self,
54        a: &impl Variable,
55        b: &impl Variable,
56        c: &impl Variable,
57    ) -> CircuitVariable;
58
59    /// Performs negation: res = -x
60    ///
61    /// # Arguments
62    /// * `x` - The variable to negate
63    ///
64    /// # Returns
65    /// A new local variable containing the negated value
66    fn neg(&mut self, x: &impl Variable) -> CircuitVariable;
67
68    /// Performs subtraction of two variables: res = x1 - x2
69    ///
70    /// This is a convenience method that calls `sub_multi` with no additional variables.
71    ///
72    /// # Arguments
73    /// * `x1` - Minuend (value to subtract from)
74    /// * `x2` - Subtrahend (value to subtract)
75    ///
76    /// # Returns
77    /// A new local variable containing the difference
78    fn sub(&mut self, x1: &impl Variable, x2: &impl Variable) -> CircuitVariable {
79        self.sub_multi(x1, x2, &[])
80    }
81
82    /// Performs subtraction of multiple variables: res = x1 - x2 - ... - xn
83    ///
84    /// # Arguments
85    /// * `x1` - Minuend (value to subtract from)
86    /// * `x2` - First subtrahend
87    /// * `xn` - Additional values to subtract
88    ///
89    /// # Returns
90    /// A new local variable containing the result of all subtractions
91    fn sub_multi(
92        &mut self,
93        x1: &impl Variable,
94        x2: &impl Variable,
95        xn: &[&dyn Variable],
96    ) -> CircuitVariable;
97
98    /// Performs multiplication of two variables: res = x1 * x2
99    ///
100    /// This is a convenience method that calls `mul_multi` with no additional variables.
101    ///
102    /// # Arguments
103    /// * `x1` - First multiplicand
104    /// * `x2` - Second multiplicand
105    ///
106    /// # Returns
107    /// A new local variable containing the product
108    fn mul(&mut self, x1: &impl Variable, x2: &impl Variable) -> CircuitVariable {
109        self.mul_multi(x1, x2, &[])
110    }
111
112    /// Performs multiplication of multiple variables: res = x1 * x2 * ... * xn
113    ///
114    /// # Arguments
115    /// * `x1` - First multiplicand
116    /// * `x2` - Second multiplicand
117    /// * `xn` - Additional multiplicands
118    ///
119    /// # Returns
120    /// A new local variable containing the product of all operands
121    fn mul_multi(
122        &mut self,
123        x1: &impl Variable,
124        x2: &impl Variable,
125        xn: &[&dyn Variable],
126    ) -> CircuitVariable;
127
128    /// Performs unchecked division: res = x1 / x2
129    ///
130    /// This division operation does not enforce that the divisor is non-zero.
131    /// If both x1 and x2 are zero, the result is defined as 0.
132    ///
133    /// # Arguments
134    /// * `x1` - Dividend
135    /// * `x2` - Divisor
136    ///
137    /// # Returns
138    /// A new local variable containing the quotient
139    ///
140    /// # Safety
141    /// This operation does not verify that x2 ≠ 0. Use `div` for checked division.
142    fn div_unchecked(&mut self, x1: &impl Variable, x2: &impl Variable) -> CircuitVariable;
143
144    /// Performs checked division: res = x1 / x2
145    ///
146    /// This division operation enforces that the divisor is non-zero.
147    /// The circuit constraint will fail if x2 equals zero.
148    ///
149    /// # Arguments
150    /// * `x1` - Dividend
151    /// * `x2` - Divisor (must be non-zero)
152    ///
153    /// # Returns
154    /// A new local variable containing the quotient
155    ///
156    /// # Panics
157    /// The circuit will be unsatisfiable if x2 == 0
158    fn div(&mut self, x1: &impl Variable, x2: &impl Variable) -> CircuitVariable;
159
160    /// Computes the multiplicative inverse: res = 1 / x
161    ///
162    /// This operation enforces that x is non-zero. The circuit constraint
163    /// will fail if x equals zero.
164    ///
165    /// # Arguments
166    /// * `x` - The variable to invert (must be non-zero)
167    ///
168    /// # Returns
169    /// A new local variable containing the multiplicative inverse
170    ///
171    /// # Panics
172    /// The circuit will be unsatisfiable if x == 0
173    fn inverse(&mut self, x: &impl Variable) -> CircuitVariable;
174
175    /// Converts a variable to its binary representation
176    ///
177    /// Decomposes the input variable into its constituent bits, returning
178    /// them as a vector of boolean variables.
179    ///
180    /// # Arguments
181    /// * `x` - The variable to decompose
182    /// * `n` - Number of bits to extract (starting from least significant bit)
183    ///
184    /// # Returns
185    /// A vector of local variables representing the binary decomposition,
186    /// where index 0 is the least significant bit
187    fn variable_to_binary(&mut self, x: &impl Variable, n: u64) -> Vec<CircuitVariable>;
188
189    /// Reconstructs a variable from its binary representation
190    ///
191    /// Combines a vector of bit variables into a single field element,
192    /// with the first element being the least significant bit.
193    ///
194    /// # Arguments
195    /// * `b` - Array of bit variables (each should be 0 or 1)
196    ///
197    /// # Returns
198    /// A local variable representing the packed binary value
199    fn variable_from_binary(&mut self, b: &[&dyn Variable]) -> CircuitVariable;
200
201    /// Performs bitwise XOR operation: res = x1 ^ x2
202    ///
203    /// # Arguments
204    /// * `x1` - First operand
205    /// * `x2` - Second operand
206    ///
207    /// # Returns
208    /// A new local variable containing the XOR result
209    fn xor(&mut self, x1: &impl Variable, x2: &impl Variable) -> CircuitVariable;
210
211    /// Performs bitwise OR operation: res = x1 | x2
212    ///
213    /// # Arguments
214    /// * `x1` - First operand
215    /// * `x2` - Second operand
216    ///
217    /// # Returns
218    /// A new local variable containing the OR result
219    fn or(&mut self, x1: &impl Variable, x2: &impl Variable) -> CircuitVariable;
220
221    /// Performs bitwise AND operation: res = x1 & x2
222    ///
223    /// # Arguments
224    /// * `x1` - First operand
225    /// * `x2` - Second operand
226    ///
227    /// # Returns
228    /// A new local variable containing the AND result
229    fn and(&mut self, x1: &impl Variable, x2: &impl Variable) -> CircuitVariable;
230
231    /// Performs conditional selection: res = x1 ? x2 : x3
232    ///
233    /// If x1 is non-zero (true), returns x2; otherwise returns x3.
234    /// This is equivalent to a ternary operator in programming languages.
235    ///
236    /// # Arguments
237    /// * `x1` - Condition variable (typically 0 or 1)
238    /// * `x2` - Value to return if condition is true
239    /// * `x3` - Value to return if condition is false
240    ///
241    /// # Returns
242    /// A new local variable containing the selected value
243    fn select(
244        &mut self,
245        x1: &impl Variable,
246        x2: &impl Variable,
247        x3: &impl Variable,
248    ) -> CircuitVariable;
249
250    /// Performs a 2-bit lookup table operation
251    ///
252    /// Selects one of four values (y1, y2, y3, y4) based on a 2-bit index
253    /// formed by concatenating bits b1 and b0 (b1 is MSB, b0 is LSB).
254    ///
255    /// # Arguments
256    /// * `b0` - Least significant bit of the index
257    /// * `b1` - Most significant bit of the index
258    /// * `y1` - Value for index 00 (b1=0, b0=0)
259    /// * `y2` - Value for index 01 (b1=0, b0=1)
260    /// * `y3` - Value for index 10 (b1=1, b0=0)
261    /// * `y4` - Value for index 11 (b1=1, b0=1)
262    ///
263    /// # Returns
264    /// The selected value based on the 2-bit index
265    fn lookup2(
266        &mut self,
267        b0: &impl Variable,
268        b1: &impl Variable,
269        y1: &impl Variable,
270        y2: &impl Variable,
271        y3: &impl Variable,
272        y4: &impl Variable,
273    ) -> CircuitVariable;
274
275    /// Tests if a variable is zero
276    ///
277    /// Returns 1 if the input variable equals zero, 0 otherwise.
278    /// This is useful for implementing conditional logic based on zero checks.
279    ///
280    /// # Arguments
281    /// * `x` - The variable to test
282    ///
283    /// # Returns
284    /// A boolean variable (1 if x == 0, 0 if x != 0)
285    fn is_zero(&mut self, x: &impl Variable) -> CircuitVariable;
286
287    /// Compares two variables and returns the comparison result
288    ///
289    /// Returns a three-way comparison result:
290    /// * 1 if x1 > x2
291    /// * 0 if x1 = x2  
292    /// * -1 if x1 < x2
293    ///
294    /// # Arguments
295    /// * `x1` - First value to compare
296    /// * `x2` - Second value to compare
297    ///
298    /// # Returns
299    /// A local variable containing the comparison result (-1, 0, or 1)
300    fn cmp(&mut self, x1: &impl Variable, x2: &impl Variable) -> CircuitVariable;
301
302    /// Asserts that two variables are equal
303    ///
304    /// Adds a constraint requiring x1 == x2. The circuit will be
305    /// unsatisfiable if this condition is not met.
306    ///
307    /// # Arguments
308    /// * `x1` - First variable
309    /// * `x2` - Second variable
310    ///
311    /// # Panics
312    /// The circuit will be unsatisfiable if x1 != x2
313    fn assert_is_equal(&mut self, x1: &impl Variable, x2: &impl Variable);
314
315    /// Asserts that two variables are different
316    ///
317    /// Adds a constraint requiring x1 != x2. The circuit will be
318    /// unsatisfiable if this condition is not met.
319    ///
320    /// # Arguments
321    /// * `x1` - First variable
322    /// * `x2` - Second variable
323    ///
324    /// # Panics
325    /// The circuit will be unsatisfiable if x1 == x2
326    fn assert_is_different(&mut self, x1: &impl Variable, x2: &impl Variable);
327
328    /// Asserts that a variable is a boolean value
329    ///
330    /// Adds a constraint requiring x to be either 0 or 1.
331    /// The circuit will be unsatisfiable if x has any other value.
332    ///
333    /// # Arguments
334    /// * `x` - The variable to constrain as boolean
335    ///
336    /// # Panics
337    /// The circuit will be unsatisfiable if x is not 0 or 1
338    fn assert_is_boolean(&mut self, x: &impl Variable);
339
340    /// Asserts that a variable is a crumb (2-bit value)
341    ///
342    /// Adds a constraint requiring x to be one of {0, 1, 2, 3}.
343    /// The circuit will be unsatisfiable if x has any other value.
344    ///
345    /// # Arguments
346    /// * `x` - The variable to constrain as a crumb
347    ///
348    /// # Panics
349    /// The circuit will be unsatisfiable if x is not in {0, 1, 2, 3}
350    fn assert_is_crumb(&mut self, x: &impl Variable);
351
352    /// Asserts that a variable is less than or equal to a bound
353    ///
354    /// Adds a constraint requiring v <= bound. The circuit will be
355    /// unsatisfiable if this condition is not met.
356    ///
357    /// # Arguments
358    /// * `v` - The variable to check
359    /// * `bound` - The upper bound
360    ///
361    /// # Panics
362    /// The circuit will be unsatisfiable if v > bound
363    fn assert_is_less_or_equal(&mut self, v: &impl Variable, bound: &impl Variable);
364
365    /// Prints a debug message during circuit execution
366    ///
367    /// This is primarily useful for debugging circuits. The actual
368    /// implementation depends on the backend prover system.
369    ///
370    /// # Arguments
371    /// * `message` - The variable value to print
372    fn println(&mut self, message: &impl Variable);
373}