1use crate::{
10 gates::{CondSelectGate, LogicOrGate, LogicOrOutputGate},
11 BoolVar, Circuit, CircuitError, PlonkCircuit, Variable,
12};
13use ark_ff::PrimeField;
14use ark_std::{boxed::Box, string::ToString};
15
16impl<F: PrimeField> PlonkCircuit<F> {
17 pub fn logic_or_gate(&mut self, a: BoolVar, b: BoolVar) -> Result<(), CircuitError> {
20 self.check_var_bound(a.into())?;
21 self.check_var_bound(b.into())?;
22 let wire_vars = &[a.into(), b.into(), 0, 0, 0];
23 self.insert_gate(wire_vars, Box::new(LogicOrGate))?;
24 Ok(())
25 }
26
27 pub fn is_equal(&mut self, a: Variable, b: Variable) -> Result<BoolVar, CircuitError> {
30 self.check_var_bound(a)?;
31 self.check_var_bound(b)?;
32 let delta = self.sub(a, b)?;
33 self.is_zero(delta)
34 }
35
36 pub fn is_zero(&mut self, a: Variable) -> Result<BoolVar, CircuitError> {
39 self.check_var_bound(a)?;
40
41 let a_val = self.witness(a)?;
44 let (y, a_inv) = if a_val.is_zero() {
45 (F::one(), F::zero())
46 } else {
47 (
48 F::zero(),
49 a_val.inverse().ok_or_else(|| {
50 CircuitError::FieldAlgebraError("Unable to find inverse".to_string())
51 })?,
52 )
53 };
54 let y = self.create_boolean_variable_unchecked(y)?;
55 let a_inv = self.create_variable(a_inv)?;
56
57 self.mul_add_gate(
59 &[a, a_inv, self.one(), y.into(), self.one()],
60 &[F::one(), F::one()],
61 )?;
62 self.mul_gate(y.into(), a, self.zero())?;
64 Ok(y)
65 }
66
67 pub fn non_zero_gate(&mut self, var: Variable) -> Result<(), CircuitError> {
70 let inverse = self.witness(var)?.inverse().unwrap_or_else(F::zero);
71 let inv_var = self.create_variable(inverse)?;
72 let one_var = self.one();
73 self.mul_gate(var, inv_var, one_var)
74 }
75
76 pub fn logic_neg(&mut self, a: BoolVar) -> Result<BoolVar, CircuitError> {
80 self.is_zero(a.into())
81 }
82
83 pub fn logic_and(&mut self, a: BoolVar, b: BoolVar) -> Result<BoolVar, CircuitError> {
87 let c = self
88 .create_boolean_variable_unchecked(self.witness(a.into())? * self.witness(b.into())?)?;
89 self.mul_gate(a.into(), b.into(), c.into())?;
90 Ok(c)
91 }
92
93 pub fn logic_and_all(&mut self, vars: &[BoolVar]) -> Result<BoolVar, CircuitError> {
97 if vars.is_empty() {
98 return Err(CircuitError::ParameterError(
99 "logic_and_all: empty variable list".to_string(),
100 ));
101 }
102 let mut res = vars[0];
103 for &var in vars.iter().skip(1) {
104 res = self.logic_and(res, var)?;
105 }
106 Ok(res)
107 }
108
109 pub fn logic_or(&mut self, a: BoolVar, b: BoolVar) -> Result<BoolVar, CircuitError> {
113 self.check_var_bound(a.into())?;
114 self.check_var_bound(b.into())?;
115
116 let a_val = self.witness(a.into())?;
117 let b_val = self.witness(b.into())?;
118 let c_val = a_val + b_val - a_val * b_val;
119
120 let c = self.create_boolean_variable_unchecked(c_val)?;
121 let wire_vars = &[a.into(), b.into(), 0, 0, c.into()];
122 self.insert_gate(wire_vars, Box::new(LogicOrOutputGate))?;
123
124 Ok(c)
125 }
126
127 pub fn enforce_true(&mut self, a: Variable) -> Result<(), CircuitError> {
130 self.enforce_constant(a, F::one())
131 }
132
133 pub fn enforce_false(&mut self, a: Variable) -> Result<(), CircuitError> {
136 self.enforce_constant(a, F::zero())
137 }
138
139 pub fn conditional_select(
142 &mut self,
143 b: BoolVar,
144 x_0: Variable,
145 x_1: Variable,
146 ) -> Result<Variable, CircuitError> {
147 self.check_var_bound(b.into())?;
148 self.check_var_bound(x_0)?;
149 self.check_var_bound(x_1)?;
150
151 let y = if self.witness(b.into())? == F::zero() {
153 self.create_variable(self.witness(x_0)?)?
154 } else if self.witness(b.into())? == F::one() {
155 self.create_variable(self.witness(x_1)?)?
156 } else {
157 return Err(CircuitError::ParameterError(
158 "b in Conditional Selection gate is not a boolean variable".to_string(),
159 ));
160 };
161 let wire_vars = [b.into(), x_0, b.into(), x_1, y];
162 self.insert_gate(&wire_vars, Box::new(CondSelectGate))?;
163 Ok(y)
164 }
165}
166
167#[cfg(test)]
168mod test {
169 use crate::{
170 gadgets::test_utils::test_variable_independence_for_circuit, Circuit, CircuitError,
171 PlonkCircuit,
172 };
173 use ark_bls12_377::Fq as Fq377;
174 use ark_ed_on_bls12_377::Fq as FqEd377;
175 use ark_ed_on_bls12_381::Fq as FqEd381;
176 use ark_ed_on_bn254::Fq as FqEd254;
177 use ark_ff::PrimeField;
178
179 #[test]
180 fn test_logic_or() -> Result<(), CircuitError> {
181 test_logic_or_helper::<FqEd254>()?;
182 test_logic_or_helper::<FqEd377>()?;
183 test_logic_or_helper::<FqEd381>()?;
184 test_logic_or_helper::<Fq377>()
185 }
186
187 fn test_logic_or_helper<F: PrimeField>() -> Result<(), CircuitError> {
188 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
189 let false_var = circuit.false_var();
190 let true_var = circuit.true_var();
191 let should_be_true = circuit.logic_or(false_var, true_var)?;
193 assert!(circuit.witness(should_be_true.into())?.eq(&F::one()));
194 let should_be_true = circuit.logic_or(true_var, false_var)?;
195 assert!(circuit.witness(should_be_true.into())?.eq(&F::one()));
196 let should_be_true = circuit.logic_or(true_var, true_var)?;
197 assert!(circuit.witness(should_be_true.into())?.eq(&F::one()));
198 let should_be_false = circuit.logic_or(false_var, false_var)?;
200 assert!(circuit.witness(should_be_false.into())?.eq(&F::zero()));
201 assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
202
203 Ok(())
204 }
205 #[test]
206 fn test_logic_or_gate() -> Result<(), CircuitError> {
207 test_logic_or_gate_helper::<FqEd254>()?;
208 test_logic_or_gate_helper::<FqEd377>()?;
209 test_logic_or_gate_helper::<FqEd381>()?;
210 test_logic_or_gate_helper::<Fq377>()
211 }
212
213 fn test_logic_or_gate_helper<F: PrimeField>() -> Result<(), CircuitError> {
214 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
215 let false_var = circuit.false_var();
216 let true_var = circuit.true_var();
217 circuit.logic_or_gate(false_var, true_var)?;
219 circuit.logic_or_gate(true_var, false_var)?;
220 circuit.logic_or_gate(true_var, true_var)?;
221 assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
222 circuit.logic_or_gate(false_var, false_var)?;
224 assert!(circuit.check_circuit_satisfiability(&[]).is_err());
225
226 let circuit_1 = build_logic_or_circuit(true, true)?;
227 let circuit_2 = build_logic_or_circuit(false, true)?;
228 test_variable_independence_for_circuit::<F>(circuit_1, circuit_2)?;
229
230 Ok(())
231 }
232
233 fn build_logic_or_circuit<F: PrimeField>(
234 a: bool,
235 b: bool,
236 ) -> Result<PlonkCircuit<F>, CircuitError> {
237 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
238 let a = circuit.create_boolean_variable(a)?;
239 let b = circuit.create_boolean_variable(b)?;
240 circuit.logic_or_gate(a, b)?;
241 circuit.finalize_for_arithmetization()?;
242 Ok(circuit)
243 }
244
245 #[test]
246 fn test_logic_and() -> Result<(), CircuitError> {
247 test_logic_and_helper::<FqEd254>()?;
248 test_logic_and_helper::<FqEd377>()?;
249 test_logic_and_helper::<FqEd381>()?;
250 test_logic_and_helper::<Fq377>()
251 }
252
253 fn test_logic_and_helper<F: PrimeField>() -> Result<(), CircuitError> {
254 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
255 let false_var = circuit.false_var();
256 let true_var = circuit.true_var();
257 let a = circuit.logic_and(false_var, true_var)?;
259 assert_eq!(F::zero(), circuit.witness(a.into())?);
260 let b = circuit.logic_and(true_var, false_var)?;
261 assert_eq!(F::zero(), circuit.witness(b.into())?);
262 let c = circuit.logic_and(true_var, true_var)?;
263 assert_eq!(F::one(), circuit.witness(c.into())?);
264 let d = circuit.logic_and_all(&[false_var, true_var, true_var])?;
265 assert_eq!(F::zero(), circuit.witness(d.into())?);
266 let e = circuit.logic_and_all(&[true_var, true_var, true_var])?;
267 assert_eq!(F::one(), circuit.witness(e.into())?);
268 assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
269 *circuit.witness_mut(e.into()) = F::zero();
271 assert!(circuit.check_circuit_satisfiability(&[]).is_err());
272 *circuit.witness_mut(e.into()) = F::one();
273 assert!(circuit.logic_and_all(&[]).is_err());
274
275 let circuit_1 = build_logic_and_circuit(true, true)?;
276 let circuit_2 = build_logic_and_circuit(false, true)?;
277 test_variable_independence_for_circuit::<F>(circuit_1, circuit_2)?;
278
279 Ok(())
280 }
281
282 fn build_logic_and_circuit<F: PrimeField>(
283 a: bool,
284 b: bool,
285 ) -> Result<PlonkCircuit<F>, CircuitError> {
286 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
287 let a = circuit.create_boolean_variable(a)?;
288 let b = circuit.create_boolean_variable(b)?;
289 circuit.logic_and(a, b)?;
290 circuit.finalize_for_arithmetization()?;
291 Ok(circuit)
292 }
293
294 #[test]
295 fn test_is_equal() -> Result<(), CircuitError> {
296 test_is_equal_helper::<FqEd254>()?;
297 test_is_equal_helper::<FqEd377>()?;
298 test_is_equal_helper::<FqEd381>()?;
299 test_is_equal_helper::<Fq377>()
300 }
301 fn test_is_equal_helper<F: PrimeField>() -> Result<(), CircuitError> {
302 let mut circuit = PlonkCircuit::<F>::new_turbo_plonk();
303 let val = F::from(31415u32);
304 let a = circuit.create_variable(val)?;
305 let b = circuit.create_variable(val)?;
306 let a_b_eq = circuit.is_equal(a, b)?;
307 let a_zero_eq = circuit.is_equal(a, circuit.zero())?;
308
309 assert_eq!(circuit.witness(a_b_eq.into())?, F::one());
311 assert_eq!(circuit.witness(a_zero_eq.into())?, F::zero());
312 assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
313 *circuit.witness_mut(b) = val + F::one();
314 assert!(circuit.check_circuit_satisfiability(&[]).is_err());
315 assert!(circuit.is_equal(circuit.num_vars(), a).is_err());
317
318 let circuit_1 = build_is_equal_circuit(F::one(), F::one())?;
319 let circuit_2 = build_is_equal_circuit(F::zero(), F::one())?;
320 test_variable_independence_for_circuit(circuit_1, circuit_2)?;
321
322 Ok(())
323 }
324
325 fn build_is_equal_circuit<F: PrimeField>(a: F, b: F) -> Result<PlonkCircuit<F>, CircuitError> {
326 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
327 let a = circuit.create_variable(a)?;
328 let b = circuit.create_variable(b)?;
329 circuit.is_equal(a, b)?;
330 circuit.finalize_for_arithmetization()?;
331 Ok(circuit)
332 }
333
334 #[test]
335 fn test_check_is_zero() -> Result<(), CircuitError> {
336 test_check_is_zero_helper::<FqEd254>()?;
337 test_check_is_zero_helper::<FqEd377>()?;
338 test_check_is_zero_helper::<FqEd381>()?;
339 test_check_is_zero_helper::<Fq377>()
340 }
341 fn test_check_is_zero_helper<F: PrimeField>() -> Result<(), CircuitError> {
342 let mut circuit = PlonkCircuit::<F>::new_turbo_plonk();
343 let val = F::from(31415u32);
344 let a = circuit.create_variable(val)?;
345 let a_zero_eq = circuit.is_zero(a)?;
346 let zero_zero_eq = circuit.is_zero(circuit.zero())?;
347
348 assert_eq!(circuit.witness(a_zero_eq.into())?, F::zero());
350 assert_eq!(circuit.witness(zero_zero_eq.into())?, F::one());
351 assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
352 *circuit.witness_mut(zero_zero_eq.into()) = F::zero();
353 assert!(circuit.check_circuit_satisfiability(&[]).is_err());
354 *circuit.witness_mut(zero_zero_eq.into()) = F::one();
355 *circuit.witness_mut(a) = F::zero();
356 assert!(circuit.check_circuit_satisfiability(&[]).is_err());
357 assert!(circuit.is_zero(circuit.num_vars()).is_err());
359
360 let circuit_1 = build_check_is_zero_circuit(F::one())?;
361 let circuit_2 = build_check_is_zero_circuit(F::zero())?;
362 test_variable_independence_for_circuit(circuit_1, circuit_2)?;
363
364 Ok(())
365 }
366
367 fn build_check_is_zero_circuit<F: PrimeField>(a: F) -> Result<PlonkCircuit<F>, CircuitError> {
368 let mut circuit = PlonkCircuit::new_turbo_plonk();
369 let a = circuit.create_variable(a)?;
370 circuit.is_zero(a)?;
371 circuit.finalize_for_arithmetization()?;
372 Ok(circuit)
373 }
374
375 #[test]
376 fn test_conditional_select() -> Result<(), CircuitError> {
377 test_conditional_select_helper::<FqEd254>()?;
378 test_conditional_select_helper::<FqEd377>()?;
379 test_conditional_select_helper::<FqEd381>()?;
380 test_conditional_select_helper::<Fq377>()
381 }
382
383 fn test_conditional_select_helper<F: PrimeField>() -> Result<(), CircuitError> {
384 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
385 let bit_true = circuit.true_var();
386 let bit_false = circuit.false_var();
387
388 let x_0 = circuit.create_variable(F::from(23u32))?;
389 let x_1 = circuit.create_variable(F::from(24u32))?;
390 let select_true = circuit.conditional_select(bit_true, x_0, x_1)?;
391 let select_false = circuit.conditional_select(bit_false, x_0, x_1)?;
392
393 assert_eq!(circuit.witness(select_true)?, circuit.witness(x_1)?);
394 assert_eq!(circuit.witness(select_false)?, circuit.witness(x_0)?);
395 assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
396
397 *circuit.witness_mut(bit_false.into()) = F::one();
399 assert!(circuit.check_circuit_satisfiability(&[]).is_err());
400 assert!(circuit
402 .conditional_select(bit_false, circuit.num_vars(), x_1)
403 .is_err());
404
405 let circuit_1 = build_conditional_select_circuit(true, F::from(23u32), F::from(24u32))?;
409 let circuit_2 = build_conditional_select_circuit(false, F::from(99u32), F::from(98u32))?;
410 test_variable_independence_for_circuit(circuit_1, circuit_2)?;
411 Ok(())
412 }
413
414 fn build_conditional_select_circuit<F: PrimeField>(
415 bit: bool,
416 x_0: F,
417 x_1: F,
418 ) -> Result<PlonkCircuit<F>, CircuitError> {
419 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
420 let bit_var = circuit.create_boolean_variable(bit)?;
421 let x_0_var = circuit.create_variable(x_0)?;
422 let x_1_var = circuit.create_variable(x_1)?;
423 circuit.conditional_select(bit_var, x_0_var, x_1_var)?;
424 circuit.finalize_for_arithmetization()?;
425 Ok(circuit)
426 }
427
428 #[test]
429 fn test_non_zero_gate() -> Result<(), CircuitError> {
430 test_non_zero_gate_helper::<FqEd254>()?;
431 test_non_zero_gate_helper::<FqEd377>()?;
432 test_non_zero_gate_helper::<FqEd381>()?;
433 test_non_zero_gate_helper::<Fq377>()
434 }
435 fn test_non_zero_gate_helper<F: PrimeField>() -> Result<(), CircuitError> {
436 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
438 let non_zero_var = circuit.create_variable(F::from(2_u32))?;
439 let _ = circuit.non_zero_gate(non_zero_var);
440 assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
441
442 let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
443 let zero_var = circuit.create_variable(F::from(0_u32))?;
444 let _ = circuit.non_zero_gate(zero_var);
445 assert!(circuit.check_circuit_satisfiability(&[]).is_err());
446
447 Ok(())
448 }
449}