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}