@ -0,0 +1,34 @@ |
|||
[package] |
|||
name = "arithmetic" |
|||
version = "0.1.0" |
|||
edition = "2021" |
|||
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|||
|
|||
[dependencies] |
|||
|
|||
ark-ff = { version = "^0.3.0", default-features = false } |
|||
ark-std = { version = "^0.3.0", default-features = false } |
|||
ark-poly = { version = "^0.3.0", default-features = false } |
|||
ark-serialize = { version = "^0.3.0", default-features = false } |
|||
ark-bls12-381 = { version = "0.3.0", default-features = false, features = [ "curve" ] } |
|||
|
|||
rand_chacha = { version = "0.3.0", default-features = false } |
|||
displaydoc = { version = "0.2.3", default-features = false } |
|||
rayon = { version = "1.5.2", default-features = false, optional = true } |
|||
|
|||
[dev-dependencies] |
|||
ark-ec = { version = "^0.3.0", default-features = false } |
|||
|
|||
[features] |
|||
# default = [ "parallel", "print-trace" ] |
|||
default = [ "parallel" ] |
|||
parallel = [ |
|||
"rayon", |
|||
"ark-std/parallel", |
|||
"ark-ff/parallel", |
|||
"ark-poly/parallel" |
|||
] |
|||
print-trace = [ |
|||
"ark-std/print-trace" |
|||
] |
@ -0,0 +1,21 @@ |
|||
//! Error module.
|
|||
|
|||
use ark_std::string::String;
|
|||
use displaydoc::Display;
|
|||
|
|||
/// A `enum` specifying the possible failure modes of the arithmetics.
|
|||
#[derive(Display, Debug)]
|
|||
pub enum ArithErrors {
|
|||
/// Invalid parameters: {0}
|
|||
InvalidParameters(String),
|
|||
/// Should not arrive to this point
|
|||
ShouldNotArrive,
|
|||
/// An error during (de)serialization: {0}
|
|||
SerializationErrors(ark_serialize::SerializationError),
|
|||
}
|
|||
|
|||
impl From<ark_serialize::SerializationError> for ArithErrors {
|
|||
fn from(e: ark_serialize::SerializationError) -> Self {
|
|||
Self::SerializationErrors(e)
|
|||
}
|
|||
}
|
@ -0,0 +1,7 @@ |
|||
mod errors;
|
|||
mod multilinear_polynomial;
|
|||
mod virtual_polynomial;
|
|||
|
|||
pub use errors::ArithErrors;
|
|||
pub use multilinear_polynomial::{random_zero_mle_list, DenseMultilinearExtension};
|
|||
pub use virtual_polynomial::{build_eq_x_r, VPAuxInfo, VirtualPolynomial};
|
@ -0,0 +1,33 @@ |
|||
use ark_ff::PrimeField;
|
|||
use ark_std::{end_timer, rand::RngCore, start_timer};
|
|||
use std::rc::Rc;
|
|||
|
|||
pub use ark_poly::DenseMultilinearExtension;
|
|||
|
|||
// Build a randomize list of mle-s whose sum is zero.
|
|||
pub fn random_zero_mle_list<F: PrimeField, R: RngCore>(
|
|||
nv: usize,
|
|||
degree: usize,
|
|||
rng: &mut R,
|
|||
) -> Vec<Rc<DenseMultilinearExtension<F>>> {
|
|||
let start = start_timer!(|| "sample random zero mle list");
|
|||
|
|||
let mut multiplicands = Vec::with_capacity(degree);
|
|||
for _ in 0..degree {
|
|||
multiplicands.push(Vec::with_capacity(1 << nv))
|
|||
}
|
|||
for _ in 0..(1 << nv) {
|
|||
multiplicands[0].push(F::zero());
|
|||
for e in multiplicands.iter_mut().skip(1) {
|
|||
e.push(F::rand(rng));
|
|||
}
|
|||
}
|
|||
|
|||
let list = multiplicands
|
|||
.into_iter()
|
|||
.map(|x| Rc::new(DenseMultilinearExtension::from_evaluations_vec(nv, x)))
|
|||
.collect();
|
|||
|
|||
end_timer!(start);
|
|||
list
|
|||
}
|
@ -0,0 +1,64 @@ |
|||
//! Error module.
|
|||
|
|||
use arithmetic::ArithErrors;
|
|||
use ark_serialize::SerializationError;
|
|||
use ark_std::string::String;
|
|||
use displaydoc::Display;
|
|||
use pcs::prelude::PCSErrors;
|
|||
use poly_iop::prelude::PolyIOPErrors;
|
|||
use transcript::TranscriptErrors;
|
|||
|
|||
/// A `enum` specifying the possible failure modes of hyperplonk.
|
|||
#[allow(dead_code)]
|
|||
// todo: REMOVE
|
|||
#[derive(Display, Debug)]
|
|||
pub enum HyperPlonkErrors {
|
|||
/// Invalid Prover: {0}
|
|||
InvalidProver(String),
|
|||
/// Invalid Verifier: {0}
|
|||
InvalidVerifier(String),
|
|||
/// Invalid Proof: {0}
|
|||
InvalidProof(String),
|
|||
/// Invalid parameters: {0}
|
|||
InvalidParameters(String),
|
|||
/// An error during (de)serialization: {0}
|
|||
SerializationError(SerializationError),
|
|||
/// PolyIOP error {0}
|
|||
PolyIOPErrors(PolyIOPErrors),
|
|||
/// PCS error {0}
|
|||
PCSErrors(PCSErrors),
|
|||
/// Transcript error {0}
|
|||
TranscriptError(TranscriptErrors),
|
|||
/// Arithmetic Error: {0}
|
|||
ArithmeticErrors(ArithErrors),
|
|||
}
|
|||
|
|||
impl From<SerializationError> for HyperPlonkErrors {
|
|||
fn from(e: ark_serialize::SerializationError) -> Self {
|
|||
Self::SerializationError(e)
|
|||
}
|
|||
}
|
|||
|
|||
impl From<PolyIOPErrors> for HyperPlonkErrors {
|
|||
fn from(e: PolyIOPErrors) -> Self {
|
|||
Self::PolyIOPErrors(e)
|
|||
}
|
|||
}
|
|||
|
|||
impl From<PCSErrors> for HyperPlonkErrors {
|
|||
fn from(e: PCSErrors) -> Self {
|
|||
Self::PCSErrors(e)
|
|||
}
|
|||
}
|
|||
|
|||
impl From<TranscriptErrors> for HyperPlonkErrors {
|
|||
fn from(e: TranscriptErrors) -> Self {
|
|||
Self::TranscriptError(e)
|
|||
}
|
|||
}
|
|||
|
|||
impl From<ArithErrors> for HyperPlonkErrors {
|
|||
fn from(e: ArithErrors) -> Self {
|
|||
Self::ArithmeticErrors(e)
|
|||
}
|
|||
}
|
@ -1,8 +1,851 @@ |
|||
//! Main module for the HyperPlonk PolyIOP.
|
|||
|
|||
use arithmetic::VPAuxInfo;
|
|||
use ark_ec::PairingEngine;
|
|||
use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
|
|||
use ark_std::{end_timer, log2, start_timer, One, Zero};
|
|||
use errors::HyperPlonkErrors;
|
|||
use pcs::prelude::{compute_qx_degree, merge_polynomials, PCSErrors, PolynomialCommitmentScheme};
|
|||
use poly_iop::{
|
|||
prelude::{PermutationCheck, SumCheck, ZeroCheck},
|
|||
PolyIOP,
|
|||
};
|
|||
use selectors::SelectorColumn;
|
|||
use std::{marker::PhantomData, rc::Rc};
|
|||
use structs::{
|
|||
HyperPlonkParams, HyperPlonkProof, HyperPlonkProvingKey, HyperPlonkSubClaim,
|
|||
HyperPlonkVerifyingKey,
|
|||
};
|
|||
use utils::build_f;
|
|||
use witness::WitnessColumn;
|
|||
|
|||
mod errors;
|
|||
mod selectors;
|
|||
mod structs;
|
|||
mod utils;
|
|||
mod witness;
|
|||
|
|||
/// A trait for HyperPlonk Poly-IOPs.
|
|||
/// A HyperPlonk is derived from SumChecks, ZeroChecks and PermutationChecks.
|
|||
pub trait HyperPlonkSNARK<E, PCS>: |
|||
SumCheck<E::Fr> + ZeroCheck<E::Fr> + PermutationCheck<E::Fr>
|
|||
where
|
|||
E: PairingEngine,
|
|||
PCS: PolynomialCommitmentScheme<E>,
|
|||
{
|
|||
type Parameters;
|
|||
type ProvingKey;
|
|||
type VerifyingKey;
|
|||
type Proof;
|
|||
type SubClaim;
|
|||
|
|||
/// Generate the preprocessed polynomials output by the indexer.
|
|||
///
|
|||
/// Inputs:
|
|||
/// - `params`: HyperPlonk instance parameters
|
|||
/// - `permutation`: the permutation for the copy constraints
|
|||
/// - `selectors`: the list of selector vectors for custom gates
|
|||
/// Outputs:
|
|||
/// - The HyperPlonk proving key, which includes the preprocessed
|
|||
/// polynomials.
|
|||
fn preprocess(
|
|||
params: &Self::Parameters,
|
|||
pcs_srs: &PCS::SRS,
|
|||
permutation: &[E::Fr],
|
|||
selectors: &[SelectorColumn<E::Fr>],
|
|||
) -> Result<(Self::ProvingKey, Self::VerifyingKey), HyperPlonkErrors>;
|
|||
|
|||
/// Generate HyperPlonk SNARK proof.
|
|||
///
|
|||
/// Inputs:
|
|||
/// - `pk`: circuit proving key
|
|||
/// - `pub_input`: online public input
|
|||
/// - `witness`: witness assignment
|
|||
/// - `transcript`: the transcript used for generating pseudorandom
|
|||
/// challenges
|
|||
/// Outputs:
|
|||
/// - The HyperPlonk SNARK proof.
|
|||
fn prove(
|
|||
pk: &Self::ProvingKey,
|
|||
pub_input: &[E::Fr],
|
|||
witnesses: &[WitnessColumn<E::Fr>],
|
|||
transcript: &mut Self::Transcript,
|
|||
) -> Result<Self::Proof, HyperPlonkErrors>;
|
|||
|
|||
/// Verify the HyperPlonk proof and generate the evaluation subclaims to be
|
|||
/// checked later by the SNARK verifier.
|
|||
///
|
|||
/// Inputs:
|
|||
/// - `params`: instance parameter
|
|||
/// - `pub_input`: online public input
|
|||
/// - `proof`: HyperPlonk SNARK proof
|
|||
/// - `transcript`: the transcript used for generating pseudorandom
|
|||
/// challenges
|
|||
/// Outputs:
|
|||
/// - Return error if the verification fails, otherwise return the
|
|||
/// evaluation subclaim
|
|||
fn verify(
|
|||
params: &Self::VerifyingKey,
|
|||
pub_input: &[E::Fr],
|
|||
proof: &Self::Proof,
|
|||
transcript: &mut Self::Transcript,
|
|||
) -> Result<Self::SubClaim, HyperPlonkErrors>;
|
|||
}
|
|||
|
|||
impl<E, PCS> HyperPlonkSNARK<E, PCS> for PolyIOP<E::Fr>
|
|||
where
|
|||
E: PairingEngine,
|
|||
// Ideally we want to access polynomial as PCS::Polynomial, instead of instantiating it here.
|
|||
// But since PCS::Polynomial can be both univariate or multivariate in our implementation
|
|||
// we cannot bound PCS::Polynomial with a property trait bound.
|
|||
PCS: PolynomialCommitmentScheme<
|
|||
E,
|
|||
Polynomial = Rc<DenseMultilinearExtension<E::Fr>>,
|
|||
Point = Vec<E::Fr>,
|
|||
Evaluation = E::Fr,
|
|||
>,
|
|||
{
|
|||
type Parameters = HyperPlonkParams;
|
|||
type ProvingKey = HyperPlonkProvingKey<E, PCS>;
|
|||
type VerifyingKey = HyperPlonkVerifyingKey<E, PCS>;
|
|||
type Proof = HyperPlonkProof<E, PCS, Self, Self>;
|
|||
type SubClaim = HyperPlonkSubClaim<E::Fr, Self, Self>;
|
|||
|
|||
/// Generate the preprocessed polynomials output by the indexer.
|
|||
///
|
|||
/// Inputs:
|
|||
/// - `params`: HyperPlonk instance parameters
|
|||
/// - `permutation`: the permutation for the copy constraints
|
|||
/// - `selectors`: the list of selector vectors for custom gates
|
|||
/// Outputs:
|
|||
/// - The HyperPlonk proving key, which includes the preprocessed
|
|||
/// polynomials.
|
|||
fn preprocess(
|
|||
params: &Self::Parameters,
|
|||
pcs_srs: &PCS::SRS,
|
|||
permutation: &[E::Fr],
|
|||
selectors: &[SelectorColumn<E::Fr>],
|
|||
) -> Result<(Self::ProvingKey, Self::VerifyingKey), HyperPlonkErrors> {
|
|||
let num_vars = params.nv;
|
|||
let log_num_witness_polys = params.log_n_wires;
|
|||
|
|||
// number of variables in merged polynomial for Multilinear-KZG
|
|||
let merged_nv = num_vars + log_num_witness_polys;
|
|||
// degree of q(x) for Univariate-KZG
|
|||
let supported_uni_degree = compute_qx_degree(num_vars, 1 << log_num_witness_polys);
|
|||
|
|||
// extract PCS prover and verifier keys from SRS
|
|||
let (pcs_prover_param, pcs_verifier_param) = PCS::trim(
|
|||
pcs_srs,
|
|||
log2(supported_uni_degree) as usize,
|
|||
Some(merged_nv + 1),
|
|||
)?;
|
|||
|
|||
// build permutation oracles
|
|||
let permutation_oracles = Rc::new(DenseMultilinearExtension::from_evaluations_slice(
|
|||
// num_vars = merged_nv + 1 because this oracle encodes both s_id and s_perm
|
|||
merged_nv + 1,
|
|||
permutation,
|
|||
));
|
|||
|
|||
let perm_com = PCS::commit(&pcs_prover_param, &permutation_oracles)?;
|
|||
|
|||
// build selector oracles and commit to it
|
|||
let selector_oracles: Vec<Rc<DenseMultilinearExtension<E::Fr>>> = selectors
|
|||
.iter()
|
|||
.map(|s| Rc::new(DenseMultilinearExtension::from(s)))
|
|||
.collect();
|
|||
|
|||
let selector_com = selector_oracles
|
|||
.iter()
|
|||
.map(|poly| PCS::commit(&pcs_prover_param, poly))
|
|||
.collect::<Result<Vec<PCS::Commitment>, PCSErrors>>()?;
|
|||
|
|||
Ok((
|
|||
Self::ProvingKey {
|
|||
params: params.clone(),
|
|||
permutation_oracles,
|
|||
selector_oracles,
|
|||
pcs_param: pcs_prover_param,
|
|||
},
|
|||
Self::VerifyingKey {
|
|||
params: params.clone(),
|
|||
pcs_param: pcs_verifier_param,
|
|||
selector_com,
|
|||
perm_com,
|
|||
},
|
|||
))
|
|||
}
|
|||
|
|||
/// Generate HyperPlonk SNARK proof.
|
|||
///
|
|||
/// Inputs:
|
|||
/// - `pk`: circuit proving key
|
|||
/// - `pub_input`: online public input of length 2^\ell
|
|||
/// - `witness`: witness assignment of length 2^n
|
|||
/// - `transcript`: the transcript used for generating pseudorandom
|
|||
/// challenges
|
|||
/// Outputs:
|
|||
/// - The HyperPlonk SNARK proof.
|
|||
///
|
|||
/// Steps:
|
|||
///
|
|||
/// 1. Commit Witness polynomials `w_i(x)` and append commitment to
|
|||
/// transcript
|
|||
///
|
|||
/// 2. Run ZeroCheck on
|
|||
///
|
|||
/// `f(q_0(x),...q_l(x), w_0(x),...w_d(x))`
|
|||
///
|
|||
/// where `f` is the constraint polynomial i.e.,
|
|||
/// ```ignore
|
|||
/// f(q_l, q_r, q_m, q_o, w_a, w_b, w_c)
|
|||
/// = q_l w_a(x) + q_r w_b(x) + q_m w_a(x)w_b(x) - q_o w_c(x)
|
|||
/// ```
|
|||
/// in vanilla plonk, and obtain a ZeroCheckSubClaim
|
|||
///
|
|||
/// 3. Run permutation check on `\{w_i(x)\}` and `permutation_oracles`, and
|
|||
/// obtain a PermCheckSubClaim.
|
|||
///
|
|||
/// 4. Generate evaluations and corresponding proofs
|
|||
/// - permutation check evaluations and proofs
|
|||
/// - zero check evaluations and proofs
|
|||
/// - public input consistency checks
|
|||
fn prove(
|
|||
pk: &Self::ProvingKey,
|
|||
pub_input: &[E::Fr],
|
|||
witnesses: &[WitnessColumn<E::Fr>],
|
|||
transcript: &mut Self::Transcript,
|
|||
) -> Result<Self::Proof, HyperPlonkErrors> {
|
|||
let start = start_timer!(|| "hyperplonk proving");
|
|||
|
|||
// witness assignment of length 2^n
|
|||
let num_vars = pk.params.nv;
|
|||
let log_num_witness_polys = pk.params.log_n_wires;
|
|||
// number of variables in merged polynomial for Multilinear-KZG
|
|||
let merged_nv = num_vars + log_num_witness_polys;
|
|||
// degree of q(x) for Univariate-KZG
|
|||
let _supported_uni_degree = compute_qx_degree(num_vars, 1 << log_num_witness_polys);
|
|||
// online public input of length 2^\ell
|
|||
let ell = pk.params.log_pub_input_len;
|
|||
|
|||
let witness_polys: Vec<Rc<DenseMultilinearExtension<E::Fr>>> = witnesses
|
|||
.iter()
|
|||
.map(|w| Rc::new(DenseMultilinearExtension::from(w)))
|
|||
.collect();
|
|||
let pi_poly = Rc::new(DenseMultilinearExtension::from_evaluations_slice(
|
|||
ell as usize,
|
|||
pub_input,
|
|||
));
|
|||
|
|||
// =======================================================================
|
|||
// 0. sanity checks
|
|||
// =======================================================================
|
|||
// public input length
|
|||
if pub_input.len() != 1 << ell {
|
|||
return Err(HyperPlonkErrors::InvalidProver(format!(
|
|||
"Public input length is not correct: got {}, expect {}",
|
|||
pub_input.len(),
|
|||
1 << ell
|
|||
)));
|
|||
}
|
|||
// witnesses length
|
|||
for (i, w) in witnesses.iter().enumerate() {
|
|||
if w.0.len() != 1 << num_vars {
|
|||
return Err(HyperPlonkErrors::InvalidProver(format!(
|
|||
"{}-th witness length is not correct: got {}, expect {}",
|
|||
i,
|
|||
pub_input.len(),
|
|||
1 << ell
|
|||
)));
|
|||
}
|
|||
}
|
|||
// check public input matches witness[0]'s first 2^ell elements
|
|||
let pi_in_w0 =
|
|||
Rc::new(witness_polys[0].fix_variables(vec![E::Fr::zero(); num_vars - ell].as_ref()));
|
|||
|
|||
if pi_in_w0 != pi_poly {
|
|||
return Err(HyperPlonkErrors::InvalidProver(format!(
|
|||
"Public input {:?} does not match witness[0] {:?}",
|
|||
pi_poly, pi_in_w0,
|
|||
)));
|
|||
}
|
|||
// =======================================================================
|
|||
// 1. Commit Witness polynomials `w_i(x)` and append commitment to
|
|||
// transcript
|
|||
// =======================================================================
|
|||
let step = start_timer!(|| "commit witnesses");
|
|||
let mut witness_commits = vec![];
|
|||
// TODO: batch commit
|
|||
for wi_poly in witness_polys.iter() {
|
|||
let wi_com = PCS::commit(&pk.pcs_param, wi_poly)?;
|
|||
witness_commits.push(wi_com);
|
|||
}
|
|||
|
|||
let w_merged = merge_polynomials(&witness_polys)?;
|
|||
if w_merged.num_vars != merged_nv {
|
|||
return Err(HyperPlonkErrors::InvalidParameters(format!(
|
|||
"merged witness poly has a different num_var ({}) from expected ({})",
|
|||
w_merged.num_vars, merged_nv
|
|||
)));
|
|||
}
|
|||
let w_merged_com = PCS::commit(&pk.pcs_param, &Rc::new(w_merged.clone()))?;
|
|||
|
|||
transcript.append_serializable_element(b"w", &w_merged_com)?;
|
|||
end_timer!(step);
|
|||
|
|||
// =======================================================================
|
|||
// 2 Run ZeroCheck on
|
|||
//
|
|||
// `f(q_0(x),...q_l(x), w_0(x),...w_d(x))`
|
|||
//
|
|||
// where `f` is the constraint polynomial i.e.,
|
|||
//
|
|||
// f(q_l, q_r, q_m, q_o, w_a, w_b, w_c)
|
|||
// = q_l w_a(x) + q_r w_b(x) + q_m w_a(x)w_b(x) - q_o w_c(x)
|
|||
//
|
|||
// in vanilla plonk, and obtain a ZeroCheckSubClaim
|
|||
// =======================================================================
|
|||
let step = start_timer!(|| "ZeroCheck on f");
|
|||
|
|||
let fx = build_f(
|
|||
&pk.params.gate_func,
|
|||
pk.params.nv,
|
|||
&pk.selector_oracles,
|
|||
&witness_polys,
|
|||
)?;
|
|||
|
|||
let zero_check_proof = <Self as ZeroCheck<E::Fr>>::prove(&fx, transcript)?;
|
|||
end_timer!(step);
|
|||
|
|||
// =======================================================================
|
|||
// 3. Run permutation check on `\{w_i(x)\}` and `permutation_oracles`, and
|
|||
// obtain a PermCheckSubClaim.
|
|||
//
|
|||
// 3.1. `generate_challenge` from current transcript (generate beta, gamma)
|
|||
// 3.2. `compute_product` to build `prod(x)` etc. from f, g and s_perm
|
|||
// 3.3. push a commitment of `prod(x)` to the transcript
|
|||
// 3.4. `update_challenge` with the updated transcript
|
|||
// 3.5. `prove` to generate the proof
|
|||
// =======================================================================
|
|||
let step = start_timer!(|| "Permutation check on w_i(x)");
|
|||
|
|||
// 3.1 `generate_challenge` from current transcript (generate beta, gamma)
|
|||
let mut permutation_challenge = Self::generate_challenge(transcript)?;
|
|||
|
|||
// 3.2. `compute_product` to build `prod(x)` etc. from f, g and s_perm
|
|||
// s_perm is the second half of permutation oracle
|
|||
let s_perm = pk.permutation_oracles.fix_variables(&[E::Fr::one()]);
|
|||
|
|||
// This function returns 3 MLEs:
|
|||
// - prod(x)
|
|||
// - numerator
|
|||
// - denominator
|
|||
// See function signature for details.
|
|||
let prod_x_and_aux_info =
|
|||
Self::compute_prod_evals(&permutation_challenge, &w_merged, &w_merged, &s_perm)?;
|
|||
|
|||
// 3.3 push a commitment of `prod(x)` to the transcript
|
|||
let prod_com = PCS::commit(&pk.pcs_param, &Rc::new(prod_x_and_aux_info[0].clone()))?;
|
|||
|
|||
// 3.4. `update_challenge` with the updated transcript
|
|||
Self::update_challenge(&mut permutation_challenge, transcript, &prod_com)?;
|
|||
|
|||
// 3.5. `prove` to generate the proof
|
|||
let perm_check_proof = <Self as PermutationCheck<E::Fr>>::prove(
|
|||
&prod_x_and_aux_info,
|
|||
&permutation_challenge,
|
|||
transcript,
|
|||
)?;
|
|||
end_timer!(step);
|
|||
|
|||
// =======================================================================
|
|||
// 4. Generate evaluations and corresponding proofs
|
|||
// - permutation check evaluations and proofs
|
|||
// - wi_poly(r_perm_check) where r_perm_check is from perm_check_proof
|
|||
// - selector_poly(r_perm_check)
|
|||
//
|
|||
// - zero check evaluations and proofs
|
|||
// - wi_poly(r_zero_check) where r_zero_check is from zero_check_proof
|
|||
// - selector_poly(r_zero_check)
|
|||
//
|
|||
// - public input consistency checks
|
|||
// - pi_poly(r_pi) where r_pi is sampled from transcript
|
|||
// =======================================================================
|
|||
let step = start_timer!(|| "opening and evaluations");
|
|||
|
|||
// 4.1 permutation check
|
|||
let mut witness_zero_check_evals = vec![];
|
|||
let mut witness_zero_check_openings = vec![];
|
|||
// TODO: parallelization
|
|||
// TODO: Batch opening
|
|||
|
|||
// open permutation check proof
|
|||
let (witness_perm_check_opening, witness_perm_check_eval) = PCS::open(
|
|||
&pk.pcs_param,
|
|||
&Rc::new(w_merged.clone()),
|
|||
&perm_check_proof.point,
|
|||
)?;
|
|||
// sanity checks
|
|||
if w_merged.evaluate(&perm_check_proof.point).ok_or_else(|| {
|
|||
HyperPlonkErrors::InvalidParameters("evaluation dimension does not match".to_string())
|
|||
})? != witness_perm_check_eval
|
|||
{
|
|||
return Err(HyperPlonkErrors::InvalidProver(
|
|||
"Evaluation is different from PCS opening".to_string(),
|
|||
));
|
|||
}
|
|||
|
|||
// 4.2 open zero check proof
|
|||
// TODO: batch opening
|
|||
for wire_poly in witness_polys {
|
|||
// Open zero check proof
|
|||
let (zero_proof, zero_eval) =
|
|||
PCS::open(&pk.pcs_param, &wire_poly, &zero_check_proof.point)?;
|
|||
{
|
|||
if wire_poly.evaluate(&zero_check_proof.point).ok_or_else(|| {
|
|||
HyperPlonkErrors::InvalidParameters(
|
|||
"evaluation dimension does not match".to_string(),
|
|||
)
|
|||
})? != zero_eval
|
|||
{
|
|||
return Err(HyperPlonkErrors::InvalidProver(
|
|||
"Evaluation is different from PCS opening".to_string(),
|
|||
));
|
|||
}
|
|||
}
|
|||
witness_zero_check_evals.push(zero_eval);
|
|||
witness_zero_check_openings.push(zero_proof);
|
|||
}
|
|||
|
|||
// Open permutation check proof
|
|||
let (perm_oracle_opening, perm_oracle_eval) = PCS::open(
|
|||
&pk.pcs_param,
|
|||
&pk.permutation_oracles,
|
|||
&[&[E::Fr::one()], perm_check_proof.point.as_slice()].concat(),
|
|||
)?;
|
|||
{
|
|||
// sanity check
|
|||
if s_perm.evaluate(&perm_check_proof.point).ok_or_else(|| {
|
|||
HyperPlonkErrors::InvalidParameters(
|
|||
"evaluation dimension does not match".to_string(),
|
|||
)
|
|||
})? != perm_oracle_eval
|
|||
{
|
|||
return Err(HyperPlonkErrors::InvalidProver(
|
|||
"Evaluation is different from PCS opening".to_string(),
|
|||
));
|
|||
}
|
|||
}
|
|||
|
|||
let mut selector_oracle_openings = vec![];
|
|||
let mut selector_oracle_evals = vec![];
|
|||
|
|||
// TODO: parallelization
|
|||
for selector_poly in pk.selector_oracles.iter() {
|
|||
// Open zero check proof
|
|||
// during verification, use this eval against subclaim
|
|||
let (zero_proof, zero_eval) =
|
|||
PCS::open(&pk.pcs_param, selector_poly, &zero_check_proof.point)?;
|
|||
{
|
|||
if selector_poly
|
|||
.evaluate(&zero_check_proof.point)
|
|||
.ok_or_else(|| {
|
|||
HyperPlonkErrors::InvalidParameters(
|
|||
"evaluation dimension does not match".to_string(),
|
|||
)
|
|||
})?
|
|||
!= zero_eval
|
|||
{
|
|||
return Err(HyperPlonkErrors::InvalidProver(
|
|||
"Evaluation is different from PCS
|
|||
opening"
|
|||
.to_string(),
|
|||
));
|
|||
}
|
|||
}
|
|||
selector_oracle_openings.push(zero_proof);
|
|||
selector_oracle_evals.push(zero_eval);
|
|||
}
|
|||
|
|||
// 4.3 public input consistency checks
|
|||
let r_pi = transcript.get_and_append_challenge_vectors(b"r_pi", ell)?;
|
|||
|
|||
let (pi_opening, pi_eval) = PCS::open(&pk.pcs_param, &pi_in_w0, &r_pi)?;
|
|||
{
|
|||
// sanity check
|
|||
if pi_poly.evaluate(&r_pi).ok_or_else(|| {
|
|||
HyperPlonkErrors::InvalidParameters(
|
|||
"evaluation dimension does not match".to_string(),
|
|||
)
|
|||
})? != pi_eval
|
|||
{
|
|||
return Err(HyperPlonkErrors::InvalidProver(
|
|||
"Evaluation is different from PCS opening".to_string(),
|
|||
));
|
|||
}
|
|||
}
|
|||
|
|||
end_timer!(step);
|
|||
end_timer!(start);
|
|||
|
|||
Ok(HyperPlonkProof {
|
|||
// PCS components
|
|||
witness_commits,
|
|||
w_merged_com,
|
|||
// We do not validate prod(x), this is checked by subclaim
|
|||
prod_commit: prod_com,
|
|||
witness_perm_check_opening,
|
|||
witness_zero_check_openings,
|
|||
witness_perm_check_eval,
|
|||
witness_zero_check_evals,
|
|||
perm_oracle_opening,
|
|||
perm_oracle_eval,
|
|||
selector_oracle_openings,
|
|||
selector_oracle_evals,
|
|||
pi_eval,
|
|||
pi_opening,
|
|||
// IOP components
|
|||
zero_check_proof,
|
|||
perm_check_proof,
|
|||
})
|
|||
}
|
|||
|
|||
/// Verify the HyperPlonk proof and generate the evaluation subclaims to be
|
|||
/// checked later by the SNARK verifier.
|
|||
///
|
|||
/// Inputs:
|
|||
/// - `params`: instance parameter
|
|||
/// - `pub_input`: online public input
|
|||
/// - `proof`: HyperPlonk SNARK proof
|
|||
/// - `transcript`: the transcript used for generating pseudorandom
|
|||
/// challenges
|
|||
/// Outputs:
|
|||
/// - Return error if the verification fails, otherwise return the
|
|||
/// evaluation subclaim
|
|||
///
|
|||
/// 1. Verify zero_check_proof on
|
|||
///
|
|||
/// `f(q_0(x),...q_l(x), w_0(x),...w_d(x))`
|
|||
///
|
|||
/// where `f` is the constraint polynomial i.e.,
|
|||
/// ```ignore
|
|||
/// f(q_l, q_r, q_m, q_o, w_a, w_b, w_c)
|
|||
/// = q_l w_a(x) + q_r w_b(x) + q_m w_a(x)w_b(x) - q_o w_c(x)
|
|||
/// ```
|
|||
/// in vanilla plonk, and obtain a ZeroCheckSubClaim
|
|||
///
|
|||
/// 2. Verify perm_check_proof on `\{w_i(x)\}` and `permutation_oracles`
|
|||
///
|
|||
/// 3. Verify the opening against the commitment:
|
|||
/// - check permutation check evaluations
|
|||
/// - check zero check evaluations
|
|||
/// - public input consistency checks
|
|||
/// 4. check subclaim validity // todo
|
|||
fn verify(
|
|||
vk: &Self::VerifyingKey,
|
|||
pub_input: &[E::Fr],
|
|||
proof: &Self::Proof,
|
|||
transcript: &mut Self::Transcript,
|
|||
) -> Result<Self::SubClaim, HyperPlonkErrors> {
|
|||
let start = start_timer!(|| "hyperplonk verification");
|
|||
|
|||
// witness assignment of length 2^n
|
|||
let num_var = vk.params.nv;
|
|||
let log_num_witness_polys = vk.params.log_n_wires;
|
|||
// number of variables in merged polynomial for Multilinear-KZG
|
|||
let merged_nv = num_var + log_num_witness_polys;
|
|||
|
|||
// online public input of length 2^\ell
|
|||
let ell = vk.params.log_pub_input_len;
|
|||
|
|||
let pi_poly = DenseMultilinearExtension::from_evaluations_slice(ell as usize, pub_input);
|
|||
|
|||
// =======================================================================
|
|||
// 0. sanity checks
|
|||
// =======================================================================
|
|||
// public input length
|
|||
if pub_input.len() != 1 << ell {
|
|||
return Err(HyperPlonkErrors::InvalidProver(format!(
|
|||
"Public input length is not correct: got {}, expect {}",
|
|||
pub_input.len(),
|
|||
1 << ell
|
|||
)));
|
|||
}
|
|||
|
|||
// =======================================================================
|
|||
// 1. Verify zero_check_proof on
|
|||
// `f(q_0(x),...q_l(x), w_0(x),...w_d(x))`
|
|||
//
|
|||
// where `f` is the constraint polynomial i.e.,
|
|||
//
|
|||
// f(q_l, q_r, q_m, q_o, w_a, w_b, w_c)
|
|||
// = q_l w_a(x) + q_r w_b(x) + q_m w_a(x)w_b(x) - q_o w_c(x)
|
|||
//
|
|||
// =======================================================================
|
|||
let step = start_timer!(|| "verify zero check");
|
|||
// Zero check and sum check have different AuxInfo because `w_merged` and
|
|||
// `Prod(x)` have degree and num_vars
|
|||
let zero_check_aux_info = VPAuxInfo::<E::Fr> {
|
|||
// TODO: get the real max degree from gate_func
|
|||
// Here we use 6 is because the test has q[0] * w[0]^5 which is degree 6
|
|||
max_degree: 6,
|
|||
num_variables: num_var,
|
|||
phantom: PhantomData::default(),
|
|||
};
|
|||
|
|||
// push witness to transcript
|
|||
transcript.append_serializable_element(b"w", &proof.w_merged_com)?;
|
|||
|
|||
let zero_check_sub_claim = <Self as ZeroCheck<E::Fr>>::verify(
|
|||
&proof.zero_check_proof,
|
|||
&zero_check_aux_info,
|
|||
transcript,
|
|||
)?;
|
|||
end_timer!(step);
|
|||
// =======================================================================
|
|||
// 2. Verify perm_check_proof on `\{w_i(x)\}` and `permutation_oracles`
|
|||
// =======================================================================
|
|||
// Zero check and sum check have different AuxInfo because `w_merged` and
|
|||
// `Prod(x)` have degree and num_vars
|
|||
let perm_check_aux_info = VPAuxInfo::<E::Fr> {
|
|||
// Prod(x) has a max degree of 2
|
|||
max_degree: 2,
|
|||
// degree of merged poly
|
|||
num_variables: merged_nv,
|
|||
phantom: PhantomData::default(),
|
|||
};
|
|||
let mut challenge = <Self as PermutationCheck<E::Fr>>::generate_challenge(transcript)?;
|
|||
<Self as PermutationCheck<E::Fr>>::update_challenge(
|
|||
&mut challenge,
|
|||
transcript,
|
|||
&proof.prod_commit,
|
|||
)?;
|
|||
|
|||
let perm_check_sub_claim = <Self as PermutationCheck<E::Fr>>::verify(
|
|||
&proof.perm_check_proof,
|
|||
&perm_check_aux_info,
|
|||
transcript,
|
|||
)?;
|
|||
|
|||
end_timer!(step);
|
|||
// =======================================================================
|
|||
// 3. Verify the opening against the commitment
|
|||
// =======================================================================
|
|||
let step = start_timer!(|| "verify commitments");
|
|||
|
|||
let perm_point = &perm_check_sub_claim
|
|||
.zero_check_sub_claim
|
|||
.sum_check_sub_claim
|
|||
.point;
|
|||
let zero_point = &zero_check_sub_claim.sum_check_sub_claim.point;
|
|||
|
|||
// =======================================================================
|
|||
// 3.1 check permutation check evaluations
|
|||
// =======================================================================
|
|||
// witness for permutation check
|
|||
if !PCS::verify(
|
|||
&vk.pcs_param,
|
|||
&proof.w_merged_com,
|
|||
perm_point,
|
|||
&proof.witness_perm_check_eval,
|
|||
&proof.witness_perm_check_opening,
|
|||
)? {
|
|||
return Err(HyperPlonkErrors::InvalidProof(
|
|||
"pcs verification failed".to_string(),
|
|||
));
|
|||
}
|
|||
|
|||
// perm for permutation check
|
|||
if !PCS::verify(
|
|||
&vk.pcs_param,
|
|||
&vk.perm_com,
|
|||
&[&[E::Fr::one()], perm_point.as_slice()].concat(),
|
|||
&proof.perm_oracle_eval,
|
|||
&proof.perm_oracle_opening,
|
|||
)? {
|
|||
return Err(HyperPlonkErrors::InvalidProof(
|
|||
"pcs verification failed".to_string(),
|
|||
));
|
|||
}
|
|||
|
|||
// =======================================================================
|
|||
// 3.2 check zero check evaluations
|
|||
// =======================================================================
|
|||
// witness for zero check
|
|||
// TODO: batch verification
|
|||
for (commitment, (opening, eval)) in proof.witness_commits.iter().zip(
|
|||
proof
|
|||
.witness_zero_check_openings
|
|||
.iter()
|
|||
.zip(proof.witness_zero_check_evals.iter()),
|
|||
) {
|
|||
if !PCS::verify(&vk.pcs_param, commitment, zero_point, eval, opening)? {
|
|||
return Err(HyperPlonkErrors::InvalidProof(
|
|||
"pcs verification failed".to_string(),
|
|||
));
|
|||
}
|
|||
}
|
|||
|
|||
// selector for zero check
|
|||
// TODO: for now we only support a single selector polynomial
|
|||
for (opening, eval) in proof
|
|||
.selector_oracle_openings
|
|||
.iter()
|
|||
.zip(proof.selector_oracle_evals.iter())
|
|||
{
|
|||
if !PCS::verify(
|
|||
&vk.pcs_param,
|
|||
&vk.selector_com[0],
|
|||
perm_point,
|
|||
eval,
|
|||
opening,
|
|||
)? {
|
|||
return Err(HyperPlonkErrors::InvalidProof(
|
|||
"pcs verification failed".to_string(),
|
|||
));
|
|||
}
|
|||
}
|
|||
|
|||
// let f_eval = eval_f(
|
|||
// &vk.params.gate_func,
|
|||
// &proof.selector_oracle_evals,
|
|||
// &proof.witness_zero_check_evals,
|
|||
// )?;
|
|||
// if f_eval != zero_check_sub_claim.sum_check_sub_claim.expected_evaluation {
|
|||
// return Err(HyperPlonkErrors::InvalidProof(
|
|||
// "zero check evaluation failed".to_string(),
|
|||
// ));
|
|||
// }
|
|||
|
|||
// =======================================================================
|
|||
// 3.3 public input consistency checks
|
|||
// =======================================================================
|
|||
let mut r_pi = transcript.get_and_append_challenge_vectors(b"r_pi", ell)?;
|
|||
let pi_eval = pi_poly.evaluate(&r_pi).ok_or_else(|| {
|
|||
HyperPlonkErrors::InvalidParameters("evaluation dimension does not match".to_string())
|
|||
})?;
|
|||
r_pi = [vec![E::Fr::zero(); num_var - ell], r_pi].concat();
|
|||
if !PCS::verify(
|
|||
&vk.pcs_param,
|
|||
&proof.witness_commits[0],
|
|||
&r_pi,
|
|||
&pi_eval,
|
|||
&proof.pi_opening,
|
|||
)? {
|
|||
return Err(HyperPlonkErrors::InvalidProof(
|
|||
"pcs verification failed".to_string(),
|
|||
));
|
|||
}
|
|||
|
|||
end_timer!(step);
|
|||
end_timer!(start);
|
|||
// todo: verify the subclaim within snark
|
|||
Ok(HyperPlonkSubClaim {
|
|||
zero_check_sub_claim,
|
|||
perm_check_sub_claim,
|
|||
pub_input_sub_claim: (vec![], E::Fr::default()), // FIXME
|
|||
})
|
|||
}
|
|||
}
|
|||
|
|||
#[cfg(test)]
|
|||
mod tests {
|
|||
use super::*;
|
|||
use crate::{selectors::SelectorColumn, structs::CustomizedGates, witness::WitnessColumn};
|
|||
use ark_bls12_381::Bls12_381;
|
|||
use ark_std::test_rng;
|
|||
use pcs::prelude::KZGMultilinearPCS;
|
|||
use poly_iop::{identity_permutation_mle, random_permutation_mle};
|
|||
use transcript::IOPTranscript;
|
|||
|
|||
#[test]
|
|||
fn it_works() {
|
|||
let result = 2 + 2;
|
|||
assert_eq!(result, 4);
|
|||
fn test_hyperplonk_e2e() -> Result<(), HyperPlonkErrors> {
|
|||
// Example:
|
|||
// q_L(X) * W_1(X)^5 - W_2(X) = 0
|
|||
// is represented as
|
|||
// vec![
|
|||
// ( 1, Some(id_qL), vec![id_W1, id_W1, id_W1, id_W1, id_W1]),
|
|||
// (-1, None, vec![id_W2])
|
|||
// ]
|
|||
//
|
|||
// 4 public input
|
|||
// 1 selector,
|
|||
// 2 witnesses,
|
|||
// 2 variables for MLE,
|
|||
// 4 wires,
|
|||
let gates = CustomizedGates {
|
|||
gates: vec![(1, Some(0), vec![0, 0, 0, 0, 0]), (-1, None, vec![1])],
|
|||
};
|
|||
test_hyperplonk_helper::<Bls12_381>(2, 2, 0, 1, gates)
|
|||
}
|
|||
|
|||
fn test_hyperplonk_helper<E: PairingEngine>(
|
|||
nv: usize,
|
|||
log_pub_input_len: usize,
|
|||
log_n_selectors: usize,
|
|||
log_n_wires: usize,
|
|||
gate_func: CustomizedGates,
|
|||
) -> Result<(), HyperPlonkErrors> {
|
|||
let mut rng = test_rng();
|
|||
// system parameters
|
|||
let params = HyperPlonkParams {
|
|||
nv,
|
|||
log_pub_input_len,
|
|||
log_n_selectors,
|
|||
log_n_wires,
|
|||
gate_func,
|
|||
};
|
|||
let pcs_srs = KZGMultilinearPCS::<E>::gen_srs_for_testing(&mut rng, 15)?;
|
|||
let merged_nv = nv + log_n_wires;
|
|||
|
|||
let s_perm = random_permutation_mle(merged_nv, &mut rng);
|
|||
let s_id = identity_permutation_mle(merged_nv);
|
|||
let perm: Vec<E::Fr> = [s_id.evaluations, s_perm.evaluations].concat();
|
|||
|
|||
let q1 = SelectorColumn(vec![E::Fr::one(), E::Fr::one(), E::Fr::one(), E::Fr::one()]);
|
|||
// w1 := [0, 1, 2, 3]
|
|||
let w1 = WitnessColumn(vec![
|
|||
E::Fr::zero(),
|
|||
E::Fr::one(),
|
|||
E::Fr::from(2u64),
|
|||
E::Fr::from(3u64),
|
|||
]);
|
|||
// w2 := [0^5, 1^5, 2^5, 3^5]
|
|||
let w2 = WitnessColumn(vec![
|
|||
E::Fr::zero(),
|
|||
E::Fr::one(),
|
|||
E::Fr::from(32u64),
|
|||
E::Fr::from(243u64),
|
|||
]);
|
|||
// public input = w1
|
|||
let pi = w1.clone();
|
|||
|
|||
// generate pk and vks
|
|||
let (pk, vk) = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::preprocess(
|
|||
¶ms,
|
|||
&pcs_srs,
|
|||
&perm,
|
|||
&[q1],
|
|||
)?;
|
|||
|
|||
// generate a proof and verify
|
|||
let mut transcript = IOPTranscript::<E::Fr>::new(b"test hyperplonk");
|
|||
let proof = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::prove(
|
|||
&pk,
|
|||
&pi.0,
|
|||
&[w1, w2],
|
|||
&mut transcript,
|
|||
)?;
|
|||
|
|||
let mut transcript = IOPTranscript::<E::Fr>::new(b"test hyperplonk");
|
|||
let _sub_claim = <PolyIOP<E::Fr> as HyperPlonkSNARK<E, KZGMultilinearPCS<E>>>::verify(
|
|||
&vk,
|
|||
&pi.0,
|
|||
&proof,
|
|||
&mut transcript,
|
|||
)?;
|
|||
|
|||
Ok(())
|
|||
}
|
|||
}
|
@ -0,0 +1,46 @@ |
|||
use crate::errors::HyperPlonkErrors;
|
|||
use ark_ff::PrimeField;
|
|||
use ark_poly::DenseMultilinearExtension;
|
|||
use ark_std::log2;
|
|||
|
|||
/// A column of selectors of length `#constraints`
|
|||
#[derive(Debug, Clone)]
|
|||
pub struct SelectorColumn<F: PrimeField>(pub(crate) Vec<F>);
|
|||
|
|||
impl<F: PrimeField> SelectorColumn<F> {
|
|||
/// the number of variables for MLE to present a column.
|
|||
pub fn get_nv(&self) -> usize {
|
|||
log2(self.0.len()) as usize
|
|||
}
|
|||
|
|||
/// Build selector columns from rows
|
|||
pub fn from_selector_rows(
|
|||
selector_rows: &[SelectorColumn<F>],
|
|||
) -> Result<Vec<Self>, HyperPlonkErrors> {
|
|||
if selector_rows.is_empty() {
|
|||
return Err(HyperPlonkErrors::InvalidParameters(
|
|||
"empty witness rows".to_string(),
|
|||
));
|
|||
}
|
|||
|
|||
let mut res = Vec::with_capacity(selector_rows.len());
|
|||
let num_wires = selector_rows[0].0.len();
|
|||
|
|||
for i in 0..num_wires {
|
|||
let mut cur_column = Vec::new();
|
|||
for row in selector_rows.iter() {
|
|||
cur_column.push(row.0[i])
|
|||
}
|
|||
res.push(Self(cur_column))
|
|||
}
|
|||
|
|||
Ok(res)
|
|||
}
|
|||
}
|
|||
|
|||
impl<F: PrimeField> From<&SelectorColumn<F>> for DenseMultilinearExtension<F> {
|
|||
fn from(witness: &SelectorColumn<F>) -> Self {
|
|||
let nv = witness.get_nv();
|
|||
Self::from_evaluations_slice(nv, witness.0.as_ref())
|
|||
}
|
|||
}
|
@ -0,0 +1,156 @@ |
|||
//! Main module for the HyperPlonk PolyIOP.
|
|||
|
|||
use ark_ec::PairingEngine;
|
|||
use ark_ff::PrimeField;
|
|||
use ark_poly::DenseMultilinearExtension;
|
|||
use pcs::PolynomialCommitmentScheme;
|
|||
use poly_iop::prelude::{PermutationCheck, ZeroCheck};
|
|||
use std::rc::Rc;
|
|||
|
|||
/// The sub-claim for the HyperPlonk PolyIOP, consists of the following:
|
|||
/// - the SubClaim for the zero-check PIOP
|
|||
/// - the SubClaim for the permutation-check PIOP
|
|||
/// - the SubClaim for public input consistency
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct HyperPlonkSubClaim<F: PrimeField, ZC: ZeroCheck<F>, PC: PermutationCheck<F>> {
|
|||
/// the SubClaim for the custom gate zerocheck
|
|||
pub zero_check_sub_claim: ZC::ZeroCheckSubClaim,
|
|||
/// the SubClaim for the permutation check
|
|||
pub perm_check_sub_claim: PC::PermutationCheckSubClaim,
|
|||
/// the public input consistency check
|
|||
pub pub_input_sub_claim: (Vec<F>, F), // (point, expected_eval)
|
|||
}
|
|||
|
|||
/// The proof for the HyperPlonk PolyIOP, consists of the following:
|
|||
/// - a batch commitment to all the witness MLEs
|
|||
/// - a batch opening to all the MLEs at certain index
|
|||
/// - the zero-check proof for checking custom gate-satisfiability
|
|||
/// - the permutation-check proof for checking the copy constraints
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct HyperPlonkProof<
|
|||
E: PairingEngine,
|
|||
PCS: PolynomialCommitmentScheme<E>,
|
|||
ZC: ZeroCheck<E::Fr>,
|
|||
PC: PermutationCheck<E::Fr>,
|
|||
> {
|
|||
// =======================================================================
|
|||
// PCS components
|
|||
// =======================================================================
|
|||
/// PCS commit for witnesses
|
|||
// TODO: replace me with a batch commitment
|
|||
pub witness_commits: Vec<PCS::Commitment>,
|
|||
pub w_merged_com: PCS::Commitment,
|
|||
/// PCS commit for prod(x)
|
|||
// TODO: replace me with a batch commitment
|
|||
pub prod_commit: PCS::Commitment,
|
|||
/// PCS openings for witness on permutation check point
|
|||
// TODO: replace me with a batch opening
|
|||
pub witness_perm_check_opening: PCS::Proof,
|
|||
/// PCS openings for witness on zero check point
|
|||
// TODO: replace me with a batch opening
|
|||
pub witness_zero_check_openings: Vec<PCS::Proof>,
|
|||
/// Evaluates of witnesses on permutation check point
|
|||
pub witness_perm_check_eval: E::Fr,
|
|||
/// Evaluates of witnesses on zero check point
|
|||
pub witness_zero_check_evals: Vec<E::Fr>,
|
|||
/// PCS openings for selectors on permutation check point
|
|||
// TODO: replace me with a batch opening
|
|||
pub perm_oracle_opening: PCS::Proof,
|
|||
/// Evaluates of selectors on permutation check point
|
|||
pub perm_oracle_eval: E::Fr,
|
|||
/// PCS openings for selectors on zero check point
|
|||
// TODO: replace me with a batch opening
|
|||
pub selector_oracle_openings: Vec<PCS::Proof>,
|
|||
/// Evaluates of selectors on zero check point
|
|||
pub selector_oracle_evals: Vec<E::Fr>,
|
|||
/// Evaluates of public inputs on r_pi from transcript
|
|||
pub pi_eval: E::Fr,
|
|||
/// Opening of public inputs on r_pi from transcript
|
|||
pub pi_opening: PCS::Proof,
|
|||
// =======================================================================
|
|||
// IOP components
|
|||
// =======================================================================
|
|||
/// the custom gate zerocheck proof
|
|||
pub zero_check_proof: ZC::ZeroCheckProof,
|
|||
/// the permutation check proof for copy constraints
|
|||
pub perm_check_proof: PC::PermutationProof,
|
|||
}
|
|||
|
|||
/// The HyperPlonk instance parameters, consists of the following:
|
|||
/// - the number of variables in the poly-IOP
|
|||
/// - binary log of the number of public input variables
|
|||
/// - binary log of the number of selectors
|
|||
/// - binary log of the number of witness wires
|
|||
/// - the customized gate function
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct HyperPlonkParams {
|
|||
/// the number of variables in polys
|
|||
pub nv: usize,
|
|||
/// binary log of the public input length
|
|||
pub log_pub_input_len: usize,
|
|||
// binary log of the number of selectors
|
|||
pub log_n_selectors: usize,
|
|||
/// binary log of the number of witness wires
|
|||
pub log_n_wires: usize,
|
|||
/// customized gate function
|
|||
pub gate_func: CustomizedGates,
|
|||
}
|
|||
|
|||
/// The HyperPlonk proving key, consists of the following:
|
|||
/// - the hyperplonk instance parameters
|
|||
/// - the preprocessed polynomials output by the indexer
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct HyperPlonkProvingKey<E: PairingEngine, PCS: PolynomialCommitmentScheme<E>> {
|
|||
/// hyperplonk instance parameters
|
|||
pub params: HyperPlonkParams,
|
|||
/// the preprocessed permutation polynomials
|
|||
pub permutation_oracles: Rc<DenseMultilinearExtension<E::Fr>>,
|
|||
/// the preprocessed selector polynomials
|
|||
// TODO: merge the list into a single MLE
|
|||
pub selector_oracles: Vec<Rc<DenseMultilinearExtension<E::Fr>>>,
|
|||
/// the parameters for PCS commitment
|
|||
pub pcs_param: PCS::ProverParam,
|
|||
}
|
|||
|
|||
/// The HyperPlonk verifying key, consists of the following:
|
|||
/// - the hyperplonk instance parameters
|
|||
/// - the preprocessed polynomials output by the indexer
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct HyperPlonkVerifyingKey<E: PairingEngine, PCS: PolynomialCommitmentScheme<E>> {
|
|||
/// hyperplonk instance parameters
|
|||
pub params: HyperPlonkParams,
|
|||
/// the parameters for PCS commitment
|
|||
pub pcs_param: PCS::VerifierParam,
|
|||
/// Selector's commitment
|
|||
// TODO: replace me with a batch commitment
|
|||
pub selector_com: Vec<PCS::Commitment>,
|
|||
/// Permutation oracle's commitment
|
|||
pub perm_com: PCS::Commitment,
|
|||
}
|
|||
|
|||
/// Customized gate is a list of tuples of
|
|||
/// (coefficient, selector_index, wire_indices)
|
|||
///
|
|||
/// Example:
|
|||
/// q_L(X) * W_1(X)^5 - W_2(X)
|
|||
/// is represented as
|
|||
/// vec![
|
|||
/// ( 1, Some(id_qL), vec![id_W1, id_W1, id_W1, id_W1, id_W1]),
|
|||
/// (-1, None, vec![id_W2])
|
|||
/// ]
|
|||
///
|
|||
/// CustomizedGates {
|
|||
/// gates: vec![
|
|||
/// (1, Some(0), vec![0, 0, 0, 0, 0]),
|
|||
/// (-1, None, vec![1])
|
|||
/// ],
|
|||
/// };
|
|||
/// where id_qL = 0 // first selector
|
|||
/// id_W1 = 0 // first witness
|
|||
/// id_w2 = 1 // second witness
|
|||
///
|
|||
/// NOTE: here coeff is a signed integer, instead of a field element
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct CustomizedGates {
|
|||
pub(crate) gates: Vec<(i64, Option<usize>, Vec<usize>)>,
|
|||
}
|
@ -0,0 +1,210 @@ |
|||
use std::rc::Rc;
|
|||
|
|||
use arithmetic::VirtualPolynomial;
|
|||
use ark_ff::PrimeField;
|
|||
use ark_poly::DenseMultilinearExtension;
|
|||
|
|||
use crate::{errors::HyperPlonkErrors, structs::CustomizedGates};
|
|||
|
|||
/// Build MLE from matrix of witnesses.
|
|||
///
|
|||
/// Given a matrix := [row1, row2, ...] where
|
|||
/// row1:= (a1, a2, ...)
|
|||
/// row2:= (b1, b2, ...)
|
|||
/// row3:= (c1, c2, ...)
|
|||
///
|
|||
/// output mle(a1,b1,c1, ...), mle(a2,b2,c2, ...), ...
|
|||
#[macro_export]
|
|||
macro_rules! build_mle {
|
|||
($rows:expr) => {{
|
|||
let mut res = Vec::with_capacity($rows.len());
|
|||
let num_vars = log2($rows.len()) as usize;
|
|||
let num_mles = $rows[0].0.len();
|
|||
|
|||
for i in 0..num_mles {
|
|||
let mut cur_coeffs = Vec::new();
|
|||
for row in $rows.iter() {
|
|||
cur_coeffs.push(row.0[i])
|
|||
}
|
|||
res.push(Rc::new(DenseMultilinearExtension::from_evaluations_vec(
|
|||
num_vars, cur_coeffs,
|
|||
)))
|
|||
}
|
|||
|
|||
Ok(res)
|
|||
}};
|
|||
}
|
|||
|
|||
/// build `f(w_0(x),...w_d(x))` where `f` is the constraint polynomial
|
|||
/// i.e., `f(a, b, c) = q_l a(x) + q_r b(x) + q_m a(x)b(x) - q_o c(x)` in
|
|||
/// vanilla plonk
|
|||
pub(crate) fn build_f<F: PrimeField>(
|
|||
gates: &CustomizedGates,
|
|||
num_vars: usize,
|
|||
selector_mles: &[Rc<DenseMultilinearExtension<F>>],
|
|||
witness_mles: &[Rc<DenseMultilinearExtension<F>>],
|
|||
) -> Result<VirtualPolynomial<F>, HyperPlonkErrors> {
|
|||
// TODO: check that selector and witness lengths match what is in
|
|||
// the gate definition
|
|||
|
|||
for selector_mle in selector_mles.iter() {
|
|||
if selector_mle.num_vars != num_vars {
|
|||
return Err(HyperPlonkErrors::InvalidParameters(format!(
|
|||
"selector has different number of vars: {} vs {}",
|
|||
selector_mle.num_vars, num_vars
|
|||
)));
|
|||
}
|
|||
}
|
|||
|
|||
for witness_mle in witness_mles.iter() {
|
|||
if witness_mle.num_vars != num_vars {
|
|||
return Err(HyperPlonkErrors::InvalidParameters(format!(
|
|||
"selector has different number of vars: {} vs {}",
|
|||
witness_mle.num_vars, num_vars
|
|||
)));
|
|||
}
|
|||
}
|
|||
|
|||
let mut res = VirtualPolynomial::<F>::new(num_vars);
|
|||
|
|||
for (coeff, selector, witnesses) in gates.gates.iter() {
|
|||
let coeff_fr = if *coeff < 0 {
|
|||
-F::from(-*coeff as u64)
|
|||
} else {
|
|||
F::from(*coeff as u64)
|
|||
};
|
|||
let mut mle_list = vec![];
|
|||
match *selector {
|
|||
Some(s) => mle_list.push(selector_mles[s].clone()),
|
|||
None => (),
|
|||
};
|
|||
for &witness in witnesses.iter() {
|
|||
mle_list.push(witness_mles[witness].clone())
|
|||
}
|
|||
res.add_mle_list(mle_list, coeff_fr)?;
|
|||
}
|
|||
|
|||
Ok(res)
|
|||
}
|
|||
|
|||
#[allow(dead_code)]
|
|||
pub(crate) fn eval_f<F: PrimeField>(
|
|||
gates: &CustomizedGates,
|
|||
selector_evals: &[F],
|
|||
witness_evals: &[F],
|
|||
) -> Result<F, HyperPlonkErrors> {
|
|||
let mut res = F::zero();
|
|||
for (coeff, selector, witnesses) in gates.gates.iter() {
|
|||
let mut cur_value = if *coeff < 0 {
|
|||
-F::from(-*coeff as u64)
|
|||
} else {
|
|||
F::from(*coeff as u64)
|
|||
};
|
|||
cur_value *= match selector {
|
|||
Some(s) => selector_evals[*s],
|
|||
None => F::one(),
|
|||
};
|
|||
for &witness in witnesses.iter() {
|
|||
cur_value *= witness_evals[witness]
|
|||
}
|
|||
res += cur_value;
|
|||
}
|
|||
Ok(res)
|
|||
}
|
|||
|
|||
#[cfg(test)]
|
|||
mod test {
|
|||
use super::*;
|
|||
use ark_bls12_381::Fr;
|
|||
use ark_ff::PrimeField;
|
|||
use ark_poly::MultilinearExtension;
|
|||
#[test]
|
|||
fn test_build_gate() -> Result<(), HyperPlonkErrors> {
|
|||
test_build_gate_helper::<Fr>()
|
|||
}
|
|||
|
|||
fn test_build_gate_helper<F: PrimeField>() -> Result<(), HyperPlonkErrors> {
|
|||
let num_vars = 2;
|
|||
|
|||
// ql = 3x1x2 + 2x2 whose evaluations are
|
|||
// 0, 0 |-> 0
|
|||
// 0, 1 |-> 2
|
|||
// 1, 0 |-> 0
|
|||
// 1, 1 |-> 5
|
|||
let ql_eval = vec![F::zero(), F::from(2u64), F::zero(), F::from(5u64)];
|
|||
let ql = Rc::new(DenseMultilinearExtension::from_evaluations_vec(2, ql_eval));
|
|||
|
|||
// W1 = x1x2 + x1 whose evaluations are
|
|||
// 0, 0 |-> 0
|
|||
// 0, 1 |-> 0
|
|||
// 1, 0 |-> 1
|
|||
// 1, 1 |-> 2
|
|||
let w_eval = vec![F::zero(), F::zero(), F::from(1u64), F::from(2u64)];
|
|||
let w1 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(2, w_eval));
|
|||
|
|||
// W2 = x1 + x2 whose evaluations are
|
|||
// 0, 0 |-> 0
|
|||
// 0, 1 |-> 1
|
|||
// 1, 0 |-> 1
|
|||
// 1, 1 |-> 2
|
|||
let w_eval = vec![F::zero(), F::one(), F::from(1u64), F::from(2u64)];
|
|||
let w2 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(2, w_eval));
|
|||
|
|||
// Example:
|
|||
// q_L(X) * W_1(X)^5 - W_2(X)
|
|||
// is represented as
|
|||
// vec![
|
|||
// ( 1, Some(id_qL), vec![id_W1, id_W1, id_W1, id_W1, id_W1]),
|
|||
// (-1, None, vec![id_W2])
|
|||
// ]
|
|||
let gates = CustomizedGates {
|
|||
gates: vec![(1, Some(0), vec![0, 0, 0, 0, 0]), (-1, None, vec![1])],
|
|||
};
|
|||
let f = build_f(&gates, num_vars, &[ql.clone()], &[w1.clone(), w2.clone()])?;
|
|||
|
|||
// Sanity check on build_f
|
|||
// f(0, 0) = 0
|
|||
assert_eq!(f.evaluate(&[F::zero(), F::zero()])?, F::zero());
|
|||
// f(0, 1) = 2 * 0^5 + (-1) * 1 = -1
|
|||
assert_eq!(f.evaluate(&[F::zero(), F::one()])?, -F::one());
|
|||
// f(1, 0) = 0 * 1^5 + (-1) * 1 = -1
|
|||
assert_eq!(f.evaluate(&[F::one(), F::zero()])?, -F::one());
|
|||
// f(1, 1) = 5 * 2^5 + (-1) * 2 = 158
|
|||
assert_eq!(f.evaluate(&[F::one(), F::one()])?, F::from(158u64));
|
|||
|
|||
// test eval_f
|
|||
{
|
|||
let point = [F::zero(), F::zero()];
|
|||
let selector_evals = ql.evaluate(&point).unwrap();
|
|||
let witness_evals = [w1.evaluate(&point).unwrap(), w2.evaluate(&point).unwrap()];
|
|||
let eval_f = eval_f(&gates, &[selector_evals], &witness_evals)?;
|
|||
// f(0, 0) = 0
|
|||
assert_eq!(eval_f, F::zero());
|
|||
}
|
|||
{
|
|||
let point = [F::zero(), F::one()];
|
|||
let selector_evals = ql.evaluate(&point).unwrap();
|
|||
let witness_evals = [w1.evaluate(&point).unwrap(), w2.evaluate(&point).unwrap()];
|
|||
let eval_f = eval_f(&gates, &[selector_evals], &witness_evals)?;
|
|||
// f(0, 1) = 2 * 0^5 + (-1) * 1 = -1
|
|||
assert_eq!(eval_f, -F::one());
|
|||
}
|
|||
{
|
|||
let point = [F::one(), F::zero()];
|
|||
let selector_evals = ql.evaluate(&point).unwrap();
|
|||
let witness_evals = [w1.evaluate(&point).unwrap(), w2.evaluate(&point).unwrap()];
|
|||
let eval_f = eval_f(&gates, &[selector_evals], &witness_evals)?;
|
|||
// f(1, 0) = 0 * 1^5 + (-1) * 1 = -1
|
|||
assert_eq!(eval_f, -F::one());
|
|||
}
|
|||
{
|
|||
let point = [F::one(), F::one()];
|
|||
let selector_evals = ql.evaluate(&point).unwrap();
|
|||
let witness_evals = [w1.evaluate(&point).unwrap(), w2.evaluate(&point).unwrap()];
|
|||
let eval_f = eval_f(&gates, &[selector_evals], &witness_evals)?;
|
|||
// f(1, 1) = 5 * 2^5 + (-1) * 2 = 158
|
|||
assert_eq!(eval_f, F::from(158u64));
|
|||
}
|
|||
Ok(())
|
|||
}
|
|||
}
|
@ -0,0 +1,67 @@ |
|||
use crate::{build_mle, errors::HyperPlonkErrors};
|
|||
use ark_ff::PrimeField;
|
|||
use ark_poly::DenseMultilinearExtension;
|
|||
use ark_std::log2;
|
|||
use std::rc::Rc;
|
|||
|
|||
/// A row of witnesses of width `#wires`
|
|||
#[derive(Debug, Clone)]
|
|||
pub struct WitnessRow<F: PrimeField>(pub(crate) Vec<F>);
|
|||
|
|||
/// A column of witnesses of length `#constraints`
|
|||
#[derive(Debug, Clone)]
|
|||
pub struct WitnessColumn<F: PrimeField>(pub(crate) Vec<F>);
|
|||
|
|||
impl<F: PrimeField> WitnessColumn<F> {
|
|||
/// the number of variables for MLE to present a column.
|
|||
pub fn get_nv(&self) -> usize {
|
|||
log2(self.0.len()) as usize
|
|||
}
|
|||
|
|||
/// Build witness columns from rows
|
|||
pub fn from_witness_rows(
|
|||
witness_rows: &[WitnessRow<F>],
|
|||
) -> Result<Vec<Self>, HyperPlonkErrors> {
|
|||
if witness_rows.is_empty() {
|
|||
return Err(HyperPlonkErrors::InvalidParameters(
|
|||
"empty witness rows".to_string(),
|
|||
));
|
|||
}
|
|||
|
|||
let mut res = Vec::with_capacity(witness_rows.len());
|
|||
let num_wires = witness_rows[0].0.len();
|
|||
|
|||
for i in 0..num_wires {
|
|||
let mut cur_column = Vec::new();
|
|||
for row in witness_rows.iter() {
|
|||
cur_column.push(row.0[i])
|
|||
}
|
|||
res.push(Self(cur_column))
|
|||
}
|
|||
|
|||
Ok(res)
|
|||
}
|
|||
}
|
|||
|
|||
impl<F: PrimeField> From<&WitnessColumn<F>> for DenseMultilinearExtension<F> {
|
|||
fn from(witness: &WitnessColumn<F>) -> Self {
|
|||
let nv = witness.get_nv();
|
|||
Self::from_evaluations_slice(nv, witness.0.as_ref())
|
|||
}
|
|||
}
|
|||
|
|||
impl<F: PrimeField> WitnessRow<F> {
|
|||
/// Build MLE from matrix of witnesses.
|
|||
///
|
|||
/// Given a matrix := [row1, row2, ...] where
|
|||
/// row1:= (a1, a2, ...)
|
|||
/// row2:= (b1, b2, ...)
|
|||
/// row3:= (c1, c2, ...)
|
|||
///
|
|||
/// output mle(a1,b1,c1, ...), mle(a2,b2,c2, ...), ...
|
|||
pub fn build_mles(
|
|||
matrix: &[Self],
|
|||
) -> Result<Vec<Rc<DenseMultilinearExtension<F>>>, HyperPlonkErrors> {
|
|||
build_mle!(matrix)
|
|||
}
|
|||
}
|
@ -1,3 +0,0 @@ |
|||
use ark_ec::{AffineCurve, PairingEngine};
|
|||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write};
|
|||
use ark_std::vec::Vec;
|
@ -1,126 +0,0 @@ |
|||
//! Main module for the HyperPlonk PolyIOP.
|
|||
|
|||
use crate::{errors::PolyIOPErrors, perm_check::PermutationCheck, zero_check::ZeroCheck};
|
|||
use ark_ff::PrimeField;
|
|||
use ark_poly::DenseMultilinearExtension;
|
|||
use std::rc::Rc;
|
|||
use transcript::IOPTranscript;
|
|||
|
|||
/// A trait for HyperPlonk Poly-IOPs
|
|||
pub trait HyperPlonkPIOP<F: PrimeField> {
|
|||
type Parameters;
|
|||
type ProvingKey;
|
|||
type Proof;
|
|||
type SubClaim;
|
|||
|
|||
/// Generate the preprocessed polynomials output by the indexer.
|
|||
///
|
|||
/// Inputs:
|
|||
/// - `params`: HyperPlonk instance parameters
|
|||
/// - `permutation`: the permutation for the copy constraints
|
|||
/// - `selectors`: the list of selector vectors for custom gates
|
|||
/// Outputs:
|
|||
/// - The HyperPlonk proving key, which includes the preprocessed
|
|||
/// polynomials.
|
|||
fn preprocess(
|
|||
params: &Self::Parameters,
|
|||
permutation: &[F],
|
|||
selectors: &[&[F]],
|
|||
) -> Result<Self::ProvingKey, PolyIOPErrors>;
|
|||
|
|||
/// Generate HyperPlonk PIOP proof.
|
|||
///
|
|||
/// Inputs:
|
|||
/// - `pk`: circuit proving key
|
|||
/// - `pub_input`: online public input
|
|||
/// - `witness`: witness assignement
|
|||
/// - `transcript`: the transcript used for generating pseudorandom
|
|||
/// challenges
|
|||
/// Outputs:
|
|||
/// - The HyperPlonk PIOP proof.
|
|||
fn prove(
|
|||
pk: &Self::ProvingKey,
|
|||
pub_input: &[F],
|
|||
witness: &[&[F]],
|
|||
transcript: &mut IOPTranscript<F>,
|
|||
) -> Result<Self::Proof, PolyIOPErrors>;
|
|||
|
|||
/// Verify the HyperPlonk proof and generate the evaluation subclaims to be
|
|||
/// checked later by the SNARK verifier.
|
|||
///
|
|||
/// Inputs:
|
|||
/// - `params`: instance parameter
|
|||
/// - `pub_input`: online public input
|
|||
/// - `proof`: HyperPlonk PIOP proof
|
|||
/// - `transcript`: the transcript used for generating pseudorandom
|
|||
/// challenges
|
|||
/// Outputs:
|
|||
/// - Return error if the verification fails, otherwise return the
|
|||
/// evaluation subclaim
|
|||
fn verify(
|
|||
params: &Self::Parameters,
|
|||
pub_input: &[F],
|
|||
proof: &Self::Proof,
|
|||
transcript: &mut IOPTranscript<F>,
|
|||
) -> Result<Self::SubClaim, PolyIOPErrors>;
|
|||
}
|
|||
|
|||
/// The sub-claim for the HyperPlonk PolyIOP, consists of the following:
|
|||
/// - the SubClaim for the zero-check PIOP
|
|||
/// - the SubClaim for the permutation-check PIOP
|
|||
/// - the SubClaim for public input consistency
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct HyperPlonkSubClaim<F: PrimeField, ZC: ZeroCheck<F>, PC: PermutationCheck<F>> {
|
|||
/// the SubClaim for the custom gate zerocheck
|
|||
pub zero_check_sub_claim: ZC::ZeroCheckSubClaim,
|
|||
/// the SubClaim for the permutation check
|
|||
pub perm_check_sub_claim: PC::PermutationCheckSubClaim,
|
|||
/// the public input consistency check
|
|||
pub pub_input_sub_claim: (Vec<F>, F), // (point, expected_eval)
|
|||
}
|
|||
|
|||
/// The proof for the HyperPlonk PolyIOP, consists of the following:
|
|||
/// - the zero-check proof for checking custom gate-satisfiability
|
|||
/// - the permutation-check proof for checking the copy constraints
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct HyperPlonkProof<F: PrimeField, ZC: ZeroCheck<F>, PC: PermutationCheck<F>> {
|
|||
/// the custom gate zerocheck proof
|
|||
pub zero_check_proof: ZC::Proof,
|
|||
/// the permutation check proof for copy constraints
|
|||
pub perm_check_proof: PC::Proof,
|
|||
}
|
|||
|
|||
/// The HyperPlonk instance parameters, consists of the following:
|
|||
/// - the number of variables in the poly-IOP
|
|||
/// - binary log of the number of public input variables
|
|||
/// - binary log of the number of selectors
|
|||
/// - binary log of the number of witness wires
|
|||
/// - the customized gate function
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct HyperPlonkParams {
|
|||
/// the number of variables in polys
|
|||
pub nv: usize,
|
|||
/// binary log of the public input length
|
|||
pub log_pub_input_len: usize,
|
|||
// binary log of the number of selectors
|
|||
pub log_n_selectors: usize,
|
|||
/// binary log of the number of witness wires
|
|||
pub log_n_wires: usize,
|
|||
/// customized gate function
|
|||
// TODO: define a struct for it.
|
|||
pub gate_func: Vec<Vec<usize>>,
|
|||
}
|
|||
|
|||
/// The HyperPlonk proving key, consists of the following:
|
|||
/// - the hyperplonk instance parameters
|
|||
/// - the preprocessed polynomials output by the indexer
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
|||
pub struct HyperPlonkProvingKey<F: PrimeField> {
|
|||
/// hyperplonk instance parameters
|
|||
pub params: HyperPlonkParams,
|
|||
/// the preprocessed index polynomials
|
|||
pub index_oracles: Vec<Rc<DenseMultilinearExtension<F>>>,
|
|||
}
|
|||
|
|||
#[cfg(test)]
|
|||
mod test {}
|
@ -0,0 +1,11 @@ |
|||
pub use crate::{
|
|||
errors::PolyIOPErrors,
|
|||
perm_check::{
|
|||
util::{identity_permutation_mle, random_permutation_mle},
|
|||
PermutationCheck,
|
|||
},
|
|||
sum_check::SumCheck,
|
|||
utils::*,
|
|||
zero_check::ZeroCheck,
|
|||
PolyIOP,
|
|||
};
|