mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-02 13:53:07 +00:00
Merge 96ce399bb5405c9b52eb39467f1d357ff7ffd4bb into bdfb86b46e8f9749acc8bb8233cc78ee7eb6f4a5
This commit is contained in:
commit
c58122678f
@ -97,6 +97,10 @@ harness = false
|
||||
name = "reverse_index_bits"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "pi_gate_v2"
|
||||
harness = false
|
||||
|
||||
# Display math equations properly in documentation
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--html-in-header", ".cargo/katex-header.html"]
|
||||
|
||||
116
plonky2/benches/pi_gate_v2.rs
Normal file
116
plonky2/benches/pi_gate_v2.rs
Normal file
@ -0,0 +1,116 @@
|
||||
use std::any::type_name;
|
||||
use anyhow::{anyhow, Result};
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use plonky2::gates::noop::NoopGate;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, Poseidon2BN254Config, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||
|
||||
/// Benchmark for building, proving, and verifying the Plonky2 circuit.
|
||||
fn bench_circuit<F: RichField + Extendable<D>, const D:usize, C: GenericConfig<D, F = F>,>(c: &mut Criterion, circuit_size: usize, num_of_pi: usize) -> Result<()>{
|
||||
|
||||
// Create the circuit configuration
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let num_dummy_gates = match circuit_size {
|
||||
0 => return Err(anyhow!("size must be at least 1")),
|
||||
1 => 0,
|
||||
2 => 1,
|
||||
n => (1 << (n - 1)) + 1,
|
||||
};
|
||||
|
||||
for _ in 0..num_dummy_gates {
|
||||
builder.add_gate(NoopGate, vec![]);
|
||||
}
|
||||
|
||||
// The public inputs
|
||||
let mut t_list= vec![];
|
||||
for _ in 0..num_of_pi {
|
||||
let t = builder.add_virtual_public_input();
|
||||
t_list.push(t);
|
||||
}
|
||||
|
||||
// Benchmark Group
|
||||
let mut group = c.benchmark_group(format!("Circuit size = {}, pi size = {}, and Hasher = {}", circuit_size, num_of_pi, type_name::<C::Hasher>()));
|
||||
|
||||
// Benchmark the Circuit Building Phase
|
||||
group.bench_function("Build Circuit", |b| {
|
||||
b.iter(|| {
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut local_builder = CircuitBuilder::<F, D>::new(config);
|
||||
for _ in 0..num_dummy_gates {
|
||||
local_builder.add_gate(NoopGate, vec![]);
|
||||
}
|
||||
let _data = local_builder.build_unhashed_pi::<C>();
|
||||
})
|
||||
});
|
||||
|
||||
let data = builder.build_unhashed_pi::<C>();
|
||||
println!("Circuit size (degree bits): {:?}", data.common.degree_bits());
|
||||
|
||||
// Create a PartialWitness
|
||||
let mut pw = PartialWitness::new();
|
||||
for i in 0..num_of_pi {
|
||||
pw.set_target(t_list[i], F::ZERO)?;
|
||||
}
|
||||
|
||||
// Benchmark the Proving Phase
|
||||
group.bench_function("Prove Circuit", |b| {
|
||||
b.iter(|| {
|
||||
let local_pw = pw.clone();
|
||||
data.prove_unhashed_pi(local_pw).expect("Failed to prove circuit")
|
||||
})
|
||||
});
|
||||
|
||||
// Generate the proof once for verification benchmarking
|
||||
let proof_with_pis = data.prove_unhashed_pi(pw.clone()).expect("Failed to prove circuit");
|
||||
let verifier_data = data.verifier_data();
|
||||
|
||||
println!("Proof size: {} bytes", proof_with_pis.to_bytes().len());
|
||||
println!("num of pi = {}", proof_with_pis.public_inputs.len());
|
||||
|
||||
// Benchmark the Verifying Phase
|
||||
group.bench_function("Verify Proof", |b| {
|
||||
b.iter(|| {
|
||||
verifier_data.verify_unhashed_pi(proof_with_pis.clone()).expect("Failed to verify proof");
|
||||
})
|
||||
});
|
||||
|
||||
group.finish();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bench_multiple_pi_values(c: &mut Criterion){
|
||||
const D: usize = 2;
|
||||
type C1 = PoseidonGoldilocksConfig;
|
||||
type C2 = Poseidon2BN254Config;
|
||||
type F = GoldilocksField;
|
||||
|
||||
// bench_circuit::<F,D,C1>(c, 12, 10).expect("failed");
|
||||
// bench_circuit::<F,D,C2>(c, 12, 10).expect("failed");
|
||||
//
|
||||
// bench_circuit::<F,D,C1>(c, 12, 50).expect("failed");
|
||||
// bench_circuit::<F,D,C2>(c, 12, 50).expect("failed");
|
||||
//
|
||||
// bench_circuit::<F,D,C1>(c, 12, 100).expect("failed");
|
||||
// bench_circuit::<F,D,C2>(c, 12, 100).expect("failed");
|
||||
|
||||
// bench_circuit::<F,D,C1>(c, 12, 500).expect("failed");
|
||||
// bench_circuit::<F,D,C2>(c, 12, 500).expect("failed");
|
||||
|
||||
bench_circuit::<F,D,C1>(c, 12, 1000).expect("failed");
|
||||
bench_circuit::<F,D,C2>(c, 12, 1000).expect("failed");
|
||||
}
|
||||
|
||||
/// Criterion benchmark group
|
||||
criterion_group!{
|
||||
name = prove_verify_benches;
|
||||
config = Criterion::default().sample_size(10);
|
||||
targets = bench_multiple_pi_values
|
||||
}
|
||||
criterion_main!(prove_verify_benches);
|
||||
@ -247,6 +247,7 @@ where
|
||||
let prover_opts = ProverOptions {
|
||||
export_witness: Some(format!("{}_witness.json",name)),
|
||||
print_hash_statistics: HashStatisticsPrintLevel::Summary, // ::None,
|
||||
hash_public_input: true,
|
||||
};
|
||||
|
||||
let mut timing = TimingTree::new("prove", Level::Debug);
|
||||
@ -265,6 +266,7 @@ where
|
||||
|
||||
let verifier_opts = VerifierOptions {
|
||||
print_hash_statistics: HashStatisticsPrintLevel::Summary,
|
||||
hash_public_input: true,
|
||||
};
|
||||
data.verify_with_options(proof.clone(), &verifier_opts)?;
|
||||
|
||||
|
||||
@ -44,6 +44,7 @@ fn main() -> Result<()> {
|
||||
let prover_opts = ProverOptions {
|
||||
export_witness: Some(String::from("fibonacci_witness.json")),
|
||||
print_hash_statistics: HashStatisticsPrintLevel::Info,
|
||||
hash_public_input: true,
|
||||
};
|
||||
|
||||
let proof = data.prove_with_options(pw, &prover_opts)?;
|
||||
@ -55,6 +56,7 @@ fn main() -> Result<()> {
|
||||
|
||||
let verifier_opts = VerifierOptions {
|
||||
print_hash_statistics: HashStatisticsPrintLevel::Summary,
|
||||
hash_public_input: true,
|
||||
};
|
||||
data.verify_with_options(proof, &verifier_opts)
|
||||
|
||||
|
||||
@ -145,6 +145,7 @@ fn main() -> Result<()> {
|
||||
let prover_opts = ProverOptions {
|
||||
export_witness: Some(String::from("lookup_witness.json")),
|
||||
print_hash_statistics: HashStatisticsPrintLevel::None,
|
||||
hash_public_input: true,
|
||||
};
|
||||
let proof = data.prove_with_options(pw, &prover_opts)?;
|
||||
|
||||
|
||||
@ -89,6 +89,7 @@ fn main() -> Result<()> {
|
||||
let prover_opts = ProverOptions {
|
||||
export_witness: Some(String::from("multi_lookup_witness.json")),
|
||||
print_hash_statistics: HashStatisticsPrintLevel::None,
|
||||
hash_public_input: true,
|
||||
};
|
||||
let proof = data.prove_with_options(pw, &prover_opts)?;
|
||||
|
||||
|
||||
74
plonky2/examples/pi_gate_v2.rs
Normal file
74
plonky2/examples/pi_gate_v2.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use std::fs;
|
||||
use anyhow::Result;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::gates::noop::NoopGate;
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{Poseidon2BN254Config, PoseidonGoldilocksConfig};
|
||||
use plonky2::plonk::prover::ProverOptions;
|
||||
use plonky2::plonk::verifier::{HashStatisticsPrintLevel, VerifierOptions};
|
||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||
|
||||
/// An example of using Plonky2 to prove a circuit with size S
|
||||
/// and with P number of public inputs
|
||||
/// uses the `PublicInputGateV2` which doesn't hash the public input
|
||||
fn main() -> Result<()> {
|
||||
const D: usize = 2;
|
||||
|
||||
type C1 = PoseidonGoldilocksConfig;
|
||||
type C2 = Poseidon2BN254Config;
|
||||
type F = GoldilocksField;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
const S: usize = 5;
|
||||
let num_dummy_gates = (1 << (S - 1)) + 1;
|
||||
for _ in 0..num_dummy_gates {
|
||||
builder.add_gate(NoopGate, vec![]);
|
||||
}
|
||||
|
||||
const P: usize = 1000;
|
||||
// The public inputs
|
||||
let mut t_list= vec![];
|
||||
for _ in 0..P {
|
||||
let t = builder.add_virtual_public_input();
|
||||
t_list.push(t);
|
||||
}
|
||||
|
||||
// Provide initial values.
|
||||
let mut pw = PartialWitness::new();
|
||||
for i in 0..P {
|
||||
pw.set_target(t_list[i], F::ZERO)?;
|
||||
}
|
||||
|
||||
let data = builder.build_unhashed_pi::<C1>();
|
||||
println!("circuit size = {}", data.common.degree_bits());
|
||||
|
||||
let prover_opts = ProverOptions {
|
||||
export_witness: Some(String::from("pi_gate_v2_witness.json")),
|
||||
print_hash_statistics: HashStatisticsPrintLevel::Info,
|
||||
hash_public_input: false,
|
||||
};
|
||||
|
||||
let proof = data.prove_with_options(pw, &prover_opts)?;
|
||||
println!("num pi = {}", proof.public_inputs.len());
|
||||
|
||||
let verifier_opts = VerifierOptions {
|
||||
print_hash_statistics: HashStatisticsPrintLevel::Summary,
|
||||
hash_public_input: false,
|
||||
};
|
||||
|
||||
let common_circuit_data_serialized = serde_json::to_string(&data.common).unwrap();
|
||||
let verifier_only_circuit_data_serialized = serde_json::to_string(&data.verifier_only).unwrap();
|
||||
let proof_serialized = serde_json::to_string(&proof).unwrap();
|
||||
fs::write("pi_gate_v2_common.json", common_circuit_data_serialized ).expect("Unable to write file");
|
||||
fs::write("pi_gate_v2_vkey.json" , verifier_only_circuit_data_serialized ).expect("Unable to write file");
|
||||
fs::write("pi_gate_v2_proof.json" , proof_serialized ).expect("Unable to write file");
|
||||
|
||||
|
||||
assert!(data.verify_with_options(proof, &verifier_opts).is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -43,6 +43,7 @@ fn main() -> Result<()> {
|
||||
|
||||
let verifier_opts = VerifierOptions {
|
||||
print_hash_statistics: HashStatisticsPrintLevel::Summary,
|
||||
hash_public_input: true,
|
||||
};
|
||||
|
||||
assert!(data.verify_with_options(proof, &verifier_opts).is_ok());
|
||||
|
||||
87
plonky2/examples/recursive_pi_gate_v2.rs
Normal file
87
plonky2/examples/recursive_pi_gate_v2.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use anyhow::Result;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::gates::noop::NoopGate;
|
||||
use plonky2::iop::target::Target;
|
||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{Poseidon2BN254Config, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||
|
||||
/// An example of using Plonky2 to prove a proof in-circuit
|
||||
/// and with P number of public inputs
|
||||
/// uses the `PublicInputGateV2` which doesn't hash the public input
|
||||
fn main() -> Result<()> {
|
||||
const D: usize = 2;
|
||||
type C1 = PoseidonGoldilocksConfig;
|
||||
type C2 = Poseidon2BN254Config;
|
||||
type F = GoldilocksField;
|
||||
|
||||
//---------- inner layer ------------
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
const S: usize = 5;
|
||||
let num_dummy_gates = (1 << (S - 1)) + 1;
|
||||
for _ in 0..num_dummy_gates {
|
||||
builder.add_gate(NoopGate, vec![]);
|
||||
}
|
||||
|
||||
const P: usize = 150;
|
||||
// The public inputs
|
||||
let mut t_list= vec![];
|
||||
for _ in 0..P {
|
||||
let t = builder.add_virtual_public_input();
|
||||
t_list.push(t);
|
||||
}
|
||||
|
||||
// Provide initial values.
|
||||
let mut pw = PartialWitness::new();
|
||||
for i in 0..P {
|
||||
pw.set_target(t_list[i], F::ZERO)?;
|
||||
}
|
||||
|
||||
let data = builder.build::<C1>();
|
||||
println!("inner layer: circuit size = {}", data.common.degree_bits());
|
||||
|
||||
let proof = data.prove(pw)?;
|
||||
println!("inner layer: num pi = {}", proof.public_inputs.len());
|
||||
|
||||
assert!(data.verify(proof.clone()).is_ok());
|
||||
|
||||
//------------ outer layer ----------------
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let proof_t = builder.add_virtual_proof_with_pis(&data.common);
|
||||
let verifier_data_t = builder.add_virtual_verifier_data(builder.config.fri_config.cap_height);
|
||||
builder.verify_proof::<C1>(&proof_t, &verifier_data_t, &data.common);
|
||||
|
||||
let mut t_list: Vec<Target> = vec![];
|
||||
|
||||
for (i,pi) in proof_t.public_inputs.iter().enumerate() {
|
||||
let t = builder.add_virtual_public_input();
|
||||
builder.connect(*pi,t.clone());
|
||||
t_list.push(t);
|
||||
}
|
||||
|
||||
// Provide initial values.
|
||||
let mut pw = PartialWitness::new();
|
||||
for i in 0..P {
|
||||
pw.set_target(t_list[i], F::ZERO)?;
|
||||
}
|
||||
pw.set_proof_with_pis_target(&proof_t,&proof);
|
||||
pw.set_verifier_data_target(&verifier_data_t,&data.verifier_only);
|
||||
|
||||
let data = builder.build_unhashed_pi::<C1>();
|
||||
println!("outer layer: circuit size = {}", data.common.degree_bits());
|
||||
|
||||
let proof = data.prove_unhashed_pi(pw)?;
|
||||
println!("outer layer: num pi = {}", proof.public_inputs.len());
|
||||
|
||||
assert!(data.verify_unhashed_pi(proof.clone()).is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -864,6 +864,7 @@ mod tests {
|
||||
local_constants: &[],
|
||||
local_wires: &get_wires(shift, values, eval_point),
|
||||
public_inputs_hash: &HashOut::rand(),
|
||||
public_inputs: &[F::rand()],
|
||||
};
|
||||
|
||||
assert!(
|
||||
|
||||
@ -430,6 +430,7 @@ mod tests {
|
||||
local_constants: &[],
|
||||
local_wires: &get_wires(base, power as u64),
|
||||
public_inputs_hash: &HashOut::rand(),
|
||||
public_inputs: &[F::rand()],
|
||||
};
|
||||
assert!(
|
||||
gate.eval_unfiltered(vars).iter().all(|x| x.is_zero()),
|
||||
|
||||
@ -99,10 +99,12 @@ pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + S
|
||||
.map(|w| F::Extension::from_basefield(*w))
|
||||
.collect::<Vec<_>>();
|
||||
let public_inputs_hash = &vars_base.public_inputs_hash;
|
||||
let public_inputs = &vars_base.public_inputs;
|
||||
let vars = EvaluationVars {
|
||||
local_constants,
|
||||
local_wires,
|
||||
public_inputs_hash,
|
||||
public_inputs,
|
||||
};
|
||||
let values = self.eval_unfiltered(vars);
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ pub fn test_low_degree<F: RichField + Extendable<D>, G: Gate<F, D>, const D: usi
|
||||
let constant_ldes = random_low_degree_matrix::<F::Extension>(gate.num_constants(), rate_bits);
|
||||
assert_eq!(wire_ldes.len(), constant_ldes.len());
|
||||
let public_inputs_hash = &HashOut::rand();
|
||||
let pi_rand = F::rand_vec(4);
|
||||
|
||||
let constraint_evals = wire_ldes
|
||||
.iter()
|
||||
@ -36,6 +37,7 @@ pub fn test_low_degree<F: RichField + Extendable<D>, G: Gate<F, D>, const D: usi
|
||||
local_constants,
|
||||
local_wires,
|
||||
public_inputs_hash,
|
||||
public_inputs: &pi_rand,
|
||||
})
|
||||
.map(|vars| gate.eval_unfiltered(vars))
|
||||
.collect::<Vec<_>>();
|
||||
@ -107,13 +109,16 @@ pub fn test_eval_fns<
|
||||
.collect::<Vec<_>>();
|
||||
let public_inputs_hash = HashOut::rand();
|
||||
|
||||
let rand_pi = F::rand_vec(4);
|
||||
|
||||
// Batch of 1.
|
||||
let vars_base_batch =
|
||||
EvaluationVarsBaseBatch::new(1, &constants_base, &wires_base, &public_inputs_hash);
|
||||
EvaluationVarsBaseBatch::new(1, &constants_base, &wires_base, &public_inputs_hash, &rand_pi);
|
||||
let vars = EvaluationVars {
|
||||
local_constants: &constants,
|
||||
local_wires: &wires,
|
||||
public_inputs_hash: &public_inputs_hash,
|
||||
public_inputs: &rand_pi
|
||||
};
|
||||
|
||||
let evals_base = gate.eval_unfiltered_base_batch(vars_base_batch);
|
||||
@ -146,6 +151,7 @@ pub fn test_eval_fns<
|
||||
local_constants: &constants,
|
||||
local_wires: &wires,
|
||||
public_inputs_hash: &public_inputs_hash,
|
||||
public_inputs: &rand_pi,
|
||||
};
|
||||
let evals = gate.eval_unfiltered(vars);
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ pub mod packed_util;
|
||||
pub mod poseidon;
|
||||
pub mod poseidon_mds;
|
||||
pub mod public_input;
|
||||
pub mod public_input_v2;
|
||||
pub mod random_access;
|
||||
pub mod reducing;
|
||||
pub mod reducing_extension;
|
||||
|
||||
170
plonky2/src/gates/public_input_v2.rs
Normal file
170
plonky2/src/gates/public_input_v2.rs
Normal file
@ -0,0 +1,170 @@
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::ops::Range;
|
||||
|
||||
use crate::field::extension::Extendable;
|
||||
use crate::field::packed::PackedField;
|
||||
use crate::gates::gate::Gate;
|
||||
use crate::gates::packed_util::PackedEvaluableBase;
|
||||
use crate::gates::util::StridedConstraintConsumer;
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::iop::ext_target::ExtensionTarget;
|
||||
use crate::iop::generator::WitnessGeneratorRef;
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CommonCircuitData;
|
||||
use crate::plonk::vars::{
|
||||
EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch,
|
||||
EvaluationVarsBasePacked,
|
||||
};
|
||||
use crate::util::serialization::{Buffer, IoResult, Read, Write};
|
||||
|
||||
/// A gate which enforces that each wire matches a corresponding public-input element.
|
||||
///
|
||||
/// Specifically, if this gate has `num_pub_inputs` wires, then for each wire i in
|
||||
/// [0..num_pub_inputs):
|
||||
///
|
||||
/// local_wires[i] == public_inputs[i]
|
||||
///
|
||||
/// If the circuit has more public inputs than the circuit config's `num_wires` you'll need multiple gates
|
||||
#[derive(Debug)]
|
||||
pub struct PublicInputGateV2 {
|
||||
/// How many public inputs are enforced by this gate.
|
||||
pub num_pub_inputs: usize,
|
||||
/// start index from which we take the public input
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl PublicInputGateV2 {
|
||||
|
||||
/// careful with this fn, you must ensure `num_pub_inputs` <= the circuit config's `num_wires`.
|
||||
pub fn new(num_pub_inputs: usize, index: usize) -> Self {
|
||||
Self {
|
||||
num_pub_inputs,
|
||||
index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D> for PublicInputGateV2 {
|
||||
fn id(&self) -> String {
|
||||
"PublicInputGateV2".into()
|
||||
}
|
||||
|
||||
fn short_id(&self) -> String {
|
||||
"PublicInputGateV2".into()
|
||||
}
|
||||
|
||||
fn serialize(
|
||||
&self,
|
||||
dst: &mut Vec<u8>,
|
||||
_common_data: &CommonCircuitData<F, D>,
|
||||
) -> IoResult<()> {
|
||||
dst.write_usize(self.num_pub_inputs)?;
|
||||
dst.write_usize(self.index)
|
||||
}
|
||||
|
||||
fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData<F, D>) -> IoResult<Self> {
|
||||
let num_pub_inputs = src.read_usize()?;
|
||||
let index = src.read_usize()?;
|
||||
|
||||
Ok(Self {
|
||||
num_pub_inputs,
|
||||
index
|
||||
})
|
||||
}
|
||||
|
||||
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
|
||||
// For each i in [0..num_pub_inputs], the constraint is: local_wires[i] - public_inputs[i]
|
||||
// That must be 0 if the public input is correct.
|
||||
(0..self.num_pub_inputs)
|
||||
.map(|i| {
|
||||
let wire_value = vars.local_wires[i];
|
||||
let pi_value = vars.public_inputs[self.index + i].into();
|
||||
wire_value - pi_value
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn eval_unfiltered_base_one(
|
||||
&self,
|
||||
_vars: EvaluationVarsBase<F>,
|
||||
_yield_constr: StridedConstraintConsumer<F>,
|
||||
) {
|
||||
panic!("use eval_unfiltered_base_packed instead");
|
||||
}
|
||||
|
||||
fn eval_unfiltered_base_batch(&self, vars_base: EvaluationVarsBaseBatch<F>) -> Vec<F> {
|
||||
self.eval_unfiltered_base_batch_packed(vars_base)
|
||||
}
|
||||
|
||||
fn eval_unfiltered_circuit(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
vars: EvaluationTargets<D>,
|
||||
) -> Vec<ExtensionTarget<D>> {
|
||||
todo!()
|
||||
// // Circuit-level version of the same logic.
|
||||
// (0..self.num_pub_inputs)
|
||||
// .map(|i| {
|
||||
// // local_wires[i] - public_inputs[i]
|
||||
// let pi_part_ex = builder.convert_to_ext(vars.public_inputs[self.index + i]);
|
||||
// builder.sub_extension(vars.local_wires[i], pi_part_ex)
|
||||
// })
|
||||
// .collect()
|
||||
}
|
||||
|
||||
fn generators(&self, _row: usize, _local_constants: &[F]) -> Vec<WitnessGeneratorRef<F, D>> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn num_wires(&self) -> usize {
|
||||
self.num_pub_inputs
|
||||
}
|
||||
|
||||
fn num_constants(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn degree(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn num_constraints(&self) -> usize {
|
||||
self.num_pub_inputs
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> PackedEvaluableBase<F, D> for PublicInputGateV2 {
|
||||
fn eval_unfiltered_base_packed<P: PackedField<Scalar = F>>(
|
||||
&self,
|
||||
vars: EvaluationVarsBasePacked<P>,
|
||||
mut yield_constr: StridedConstraintConsumer<P>,
|
||||
) {
|
||||
yield_constr.many(
|
||||
(0..self.num_pub_inputs).map(|i| vars.local_wires[i] - vars.public_inputs[self.index + i]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::field::goldilocks_field::GoldilocksField;
|
||||
use crate::gates::gate_testing::{test_eval_fns, test_low_degree};
|
||||
use crate::gates::public_input_v2::PublicInputGateV2;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
#[test]
|
||||
fn pi_v2_low_degree() {
|
||||
test_low_degree::<GoldilocksField, _, 4>(PublicInputGateV2{num_pub_inputs:4,index:0})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pi_v2_eval_fns() -> anyhow::Result<()> {
|
||||
todo!()
|
||||
// const D: usize = 2;
|
||||
// type C = PoseidonGoldilocksConfig;
|
||||
// type F = <C as GenericConfig<D>>::F;
|
||||
// test_eval_fns::<F, C, _, D>(PublicInputGateV2{num_pub_inputs:4,index:0})
|
||||
}
|
||||
}
|
||||
@ -526,6 +526,7 @@ mod tests {
|
||||
&constants,
|
||||
),
|
||||
public_inputs_hash: &HashOut::rand(),
|
||||
public_inputs: &[F::rand()],
|
||||
};
|
||||
let bad_claimed_elements = F::rand_vec(4);
|
||||
let bad_vars = EvaluationVars {
|
||||
@ -538,6 +539,7 @@ mod tests {
|
||||
&constants,
|
||||
),
|
||||
public_inputs_hash: &HashOut::rand(),
|
||||
public_inputs: &[F::rand()],
|
||||
};
|
||||
|
||||
assert!(
|
||||
|
||||
@ -36,6 +36,8 @@ pub fn test_gate_constraints<F: RichField + Extendable<D>, const D: usize>() {
|
||||
[ make_fext::<F,D>(666)
|
||||
, make_fext::<F,D>(77)
|
||||
];
|
||||
|
||||
let pi = F::rand_vec(4);
|
||||
let input_hash = HashOut{ elements:
|
||||
[ F::from_canonical_u64(101)
|
||||
, F::from_canonical_u64(102)
|
||||
@ -47,7 +49,8 @@ pub fn test_gate_constraints<F: RichField + Extendable<D>, const D: usize>() {
|
||||
let vars = EvaluationVars
|
||||
{ local_constants: &loc_constants
|
||||
, local_wires: &loc_wires
|
||||
, public_inputs_hash: &input_hash
|
||||
, public_inputs_hash: &input_hash
|
||||
, public_inputs: &pi
|
||||
};
|
||||
|
||||
let circuit_config: CircuitConfig = CircuitConfig::standard_recursion_config();
|
||||
|
||||
@ -30,6 +30,7 @@ use crate::gates::lookup::{Lookup, LookupGate};
|
||||
use crate::gates::lookup_table::LookupTable;
|
||||
use crate::gates::noop::NoopGate;
|
||||
use crate::gates::public_input::PublicInputGate;
|
||||
use crate::gates::public_input_v2::PublicInputGateV2;
|
||||
use crate::gates::selectors::{selector_ends_lookups, selector_polynomials, selectors_lookup};
|
||||
use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget, RichField};
|
||||
use crate::hash::merkle_proofs::MerkleProofTarget;
|
||||
@ -1061,8 +1062,9 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
pub fn build_with_options<C: GenericConfig<D, F = F>>(
|
||||
self,
|
||||
commit_to_sigma: bool,
|
||||
hash_public_input: bool,
|
||||
) -> CircuitData<F, C, D> {
|
||||
let (circuit_data, success) = self.try_build_with_options(commit_to_sigma);
|
||||
let (circuit_data, success) = self.try_build_with_options(commit_to_sigma, hash_public_input);
|
||||
if !success {
|
||||
panic!("Failed to build circuit");
|
||||
}
|
||||
@ -1072,6 +1074,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
pub fn try_build_with_options<C: GenericConfig<D, F = F>>(
|
||||
mut self,
|
||||
commit_to_sigma: bool,
|
||||
hash_public_input: bool,
|
||||
) -> (CircuitData<F, C, D>, bool) {
|
||||
let mut timing = TimingTree::new("preprocess", Level::Trace);
|
||||
|
||||
@ -1085,21 +1088,52 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
// Hash the public inputs, and route them to a `PublicInputGate` which will enforce that
|
||||
// those hash wires match the claimed public inputs.
|
||||
let num_public_inputs = self.public_inputs.len();
|
||||
let public_inputs_hash =
|
||||
self.hash_n_to_hash_no_pad::<C::InnerHasher>(self.public_inputs.clone());
|
||||
let pi_gate = self.add_gate(PublicInputGate, vec![]);
|
||||
for (&hash_part, wire) in public_inputs_hash
|
||||
.elements
|
||||
.iter()
|
||||
.zip(PublicInputGate::wires_public_inputs_hash())
|
||||
{
|
||||
self.connect(hash_part, Target::wire(pi_gate, wire))
|
||||
}
|
||||
|
||||
// See <https://github.com/0xPolygonZero/plonky2/issues/456>
|
||||
// however randomization makes debugging harder as runs are not deterministic
|
||||
if self.config.randomize_unused_wires {
|
||||
self.randomize_unused_pi_wires(pi_gate);
|
||||
// only hash public input if flag is set
|
||||
if hash_public_input {
|
||||
let public_inputs_hash =
|
||||
self.hash_n_to_hash_no_pad::<C::InnerHasher>(self.public_inputs.clone());
|
||||
let pi_gate = self.add_gate(PublicInputGate, vec![]);
|
||||
for (&hash_part, wire) in public_inputs_hash
|
||||
.elements
|
||||
.iter()
|
||||
.zip(PublicInputGate::wires_public_inputs_hash())
|
||||
{
|
||||
self.connect(hash_part, Target::wire(pi_gate, wire))
|
||||
}
|
||||
|
||||
// See <https://github.com/0xPolygonZero/plonky2/issues/456>
|
||||
// however randomization makes debugging harder as runs are not deterministic
|
||||
if self.config.randomize_unused_wires {
|
||||
self.randomize_unused_pi_wires(pi_gate);
|
||||
}
|
||||
} else {
|
||||
let num_of_routed_wires = self.config.num_routed_wires;
|
||||
let num_of_pi_gates = num_public_inputs.div_ceil(num_of_routed_wires);
|
||||
let mut pi_gates = vec![];
|
||||
let all_pi = self.public_inputs.clone();
|
||||
for i in 0..num_of_pi_gates{
|
||||
// start index
|
||||
let start_i = i*num_of_routed_wires;
|
||||
// make sure we do not go past the number of public inputs.
|
||||
let end_i = core::cmp::min(start_i + num_of_routed_wires, num_public_inputs);
|
||||
// the number of public inputs in this gate.
|
||||
let num_pi_in_gate = end_i - start_i;
|
||||
|
||||
let pi_gate = self.add_gate(
|
||||
PublicInputGateV2::new(num_pi_in_gate, start_i)
|
||||
, vec![]);
|
||||
|
||||
// connect
|
||||
let wire_range = 0..num_pi_in_gate;
|
||||
for (&pi_part, wire) in all_pi[start_i .. end_i]
|
||||
.iter()
|
||||
.zip(wire_range)
|
||||
{
|
||||
self.connect(pi_part, Target::wire(pi_gate, wire))
|
||||
}
|
||||
pi_gates.push(pi_gate);
|
||||
}
|
||||
}
|
||||
|
||||
// Place LUT-related gates.
|
||||
@ -1329,11 +1363,17 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
|
||||
/// Builds a "full circuit", with both prover and verifier data.
|
||||
pub fn build<C: GenericConfig<D, F = F>>(self) -> CircuitData<F, C, D> {
|
||||
self.build_with_options(true)
|
||||
self.build_with_options(true, true)
|
||||
}
|
||||
|
||||
/// Builds a "full circuit", with both prover and verifier data.
|
||||
/// the public input are not hashed when calling this function
|
||||
pub fn build_unhashed_pi<C: GenericConfig<D, F = F>>(self) -> CircuitData<F, C, D> {
|
||||
self.build_with_options(true, false)
|
||||
}
|
||||
|
||||
pub fn mock_build<C: GenericConfig<D, F = F>>(self) -> MockCircuitData<F, C, D> {
|
||||
let circuit_data = self.build_with_options(false);
|
||||
let circuit_data = self.build_with_options(false, true);
|
||||
MockCircuitData {
|
||||
prover_only: circuit_data.prover_only,
|
||||
common: circuit_data.common,
|
||||
|
||||
@ -46,8 +46,8 @@ use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::config::{GenericConfig, Hasher};
|
||||
use crate::plonk::plonk_common::PlonkOracle;
|
||||
use crate::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs};
|
||||
use crate::plonk::prover::{prove, prove_with_options, ProverOptions};
|
||||
use crate::plonk::verifier::{verify, verify_with_options, VerifierOptions};
|
||||
use crate::plonk::prover::{prove, prove_unhashed_pi, prove_with_options, ProverOptions};
|
||||
use crate::plonk::verifier::{verify, verify_with_options, VerifierOptions, verify_unhashed_pi};
|
||||
use crate::util::serialization::{
|
||||
Buffer, GateSerializer, IoResult, Read, WitnessGeneratorSerializer, Write,
|
||||
};
|
||||
@ -199,6 +199,15 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prove_unhashed_pi(&self, inputs: PartialWitness<F>) -> Result<ProofWithPublicInputs<F, C, D>> {
|
||||
prove_unhashed_pi::<F, C, D>(
|
||||
&self.prover_only,
|
||||
&self.common,
|
||||
inputs,
|
||||
&mut TimingTree::default(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prove_with_options(&self, inputs: PartialWitness<F>, opts: &ProverOptions) -> Result<ProofWithPublicInputs<F, C, D>> {
|
||||
prove_with_options::<F, C, D>(
|
||||
&self.prover_only,
|
||||
@ -213,6 +222,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
verify::<F, C, D>(proof_with_pis, &self.verifier_only, &self.common)
|
||||
}
|
||||
|
||||
pub fn verify_unhashed_pi(&self, proof_with_pis: ProofWithPublicInputs<F, C, D>) -> Result<()> {
|
||||
verify_unhashed_pi::<F, C, D>(proof_with_pis, &self.verifier_only, &self.common)
|
||||
}
|
||||
|
||||
pub fn verify_with_options(&self, proof_with_pis: ProofWithPublicInputs<F, C, D>, verifier_options: &VerifierOptions) -> Result<()> {
|
||||
verify_with_options::<F, C, D>(proof_with_pis, &self.verifier_only, &self.common, verifier_options)
|
||||
}
|
||||
@ -302,6 +315,15 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
buffer.read_prover_circuit_data(gate_serializer, generator_serializer)
|
||||
}
|
||||
|
||||
pub fn prove_unhashed_pi(&self, inputs: PartialWitness<F>) -> Result<ProofWithPublicInputs<F, C, D>> {
|
||||
prove_unhashed_pi::<F, C, D>(
|
||||
&self.prover_only,
|
||||
&self.common,
|
||||
inputs,
|
||||
&mut TimingTree::default(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prove(&self, inputs: PartialWitness<F>) -> Result<ProofWithPublicInputs<F, C, D>> {
|
||||
prove::<F, C, D>(
|
||||
&self.prover_only,
|
||||
@ -354,6 +376,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
verify::<F, C, D>(proof_with_pis, &self.verifier_only, &self.common)
|
||||
}
|
||||
|
||||
pub fn verify_unhashed_pi(&self, proof_with_pis: ProofWithPublicInputs<F, C, D>) -> Result<()> {
|
||||
verify_unhashed_pi::<F, C, D>(proof_with_pis, &self.verifier_only, &self.common)
|
||||
}
|
||||
|
||||
pub fn verify_compressed(
|
||||
&self,
|
||||
compressed_proof_with_pis: CompressedProofWithPublicInputs<F, C, D>,
|
||||
|
||||
@ -15,7 +15,7 @@ use crate::iop::challenger::{Challenger, RecursiveChallenger};
|
||||
use crate::iop::target::Target;
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CommonCircuitData;
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher};
|
||||
use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, IntoGenericFieldVec};
|
||||
use crate::plonk::proof::{
|
||||
CompressedProof, CompressedProofWithPublicInputs, FriInferredElements, OpeningSet,
|
||||
OpeningSetTarget, Proof, ProofChallenges, ProofChallengesTarget, ProofTarget,
|
||||
@ -24,6 +24,7 @@ use crate::plonk::proof::{
|
||||
use crate::util::reverse_bits;
|
||||
|
||||
fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
public_inputs: Option<Vec<F>>,
|
||||
public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
|
||||
wires_cap: &MerkleCap<F, C::Hasher>,
|
||||
plonk_zs_partial_products_cap: &MerkleCap<F, C::Hasher>,
|
||||
@ -34,6 +35,7 @@ fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, cons
|
||||
pow_witness: F,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
hash_public_input: bool,
|
||||
) -> anyhow::Result<ProofChallenges<F, D>> {
|
||||
let config = &common_data.config;
|
||||
let num_challenges = config.num_challenges;
|
||||
@ -43,7 +45,12 @@ fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, cons
|
||||
|
||||
// Observe the instance.
|
||||
challenger.observe_hash::<C::Hasher>(*circuit_digest);
|
||||
challenger.observe_hash::<C::InnerHasher>(public_inputs_hash);
|
||||
if hash_public_input {
|
||||
challenger.observe_hash::<C::InnerHasher>(public_inputs_hash);
|
||||
} else {
|
||||
let pi_felts = public_inputs.unwrap().into_generic_field_vec();
|
||||
challenger.observe_elements(&pi_felts);
|
||||
}
|
||||
|
||||
challenger.observe_cap::<C::Hasher>(wires_cap);
|
||||
let plonk_betas = challenger.get_n_challenges(num_challenges);
|
||||
@ -98,9 +105,11 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
&self,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
hash_public_input: bool,
|
||||
) -> anyhow::Result<Vec<usize>> {
|
||||
let pi = if hash_public_input { None } else {Some(self.public_inputs.clone())};
|
||||
Ok(self
|
||||
.get_challenges(self.get_public_inputs_hash(), circuit_digest, common_data)?
|
||||
.get_challenges(pi, self.get_public_inputs_hash(), circuit_digest, common_data, hash_public_input)?
|
||||
.fri_challenges
|
||||
.fri_query_indices)
|
||||
}
|
||||
@ -108,9 +117,11 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
/// Computes all Fiat-Shamir challenges used in the Plonk proof.
|
||||
pub fn get_challenges(
|
||||
&self,
|
||||
public_inputs: Option<Vec<F>>,
|
||||
public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
hash_public_input: bool,
|
||||
) -> anyhow::Result<ProofChallenges<F, D>> {
|
||||
let Proof {
|
||||
wires_cap,
|
||||
@ -126,19 +137,25 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
},
|
||||
} = &self.proof;
|
||||
|
||||
get_challenges::<F, C, D>(
|
||||
public_inputs_hash,
|
||||
wires_cap,
|
||||
plonk_zs_partial_products_cap,
|
||||
quotient_polys_cap,
|
||||
openings,
|
||||
commit_phase_merkle_caps,
|
||||
final_poly,
|
||||
*pow_witness,
|
||||
circuit_digest,
|
||||
common_data,
|
||||
)
|
||||
let challenges =
|
||||
get_challenges::<F, C, D>(
|
||||
public_inputs,
|
||||
public_inputs_hash,
|
||||
wires_cap,
|
||||
plonk_zs_partial_products_cap,
|
||||
quotient_polys_cap,
|
||||
openings,
|
||||
commit_phase_merkle_caps,
|
||||
final_poly,
|
||||
*pow_witness,
|
||||
circuit_digest,
|
||||
common_data,
|
||||
hash_public_input
|
||||
);
|
||||
|
||||
challenges
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
@ -166,6 +183,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
} = &self.proof;
|
||||
|
||||
get_challenges::<F, C, D>(
|
||||
None,
|
||||
public_inputs_hash,
|
||||
wires_cap,
|
||||
plonk_zs_partial_products_cap,
|
||||
@ -176,6 +194,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
*pow_witness,
|
||||
circuit_digest,
|
||||
common_data,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -93,7 +93,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
circuit_digest: &<<C as GenericConfig<D>>::Hasher as Hasher<C::F>>::Hash,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<CompressedProofWithPublicInputs<F, C, D>> {
|
||||
let indices = self.fri_query_indices(circuit_digest, common_data)?;
|
||||
let indices = self.fri_query_indices(circuit_digest, common_data, true)?;
|
||||
let compressed_proof = self.proof.compress(&indices, &common_data.fri_params);
|
||||
Ok(CompressedProofWithPublicInputs {
|
||||
public_inputs: self.public_inputs,
|
||||
@ -224,6 +224,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
.decompress(&challenges, fri_inferred_elements, &common_data.fri_params);
|
||||
verify_with_challenges::<F, C, D>(
|
||||
decompressed_proof,
|
||||
self.public_inputs,
|
||||
public_inputs_hash,
|
||||
challenges,
|
||||
verifier_data,
|
||||
|
||||
@ -22,7 +22,7 @@ use crate::fri::oracle::PolynomialBatch;
|
||||
use crate::gates::lookup::LookupGate;
|
||||
use crate::gates::lookup_table::LookupTableGate;
|
||||
use crate::gates::selectors::{LookupSelectors};
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::hash::hash_types::{HashOut, RichField};
|
||||
use crate::hash::hashing::*;
|
||||
use crate::iop::challenger::Challenger;
|
||||
use crate::iop::generator::generate_partial_witness;
|
||||
@ -123,11 +123,19 @@ pub fn set_lookup_wires<
|
||||
pub struct ProverOptions {
|
||||
pub export_witness: Option<String>, // export the full witness into the given file
|
||||
pub print_hash_statistics: HashStatisticsPrintLevel,
|
||||
pub hash_public_input: bool,
|
||||
}
|
||||
|
||||
pub const DEFAULT_PROVER_OPTIONS: ProverOptions = ProverOptions {
|
||||
export_witness: None,
|
||||
print_hash_statistics: HashStatisticsPrintLevel::None,
|
||||
hash_public_input: true,
|
||||
};
|
||||
|
||||
pub const UNHASHED_PI_PROVER_OPTIONS: ProverOptions = ProverOptions {
|
||||
export_witness: None,
|
||||
print_hash_statistics: HashStatisticsPrintLevel::None,
|
||||
hash_public_input: false,
|
||||
};
|
||||
|
||||
// things we want to export to be used by third party tooling
|
||||
@ -201,6 +209,21 @@ fn collect_things_to_export<F: RichField + Extendable<D>, C: GenericConfig<D, F
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
pub fn prove_unhashed_pi<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
prover_data: &ProverOnlyCircuitData<F, C, D>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
inputs: PartialWitness<F>,
|
||||
timing: &mut TimingTree,
|
||||
) -> Result<ProofWithPublicInputs<F, C, D>> {
|
||||
prove_with_options(
|
||||
prover_data,
|
||||
common_data,
|
||||
inputs,
|
||||
timing,
|
||||
&UNHASHED_PI_PROVER_OPTIONS,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prove<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
prover_data: &ProverOnlyCircuitData<F, C, D>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
@ -269,8 +292,13 @@ where
|
||||
set_lookup_wires(prover_data, common_data, &mut partition_witness)?;
|
||||
|
||||
let public_inputs = partition_witness.get_targets(&prover_data.public_inputs);
|
||||
let pi_felts: Vec<GenericField<F>> = public_inputs.clone().into_generic_field_vec();
|
||||
let public_inputs_hash = C::InnerHasher::hash_no_pad(&pi_felts);
|
||||
let public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash =
|
||||
if prover_options.hash_public_input {
|
||||
let pi_felts: Vec<GenericField<F>> = public_inputs.clone().into_generic_field_vec();
|
||||
C::InnerHasher::hash_no_pad(&pi_felts)
|
||||
}else{
|
||||
HashOut::<F>::default()
|
||||
};
|
||||
|
||||
let witness = timed!(
|
||||
timing,
|
||||
@ -320,7 +348,12 @@ where
|
||||
|
||||
// Observe the instance.
|
||||
challenger.observe_hash::<C::Hasher>(prover_data.circuit_digest);
|
||||
challenger.observe_hash::<C::InnerHasher>(public_inputs_hash);
|
||||
if prover_options.hash_public_input {
|
||||
challenger.observe_hash::<C::InnerHasher>(public_inputs_hash);
|
||||
} else{
|
||||
let pi_felts = public_inputs.clone().into_generic_field_vec();
|
||||
challenger.observe_elements(&pi_felts);
|
||||
}
|
||||
|
||||
challenger.observe_cap::<C::Hasher>(&wires_commitment.merkle_tree.cap);
|
||||
|
||||
@ -397,6 +430,7 @@ where
|
||||
compute_quotient_polys::<F, C, D>(
|
||||
common_data,
|
||||
prover_data,
|
||||
&public_inputs,
|
||||
&public_inputs_hash,
|
||||
&wires_commitment,
|
||||
&partial_products_zs_and_lookup_commitment,
|
||||
@ -757,6 +791,7 @@ fn compute_quotient_polys<
|
||||
>(
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
prover_data: &'a ProverOnlyCircuitData<F, C, D>,
|
||||
public_inputs: &[F],
|
||||
public_inputs_hash: &<<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
|
||||
wires_commitment: &'a PolynomialBatch<F, C, D>,
|
||||
zs_partial_products_and_lookup_commitment: &'a PolynomialBatch<F, C, D>,
|
||||
@ -913,12 +948,14 @@ fn compute_quotient_polys<
|
||||
}
|
||||
}
|
||||
|
||||
let vars_batch = EvaluationVarsBaseBatch::new(
|
||||
xs_batch.len(),
|
||||
&local_constants_batch,
|
||||
&local_wires_batch,
|
||||
public_inputs_hash,
|
||||
);
|
||||
let vars_batch =
|
||||
EvaluationVarsBaseBatch::new(
|
||||
xs_batch.len(),
|
||||
&local_constants_batch,
|
||||
&local_wires_batch,
|
||||
&public_inputs_hash,
|
||||
public_inputs,
|
||||
);
|
||||
|
||||
let mut quotient_values_batch = eval_vanishing_poly_base_batch::<F, D>(
|
||||
common_data,
|
||||
|
||||
@ -15,6 +15,7 @@ pub struct EvaluationVars<'a, F: RichField + Extendable<D>, const D: usize> {
|
||||
pub local_constants: &'a [F::Extension],
|
||||
pub local_wires: &'a [F::Extension],
|
||||
pub public_inputs_hash: &'a HashOut<F>,
|
||||
pub public_inputs: &'a [F],
|
||||
}
|
||||
|
||||
/// A batch of evaluation vars, in the base field.
|
||||
@ -26,6 +27,7 @@ pub struct EvaluationVarsBaseBatch<'a, F: Field> {
|
||||
pub local_constants: &'a [F],
|
||||
pub local_wires: &'a [F],
|
||||
pub public_inputs_hash: &'a HashOut<F>,
|
||||
pub public_inputs: &'a [F],
|
||||
}
|
||||
|
||||
/// A view into `EvaluationVarsBaseBatch` for a particular evaluation point. Does not copy the data.
|
||||
@ -34,6 +36,7 @@ pub struct EvaluationVarsBase<'a, F: Field> {
|
||||
pub local_constants: PackedStridedView<'a, F>,
|
||||
pub local_wires: PackedStridedView<'a, F>,
|
||||
pub public_inputs_hash: &'a HashOut<F>,
|
||||
pub public_inputs: &'a [F],
|
||||
}
|
||||
|
||||
/// Like `EvaluationVarsBase`, but packed.
|
||||
@ -44,6 +47,7 @@ pub struct EvaluationVarsBasePacked<'a, P: PackedField> {
|
||||
pub local_constants: PackedStridedView<'a, P>,
|
||||
pub local_wires: PackedStridedView<'a, P>,
|
||||
pub public_inputs_hash: &'a HashOut<P::Scalar>,
|
||||
pub public_inputs: &'a [P::Scalar],
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> EvaluationVars<'_, F, D> {
|
||||
@ -67,6 +71,7 @@ impl<'a, F: Field> EvaluationVarsBaseBatch<'a, F> {
|
||||
local_constants: &'a [F],
|
||||
local_wires: &'a [F],
|
||||
public_inputs_hash: &'a HashOut<F>,
|
||||
public_inputs: &'a [F],
|
||||
) -> Self {
|
||||
assert_eq!(local_constants.len() % batch_size, 0);
|
||||
assert_eq!(local_wires.len() % batch_size, 0);
|
||||
@ -75,6 +80,7 @@ impl<'a, F: Field> EvaluationVarsBaseBatch<'a, F> {
|
||||
local_constants,
|
||||
local_wires,
|
||||
public_inputs_hash,
|
||||
public_inputs
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,6 +105,7 @@ impl<'a, F: Field> EvaluationVarsBaseBatch<'a, F> {
|
||||
local_constants,
|
||||
local_wires,
|
||||
public_inputs_hash: self.public_inputs_hash,
|
||||
public_inputs: self.public_inputs,
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,6 +203,7 @@ impl<'a, P: PackedField> Iterator for EvaluationVarsBaseBatchIterPacked<'a, P> {
|
||||
local_constants,
|
||||
local_wires,
|
||||
public_inputs_hash: self.vars_batch.public_inputs_hash,
|
||||
public_inputs: self.vars_batch.public_inputs,
|
||||
};
|
||||
self.i += P::WIDTH;
|
||||
Some(res)
|
||||
|
||||
@ -5,7 +5,7 @@ use anyhow::{ensure, Result};
|
||||
use crate::field::extension::Extendable;
|
||||
use crate::field::types::Field;
|
||||
use crate::fri::verifier::verify_fri_proof;
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::hash::hash_types::{HashOut, RichField};
|
||||
use crate::hash::hashing::*;
|
||||
use crate::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
|
||||
use crate::plonk::config::{GenericConfig, Hasher};
|
||||
@ -27,10 +27,17 @@ pub enum HashStatisticsPrintLevel {
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct VerifierOptions {
|
||||
pub print_hash_statistics: HashStatisticsPrintLevel,
|
||||
pub hash_public_input: bool,
|
||||
}
|
||||
|
||||
pub const DEFAULT_VERIFIER_OPTIONS: VerifierOptions = VerifierOptions {
|
||||
print_hash_statistics: HashStatisticsPrintLevel::None,
|
||||
hash_public_input: true,
|
||||
};
|
||||
|
||||
pub const UNHASHED_PI_VERIFIER_OPTIONS: VerifierOptions = VerifierOptions {
|
||||
print_hash_statistics: HashStatisticsPrintLevel::None,
|
||||
hash_public_input: false,
|
||||
};
|
||||
|
||||
pub(crate) fn verify<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
@ -45,6 +52,20 @@ pub(crate) fn verify<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, c
|
||||
&DEFAULT_VERIFIER_OPTIONS,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn verify_unhashed_pi<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
proof_with_pis: ProofWithPublicInputs<F, C, D>,
|
||||
verifier_data: &VerifierOnlyCircuitData<C, D>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> Result<()> {
|
||||
verify_with_options(
|
||||
proof_with_pis,
|
||||
verifier_data,
|
||||
common_data,
|
||||
&UNHASHED_PI_VERIFIER_OPTIONS,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn verify_with_options<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
proof_with_pis: ProofWithPublicInputs<F, C, D>,
|
||||
verifier_data: &VerifierOnlyCircuitData<C, D>,
|
||||
@ -56,16 +77,25 @@ pub(crate) fn verify_with_options<F: RichField + Extendable<D>, C: GenericConfig
|
||||
|
||||
validate_proof_with_pis_shape(&proof_with_pis, common_data)?;
|
||||
|
||||
let public_inputs_hash = proof_with_pis.get_public_inputs_hash();
|
||||
let public_inputs_hash: HashOut<F> =
|
||||
if verifier_options.hash_public_input {
|
||||
proof_with_pis.get_public_inputs_hash()
|
||||
}else {
|
||||
HashOut::<F>::default()
|
||||
};
|
||||
|
||||
if verifier_options.print_hash_statistics >= HashStatisticsPrintLevel::Info {
|
||||
print_hash_counters("after PI");
|
||||
}
|
||||
|
||||
let pi = if verifier_options.hash_public_input { None } else {Some(proof_with_pis.public_inputs.clone())};
|
||||
|
||||
let challenges = proof_with_pis.get_challenges(
|
||||
pi,
|
||||
public_inputs_hash,
|
||||
&verifier_data.circuit_digest,
|
||||
common_data,
|
||||
verifier_options.hash_public_input,
|
||||
)?;
|
||||
|
||||
if verifier_options.print_hash_statistics >= HashStatisticsPrintLevel::Info {
|
||||
@ -74,6 +104,7 @@ pub(crate) fn verify_with_options<F: RichField + Extendable<D>, C: GenericConfig
|
||||
|
||||
let result = verify_with_challenges::<F, C, D>(
|
||||
proof_with_pis.proof,
|
||||
proof_with_pis.public_inputs,
|
||||
public_inputs_hash,
|
||||
challenges,
|
||||
verifier_data,
|
||||
@ -93,6 +124,7 @@ pub(crate) fn verify_with_challenges<
|
||||
const D: usize,
|
||||
>(
|
||||
proof: Proof<F, C, D>,
|
||||
public_inputs: Vec<F>,
|
||||
public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
|
||||
challenges: ProofChallenges<F, D>,
|
||||
verifier_data: &VerifierOnlyCircuitData<C, D>,
|
||||
@ -105,6 +137,7 @@ pub(crate) fn verify_with_challenges<
|
||||
local_constants,
|
||||
local_wires,
|
||||
public_inputs_hash: &public_inputs_hash,
|
||||
public_inputs: &public_inputs,
|
||||
};
|
||||
let local_zs = &proof.openings.plonk_zs;
|
||||
let next_zs = &proof.openings.plonk_zs_next;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user