Compile to Halo2 middleware (#263)

Switching to a more recent Halo2 version revealed a problem with our
lookups - they don't pass a `lookup-any-sanity-checks` because they are
using only the fixed query. This is why I had to disable the default
features of all halo2 crates (that include `lookup-any-sanity-checks`)
and only enable the rest. I suppose we can refactor our lookups to use
`lookup` instead of `lookup_any`.
This commit is contained in:
Alex Kuzmin
2024-07-08 19:36:56 +08:00
committed by GitHub
parent 3d35bd5786
commit 32c362e01a
16 changed files with 766 additions and 953 deletions

View File

@@ -8,23 +8,22 @@ authors = ["Leo Lara <leo@leolara.me>"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[patch.crates-io]
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v0.3.0" }
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", default-features = false, rev = "da4983e" }
[patch."https://github.com/scroll-tech/halo2.git"]
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v0.3.0" }
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", default-features = false, rev = "da4983e" }
[dependencies]
pyo3 = { version = "0.19.1", features = ["extension-module"] }
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", features = [
"circuit-params",
"derive_serde",
], tag = "v0.3.0" }
polyexen = { git = "https://github.com/Dhole/polyexen.git", rev = "16a85c5411f804dc49bbf373d24ff9eedadedfbe" }
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", default-features = false, features = [ "circuit-params", "derive_serde"], rev = "da4983e"}
halo2_middleware = { git = "https://github.com/privacy-scaling-explorations/halo2.git", rev = "da4983e" }
halo2_backend = { git = "https://github.com/privacy-scaling-explorations/halo2.git", features = ["derive_serde"], rev = "da4983e" }
num-bigint = { version = "0.4", features = ["rand"] }
uuid = { version = "1.4.0", features = ["v1", "rng"] }
serde = { version = "1.0", features = ["derive"] }
serde = { version = "=1.0.203", features = ["derive"] }
serde_json = "1.0"
hyperplonk_benchmark = { git = "https://github.com/qwang98/plonkish.git", branch = "main", package = "benchmark" }
plonkish_backend = { git = "https://github.com/qwang98/plonkish.git", branch = "main", package = "plonkish_backend" }

View File

@@ -7,7 +7,10 @@ use chiquito::{
CircuitContext, StepTypeSetupContext, StepTypeWGHandler,
},
plonkish::{
backend::halo2::{chiquitoSuperCircuit2Halo2, ChiquitoHalo2SuperCircuit},
backend::halo2::{
chiquitoSuperCircuit2Halo2, halo2_verify, ChiquitoHalo2SuperCircuit, DummyRng,
Halo2Prover, PlonkishHalo2,
},
compiler::{
cell_manager::{MaxWidthCellManager, SingleRowCellManager},
config,
@@ -18,10 +21,8 @@ use chiquito::{
poly::ToExpr,
sbpir::query::Queriable,
};
use halo2_proofs::{
dev::MockProver,
halo2curves::{bn256::Fr, group::ff::PrimeField},
};
use halo2_proofs::halo2curves::{bn256::Fr, group::ff::PrimeField};
use rand_chacha::rand_core::block::BlockRng;
use std::{fmt::Write, hash::Hash};
pub const IV_LEN: usize = 8;
@@ -1480,17 +1481,25 @@ fn main() {
f: true, // 8bits
};
let circuit =
ChiquitoHalo2SuperCircuit::new(compiled, super_circuit.get_mapping().generate(values));
let witness = super_circuit.get_mapping().generate(values);
let mut circuit = ChiquitoHalo2SuperCircuit::new(compiled);
let prover = MockProver::run(9, &circuit, Vec::new()).unwrap();
let result = prover.verify();
let rng = BlockRng::new(DummyRng {});
let halo2_prover = circuit.create_halo2_prover(9, rng);
let (proof, instance) = halo2_prover.generate_proof(witness);
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
println!("result = {:#?}", result);
if let Err(failures) = &result {
for failure in failures.iter() {
println!("{}", failure);
}
if let Err(failure) = &result {
println!("{}", failure);
}
}

View File

@@ -5,14 +5,14 @@ use chiquito::{
frontend::dsl::{circuit, trace::DSLTraceGenerator}, /* main function for constructing an AST
* circuit */
plonkish::{
backend::halo2::{chiquito2Halo2, ChiquitoHalo2Circuit},
backend::halo2::{halo2_verify, DummyRng, Halo2Prover, PlonkishHalo2},
compiler::{
cell_manager::SingleRowCellManager, // input for constructing the compiler
compile, // input for constructing the compiler
config,
step_selector::SimpleStepSelectorBuilder,
PlonkishCompilationResult,
},
ir::{assignments::AssignmentGenerator, Circuit},
}, /* compiles to
* Chiquito Halo2
* backend,
@@ -22,12 +22,13 @@ use chiquito::{
* circuit */
poly::ToField,
};
use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr};
use halo2_proofs::halo2curves::bn256::Fr;
use rand_chacha::rand_core::block::BlockRng;
const MAX_FACTORIAL: usize = 10;
type AssignGen<F> = AssignmentGenerator<F, DSLTraceGenerator<F, u32>>;
fn generate<F: Field + From<u64> + Hash>() -> (Circuit<F>, Option<AssignGen<F>>) {
fn generate<F: Field + From<u64> + Hash>() -> PlonkishCompilationResult<F, DSLTraceGenerator<F, u32>>
{
// table for the circuit:
// | step_type | i | x |
// ----------------------------------
@@ -134,50 +135,45 @@ fn generate<F: Field + From<u64> + Hash>() -> (Circuit<F>, Option<AssignGen<F>>)
// standard main function for a Halo2 circuit
fn main() {
let (chiquito, wit_gen) = generate::<Fr>();
let compiled = chiquito2Halo2(chiquito);
let circuit = ChiquitoHalo2Circuit::new(compiled, wit_gen.map(|g| g.generate(0)));
let mut plonkish = generate::<Fr>();
let rng = BlockRng::new(DummyRng {});
let prover = MockProver::<Fr>::run(10, &circuit, circuit.instance()).unwrap();
let halo2_prover = plonkish.create_halo2_prover(10, rng);
let result = prover.verify();
let (proof, instance) =
halo2_prover.generate_proof(plonkish.assignment_generator.unwrap().generate(0));
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
println!("result = {:#?}", result);
if let Err(failures) = &result {
for failure in failures.iter() {
println!("{}", failure);
}
if let Err(error) = &result {
println!("{}", error);
}
// plaf boilerplate
use chiquito::plonkish::backend::plaf::chiquito2Plaf;
use polyexen::plaf::backends::halo2::PlafH2Circuit;
let mut plonkish = generate::<Fr>();
let rng = BlockRng::new(DummyRng {});
// get Chiquito ir
let (circuit, wit_gen) = generate::<Fr>();
// get Plaf
let (plaf, plaf_wit_gen) = chiquito2Plaf(circuit, 8, false);
let wit = plaf_wit_gen.generate(wit_gen.map(|v| v.generate(7)));
let halo2_prover = plonkish.create_halo2_prover(8, rng);
// debug only: print witness
// println!("{}", polyexen::plaf::WitnessDisplayCSV(&wit));
let (proof, instance) =
halo2_prover.generate_proof(plonkish.assignment_generator.unwrap().generate(7));
// get Plaf halo2 circuit from Plaf's halo2 backend
// this is just a proof of concept, because Plaf only has backend for halo2
// this is unnecessary because Chiquito has a halo2 backend already
let plaf_circuit = PlafH2Circuit { plaf, wit };
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
// same as halo2 boilerplate above
let prover_plaf = MockProver::<Fr>::run(8, &plaf_circuit, Vec::new()).unwrap();
println!("result = {:#?}", result);
let result_plaf = prover_plaf.verify();
println!("result = {:#?}", result_plaf);
if let Err(failures) = &result_plaf {
for failure in failures.iter() {
println!("{}", failure);
}
if let Err(error) = &result {
println!("{}", error);
}
}

View File

@@ -5,14 +5,14 @@ use chiquito::{
frontend::dsl::{circuit, trace::DSLTraceGenerator}, /* main function for constructing an AST
* circuit */
plonkish::{
backend::halo2::{chiquito2Halo2, ChiquitoHalo2Circuit},
backend::halo2::{halo2_verify, DummyRng, Halo2Prover, PlonkishHalo2},
compiler::{
cell_manager::SingleRowCellManager, // input for constructing the compiler
compile, // input for constructing the compiler
config,
step_selector::SimpleStepSelectorBuilder,
PlonkishCompilationResult,
},
ir::{assignments::AssignmentGenerator, Circuit},
}, /* compiles to
* Chiquito Halo2
* backend,
@@ -22,15 +22,15 @@ use chiquito::{
* circuit */
poly::ToField,
};
use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr};
use halo2_proofs::halo2curves::bn256::Fr;
use rand_chacha::rand_core::block::BlockRng;
// This example file extends the rust example file 'fibonacci.rs',
// describing usage of multiple steptypes, padding, and exposing signals.
type AssignGen<F> = AssignmentGenerator<F, DSLTraceGenerator<F, u32>>;
// the main circuit function
fn fibo_circuit<F: Field + From<u64> + Hash>() -> (Circuit<F>, Option<AssignGen<F>>)
fn fibo_circuit<F: Field + From<u64> + Hash>(
) -> PlonkishCompilationResult<F, DSLTraceGenerator<F, u32>>
// u32 is for external input that indicates the number of fibnoacci iterations
{
use chiquito::{
@@ -205,50 +205,24 @@ fn fibo_circuit<F: Field + From<u64> + Hash>() -> (Circuit<F>, Option<AssignGen<
// standard main function for a Halo2 circuit
fn main() {
let (chiquito, wit_gen) = fibo_circuit::<Fr>();
let compiled = chiquito2Halo2(chiquito);
let circuit = ChiquitoHalo2Circuit::new(compiled, wit_gen.map(|g| g.generate(7)));
let mut plonkish = fibo_circuit::<Fr>();
let rng = BlockRng::new(DummyRng {});
let prover = MockProver::<Fr>::run(7, &circuit, circuit.instance()).unwrap();
let halo2_prover = plonkish.create_halo2_prover(7, rng);
let result = prover.verify();
let (proof, instance) =
halo2_prover.generate_proof(plonkish.assignment_generator.unwrap().generate(7));
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
println!("{:#?}", result);
if let Err(failures) = &result {
for failure in failures.iter() {
println!("{}", failure);
}
}
// plaf boilerplate
use chiquito::plonkish::backend::plaf::chiquito2Plaf;
use polyexen::plaf::{backends::halo2::PlafH2Circuit, WitnessDisplayCSV};
// get Chiquito ir
let (circuit, wit_gen) = fibo_circuit::<Fr>();
// get Plaf
let (plaf, plaf_wit_gen) = chiquito2Plaf(circuit, 8, false);
let wit = plaf_wit_gen.generate(wit_gen.map(|v| v.generate(7)));
// debug only: print witness
println!("{}", WitnessDisplayCSV(&wit));
// get Plaf halo2 circuit from Plaf's halo2 backend
// this is just a proof of concept, because Plaf only has backend for halo2
// this is unnecessary because Chiquito has a halo2 backend already
let plaf_circuit = PlafH2Circuit { plaf, wit };
// same as halo2 boilerplate above
let prover_plaf = MockProver::<Fr>::run(8, &plaf_circuit, plaf_circuit.instance()).unwrap();
let result_plaf = prover_plaf.verify();
println!("result = {:#?}", result_plaf);
if let Err(failures) = &result_plaf {
for failure in failures.iter() {
println!("{}", failure);
}
if let Err(failure) = &result {
println!("{}", failure);
}
}

View File

@@ -6,7 +6,7 @@ use chiquito::{
* circuit */
plonkish::{
backend::{
halo2::{chiquito2Halo2, ChiquitoHalo2Circuit},
halo2::{halo2_verify, DummyRng, Halo2Prover, PlonkishHalo2},
hyperplonk::ChiquitoHyperPlonkCircuit,
},
compiler::{
@@ -14,8 +14,8 @@ use chiquito::{
compile, // input for constructing the compiler
config,
step_selector::SimpleStepSelectorBuilder,
PlonkishCompilationResult,
},
ir::{assignments::AssignmentGenerator, Circuit},
}, /* compiles to
* Chiquito Halo2
* backend,
@@ -26,7 +26,8 @@ use chiquito::{
poly::ToField,
sbpir::SBPIR,
};
use halo2_proofs::dev::MockProver;
use halo2_proofs::halo2curves::bn256::Fr;
use rand_chacha::rand_core::block::BlockRng;
// the main circuit function: returns the compiled IR of a Chiquito circuit
// Generic types F, (), (u64, 64) stand for:
@@ -35,8 +36,7 @@ use halo2_proofs::dev::MockProver;
// 3. two witness generation arguments both of u64 type, i.e. (u64, u64)
type FiboReturn<F> = (
Circuit<F>,
Option<AssignmentGenerator<F>>,
PlonkishCompilationResult<F, DSLTraceGenerator<F>>,
SBPIR<F, DSLTraceGenerator<F>>,
);
@@ -98,12 +98,12 @@ fn fibo_circuit<F: Field + From<u64> + Hash>() -> FiboReturn<F> {
ctx.pragma_num_steps(16);
// trace function is responsible for adding step instantiations defined in step_type_def
// function above trace function is Turing complete and allows arbitrary user
// defined logics for assigning witness values
// Trace function is responsible for adding step instantiations defined in `step_type_def`
// function above. Trace function is Turing-complete and allows arbitrary user-defined
// logic for assigning witness values
ctx.trace(move |ctx: _, _| {
// add function adds a step instantiation to the main circuit and calls witness
// generation function defined in step_type_def input values for witness
// Add function adds a step instantiation to the main circuit and calls witness
// generation function defined in step_type_def. Input values for witness
// generation function are (1, 1) in this step instance
ctx.add(&fibo_step, (1, 1));
let mut a = 1;
@@ -124,7 +124,7 @@ fn fibo_circuit<F: Field + From<u64> + Hash>() -> FiboReturn<F> {
&fibo,
);
(compiled.0, compiled.1, fibo)
(compiled, fibo)
}
// After compiling Chiquito AST to an IR, it is further parsed by a Chiquito Halo2 backend and
@@ -132,79 +132,63 @@ fn fibo_circuit<F: Field + From<u64> + Hash>() -> FiboReturn<F> {
// standard main function for a Halo2 circuit
fn main() {
let (chiquito, wit_gen, _) = fibo_circuit::<Fr>();
let compiled = chiquito2Halo2(chiquito);
let circuit = ChiquitoHalo2Circuit::new(compiled, wit_gen.map(|g| g.generate(())));
let (mut chiquito, _) = fibo_circuit::<Fr>();
let prover = MockProver::<Fr>::run(7, &circuit, circuit.instance()).unwrap();
let rng = BlockRng::new(DummyRng {});
let result = prover.verify();
let halo2_prover = chiquito.create_halo2_prover(7, rng);
println!("{:#?}", result);
let (proof, instance) =
halo2_prover.generate_proof(chiquito.assignment_generator.unwrap().generate(()));
if let Err(failures) = &result {
for failure in failures.iter() {
println!("{}", failure);
}
}
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
// plaf boilerplate
use chiquito::plonkish::backend::plaf::chiquito2Plaf;
use polyexen::plaf::{backends::halo2::PlafH2Circuit, WitnessDisplayCSV};
println!("result = {:#?}", result);
// get Chiquito ir
let (circuit, wit_gen, _) = fibo_circuit::<Fr>();
// get Plaf
let (plaf, plaf_wit_gen) = chiquito2Plaf(circuit, 8, false);
let wit = plaf_wit_gen.generate(wit_gen.map(|v| v.generate(())));
// debug only: print witness
println!("{}", WitnessDisplayCSV(&wit));
// get Plaf halo2 circuit from Plaf's halo2 backend
// this is just a proof of concept, because Plaf only has backend for halo2
// this is unnecessary because Chiquito has a halo2 backend already
let plaf_circuit = PlafH2Circuit { plaf, wit };
// same as halo2 boilerplate above
let prover_plaf = MockProver::<Fr>::run(8, &plaf_circuit, plaf_circuit.instance()).unwrap();
let result_plaf = prover_plaf.verify();
println!("result = {:#?}", result_plaf);
if let Err(failures) = &result_plaf {
for failure in failures.iter() {
println!("{}", failure);
}
if let Err(error) = &result {
println!("{}", error);
}
// hyperplonk boilerplate
use hyperplonk_benchmark::proof_system::{bench_plonkish_backend, System};
use plonkish_backend::{
backend,
halo2_curves::bn256::{Bn256, Fr},
halo2_curves::bn256::{Bn256, Fr as hpFr},
pcs::{multilinear, univariate},
};
// get Chiquito ir
let (circuit, assignment_generator, _) = fibo_circuit::<Fr>();
let (plonkish_compilation_result, _) = fibo_circuit::<hpFr>();
// get assignments
let assignments = assignment_generator.unwrap().generate(());
let assignments = plonkish_compilation_result
.assignment_generator
.unwrap()
.generate(());
// get hyperplonk circuit
let mut hyperplonk_circuit = ChiquitoHyperPlonkCircuit::new(4, circuit);
let mut hyperplonk_circuit =
ChiquitoHyperPlonkCircuit::new(4, plonkish_compilation_result.circuit);
hyperplonk_circuit.set_assignment(assignments);
type GeminiKzg = multilinear::Gemini<univariate::UnivariateKzg<Bn256>>;
type HyperPlonk = backend::hyperplonk::HyperPlonk<GeminiKzg>;
bench_plonkish_backend::<HyperPlonk, Fr>(System::HyperPlonk, 4, &hyperplonk_circuit);
bench_plonkish_backend::<HyperPlonk, hpFr>(System::HyperPlonk, 4, &hyperplonk_circuit);
// pil boilerplate
use chiquito::pil::backend::powdr_pil::chiquito2Pil;
let (_, wit_gen, circuit) = fibo_circuit::<Fr>();
let (plonkish_compilation_result, circuit) = fibo_circuit::<hpFr>();
let pil = chiquito2Pil(
circuit,
Some(wit_gen.unwrap().generate_trace_witness(())),
Some(
plonkish_compilation_result
.assignment_generator
.unwrap()
.generate_trace_witness(()),
),
String::from("FiboCircuit"),
);
print!("{}", pil);

View File

@@ -3,7 +3,10 @@ use chiquito::{
lb::LookupTable, super_circuit, trace::DSLTraceGenerator, CircuitContext, StepTypeWGHandler,
},
plonkish::{
backend::halo2::{chiquitoSuperCircuit2Halo2, ChiquitoHalo2SuperCircuit},
backend::halo2::{
chiquitoSuperCircuit2Halo2, halo2_verify, ChiquitoHalo2SuperCircuit, DummyRng,
Halo2Prover, PlonkishHalo2,
},
compiler::{
cell_manager::{MaxWidthCellManager, SingleRowCellManager},
config,
@@ -14,17 +17,10 @@ use chiquito::{
poly::ToExpr,
sbpir::query::Queriable,
};
use rand_chacha::rand_core::block::BlockRng;
use std::{hash::Hash, ops::Neg};
use halo2_proofs::{
dev::MockProver,
halo2curves::{bn256::Fr, group::ff::PrimeField},
};
use std::{
fs::File,
io::{self, Write},
};
use halo2_proofs::halo2curves::{bn256::Fr, group::ff::PrimeField};
const BIT_COUNT: u64 = 3;
const PART_SIZE: u64 = 5;
@@ -2254,114 +2250,35 @@ fn keccak_super_circuit<F: PrimeField<Repr = [u8; 32]> + Eq + Hash>(
})
}
use chiquito::plonkish::backend::plaf::chiquito2Plaf;
use polyexen::plaf::{Plaf, PlafDisplayBaseTOML, PlafDisplayFixedCSV, Witness, WitnessDisplayCSV};
fn write_files(name: &str, plaf: &Plaf, wit: &Witness) -> Result<(), io::Error> {
let mut base_file = File::create(format!("{}.toml", name))?;
let mut fixed_file = File::create(format!("{}_fixed.csv", name))?;
let mut witness_file = File::create(format!("{}_witness.csv", name))?;
write!(base_file, "{}", PlafDisplayBaseTOML(plaf))?;
write!(fixed_file, "{}", PlafDisplayFixedCSV(plaf))?;
write!(witness_file, "{}", WitnessDisplayCSV(wit))?;
println!("write file success...{}", name);
Ok(())
}
fn keccak_plaf(circuit_param: KeccakCircuit, k: u32) {
let super_circuit = keccak_super_circuit::<Fr>(circuit_param.bytes.len());
let witness = super_circuit.get_mapping().generate(circuit_param);
for wit_gen in witness.values() {
let wit_gen = wit_gen.clone();
let mut circuit = super_circuit.get_sub_circuits()[0].clone();
circuit
.columns
.append(&mut super_circuit.get_sub_circuits()[1].columns);
circuit
.columns
.append(&mut super_circuit.get_sub_circuits()[2].columns);
circuit
.columns
.append(&mut super_circuit.get_sub_circuits()[3].columns);
circuit
.columns
.append(&mut super_circuit.get_sub_circuits()[4].columns);
circuit
.columns
.append(&mut super_circuit.get_sub_circuits()[5].columns);
circuit
.columns
.append(&mut super_circuit.get_sub_circuits()[6].columns);
for (key, value) in super_circuit.get_sub_circuits()[0].fixed_assignments.iter() {
circuit.fixed_assignments.insert(key.clone(), value.clone());
}
for (key, value) in super_circuit.get_sub_circuits()[1].fixed_assignments.iter() {
circuit.fixed_assignments.insert(key.clone(), value.clone());
}
for (key, value) in super_circuit.get_sub_circuits()[2].fixed_assignments.iter() {
circuit.fixed_assignments.insert(key.clone(), value.clone());
}
for (key, value) in super_circuit.get_sub_circuits()[3].fixed_assignments.iter() {
circuit.fixed_assignments.insert(key.clone(), value.clone());
}
for (key, value) in super_circuit.get_sub_circuits()[4].fixed_assignments.iter() {
circuit.fixed_assignments.insert(key.clone(), value.clone());
}
for (key, value) in super_circuit.get_sub_circuits()[5].fixed_assignments.iter() {
circuit.fixed_assignments.insert(key.clone(), value.clone());
}
let (plaf, plaf_wit_gen) = chiquito2Plaf(circuit, k, false);
let mut plaf = plaf;
plaf.set_challenge_alias(0, "r_keccak".to_string());
let wit = plaf_wit_gen.generate(Some(wit_gen));
write_files("keccak_output", &plaf, &wit).unwrap();
}
}
fn keccak_run(circuit_param: KeccakCircuit, k: u32) -> bool {
let super_circuit = keccak_super_circuit::<Fr>(circuit_param.bytes.len());
let compiled = chiquitoSuperCircuit2Halo2(&super_circuit);
let circuit = ChiquitoHalo2SuperCircuit::new(
compiled,
super_circuit.get_mapping().generate(circuit_param),
);
let prover = MockProver::<Fr>::run(k, &circuit, Vec::new()).unwrap();
let result = prover.verify();
println!("result = {:#?}", result);
if let Err(failures) = &result {
for failure in failures.iter() {
println!("{}", failure);
}
false
} else {
true
}
}
fn main() {
let circuit_param = KeccakCircuit {
bytes: vec![0, 1, 2, 3, 4, 5, 6, 7],
};
let res = keccak_run(circuit_param, 9);
let super_circuit = keccak_super_circuit::<Fr>(circuit_param.bytes.len());
if res {
keccak_plaf(
KeccakCircuit {
bytes: vec![0, 1, 2, 3, 4, 5, 6, 7],
},
11,
);
let compiled = chiquitoSuperCircuit2Halo2(&super_circuit);
let mut circuit = ChiquitoHalo2SuperCircuit::new(compiled);
let rng = BlockRng::new(DummyRng {});
let witness = super_circuit.get_mapping().generate(circuit_param);
let halo2_prover = circuit.create_halo2_prover(9, rng);
let (proof, instance) = halo2_prover.generate_proof(witness);
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
println!("result = {:#?}", result);
if let Err(failure) = &result {
println!("{}", failure);
}
}

View File

@@ -1,14 +1,14 @@
use std::hash::Hash;
use halo2_proofs::{
dev::MockProver,
halo2curves::{bn256::Fr, group::ff::PrimeField},
};
use halo2_proofs::halo2curves::{bn256::Fr, group::ff::PrimeField};
use chiquito::{
frontend::dsl::{lb::LookupTable, super_circuit, trace::DSLTraceGenerator, CircuitContext},
plonkish::{
backend::halo2::{chiquitoSuperCircuit2Halo2, ChiquitoHalo2SuperCircuit},
backend::halo2::{
chiquitoSuperCircuit2Halo2, halo2_verify, ChiquitoHalo2SuperCircuit, DummyRng,
Halo2Prover, PlonkishHalo2,
},
compiler::{
cell_manager::SingleRowCellManager, config, step_selector::SimpleStepSelectorBuilder,
},
@@ -18,6 +18,7 @@ use chiquito::{
};
use mimc7_constants::ROUND_CONSTANTS;
use rand_chacha::rand_core::block::BlockRng;
// MiMC7 always has 91 rounds
pub const ROUNDS: usize = 91;
@@ -203,21 +204,28 @@ fn main() {
let super_circuit = mimc7_super_circuit::<Fr>();
let compiled = chiquitoSuperCircuit2Halo2(&super_circuit);
let circuit = ChiquitoHalo2SuperCircuit::new(
compiled,
super_circuit.get_mapping().generate((x_in_value, k_value)),
let mut circuit = ChiquitoHalo2SuperCircuit::new(compiled);
let rng = BlockRng::new(DummyRng {});
let witness = super_circuit.get_mapping().generate((x_in_value, k_value));
let halo2_prover = circuit.create_halo2_prover(10, rng);
let (proof, instance) = halo2_prover.generate_proof(witness);
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
let prover = MockProver::<Fr>::run(10, &circuit, circuit.instance()).unwrap();
let result = prover.verify();
println!("result = {:#?}", result);
if let Err(failures) = &result {
for failure in failures.iter() {
println!("{}", failure);
}
if let Err(failure) = &result {
println!("{}", failure);
}
// pil boilerplate

View File

@@ -1,7 +1,10 @@
use chiquito::{
frontend::dsl::{lb::LookupTable, super_circuit, trace::DSLTraceGenerator, CircuitContext},
plonkish::{
backend::halo2::{chiquitoSuperCircuit2Halo2, ChiquitoHalo2SuperCircuit},
backend::halo2::{
chiquitoSuperCircuit2Halo2, halo2_verify, ChiquitoHalo2SuperCircuit, DummyRng,
Halo2Prover, PlonkishHalo2,
},
compiler::{
cell_manager::{MaxWidthCellManager, SingleRowCellManager},
config,
@@ -11,13 +14,11 @@ use chiquito::{
},
sbpir::query::Queriable,
};
use rand_chacha::rand_core::block::BlockRng;
use std::hash::Hash;
use halo2_proofs::{
dev::MockProver,
halo2curves::{bn256::Fr, group::ff::PrimeField},
};
use halo2_proofs::halo2curves::{bn256::Fr, group::ff::PrimeField};
#[derive(Clone)]
struct RoundValues<F: PrimeField> {
@@ -705,19 +706,26 @@ fn main() {
let super_circuit = poseidon_super_circuit(lens);
let compiled = chiquitoSuperCircuit2Halo2(&super_circuit);
let circuit =
ChiquitoHalo2SuperCircuit::new(compiled, super_circuit.get_mapping().generate(values));
let witness = super_circuit.get_mapping().generate(values);
let mut circuit = ChiquitoHalo2SuperCircuit::new(compiled);
let prover = MockProver::<Fr>::run(12, &circuit, Vec::new()).unwrap();
let rng = BlockRng::new(DummyRng {});
let result = prover.verify();
let halo2_prover = circuit.create_halo2_prover(12, rng);
let (proof, instance) = halo2_prover.generate_proof(witness);
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
println!("result = {:#?}", result);
if let Err(failures) = &result {
for failure in failures.iter() {
println!("{}", failure);
}
if let Err(failure) = &result {
println!("{}", failure);
}
}

View File

@@ -13,7 +13,7 @@ use crate::{
ast::{debug_sym_factory::DebugSymRefFactory, tl::TLDecl, Identifiable, Identifier},
lang::TLDeclsParser,
},
plonkish,
plonkish::{self, compiler::PlonkishCompilationResult},
poly::{self, mielim::mi_elimination, reduce::reduce_degree, Expr},
sbpir::{query::Queriable, InternalSignal, SBPIR},
wit_gen::{NullTraceGenerator, SymbolSignalMapping, TraceGenerator},
@@ -41,10 +41,7 @@ impl<F: Field + Hash> CompilerResult<F> {
>(
&self,
config: plonkish::compiler::CompilerConfig<CM, SSB>,
) -> (
crate::plonkish::ir::Circuit<F>,
Option<plonkish::ir::assignments::AssignmentGenerator<F, InterpreterTraceGenerator>>,
) {
) -> PlonkishCompilationResult<F, InterpreterTraceGenerator> {
plonkish::compiler::compile(config, &self.circuit)
}
}

View File

@@ -2,18 +2,19 @@ use pyo3::{
prelude::*,
types::{PyDict, PyList, PyLong, PyString},
};
use rand_chacha::rand_core::block::BlockRng;
use crate::{
frontend::dsl::{StepTypeHandler, SuperCircuitContext},
pil::backend::powdr_pil::chiquito2Pil,
plonkish::{
backend::halo2::{
chiquito2Halo2, chiquitoSuperCircuit2Halo2, ChiquitoHalo2, ChiquitoHalo2Circuit,
ChiquitoHalo2SuperCircuit,
chiquito2Halo2, chiquitoSuperCircuit2Halo2, halo2_verify, ChiquitoHalo2,
ChiquitoHalo2SuperCircuit, DummyRng, Halo2Prover, PlonkishHalo2,
},
compiler::{
cell_manager::SingleRowCellManager, compile, config,
step_selector::SimpleStepSelectorBuilder,
step_selector::SimpleStepSelectorBuilder, PlonkishCompilationResult,
},
ir::{assignments::AssignmentGenerator, sc::MappingContext},
},
@@ -27,7 +28,7 @@ use crate::{
};
use core::result::Result;
use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr};
use halo2_proofs::halo2curves::bn256::Fr;
use serde::de::{self, Deserialize, Deserializer, IgnoredAny, MapAccess, Visitor};
use std::{cell::RefCell, collections::HashMap, fmt};
@@ -62,14 +63,15 @@ pub fn chiquito_ast_to_halo2(ast_json: &str) -> UUID {
serde_json::from_str(ast_json).expect("Json deserialization to Circuit failed.");
let config = config(SingleRowCellManager {}, SimpleStepSelectorBuilder {});
let (chiquito, assignment_generator) = compile(config, &circuit);
let chiquito_halo2 = chiquito2Halo2(chiquito);
let plonkish = compile(config, &circuit);
let chiquito_halo2 = chiquito2Halo2(plonkish.circuit);
let uuid = uuid();
CIRCUIT_MAP.with(|circuit_map| {
circuit_map
.borrow_mut()
.insert(uuid, (circuit, chiquito_halo2, assignment_generator));
circuit_map.borrow_mut().insert(
uuid,
(circuit, chiquito_halo2, plonkish.assignment_generator),
);
});
uuid
@@ -149,18 +151,25 @@ pub fn chiquito_super_circuit_halo2_mock_prover(
let super_assignments = mapping_ctx.get_super_assignments();
let circuit = ChiquitoHalo2SuperCircuit::new(compiled, super_assignments);
let mut circuit = ChiquitoHalo2SuperCircuit::new(compiled);
let prover = MockProver::<Fr>::run(k as u32, &circuit, circuit.instance()).unwrap();
let rng = BlockRng::new(DummyRng {});
let result = prover.verify();
let halo2_prover = circuit.create_halo2_prover(k as u32, rng);
let (proof, instance) = halo2_prover.generate_proof(super_assignments);
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
println!("result = {:#?}", result);
if let Err(failures) = &result {
for failure in failures.iter() {
println!("{}", failure);
}
if let Err(failure) = &result {
println!("{}", failure);
}
}
@@ -179,21 +188,34 @@ pub fn chiquito_halo2_mock_prover(witness_json: &str, rust_id: UUID, k: usize) {
let trace_witness: TraceWitness<Fr> =
serde_json::from_str(witness_json).expect("Json deserialization to TraceWitness failed.");
let (_, compiled, assignment_generator) = rust_id_to_halo2(rust_id);
let circuit: ChiquitoHalo2Circuit<_> = ChiquitoHalo2Circuit::new(
compiled,
assignment_generator.map(|g| g.generate(trace_witness)),
let rng = BlockRng::new(DummyRng {});
let mut plonkish = PlonkishCompilationResult {
circuit: compiled.circuit,
assignment_generator,
};
let halo2_prover = plonkish.create_halo2_prover(k as u32, rng);
let (proof, instance) = halo2_prover.generate_proof(
plonkish
.assignment_generator
.unwrap()
.generate(trace_witness),
);
let prover = MockProver::<Fr>::run(k as u32, &circuit, circuit.instance()).unwrap();
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
let result = prover.verify();
println!("result = {:#?}", result);
println!("{:#?}", result);
if let Err(failures) = &result {
for failure in failures.iter() {
println!("{}", failure);
}
if let Err(error) = &result {
println!("{}", error);
}
}

View File

@@ -321,15 +321,16 @@ fn get_block_stmts(stmt: &Statement<BigInt, Identifier>) -> Vec<Statement<BigInt
#[cfg(test)]
mod test {
use crate::plonkish::backend::halo2::{Halo2Prover, PlonkishHalo2};
use halo2_proofs::halo2curves::bn256::Fr;
use rand_chacha::rand_core::block::BlockRng;
use std::collections::HashMap;
use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr};
use crate::{
compiler::{compile, Config},
parser::ast::debug_sym_factory::DebugSymRefFactory,
plonkish::{
backend::halo2::{chiquito2Halo2, ChiquitoHalo2Circuit},
backend::halo2::{halo2_verify, DummyRng},
compiler::{
cell_manager::SingleRowCellManager, config,
step_selector::SimpleStepSelectorBuilder,
@@ -395,7 +396,7 @@ mod test {
}
#[test]
fn test_run_halo2_mock_prover() {
fn test_run_halo2_prover() {
let code = "
machine fibo(signal n) (signal b: field) {
// n and be are created automatically as shared
@@ -443,24 +444,28 @@ mod test {
chiquito.circuit.num_steps = 12;
let plonkish = chiquito.plonkish(config(
let mut plonkish = chiquito.plonkish(config(
SingleRowCellManager {},
SimpleStepSelectorBuilder {},
));
let compiled = chiquito2Halo2(plonkish.0);
let rng = BlockRng::new(DummyRng {});
let circuit = ChiquitoHalo2Circuit::new(
compiled,
let halo2_prover = plonkish.create_halo2_prover(7, rng);
let (proof, instance) = halo2_prover.generate_proof(
plonkish
.1
.map(|g| g.generate(HashMap::from([("n".to_string(), Fr::from(12))]))),
.assignment_generator
.unwrap()
.generate(HashMap::from([("n".to_string(), Fr::from(12))])),
);
let prover = MockProver::<Fr>::run(7, &circuit, circuit.instance()).unwrap();
let result = prover.verify();
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
assert!(result.is_ok());
}
@@ -474,7 +479,7 @@ mod test {
signal a: field, i;
// there is always a state called initial
// input signals get binded to the signal
// input signals get bound to the signal
// in the initial state (first instance)
state initial {
signal c;
@@ -519,28 +524,33 @@ mod test {
// .wit_gen
// .evil_assign(&mut witness, 1, ("//fibo", "i"), Fr::zero());
let plonkish = chiquito.plonkish(config(
let mut plonkish = chiquito.plonkish(config(
SingleRowCellManager {},
SimpleStepSelectorBuilder {},
));
let compiled = chiquito2Halo2(plonkish.0);
let rng = BlockRng::new(DummyRng {});
let circuit = ChiquitoHalo2Circuit::new(
compiled,
let halo2_prover = plonkish.create_halo2_prover(7, rng);
let (proof, instance) = halo2_prover.generate_proof(
plonkish
.1
.map(|g| g.generate(HashMap::from([("n".to_string(), Fr::from(12))]))),
.assignment_generator
.unwrap()
.generate(HashMap::from([("n".to_string(), Fr::from(12))])),
);
let prover = MockProver::<Fr>::run(7, &circuit, circuit.instance()).unwrap();
let result = halo2_verify(
proof,
&halo2_prover.setup.params,
&halo2_prover.setup.vk,
instance,
);
let result = prover.verify();
println!("result = {:#?}", result);
assert!(result.is_err());
if let Err(result) = result {
println!("{}", result.len());
if let Err(error) = &result {
println!("{}", error);
}
}
}

View File

@@ -1,27 +1,56 @@
use std::{collections::HashMap, hash::Hash};
use std::{collections::HashMap, hash::Hash, vec};
use halo2_backend::plonk::{
keygen::{keygen_pk, keygen_vk},
prover::ProverSingle,
verifier::verify_proof_single,
Error as ErrorBack,
};
use halo2_middleware::{
circuit::{Any as Columns, Cell as CellMid, ColumnMid, CompiledCircuit, Preprocessing},
permutation::AssemblyMid,
zal::impls::{H2cEngine, PlonkEngineConfig},
};
use halo2_proofs::{
arithmetic::Field,
circuit::{Cell, Layouter, Region, RegionIndex, SimpleFloorPlanner, Value},
halo2curves::ff::PrimeField,
plonk::{
Advice, Any, Circuit as h2Circuit, Column, ConstraintSystem, Error, Expression, FirstPhase,
Fixed, Instance, SecondPhase, ThirdPhase, VirtualCells,
halo2curves::{
bn256::{Bn256, Fr, G1Affine},
ff::PrimeField,
},
plonk::{
Advice, Any, Column, ConstraintSystem, ConstraintSystemMid, Error, Expression, FirstPhase,
Fixed, Instance, ProvingKey, SecondPhase, ThirdPhase, VerifyingKey, VirtualCells,
},
poly::{
commitment::Params,
kzg::{
commitment::{KZGCommitmentScheme, ParamsKZG},
multiopen::{ProverSHPLONK, VerifierSHPLONK},
strategy::SingleStrategy,
},
Rotation,
},
transcript::{
Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer,
},
poly::Rotation,
};
use rand_chacha::rand_core::block::{BlockRng, BlockRngCore};
use crate::{
field::Field as ChiquitoField,
plonkish::ir::{
assignments::Assignments,
sc::{SuperAssignments, SuperCircuit},
Circuit, Column as cColumn,
ColumnType::{Advice as cAdvice, Fixed as cFixed, Halo2Advice, Halo2Fixed},
PolyExpr,
plonkish::{
compiler::PlonkishCompilationResult,
ir::{
assignments::Assignments,
sc::{SuperAssignments, SuperCircuit},
Circuit, Column as cColumn,
ColumnType::{Advice as cAdvice, Fixed as cFixed, Halo2Advice, Halo2Fixed},
PolyExpr,
},
},
poly::ToField,
util::UUID,
wit_gen::TraceGenerator,
};
impl<T: PrimeField + From<u64>> ChiquitoField for T {
@@ -50,6 +79,18 @@ pub fn chiquito2Halo2<F: PrimeField + From<u64> + Hash>(circuit: Circuit<F>) ->
ChiquitoHalo2::new(circuit)
}
fn compile_middleware<F: PrimeField + From<u64> + Hash, C: Halo2Configurable<F>>(
k: u32,
circuit: &mut C,
) -> Result<CompiledCircuit<F>, Error> {
let (cs, preprocessing) = circuit.configure(k)?;
Ok(CompiledCircuit {
cs: cs.clone().into(),
preprocessing,
})
}
#[allow(non_snake_case)]
pub fn chiquitoSuperCircuit2Halo2<F: PrimeField + From<u64> + Hash, MappingArgs>(
super_circuit: &SuperCircuit<F, MappingArgs>,
@@ -65,7 +106,7 @@ pub fn chiquitoSuperCircuit2Halo2<F: PrimeField + From<u64> + Hash, MappingArgs>
pub struct ChiquitoHalo2<F: PrimeField + From<u64>> {
pub debug: bool,
circuit: Circuit<F>,
pub circuit: Circuit<F>,
advice_columns: HashMap<UUID, Column<Advice>>,
fixed_columns: HashMap<UUID, Column<Fixed>>,
@@ -74,6 +115,59 @@ pub struct ChiquitoHalo2<F: PrimeField + From<u64>> {
ir_id: UUID,
}
trait Halo2Configurable<F: Field> {
fn configure(&mut self, k: u32) -> Result<(ConstraintSystem<F>, Preprocessing<F>), Error> {
let mut cs = self.configure_cs();
let n = 2usize.pow(k);
if n < cs.minimum_rows() {
return Err(Error::Backend(ErrorBack::NotEnoughRowsAvailable {
current_k: k,
}));
}
let preprocessing = self.preprocessing(&mut cs, n);
Ok((cs.clone(), preprocessing))
}
fn configure_cs(&mut self) -> ConstraintSystem<F>;
fn preprocessing(&self, cs: &mut ConstraintSystem<F>, n: usize) -> Preprocessing<F>;
}
impl<F: PrimeField + Hash> Halo2Configurable<F> for ChiquitoHalo2<F> {
fn preprocessing(&self, cs: &mut ConstraintSystem<F>, n: usize) -> Preprocessing<F> {
let fixed_count = self.circuit.fixed_assignments.0.len();
let mut fixed = vec![vec![F::default(); n]; fixed_count];
for (column, values) in self.circuit.fixed_assignments.iter() {
let column = self.convert_fixed_column(column);
for (offset, value) in values.iter().enumerate() {
fixed[column.index][offset] = *value;
}
}
let mut copies = vec![];
self.collect_permutations(cs, &mut copies);
Preprocessing {
permutation: AssemblyMid { copies },
fixed,
}
}
fn configure_cs(&mut self) -> ConstraintSystem<F> {
let mut cs: ConstraintSystem<F> = ConstraintSystem::default();
self.configure_columns_sub_circuit(&mut cs);
self.configure_sub_circuit(&mut cs);
cs
}
}
impl<F: PrimeField + From<u64> + Hash> ChiquitoHalo2<F> {
pub fn new(circuit: Circuit<F>) -> ChiquitoHalo2<F> {
let ir_id = circuit.id;
@@ -87,12 +181,6 @@ impl<F: PrimeField + From<u64> + Hash> ChiquitoHalo2<F> {
}
}
pub fn configure(&mut self, meta: &mut ConstraintSystem<F>) {
self.configure_columns_sub_circuit(meta);
self.configure_sub_circuit(meta);
}
fn configure_columns_sub_circuit(&mut self, meta: &mut ConstraintSystem<F>) {
let mut advice_columns = HashMap::<UUID, Column<Advice>>::new();
let mut fixed_columns = HashMap::<UUID, Column<Fixed>>::new();
@@ -136,7 +224,7 @@ impl<F: PrimeField + From<u64> + Hash> ChiquitoHalo2<F> {
self.fixed_columns = fixed_columns;
}
pub fn configure_sub_circuit(&mut self, meta: &mut ConstraintSystem<F>) {
fn configure_sub_circuit(&mut self, meta: &mut ConstraintSystem<F>) {
if !self.circuit.exposed.is_empty() {
self.instance_column = Some(meta.instance_column());
}
@@ -170,83 +258,6 @@ impl<F: PrimeField + From<u64> + Hash> ChiquitoHalo2<F> {
}
}
pub fn synthesize(&self, layouter: &mut impl Layouter<F>, witness: Option<&Assignments<F>>) {
let _ = layouter.assign_region(
|| "circuit",
|mut region| {
self.annotate_circuit(&mut region);
self.assign_fixed(&mut region, &self.circuit.fixed_assignments)?;
if let Some(witness) = &witness {
self.assign_advice(&mut region, witness)?;
}
Ok(())
},
);
for (index, (column, rotation)) in self.circuit.exposed.iter().enumerate() {
let halo2_column =
Column::<Any>::from(*self.advice_columns.get(&column.uuid()).unwrap());
let cell = new_cell(
halo2_column,
// For single row cell manager, forward signal rotation is always zero.
// For max width cell manager, rotation can be non-zero.
// Offset is absolute row index calculated in `compile_exposed`.
*rotation as usize,
);
let _ = layouter.constrain_instance(cell, self.instance_column.unwrap(), index);
}
}
fn assign_advice(&self, region: &mut Region<F>, witness: &Assignments<F>) -> Result<(), Error> {
for (column, assignments) in witness.iter() {
let column = self.convert_advice_column(column);
for (offset, value) in assignments.iter().enumerate() {
region.assign_advice(|| "", column, offset, || Value::known(*value))?;
}
}
Ok(())
}
fn assign_fixed(&self, region: &mut Region<F>, fixed: &Assignments<F>) -> Result<(), Error> {
for (column, values) in fixed.iter() {
let column = self.convert_fixed_column(column);
for (offset, value) in values.iter().enumerate() {
region.assign_fixed(|| "", column, offset, || Value::known(*value))?;
}
}
Ok(())
}
fn annotate_circuit(&self, region: &mut Region<F>) {
for column in self.circuit.columns.iter() {
match column.ctype {
cAdvice | Halo2Advice => {
let halo2_column = self
.advice_columns
.get(&column.uuid())
.expect("advice column not found");
region.name_column(|| column.annotation.clone(), *halo2_column);
}
cFixed | Halo2Fixed => {
let halo2_column = self
.fixed_columns
.get(&column.uuid())
.expect("fixed column not found");
region.name_column(|| column.annotation.clone(), *halo2_column);
}
}
}
}
fn convert_poly(&self, meta: &mut VirtualCells<'_, F>, src: &PolyExpr<F>) -> Expression<F> {
match src {
PolyExpr::Const(c, _) => Expression::Constant(*c),
@@ -322,30 +333,51 @@ impl<F: PrimeField + From<u64> + Hash> ChiquitoHalo2<F> {
_ => panic!("wrong column type"),
}
}
fn collect_permutations(
&self,
cs: &mut ConstraintSystem<F>,
copies: &mut Vec<(CellMid, CellMid)>,
) {
self.circuit
.exposed
.iter()
.enumerate()
.for_each(|(row, (column, offset))| {
let col_type: Columns = match column.ctype {
cAdvice | Halo2Advice => Columns::Advice,
cFixed | Halo2Fixed => Columns::Fixed,
};
let index = if col_type == Columns::Advice {
let column = self.convert_advice_column(column);
cs.enable_equality(column);
column.index
} else {
let column = self.convert_fixed_column(column);
cs.enable_equality(column);
column.index
};
let column_mid = ColumnMid::new(col_type, index);
let instance_column = ColumnMid::new(Columns::Instance, 0);
cs.enable_equality(instance_column);
copies.push((
CellMid {
column: column_mid,
row: *offset as usize,
},
CellMid {
column: instance_column,
row,
},
));
});
}
}
#[allow(dead_code)]
// From Plaf Halo2 backend.
// _Cell is a helper struct used for constructing Halo2 Cell.
struct _Cell {
region_index: RegionIndex,
row_offset: usize,
column: Column<Any>,
}
// From Plaf Halo2 backend.
fn new_cell(column: Column<Any>, offset: usize) -> Cell {
let cell = _Cell {
region_index: RegionIndex::from(0),
row_offset: offset,
column,
};
// NOTE: We use unsafe here to construct a Cell, which doesn't have a public constructor. This
// helps us set the copy constraints easily (without having to store all assigned cells
// previously)
unsafe { std::mem::transmute::<_Cell, Cell>(cell) }
}
pub fn to_halo2_advice<F: PrimeField>(
fn to_halo2_advice<F: PrimeField>(
meta: &mut ConstraintSystem<F>,
column: &cColumn,
) -> Column<Advice> {
@@ -357,160 +389,333 @@ pub fn to_halo2_advice<F: PrimeField>(
}
}
#[derive(Clone, Default, Debug)]
pub struct ChiquitoHalo2Circuit<F: PrimeField + From<u64>> {
compiled: ChiquitoHalo2<F>,
witness: Option<Assignments<F>>,
}
impl<F: PrimeField + From<u64> + Hash> ChiquitoHalo2Circuit<F> {
pub fn new(compiled: ChiquitoHalo2<F>, witness: Option<Assignments<F>>) -> Self {
Self { compiled, witness }
}
pub fn instance(&self) -> Vec<Vec<F>> {
if !self.compiled.circuit.exposed.is_empty() {
if let Some(witness) = &self.witness {
return vec![self.compiled.circuit.instance(witness)];
}
}
Vec::new()
}
}
impl<F: PrimeField + From<u64> + Hash> h2Circuit<F> for ChiquitoHalo2Circuit<F> {
type Config = ChiquitoHalo2<F>;
type FloorPlanner = SimpleFloorPlanner;
type Params = ChiquitoHalo2<F>;
fn without_witnesses(&self) -> Self {
Self {
compiled: self.compiled.clone(),
witness: self.witness.clone().map(|mut w| {
w.clear();
w
}),
}
}
fn params(&self) -> Self::Params {
self.compiled.clone()
}
fn configure_with_params(
meta: &mut ConstraintSystem<F>,
mut compiled: Self::Params,
) -> Self::Config {
compiled.configure(meta);
compiled
}
fn synthesize(
&self,
compiled: Self::Config,
mut layouter: impl Layouter<F>,
) -> Result<(), Error> {
compiled.synthesize(&mut layouter, self.witness.as_ref());
Ok(())
}
fn configure(_: &mut ConstraintSystem<F>) -> Self::Config {
unreachable!()
}
}
#[derive(Debug, Default)]
#[derive(Clone, Debug, Default)]
pub struct ChiquitoHalo2SuperCircuit<F: PrimeField + From<u64>> {
sub_circuits: Vec<ChiquitoHalo2<F>>,
witness: SuperAssignments<F>,
}
impl<F: PrimeField + From<u64> + Hash> ChiquitoHalo2SuperCircuit<F> {
pub fn new(sub_circuits: Vec<ChiquitoHalo2<F>>, witness: SuperAssignments<F>) -> Self {
Self {
sub_circuits,
witness,
}
pub fn new(sub_circuits: Vec<ChiquitoHalo2<F>>) -> Self {
Self { sub_circuits }
}
}
impl<F: PrimeField + Hash> Halo2Configurable<F> for ChiquitoHalo2SuperCircuit<F> {
fn configure_cs(&mut self) -> ConstraintSystem<F> {
let mut cs = ConstraintSystem::default();
self.sub_circuits
.iter_mut()
.for_each(|c| c.configure_columns_sub_circuit(&mut cs));
let advice_columns: HashMap<UUID, Column<Advice>> =
self.sub_circuits
.iter()
.fold(HashMap::default(), |mut acc, s| {
acc.extend(s.advice_columns.clone());
acc
});
let fixed_columns: HashMap<UUID, Column<Fixed>> =
self.sub_circuits
.iter()
.fold(HashMap::default(), |mut acc, s| {
acc.extend(s.fixed_columns.clone());
acc
});
self.sub_circuits.iter_mut().for_each(|sub_circuit| {
sub_circuit.advice_columns = advice_columns.clone();
sub_circuit.fixed_columns = fixed_columns.clone();
sub_circuit.configure_sub_circuit(&mut cs)
});
cs
}
pub fn instance(&self) -> Vec<Vec<F>> {
let mut result = Vec::new();
fn preprocessing(&self, cs: &mut ConstraintSystem<F>, n: usize) -> Preprocessing<F> {
let fixed_columns: HashMap<UUID, Column<Fixed>> =
self.sub_circuits
.iter()
.fold(HashMap::default(), |mut acc, s| {
acc.extend(s.fixed_columns.clone());
acc
});
for sub_circuit in &self.sub_circuits {
if !sub_circuit.circuit.exposed.is_empty() {
let instance_values = sub_circuit.circuit.instance(
self.witness
.get(&sub_circuit.ir_id)
let fixed_count = fixed_columns.len();
let mut fixed = vec![vec![F::default(); n]; fixed_count];
let mut copies = vec![];
for subcircuit in self.sub_circuits.iter() {
for (column, values) in subcircuit.circuit.fixed_assignments.iter() {
let column = fixed_columns.get(&column.uuid()).unwrap();
for (offset, value) in values.iter().enumerate() {
fixed[column.index][offset] = *value;
}
}
subcircuit.collect_permutations(cs, &mut copies);
}
Preprocessing {
permutation: AssemblyMid { copies },
fixed,
}
}
}
/// Verify Halo2 proof
/// ### Arguments
/// * `proof` - Halo2 proof
/// * `params` - KZG parameters
/// * `vk` - Verifying key
/// * `instance` - circuit instance values
/// ### Returns
/// * `Ok(())` if the proof is valid
/// * `Err(ErrorBack)` if the proof is invalid
pub fn halo2_verify(
proof: Vec<u8>,
params: &ParamsKZG<Bn256>,
vk: &VerifyingKey<G1Affine>,
instance: Vec<Vec<Fr>>,
) -> Result<(), ErrorBack> {
// Verify
let mut verifier_transcript =
Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof.as_slice());
let verifier_params = params.verifier_params();
let strategy = SingleStrategy::new(&verifier_params);
let result = verify_proof_single::<KZGCommitmentScheme<Bn256>, VerifierSHPLONK<Bn256>, _, _, _>(
&verifier_params,
vk,
strategy,
instance,
&mut verifier_transcript,
);
result
}
/// Halo2 setup
pub struct Setup {
pub cs: ConstraintSystemMid<Fr>,
pub params: ParamsKZG<Bn256>,
pub vk: VerifyingKey<G1Affine>,
pub pk: ProvingKey<G1Affine>,
rng: BlockRng<DummyRng>,
}
/// Halo2 prover for a single circuit
pub struct SingleCircuitProver<F: PrimeField> {
pub setup: Setup,
circuit: ChiquitoHalo2<F>,
}
#[allow(clippy::type_complexity)]
fn create_prover<'a>(
setup: &'a Setup,
instance: &[Vec<Fr>],
transcript: &'a mut Blake2bWrite<Vec<u8>, G1Affine, Challenge255<G1Affine>>,
) -> ProverSingle<
'a,
'a,
KZGCommitmentScheme<Bn256>,
ProverSHPLONK<'a, Bn256>,
Challenge255<G1Affine>,
BlockRng<DummyRng>,
Blake2bWrite<Vec<u8>, G1Affine, Challenge255<G1Affine>>,
H2cEngine,
> {
ProverSingle::<
KZGCommitmentScheme<Bn256>,
ProverSHPLONK<'_, Bn256>,
_,
_,
_,
_,
>::new_with_engine(
PlonkEngineConfig::new()
.set_curve::<G1Affine>()
.set_msm(H2cEngine::new())
.build(),
&setup.params,
&setup.pk,
instance.to_vec(),
setup.rng.clone(),
transcript,
)
.unwrap()
}
fn assign_witness(
circuit: &ChiquitoHalo2<Fr>,
witness: &Assignments<Fr>,
assigned_witness: &mut [Option<Vec<Fr>>],
) {
for (column, values) in witness.iter() {
let circuit_column = circuit.advice_columns.get(&column.uuid()).unwrap();
let halo2_column = Column::<Any>::from(*circuit_column);
for (offset, value) in values.iter().enumerate() {
assigned_witness[halo2_column.index].as_mut().unwrap()[offset] = *value;
}
}
}
/// Halo2 prover for a super circuit
pub struct SuperCircuitProver<F: PrimeField> {
pub setup: Setup,
circuit: ChiquitoHalo2SuperCircuit<F>,
}
pub trait Halo2Prover {
/// Witness type
type W;
/// Generate Halo2 proof
/// #### Arguments
/// * `witness` - circuit witness
/// #### Returns
/// * a tuple of proof and instance values
fn generate_proof(&self, witness: Self::W) -> (Vec<u8>, Vec<Vec<Fr>>);
}
impl Halo2Prover for SuperCircuitProver<Fr> {
type W = SuperAssignments<Fr>;
fn generate_proof(&self, witnesses: Self::W) -> (Vec<u8>, Vec<Vec<Fr>>) {
let mut instance = Vec::new();
for circuit in self.circuit.sub_circuits.iter() {
if !circuit.circuit.exposed.is_empty() {
let instance_values = circuit.circuit.instance(
witnesses
.get(&circuit.ir_id)
.expect("No matching witness found for given UUID."),
);
result.push(instance_values);
instance.push(instance_values);
}
}
result
// Proving
let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]);
let mut prover = create_prover(&self.setup, &instance, &mut transcript);
for phase in 0..self.setup.cs.phases() {
let mut assigned_witness =
vec![
Some(vec![Fr::default(); self.setup.params.n() as usize]);
self.setup.cs.num_advice_columns
];
for circuit in self.circuit.sub_circuits.iter() {
if let Some(assignments) = witnesses.get(&circuit.ir_id) {
assign_witness(circuit, assignments, &mut assigned_witness);
}
}
// TODO ignoring the challenges produced by the phase, but can they be useful later?
let _ = prover.commit_phase(phase as u8, assigned_witness).unwrap();
}
prover.create_proof().unwrap();
let proof = transcript.finalize();
(proof, instance)
}
}
impl<F: PrimeField + From<u64> + Hash> h2Circuit<F> for ChiquitoHalo2SuperCircuit<F> {
type Config = Vec<ChiquitoHalo2<F>>;
impl Halo2Prover for SingleCircuitProver<Fr> {
type W = Assignments<Fr>;
type FloorPlanner = SimpleFloorPlanner;
fn generate_proof(&self, witness: Self::W) -> (Vec<u8>, Vec<Vec<Fr>>) {
let mut instance = Vec::new();
type Params = Vec<ChiquitoHalo2<F>>;
fn without_witnesses(&self) -> Self {
Self::default()
}
fn params(&self) -> Self::Params {
self.sub_circuits.clone()
}
fn configure_with_params(
meta: &mut ConstraintSystem<F>,
mut sub_circuits: Self::Params,
) -> Self::Config {
sub_circuits
.iter_mut()
.for_each(|c| c.configure_columns_sub_circuit(meta));
let advice_columns: HashMap<UUID, Column<Advice>> =
sub_circuits.iter().fold(HashMap::default(), |mut acc, s| {
acc.extend(s.advice_columns.clone());
acc
});
let fixed_columns: HashMap<UUID, Column<Fixed>> =
sub_circuits.iter().fold(HashMap::default(), |mut acc, s| {
acc.extend(s.fixed_columns.clone());
acc
});
sub_circuits.iter_mut().for_each(|sub_circuit| {
sub_circuit.advice_columns = advice_columns.clone();
sub_circuit.fixed_columns = fixed_columns.clone();
sub_circuit.configure_sub_circuit(meta)
});
sub_circuits
}
fn synthesize(
&self,
sub_circuits: Self::Config,
mut layouter: impl Layouter<F>,
) -> Result<(), Error> {
for sub_circuit in sub_circuits {
sub_circuit.synthesize(&mut layouter, self.witness.get(&sub_circuit.ir_id))
if !self.circuit.circuit.exposed.is_empty() {
let instance_values = self.circuit.circuit.instance(&witness);
instance.push(instance_values);
}
Ok(())
}
// Proving
let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]);
fn configure(_: &mut ConstraintSystem<F>) -> Self::Config {
unreachable!()
let mut prover = create_prover(&self.setup, &instance, &mut transcript);
for phase in 0..self.setup.cs.phases() {
let mut assigned_witness =
vec![
Some(vec![Fr::default(); self.setup.params.n() as usize]);
self.setup.cs.num_advice_columns
];
assign_witness(&self.circuit, &witness, &mut assigned_witness);
// TODO ignoring the challenges produced by the phase, but can they be useful later?
let _ = prover.commit_phase(phase as u8, assigned_witness).unwrap();
}
prover.create_proof().unwrap();
let proof = transcript.finalize();
(proof, instance)
}
}
pub trait PlonkishHalo2<F: PrimeField, P: Halo2Prover> {
/// Create a Halo2 prover
///
/// ### Arguments
/// * `k` - logaritmic size of the circuit
/// * `rng` - random number generator
///
/// ### Returns
/// * a Halo2 prover
fn create_halo2_prover(&mut self, k: u32, rng: BlockRng<DummyRng>) -> P;
}
impl<TG: TraceGenerator<Fr> + Default> PlonkishHalo2<Fr, SingleCircuitProver<Fr>>
for PlonkishCompilationResult<Fr, TG>
{
fn create_halo2_prover(&mut self, k: u32, rng: BlockRng<DummyRng>) -> SingleCircuitProver<Fr> {
let mut circuit = ChiquitoHalo2::new(self.circuit.clone());
let compiled = compile_middleware(k, &mut circuit).unwrap();
let setup = create_setup(k, rng, compiled);
SingleCircuitProver { setup, circuit }
}
}
impl PlonkishHalo2<Fr, SuperCircuitProver<Fr>> for ChiquitoHalo2SuperCircuit<Fr> {
fn create_halo2_prover(&mut self, k: u32, rng: BlockRng<DummyRng>) -> SuperCircuitProver<Fr> {
let compiled = compile_middleware(k, self).unwrap();
let setup = create_setup(k, rng, compiled);
SuperCircuitProver {
circuit: self.clone(),
setup,
}
}
}
fn create_setup(k: u32, rng: BlockRng<DummyRng>, circuit: CompiledCircuit<Fr>) -> Setup {
let params = ParamsKZG::<Bn256>::setup::<BlockRng<DummyRng>>(k, rng.clone());
let vk = keygen_vk(&params, &circuit).expect("keygen_vk should not fail");
let pk = keygen_pk(&params, vk.clone(), &circuit).expect("keygen_pk should not fail");
Setup {
cs: circuit.cs,
params,
vk,
pk,
rng,
}
}
/// ⚠️ Not for production use! ⚠️
///
/// One-number generator that can be used as a deterministic Rng outputting fixed values.
#[derive(Clone)]
pub struct DummyRng {}
impl BlockRngCore for DummyRng {
type Item = u32;
type Results = [u32; 16];
fn generate(&mut self, results: &mut Self::Results) {
for elem in results.iter_mut() {
*elem = 1;
}
}
}

View File

@@ -1,3 +1,2 @@
pub mod halo2;
pub mod hyperplonk;
pub mod plaf;

View File

@@ -1,327 +0,0 @@
use std::{collections::HashMap, hash::Hash};
use halo2_proofs::halo2curves::ff::PrimeField;
use crate::{
plonkish::ir::{
assignments::Assignments,
Circuit as cCircuit, Column as cColumn,
ColumnType::{Advice as cAdvice, Fixed as cFixed, Halo2Advice, Halo2Fixed},
PolyExpr as cPolyExpr,
},
util::UUID,
};
use num_bigint::BigUint;
use polyexen::{
expr::{get_field_p, Column as pColumn, ColumnKind, ColumnQuery, Expr as pExpr, PlonkVar},
plaf::{
ColumnFixed, ColumnPublic, ColumnWitness, CopyC as pCopyC, Lookup as pLookup, Plaf,
Poly as pPoly, Witness as pWitness,
},
};
#[allow(non_snake_case)]
pub fn chiquito2Plaf<F: PrimeField<Repr = [u8; 32]>>(
circuit: cCircuit<F>,
k: u32,
debug: bool,
) -> (Plaf, ChiquitoPlafWitGen) {
let mut chiquito_plaf = ChiquitoPlaf::new(circuit, debug);
let plaf = chiquito_plaf.get_plaf(k);
let empty_witness = plaf.gen_empty_witness();
let wit_gen =
ChiquitoPlafWitGen::new(empty_witness, chiquito_plaf.c_column_id_to_p_column_index);
(plaf, wit_gen)
}
#[derive(Clone, Debug)]
pub struct ChiquitoPlaf<F: PrimeField> {
debug: bool,
circuit: cCircuit<F>,
// Chiquito column id doesn't start from zero.
// Plaf column index starts from 0 for each column type (advice, fixed, and instance).
// Therefore a mapping is needed to convert chiquito column id to plaf index.
c_column_id_to_p_column_index: HashMap<UUID, usize>,
}
impl<F: PrimeField<Repr = [u8; 32]>> ChiquitoPlaf<F> {
pub fn new(circuit: cCircuit<F>, debug: bool) -> ChiquitoPlaf<F> {
ChiquitoPlaf {
debug,
circuit,
c_column_id_to_p_column_index: HashMap::new(),
}
}
pub fn get_plaf(&mut self, k: u32) -> Plaf {
let mut plaf = Plaf::default();
let p = get_field_p::<F>();
plaf.info.p = p;
plaf.info.num_rows = 2usize.pow(k);
let mut c_column_id_to_p_column_index = HashMap::<UUID, usize>::new();
let mut advice_index = 0;
let mut fixed_index = 0;
for column in self.circuit.columns.iter() {
if self.debug {
println!("annotation: {}, id: {}", column.annotation, column.id);
}
self.convert_and_push_plaf_column(
column,
&mut plaf,
&mut c_column_id_to_p_column_index,
&mut advice_index,
&mut fixed_index,
);
if self.debug {
println!("MAP {:#?}", c_column_id_to_p_column_index);
}
}
self.c_column_id_to_p_column_index = c_column_id_to_p_column_index;
for c_poly in &mut self.circuit.polys.iter() {
let plaf_poly = pPoly {
name: c_poly.annotation.clone(),
exp: self.convert_plaf_poly(&c_poly.expr),
};
plaf.polys.push(plaf_poly);
}
for lookup in self.circuit.lookups.iter() {
let exps = lookup.exprs.clone().into_iter().fold(
(Vec::default(), Vec::default()),
|mut result, tuple| {
result.0.push(self.convert_plaf_poly(&tuple.0));
result.1.push(self.convert_plaf_poly(&tuple.1));
result
},
);
let plaf_lookup = pLookup {
name: lookup.annotation.clone(),
exps,
};
plaf.lookups.push(plaf_lookup);
}
// Fixed
let mut fixed: Vec<Vec<Option<BigUint>>> = Vec::with_capacity(plaf.columns.fixed.len());
for _i in 0..plaf.columns.fixed.len() {
fixed.push(vec![None; plaf.info.num_rows]);
}
for (column, values) in self.circuit.fixed_assignments.clone().0.into_iter() {
let column = self
.c_column_id_to_p_column_index
.get(&column.uuid())
.expect("plaf column not found for fixed signal");
for (offset, value) in values.iter().enumerate() {
// region.assign_fixed(|| "", *column, offset, || Value::known(value.clone()));
fixed[*column][offset] = Some(BigUint::from_bytes_le(&value.to_repr()));
}
}
plaf.fixed = fixed;
if !self.circuit.exposed.is_empty() {
// Public column not pulled from Chiquito ir, because it's not stored anywhere.
// Therefore, we create a Plaf public column from scratch.
let plaf_public = ColumnPublic::new(String::from(
"exposed forward signal values in first step instance",
));
plaf.columns.public.push(plaf_public);
}
for (index, (c_column, rotation)) in self.circuit.exposed.iter().enumerate() {
let public_column = pColumn {
kind: ColumnKind::Public,
index: 0, // Chiquito only has one public column, so the index is always 0.
};
let witness_index = self
.c_column_id_to_p_column_index
.get(&c_column.uuid())
.unwrap();
let witness_column = pColumn {
kind: ColumnKind::Witness,
index: *witness_index,
};
let copy = pCopyC {
columns: (public_column, witness_column),
offsets: vec![(index, *rotation as usize)],
};
plaf.copys.push(copy);
}
plaf
}
fn convert_and_push_plaf_column(
&self,
column: &cColumn,
plaf: &mut Plaf,
c_column_id_to_p_column_index: &mut HashMap<UUID, usize>,
advice_index: &mut usize,
fixed_index: &mut usize,
) {
match column.ctype {
cAdvice => {
let plaf_witness = ColumnWitness::new(column.annotation.clone(), column.phase);
self.add_id_index_mapping(column, c_column_id_to_p_column_index, advice_index);
plaf.columns.witness.push(plaf_witness);
}
cFixed => {
let plaf_fixed = ColumnFixed::new(column.annotation.clone());
self.add_id_index_mapping(column, c_column_id_to_p_column_index, fixed_index);
plaf.columns.fixed.push(plaf_fixed);
}
Halo2Advice => {
panic!("Imported Halo2Advice is not supported");
}
Halo2Fixed => {
panic!("Imported Halo2Fixed is not supported");
}
}
}
fn convert_plaf_poly(&self, chiquito_poly: &cPolyExpr<F>) -> pExpr<PlonkVar> {
match chiquito_poly {
cPolyExpr::Const(c, _) => pExpr::Const(BigUint::from_bytes_le(&c.to_repr())),
cPolyExpr::Sum(es, _) => {
let mut iter = es.iter();
let first = self.convert_plaf_poly(iter.next().unwrap());
iter.fold(first, |acc, e| acc + self.convert_plaf_poly(e))
}
cPolyExpr::Mul(es, _) => {
let mut iter = es.iter();
let first = self.convert_plaf_poly(iter.next().unwrap());
iter.fold(first, |acc, e| acc * self.convert_plaf_poly(e))
}
cPolyExpr::Neg(e, _) => -self.convert_plaf_poly(e),
cPolyExpr::Pow(e, n, _) => {
if *n == 0 {
pExpr::Const(BigUint::from(1u32))
} else {
let e = self.convert_plaf_poly(e);
(1..*n).fold(e.clone(), |acc, _| acc * e.clone())
}
}
cPolyExpr::Halo2Expr(e, _) => pExpr::from(e),
cPolyExpr::Query((column, rotation, annotation), _) => {
let index = self
.c_column_id_to_p_column_index
.get(&column.uuid())
.unwrap();
if self.debug {
println!(
"GET c column id {} match p column index {}",
column.uuid(),
index
);
println!("MAP {:#?}", self.c_column_id_to_p_column_index);
}
pExpr::Var(PlonkVar::Query(
self.convert_plaf_query(column, rotation, annotation, *index),
))
}
cPolyExpr::MI(_, _) => panic!("mi elimination not done"),
}
}
fn add_id_index_mapping(
&self,
column: &cColumn,
c_column_id_to_p_column_index: &mut HashMap<UUID, usize>,
counter: &mut usize,
) {
c_column_id_to_p_column_index.insert(column.uuid(), *counter);
if self.debug {
println!(
"c column id {} match p column index {}",
column.uuid(),
counter
);
}
*counter += 1;
}
fn convert_plaf_query(
&self,
column: &cColumn,
rotation: &i32,
_annotation: &str,
index: usize, // Plaf index starts from 0 for each column type.
) -> ColumnQuery {
match column.ctype {
cAdvice => ColumnQuery {
column: pColumn {
kind: ColumnKind::Witness,
index,
},
rotation: *rotation,
},
cFixed => ColumnQuery {
column: pColumn {
kind: ColumnKind::Fixed,
index,
},
rotation: *rotation,
},
Halo2Advice | Halo2Fixed => {
panic!("Imported Halo2Advice and Halo2Fixed are not supported")
}
}
}
}
pub struct ChiquitoPlafWitGen {
empty_witness: pWitness,
c_column_id_to_p_column_index: HashMap<UUID, usize>,
}
impl ChiquitoPlafWitGen {
fn new(empty_witness: pWitness, c_column_id_to_p_column_index: HashMap<UUID, usize>) -> Self {
Self {
empty_witness,
c_column_id_to_p_column_index,
}
}
pub fn generate<F: PrimeField<Repr = [u8; 32]> + Hash>(
&self,
witness: Option<Assignments<F>>,
) -> pWitness {
let mut plaf_witness = pWitness {
num_rows: self.empty_witness.num_rows,
columns: self.empty_witness.columns.clone(),
witness: self.empty_witness.witness.clone(),
};
if let Some(witness) = &witness {
for (column, assignments) in witness.iter() {
let p_column_index = self
.c_column_id_to_p_column_index
.get(&column.uuid())
.unwrap_or_else(|| panic!("plaf column not found for column {:?}", column));
for (offset, value) in assignments.iter().enumerate() {
plaf_witness.witness[*p_column_index][offset] =
Some(BigUint::from_bytes_le(&value.to_repr()));
}
}
plaf_witness
} else {
plaf_witness
}
}
}

View File

@@ -43,12 +43,20 @@ pub fn compile<
>(
config: CompilerConfig<CM, SSB>,
ast: &astCircuit<F, TG>,
) -> (Circuit<F>, Option<AssignmentGenerator<F, TG>>) {
) -> PlonkishCompilationResult<F, TG> {
let (mut unit, assignment) = compile_phase1(config, ast);
compile_phase2(&mut unit);
(unit.into(), assignment)
PlonkishCompilationResult {
circuit: unit.into(),
assignment_generator: assignment,
}
}
pub struct PlonkishCompilationResult<F, TG> {
pub circuit: Circuit<F>,
pub assignment_generator: Option<AssignmentGenerator<F, TG>>,
}
pub fn compile_phase1<
@@ -615,11 +623,13 @@ mod test {
let mock_ast_circuit = astCircuit::<Fr, NullTraceGenerator>::default();
let (circuit, assignment_generator) =
compile::<Fr, SingleRowCellManager, SimpleStepSelectorBuilder, NullTraceGenerator>(
config,
&mock_ast_circuit,
);
let PlonkishCompilationResult {
circuit,
assignment_generator,
} = compile::<Fr, SingleRowCellManager, SimpleStepSelectorBuilder, NullTraceGenerator>(
config,
&mock_ast_circuit,
);
assert_eq!(circuit.columns.len(), 1);
assert_eq!(circuit.exposed.len(), 0);

View File

@@ -15,6 +15,8 @@ pub mod sc;
#[derive(Clone, Default)]
pub struct Circuit<F> {
pub columns: Vec<Column>,
/// Exposed cells of the Column at the given rotation. Used to generate the instance
/// (equivalent to public inputs)
pub exposed: Vec<(Column, i32)>,
pub polys: Vec<Poly<F>>,