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 }