Skip to content

Commit

Permalink
feat!: remove the compress_selectors field from VerifyingKey (#310)
Browse files Browse the repository at this point in the history
* feat!: remove the "compress_selectors" field from PK & VK

*feat: add the "keygen_pk_custom" func

* chore: add the comments regarding the use of keygen utils

* feat: add "create_proof_custom_with_engine" func
  • Loading branch information
duguorong009 authored Apr 12, 2024
1 parent d03d6c7 commit 3600207
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 41 deletions.
4 changes: 0 additions & 4 deletions halo2_backend/src/plonk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ pub struct VerifyingKey<C: CurveAffine> {
cs_degree: usize,
/// The representative of this `VerifyingKey` in transcripts.
transcript_repr: C::Scalar,
/// Legacy field that indicates wether the circuit was compiled with compressed selectors or
/// not using the legacy API.
pub compress_selectors: Option<bool>,
}

// Current version of the VK
Expand Down Expand Up @@ -187,7 +184,6 @@ impl<C: CurveAffine> VerifyingKey<C> {
cs_degree,
// Temporary, this is not pinned.
transcript_repr: C::Scalar::ZERO,
compress_selectors: None,
};

let mut hasher = Blake2bParams::new()
Expand Down
4 changes: 2 additions & 2 deletions halo2_proofs/src/plonk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ mod verifier {
pub use halo2_backend::plonk::verifier::verify_proof;
}

pub use keygen::{keygen_pk, keygen_vk, keygen_vk_custom};
pub use keygen::{keygen_pk, keygen_pk_custom, keygen_vk, keygen_vk_custom};

pub use prover::{create_proof, create_proof_with_engine};
pub use prover::{create_proof, create_proof_custom_with_engine, create_proof_with_engine};
pub use verifier::verify_proof;

pub use error::Error;
Expand Down
48 changes: 39 additions & 9 deletions halo2_proofs/src/plonk/keygen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ use halo2_frontend::plonk::Circuit;
use halo2_middleware::ff::FromUniformBytes;

/// Generate a `VerifyingKey` from an instance of `Circuit`.
/// By default, selector compression is turned **off**.
/// By default, selector compression is turned **ON**.
///
/// **NOTE**: This `keygen_vk` is legacy one, assuming that `compress_selector: true`.
/// Hence, it is HIGHLY recommended to pair this util with `keygen_pk`.
/// In addition, when using this for key generation, user MUST use `compress_selectors: true`.
pub fn keygen_vk<'params, C, P, ConcreteCircuit>(
params: &P,
circuit: &ConcreteCircuit,
Expand All @@ -26,6 +30,11 @@ where
/// Generate a `VerifyingKey` from an instance of `Circuit`.
///
/// The selector compression optimization is turned on only if `compress_selectors` is `true`.
///
/// **NOTE**: This `keygen_vk_custom` MUST share the same `compress_selectors` with
/// `ProvingKey` generation process.
/// Otherwise, the user could get unmatching pk/vk pair.
/// Hence, it is HIGHLY recommended to pair this util with `keygen_pk_custom`.
pub fn keygen_vk_custom<'params, C, P, ConcreteCircuit>(
params: &P,
circuit: &ConcreteCircuit,
Expand All @@ -38,12 +47,15 @@ where
C::Scalar: FromUniformBytes<64>,
{
let (compiled_circuit, _, _) = compile_circuit(params.k(), circuit, compress_selectors)?;
let mut vk = backend_keygen_vk(params, &compiled_circuit)?;
vk.compress_selectors = Some(compress_selectors);
Ok(vk)
Ok(backend_keygen_vk(params, &compiled_circuit)?)
}

/// Generate a `ProvingKey` from a `VerifyingKey` and an instance of `Circuit`.
/// By default, selector compression is turned **ON**.
///
/// **NOTE**: This `keygen_pk` is legacy one, assuming that `compress_selector: true`.
/// Hence, it is HIGHLY recommended to pair this util with `keygen_vk`.
/// In addition, when using this for key generation, user MUST use `compress_selectors: true`.
pub fn keygen_pk<'params, C, P, ConcreteCircuit>(
params: &P,
vk: VerifyingKey<C>,
Expand All @@ -54,10 +66,28 @@ where
P: Params<'params, C>,
ConcreteCircuit: Circuit<C::Scalar>,
{
let (compiled_circuit, _, _) = compile_circuit(
params.k(),
circuit,
vk.compress_selectors.unwrap_or_default(),
)?;
keygen_pk_custom(params, vk, circuit, true)
}

/// Generate a `ProvingKey` from an instance of `Circuit`.
///
/// The selector compression optimization is turned on only if `compress_selectors` is `true`.
///
/// **NOTE**: This `keygen_pk_custom` MUST share the same `compress_selectors` with
/// `VerifyingKey` generation process.
/// Otherwise, the user could get unmatching pk/vk pair.
/// Hence, it is HIGHLY recommended to pair this util with `keygen_vk_custom`.
pub fn keygen_pk_custom<'params, C, P, ConcreteCircuit>(
params: &P,
vk: VerifyingKey<C>,
circuit: &ConcreteCircuit,
compress_selectors: bool,
) -> Result<ProvingKey<C>, Error>
where
C: CurveAffine,
P: Params<'params, C>,
ConcreteCircuit: Circuit<C::Scalar>,
{
let (compiled_circuit, _, _) = compile_circuit(params.k(), circuit, compress_selectors)?;
Ok(backend_keygen_pk(params, vk, &compiled_circuit)?)
}
146 changes: 120 additions & 26 deletions halo2_proofs/src/plonk/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,32 +37,9 @@ pub fn create_proof_with_engine<
where
Scheme::Scalar: WithSmallOrderMulGroup<3> + FromUniformBytes<64>,
{
if circuits.len() != instances.len() {
return Err(Error::Backend(ErrorBack::InvalidInstances));
}
let (config, cs, _) = compile_circuit_cs::<_, ConcreteCircuit>(
pk.get_vk().compress_selectors.unwrap_or_default(),
#[cfg(feature = "circuit-params")]
circuits[0].params(),
);
let mut witness_calcs: Vec<_> = circuits
.iter()
.enumerate()
.map(|(i, circuit)| WitnessCalculator::new(params.k(), circuit, &config, &cs, instances[i]))
.collect();
let mut prover = Prover::<Scheme, P, _, _, _, _>::new_with_engine(
engine, params, pk, instances, rng, transcript,
)?;
let mut challenges = HashMap::new();
let phases = prover.phases().to_vec();
for phase in phases.iter() {
let mut witnesses = Vec::with_capacity(circuits.len());
for witness_calc in witness_calcs.iter_mut() {
witnesses.push(witness_calc.calc(*phase, &challenges)?);
}
challenges = prover.commit_phase(*phase, witnesses).unwrap();
}
Ok(prover.create_proof()?)
create_proof_custom_with_engine::<Scheme, P, E, R, T, ConcreteCircuit, M>(
engine, params, pk, true, circuits, instances, rng, transcript,
)
}

/// This creates a proof for the provided `circuit` when given the public
Expand Down Expand Up @@ -94,6 +71,62 @@ where
)
}

/// This creates a proof for the provided `circuit` when given the public
/// parameters `params` and the proving key [`ProvingKey`] that was
/// generated previously for the same circuit. The provided `instances`
/// are zero-padded internally.
/// In addition, this needs the `compress_selectors` field.
#[allow(clippy::too_many_arguments)]
pub fn create_proof_custom_with_engine<
'params,
Scheme: CommitmentScheme,
P: commitment::Prover<'params, Scheme>,
E: EncodedChallenge<Scheme::Curve>,
R: RngCore,
T: TranscriptWrite<Scheme::Curve, E>,
ConcreteCircuit: Circuit<Scheme::Scalar>,
M: MsmAccel<Scheme::Curve>,
>(
engine: PlonkEngine<Scheme::Curve, M>,
params: &'params Scheme::ParamsProver,
pk: &ProvingKey<Scheme::Curve>,
compress_selectors: bool,
circuits: &[ConcreteCircuit],
instances: &[&[&[Scheme::Scalar]]],
rng: R,
transcript: &mut T,
) -> Result<(), Error>
where
Scheme::Scalar: WithSmallOrderMulGroup<3> + FromUniformBytes<64>,
{
if circuits.len() != instances.len() {
return Err(Error::Backend(ErrorBack::InvalidInstances));
}
let (config, cs, _) = compile_circuit_cs::<_, ConcreteCircuit>(
compress_selectors,
#[cfg(feature = "circuit-params")]
circuits[0].params(),
);
let mut witness_calcs: Vec<_> = circuits
.iter()
.enumerate()
.map(|(i, circuit)| WitnessCalculator::new(params.k(), circuit, &config, &cs, instances[i]))
.collect();
let mut prover = Prover::<Scheme, P, _, _, _, _>::new_with_engine(
engine, params, pk, instances, rng, transcript,
)?;
let mut challenges = HashMap::new();
let phases = prover.phases().to_vec();
for phase in phases.iter() {
let mut witnesses = Vec::with_capacity(circuits.len());
for witness_calc in witness_calcs.iter_mut() {
witnesses.push(witness_calc.calc(*phase, &challenges)?);
}
challenges = prover.commit_phase(*phase, witnesses).unwrap();
}
Ok(prover.create_proof()?)
}

#[test]
fn test_create_proof() {
use crate::{
Expand Down Expand Up @@ -163,3 +196,64 @@ fn test_create_proof() {
)
.expect("proof generation should not fail");
}

#[test]
fn test_create_proof_custom() {
use crate::{
circuit::SimpleFloorPlanner,
plonk::{keygen_pk_custom, keygen_vk_custom, ConstraintSystem, ErrorFront},
poly::kzg::{
commitment::{KZGCommitmentScheme, ParamsKZG},
multiopen::ProverSHPLONK,
},
transcript::{Blake2bWrite, Challenge255, TranscriptWriterBuffer},
};
use halo2_middleware::ff::Field;
use halo2curves::bn256::Bn256;
use rand_core::OsRng;

#[derive(Clone, Copy)]
struct MyCircuit;

impl<F: Field> Circuit<F> for MyCircuit {
type Config = ();
type FloorPlanner = SimpleFloorPlanner;
#[cfg(feature = "circuit-params")]
type Params = ();

fn without_witnesses(&self) -> Self {
*self
}

fn configure(_meta: &mut ConstraintSystem<F>) -> Self::Config {}

fn synthesize(
&self,
_config: Self::Config,
_layouter: impl crate::circuit::Layouter<F>,
) -> Result<(), ErrorFront> {
Ok(())
}
}

let params: ParamsKZG<Bn256> = ParamsKZG::setup(3, OsRng);
let compress_selectors = true;
let vk = keygen_vk_custom(&params, &MyCircuit, compress_selectors)
.expect("keygen_vk_custom should not fail");
let pk = keygen_pk_custom(&params, vk, &MyCircuit, compress_selectors)
.expect("keygen_pk_custom should not fail");
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
let engine = PlonkEngineConfig::build_default();

create_proof_custom_with_engine::<KZGCommitmentScheme<_>, ProverSHPLONK<_>, _, _, _, _, _>(
engine,
&params,
&pk,
compress_selectors,
&[MyCircuit, MyCircuit],
&[&[], &[]],
OsRng,
&mut transcript,
)
.expect("proof generation should not fail");
}

0 comments on commit 3600207

Please sign in to comment.