-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Circuit dynamic configure #2
Changes from all commits
65d5bfe
e15f649
de6aa2e
a382491
d155184
de0be6c
b56db5f
478ff44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -470,14 +470,34 @@ pub trait Circuit<F: Field> { | |
/// `Circuit` trait because its behaviour is circuit-critical. | ||
type FloorPlanner: FloorPlanner; | ||
|
||
/// Runtime parameters to configure the circuit. | ||
#[cfg(feature = "circuit-params")] | ||
type Params: Default = (); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Associated type default: rust-lang/rust#29661 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @parazyd Would turning on this unstable feature - associated type default - be a good idea? I think tradeoff is: the pro:
the cons:
other misc points:
|
||
|
||
/// Returns a copy of this circuit with no witness values (i.e. all witnesses set to | ||
/// `None`). For most circuits, this will be equal to `Self::default()`. | ||
fn without_witnesses(&self) -> Self; | ||
|
||
/// For defining runtime configuration paramters. | ||
#[cfg(feature = "circuit-params")] | ||
fn params(&self) -> Self::Params { | ||
Self::Params::default() | ||
} | ||
|
||
/// The circuit is given an opportunity to describe the exact gate | ||
/// arrangement, column arrangement, etc. | ||
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config; | ||
|
||
/// Same as configure but takes params. | ||
/// Credit: https://github.com/privacy-scaling-explorations/halo2/pull/168 | ||
#[cfg(feature = "circuit-params")] | ||
fn configure_with_params( | ||
meta: &mut ConstraintSystem<F>, | ||
_params: Self::Params, | ||
) -> Self::Config { | ||
Self::configure(meta) | ||
} | ||
|
||
/// Given the provided `cs`, synthesize the circuit. The concrete type of | ||
/// the caller will be different depending on the context, and they may or | ||
/// may not expect to have a witness present. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,6 +61,10 @@ pub fn create_proof< | |
|
||
let domain = &pk.vk.domain; | ||
let mut meta = ConstraintSystem::default(); | ||
// Since there is 1 proving key for all the circuits, the circuits should share the same configuration. | ||
#[cfg(feature = "circuit-params")] | ||
let config = ConcreteCircuit::configure_with_params(&mut meta, circuits[0].params()); | ||
#[cfg(not(feature = "circuit-params"))] | ||
let config = ConcreteCircuit::configure(&mut meta); | ||
|
||
// Selector optimizations cannot be applied here; use the ConstraintSystem | ||
|
@@ -724,63 +728,137 @@ pub fn create_proof< | |
multiopen::create_proof(params, rng, transcript, instances).map_err(|_| Error::Opening) | ||
} | ||
|
||
#[cfg(feature = "circuit-params")] | ||
#[test] | ||
fn test_create_proof() { | ||
use crate::{ | ||
circuit::SimpleFloorPlanner, | ||
pasta::pallas, | ||
plonk::{keygen_pk, keygen_vk}, | ||
transcript::{Blake2bWrite, Challenge255}, | ||
}; | ||
use pasta_curves::EqAffine; | ||
use rand_core::OsRng; | ||
|
||
#[derive(Clone, Copy)] | ||
struct MyCircuit; | ||
#[derive(Clone, Default)] | ||
struct MyCircuit { | ||
vals: Vec<Value<pallas::Base>>, | ||
} | ||
|
||
#[derive(Clone)] | ||
struct MyConfig { | ||
advices: Vec<Column<Advice>>, | ||
primary: Column<Instance>, | ||
} | ||
|
||
fn assign_free_advice<V: Copy>( | ||
mut layouter: impl crate::circuit::Layouter<pallas::Base>, | ||
column: Column<Advice>, | ||
value: Value<V>, | ||
) -> Result<crate::circuit::AssignedCell<V, pallas::Base>, crate::plonk::Error> | ||
where | ||
for<'v> Assigned<pallas::Base>: From<&'v V>, | ||
{ | ||
layouter.assign_region( | ||
|| "load private", | ||
|mut region| region.assign_advice(|| "load private", column, 0, || value), | ||
) | ||
} | ||
|
||
impl<F: Field> Circuit<F> for MyCircuit { | ||
type Config = (); | ||
impl Circuit<pallas::Base> for MyCircuit { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test case that should be helpful to see the flow. |
||
type Config = MyConfig; | ||
|
||
type FloorPlanner = SimpleFloorPlanner; | ||
|
||
type Params = Self; | ||
|
||
fn without_witnesses(&self) -> Self { | ||
*self | ||
self.clone() | ||
} | ||
|
||
fn params(&self) -> Self::Params { | ||
self.clone() | ||
} | ||
|
||
fn configure(_meta: &mut ConstraintSystem<F>) -> Self::Config {} | ||
fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config { | ||
Self::Config { | ||
advices: vec![], | ||
primary: meta.instance_column(), | ||
} | ||
} | ||
|
||
fn configure_with_params( | ||
meta: &mut ConstraintSystem<pallas::Base>, | ||
params: Self::Params, | ||
) -> Self::Config { | ||
let advices = vec![meta.advice_column(); params.vals.len()]; | ||
let primary = meta.instance_column(); | ||
|
||
for advice in advices.iter() { | ||
meta.enable_equality(*advice); | ||
} | ||
meta.enable_equality(primary); | ||
Self::Config { advices, primary } | ||
} | ||
|
||
fn synthesize( | ||
&self, | ||
_config: Self::Config, | ||
_layouter: impl crate::circuit::Layouter<F>, | ||
config: Self::Config, | ||
mut layouter: impl crate::circuit::Layouter<pallas::Base>, | ||
) -> Result<(), Error> { | ||
let mut witnessed = vec![]; | ||
for (i, val) in self.vals.iter().enumerate() { | ||
let witness = assign_free_advice( | ||
layouter.namespace(|| format!("witness {}", i)), | ||
config.advices[i], | ||
*val, | ||
)?; | ||
witnessed.push(witness); | ||
} | ||
for (i, witness) in witnessed.iter().enumerate() { | ||
layouter.constrain_instance(witness.cell(), config.primary, i)? | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
let params: Params<EqAffine> = Params::new(3); | ||
let vk = keygen_vk(¶ms, &MyCircuit).expect("keygen_vk should not fail"); | ||
let pk = keygen_pk(¶ms, vk, &MyCircuit).expect("keygen_pk should not fail"); | ||
let params: Params<EqAffine> = Params::new(5); | ||
let vals = vec![ | ||
Value::known(pallas::Base::from(1)), | ||
Value::known(pallas::Base::from(2)), | ||
Value::known(pallas::Base::from(3)), | ||
]; | ||
|
||
let circuit = MyCircuit { vals }; | ||
// Render circuit digram | ||
use crate::dev::CircuitLayout; | ||
use plotters::prelude::*; | ||
let root = BitMapBackend::new("../target/layout.png", (3840, 2160)).into_drawing_area(); | ||
root.fill(&WHITE).unwrap(); | ||
let root = root.titled("Circuit Layout", ("sans-serif", 60)).unwrap(); | ||
CircuitLayout::default().render(5, &circuit, &root).unwrap(); | ||
|
||
let vk = keygen_vk(¶ms, &circuit).expect("keygen_vk should not fail"); | ||
let pk = keygen_pk(¶ms, vk, &circuit).expect("keygen_pk should not fail"); | ||
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); | ||
|
||
// Create proof with wrong number of instances | ||
let proof = create_proof( | ||
¶ms, | ||
&pk, | ||
&[MyCircuit, MyCircuit], | ||
&[circuit.clone(), circuit.clone()], | ||
&[], | ||
OsRng, | ||
&mut transcript, | ||
); | ||
assert!(matches!(proof.unwrap_err(), Error::InvalidInstances)); | ||
|
||
let instance = vec![ | ||
pallas::Base::from(1), | ||
pallas::Base::from(2), | ||
pallas::Base::from(3), | ||
]; | ||
// Create proof with correct number of instances | ||
create_proof( | ||
¶ms, | ||
&pk, | ||
&[MyCircuit, MyCircuit], | ||
&[&[], &[]], | ||
OsRng, | ||
&mut transcript, | ||
) | ||
.expect("proof generation should not fail"); | ||
let prover = crate::dev::MockProver::run(5, &circuit, vec![instance]).unwrap(); | ||
prover.assert_satisfied(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
[toolchain] | ||
channel = "1.60.0" | ||
channel = "nightly" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I turned on the default features to generate a test circuit layout, the PSE fork has the defaults on too.