dyn_circuit.rs
1 /* This file is part of DarkFi (https://dark.fi) 2 * 3 * Copyright (C) 2020-2025 Dyne.org foundation 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Affero General Public License as 7 * published by the Free Software Foundation, either version 3 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Affero General Public License for more details. 14 * 15 * You should have received a copy of the GNU Affero General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19 use darkfi::zk::assign_free_advice; 20 use halo2_proofs::{ 21 arithmetic::Field, 22 circuit::{ 23 //floor_planner::V1, 24 Layouter, 25 SimpleFloorPlanner, 26 Value, 27 }, 28 dev::{CircuitLayout, MockProver}, 29 pasta::Fp, 30 plonk::{self, Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn}, 31 }; 32 use plotters::prelude::*; 33 use rand::rngs::OsRng; 34 35 #[derive(Clone)] 36 struct DynConfig { 37 primary: Column<InstanceColumn>, 38 advices: Vec<Column<Advice>>, 39 } 40 41 struct DynCircuit { 42 pub witnesses: Vec<Value<Fp>>, 43 } 44 45 impl Circuit<Fp> for DynCircuit { 46 type Config = DynConfig; 47 //type FloorPlanner = V1; 48 type FloorPlanner = SimpleFloorPlanner; 49 type Params = usize; 50 51 fn without_witnesses(&self) -> Self { 52 let mut witnesses = Vec::with_capacity(self.witnesses.len()); 53 for _ in &self.witnesses { 54 witnesses.push(Value::unknown()); 55 } 56 57 Self { witnesses } 58 } 59 60 fn params(&self) -> Self::Params { 61 self.witnesses.len() 62 } 63 64 fn configure_with_params( 65 meta: &mut ConstraintSystem<Fp>, 66 params: Self::Params, 67 ) -> Self::Config { 68 // NOTE: `let advices = vec![meta.advice_column(); params];` does not work as expected. 69 let mut advices = vec![]; 70 for _ in 1..params + 1 { 71 advices.push(meta.advice_column()); 72 } 73 for advice in advices.iter() { 74 meta.enable_equality(*advice); 75 } 76 77 let primary = meta.instance_column(); 78 meta.enable_equality(primary); 79 80 DynConfig { primary, advices } 81 } 82 83 fn configure(_meta: &mut ConstraintSystem<Fp>) -> Self::Config { 84 unreachable!(); 85 } 86 87 fn synthesize( 88 &self, 89 config: Self::Config, 90 mut layouter: impl Layouter<Fp>, 91 ) -> Result<(), plonk::Error> { 92 for (i, witness) in self.witnesses.iter().enumerate() { 93 let w = assign_free_advice( 94 layouter.namespace(|| "witness element"), 95 config.advices[i], 96 *witness, 97 )?; 98 99 layouter.constrain_instance(w.cell(), config.primary, i)?; 100 } 101 102 Ok(()) 103 } 104 } 105 106 #[test] 107 fn dyn_circuit() { 108 const ITERS: usize = 10; 109 const K: u32 = 4; 110 111 for i in 1..ITERS + 1 { 112 let public_inputs = vec![Fp::random(&mut OsRng); i]; 113 let witnesses = public_inputs.iter().map(|x| Value::known(*x)).collect(); 114 let circuit = DynCircuit { witnesses }; 115 let prover = MockProver::run(K, &circuit, vec![public_inputs]).unwrap(); 116 prover.assert_satisfied(); 117 118 let title = format!("target/dynamic_circuit_{i:0>2}.png"); 119 let root = BitMapBackend::new(&title, (800, 600)).into_drawing_area(); 120 CircuitLayout::default().render(K, &circuit, &root).unwrap(); 121 } 122 }