/ algorithms / src / snark / varuna / data_structures / test_circuit.rs
test_circuit.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use crate::r1cs::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
 17  use deltavm_fields::Field;
 18  
 19  use rand::{CryptoRng, Rng};
 20  
 21  #[doc(hidden)]
 22  #[derive(Clone)]
 23  /// This Circuit is only for testing and should not be used in production
 24  pub struct TestCircuit<F: Field> {
 25      pub a: Option<F>,
 26      pub b: Option<F>,
 27      pub num_constraints: usize,
 28      pub num_variables: usize,
 29      pub mul_depth: usize,
 30  }
 31  
 32  impl<F: Field> core::fmt::Debug for TestCircuit<F> {
 33      fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 34          write!(
 35              f,
 36              "TestCircuit {{ num_constraints: {}, num_variables: {}, mul_depth: {} }}",
 37              self.num_constraints, self.num_variables, self.mul_depth
 38          )
 39      }
 40  }
 41  
 42  impl<ConstraintF: Field> ConstraintSynthesizer<ConstraintF> for TestCircuit<ConstraintF> {
 43      fn generate_constraints<CS: ConstraintSystem<ConstraintF>>(&self, cs: &mut CS) -> Result<(), SynthesisError> {
 44          // Ensure the given `cs` is starting off clean.
 45          assert_eq!(1, cs.num_public_variables());
 46          assert_eq!(0, cs.num_private_variables());
 47          assert_eq!(0, cs.num_constraints());
 48  
 49          let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?;
 50          let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?;
 51  
 52          let mut mul_vars = Vec::with_capacity(self.mul_depth);
 53          for i in 0..self.mul_depth {
 54              let mul_var = cs.alloc_input(
 55                  || format!("mul_var {i}"),
 56                  || {
 57                      let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
 58                      let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
 59  
 60                      for _ in 0..(1 + i) {
 61                          a.mul_assign(&b);
 62                      }
 63                      Ok(a)
 64                  },
 65              )?;
 66              mul_vars.push(mul_var);
 67          }
 68  
 69          // For this test we should allocate self.num_variables number of variables
 70          // 2 + mul_depth variables were already allocated above, 1 is allocated by
 71          // default
 72          let dummy_variables = self.num_variables - 3 - self.mul_depth;
 73          for i in 0..dummy_variables {
 74              let _ = cs.alloc(|| format!("var {i}"), || self.a.ok_or(SynthesisError::AssignmentMissing))?;
 75          }
 76  
 77          let mul_constraints = self.mul_depth - 1;
 78          for i in 0..(self.num_constraints - mul_constraints) {
 79              cs.enforce(|| format!("constraint {i}"), |lc| lc + a, |lc| lc + b, |lc| lc + mul_vars[0]);
 80          }
 81  
 82          for i in 0..mul_constraints {
 83              cs.enforce(|| format!("constraint_mul {i}"), |lc| lc + mul_vars[i], |lc| lc + b, |lc| lc + mul_vars[i + 1]);
 84          }
 85  
 86          assert_eq!(cs.num_constraints(), self.num_constraints);
 87          assert_eq!(cs.num_public_variables() + cs.num_private_variables(), self.num_variables);
 88  
 89          Ok(())
 90      }
 91  }
 92  
 93  impl<F: Field> TestCircuit<F> {
 94      // Generate a test circuit with a random witness.
 95      pub fn gen_rand<R: Rng + CryptoRng>(
 96          mul_depth: usize,
 97          num_constraints: usize,
 98          num_variables: usize,
 99          rng: &mut R,
100      ) -> (Self, Vec<F>) {
101          let mut public_inputs: Vec<F> = Vec::with_capacity(1 + mul_depth);
102          public_inputs.push(F::one());
103  
104          let a = F::rand(rng);
105          let b = F::rand(rng);
106  
107          for j in 1..(mul_depth + 1) {
108              let mut new_var = a;
109              for _ in 0..j {
110                  new_var.mul_assign(&b);
111              }
112              public_inputs.push(new_var);
113          }
114  
115          (TestCircuit { a: Some(a), b: Some(b), num_constraints, num_variables, mul_depth }, public_inputs)
116      }
117  
118      // Generate a test circuit with a fixed witness.
119      pub fn generate_circuit_with_fixed_witness(
120          a: u128,
121          b: u128,
122          mul_depth: usize,
123          num_constraints: usize,
124          num_variables: usize,
125      ) -> (Self, Vec<F>) {
126          let mut public_inputs: Vec<F> = Vec::with_capacity(1 + mul_depth);
127          public_inputs.push(F::one());
128          let a = F::from(a);
129          let b = F::from(b);
130          for j in 1..(mul_depth + 1) {
131              let mut new_var = a;
132              for _ in 0..j {
133                  new_var.mul_assign(&b);
134              }
135              public_inputs.push(new_var);
136          }
137  
138          (TestCircuit { a: Some(a), b: Some(b), num_constraints, num_variables, mul_depth }, public_inputs)
139      }
140  }