/ algorithms / src / snark / varuna / data_structures / test_circuit.rs
test_circuit.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use crate::r1cs::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
 20  use alphavm_fields::Field;
 21  
 22  use rand::{CryptoRng, Rng};
 23  
 24  #[doc(hidden)]
 25  #[derive(Clone)]
 26  /// This Circuit is only for testing and should not be used in production
 27  pub struct TestCircuit<F: Field> {
 28      pub a: Option<F>,
 29      pub b: Option<F>,
 30      pub num_constraints: usize,
 31      pub num_variables: usize,
 32      pub mul_depth: usize,
 33  }
 34  
 35  impl<F: Field> core::fmt::Debug for TestCircuit<F> {
 36      fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 37          write!(
 38              f,
 39              "TestCircuit {{ num_constraints: {}, num_variables: {}, mul_depth: {} }}",
 40              self.num_constraints, self.num_variables, self.mul_depth
 41          )
 42      }
 43  }
 44  
 45  impl<ConstraintF: Field> ConstraintSynthesizer<ConstraintF> for TestCircuit<ConstraintF> {
 46      fn generate_constraints<CS: ConstraintSystem<ConstraintF>>(&self, cs: &mut CS) -> Result<(), SynthesisError> {
 47          // Ensure the given `cs` is starting off clean.
 48          assert_eq!(1, cs.num_public_variables());
 49          assert_eq!(0, cs.num_private_variables());
 50          assert_eq!(0, cs.num_constraints());
 51  
 52          let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?;
 53          let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?;
 54  
 55          let mut mul_vars = Vec::with_capacity(self.mul_depth);
 56          for i in 0..self.mul_depth {
 57              let mul_var = cs.alloc_input(
 58                  || format!("mul_var {i}"),
 59                  || {
 60                      let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
 61                      let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
 62  
 63                      for _ in 0..(1 + i) {
 64                          a.mul_assign(&b);
 65                      }
 66                      Ok(a)
 67                  },
 68              )?;
 69              mul_vars.push(mul_var);
 70          }
 71  
 72          // For this test we should allocate self.num_variables number of variables
 73          // 2 + mul_depth variables were already allocated above, 1 is allocated by
 74          // default
 75          let dummy_variables = self.num_variables - 3 - self.mul_depth;
 76          for i in 0..dummy_variables {
 77              let _ = cs.alloc(|| format!("var {i}"), || self.a.ok_or(SynthesisError::AssignmentMissing))?;
 78          }
 79  
 80          let mul_constraints = self.mul_depth - 1;
 81          for i in 0..(self.num_constraints - mul_constraints) {
 82              cs.enforce(|| format!("constraint {i}"), |lc| lc + a, |lc| lc + b, |lc| lc + mul_vars[0]);
 83          }
 84  
 85          for i in 0..mul_constraints {
 86              cs.enforce(|| format!("constraint_mul {i}"), |lc| lc + mul_vars[i], |lc| lc + b, |lc| lc + mul_vars[i + 1]);
 87          }
 88  
 89          assert_eq!(cs.num_constraints(), self.num_constraints);
 90          assert_eq!(cs.num_public_variables() + cs.num_private_variables(), self.num_variables);
 91  
 92          Ok(())
 93      }
 94  }
 95  
 96  impl<F: Field> TestCircuit<F> {
 97      // Generate a test circuit with a random witness.
 98      pub fn gen_rand<R: Rng + CryptoRng>(
 99          mul_depth: usize,
100          num_constraints: usize,
101          num_variables: usize,
102          rng: &mut R,
103      ) -> (Self, Vec<F>) {
104          let mut public_inputs: Vec<F> = Vec::with_capacity(1 + mul_depth);
105          public_inputs.push(F::one());
106  
107          let a = F::rand(rng);
108          let b = F::rand(rng);
109  
110          for j in 1..(mul_depth + 1) {
111              let mut new_var = a;
112              for _ in 0..j {
113                  new_var.mul_assign(&b);
114              }
115              public_inputs.push(new_var);
116          }
117  
118          (TestCircuit { a: Some(a), b: Some(b), num_constraints, num_variables, mul_depth }, public_inputs)
119      }
120  
121      // Generate a test circuit with a fixed witness.
122      pub fn generate_circuit_with_fixed_witness(
123          a: u128,
124          b: u128,
125          mul_depth: usize,
126          num_constraints: usize,
127          num_variables: usize,
128      ) -> (Self, Vec<F>) {
129          let mut public_inputs: Vec<F> = Vec::with_capacity(1 + mul_depth);
130          public_inputs.push(F::one());
131          let a = F::from(a);
132          let b = F::from(b);
133          for j in 1..(mul_depth + 1) {
134              let mut new_var = a;
135              for _ in 0..j {
136                  new_var.mul_assign(&b);
137              }
138              public_inputs.push(new_var);
139          }
140  
141          (TestCircuit { a: Some(a), b: Some(b), num_constraints, num_variables, mul_depth }, public_inputs)
142      }
143  }