rsnark_core/
api.rs

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