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 }