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}