/ tests / dyn_circuit.rs
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  }