2022-02-07 10:41:52 +01:00
|
|
|
use plonky2::field::extension_field::Extendable;
|
2022-02-08 18:16:33 +01:00
|
|
|
use plonky2::field::field_types::Field;
|
2022-02-07 10:41:52 +01:00
|
|
|
use plonky2::hash::hash_types::RichField;
|
2022-02-08 18:16:33 +01:00
|
|
|
use plonky2::iop::ext_target::ExtensionTarget;
|
2022-02-07 10:41:52 +01:00
|
|
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
2022-02-08 18:16:33 +01:00
|
|
|
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
|
|
|
|
|
use plonky2::util::reducing::ReducingFactorTarget;
|
|
|
|
|
|
2022-02-07 10:41:52 +01:00
|
|
|
use crate::config::StarkConfig;
|
2022-02-08 18:16:33 +01:00
|
|
|
use crate::constraint_consumer::RecursiveConstraintConsumer;
|
|
|
|
|
use crate::proof::{
|
|
|
|
|
StarkOpeningSetTarget, StarkProofChallengesTarget, StarkProofWithPublicInputsTarget,
|
|
|
|
|
};
|
2022-02-07 10:41:52 +01:00
|
|
|
use crate::stark::Stark;
|
2022-02-08 18:19:11 +01:00
|
|
|
use crate::vars::StarkEvaluationTargets;
|
2022-02-07 10:41:52 +01:00
|
|
|
|
2022-02-08 18:16:33 +01:00
|
|
|
pub fn verify_stark_proof<
|
|
|
|
|
F: RichField + Extendable<D>,
|
2022-02-07 10:41:52 +01:00
|
|
|
C: GenericConfig<D, F = F>,
|
|
|
|
|
S: Stark<F, D>,
|
|
|
|
|
const D: usize,
|
2022-02-08 18:16:33 +01:00
|
|
|
>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
stark: S,
|
|
|
|
|
proof_with_pis: StarkProofWithPublicInputsTarget<D>,
|
|
|
|
|
inner_config: &StarkConfig,
|
|
|
|
|
) where
|
|
|
|
|
C::Hasher: AlgebraicHasher<F>,
|
2022-02-08 18:19:11 +01:00
|
|
|
[(); S::COLUMNS]:,
|
|
|
|
|
[(); S::PUBLIC_INPUTS]:,
|
2022-02-08 18:16:33 +01:00
|
|
|
{
|
|
|
|
|
assert_eq!(proof_with_pis.public_inputs.len(), S::PUBLIC_INPUTS);
|
|
|
|
|
let degree_bits = proof_with_pis.proof.recover_degree_bits(inner_config);
|
|
|
|
|
let challenges = proof_with_pis.get_challenges::<F, C>(builder, inner_config, degree_bits);
|
|
|
|
|
|
|
|
|
|
verify_stark_proof_with_challenges::<F, C, S, D>(
|
|
|
|
|
builder,
|
|
|
|
|
stark,
|
|
|
|
|
proof_with_pis,
|
|
|
|
|
challenges,
|
|
|
|
|
inner_config,
|
|
|
|
|
degree_bits,
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-02-07 10:41:52 +01:00
|
|
|
|
2022-02-08 18:16:33 +01:00
|
|
|
/// Recursively verifies an inner proof.
|
|
|
|
|
fn verify_stark_proof_with_challenges<
|
|
|
|
|
F: RichField + Extendable<D>,
|
|
|
|
|
C: GenericConfig<D, F = F>,
|
|
|
|
|
S: Stark<F, D>,
|
|
|
|
|
const D: usize,
|
|
|
|
|
>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
stark: S,
|
|
|
|
|
proof_with_pis: StarkProofWithPublicInputsTarget<D>,
|
|
|
|
|
challenges: StarkProofChallengesTarget<D>,
|
|
|
|
|
inner_config: &StarkConfig,
|
|
|
|
|
degree_bits: usize,
|
|
|
|
|
) where
|
|
|
|
|
C::Hasher: AlgebraicHasher<F>,
|
2022-02-08 18:19:11 +01:00
|
|
|
[(); S::COLUMNS]:,
|
|
|
|
|
[(); S::PUBLIC_INPUTS]:,
|
2022-02-08 18:16:33 +01:00
|
|
|
{
|
|
|
|
|
let one = builder.one_extension();
|
|
|
|
|
|
|
|
|
|
let StarkProofWithPublicInputsTarget {
|
|
|
|
|
proof,
|
|
|
|
|
public_inputs,
|
|
|
|
|
} = proof_with_pis;
|
|
|
|
|
let local_values = &proof.openings.local_values;
|
|
|
|
|
let next_values = &proof.openings.local_values;
|
|
|
|
|
let StarkOpeningSetTarget {
|
|
|
|
|
local_values,
|
|
|
|
|
next_values,
|
|
|
|
|
permutation_zs,
|
|
|
|
|
permutation_zs_right,
|
|
|
|
|
quotient_polys,
|
|
|
|
|
} = &proof.openings;
|
|
|
|
|
let vars = StarkEvaluationTargets {
|
|
|
|
|
local_values: &local_values.to_vec().try_into().unwrap(),
|
|
|
|
|
next_values: &next_values.to_vec().try_into().unwrap(),
|
|
|
|
|
public_inputs: &public_inputs
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|t| builder.convert_to_ext(t))
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.try_into()
|
|
|
|
|
.unwrap(),
|
|
|
|
|
};
|
2022-02-08 18:24:28 +01:00
|
|
|
let zeta_pow_deg = builder.exp_power_of_2_extension(challenges.stark_zeta, degree_bits);
|
|
|
|
|
let z_h_zeta = builder.sub_extension(zeta_pow_deg, one);
|
2022-02-08 18:16:33 +01:00
|
|
|
let (l_1, l_last) =
|
2022-02-08 18:24:28 +01:00
|
|
|
eval_l_1_and_l_last_recursively(builder, degree_bits, challenges.stark_zeta, z_h_zeta);
|
2022-02-08 18:16:33 +01:00
|
|
|
let last =
|
|
|
|
|
builder.constant_extension(F::Extension::primitive_root_of_unity(degree_bits).inverse());
|
|
|
|
|
let z_last = builder.sub_extension(challenges.stark_zeta, last);
|
|
|
|
|
let mut consumer = RecursiveConstraintConsumer::<F, D>::new(
|
|
|
|
|
builder.zero_extension(),
|
|
|
|
|
challenges.stark_alphas,
|
|
|
|
|
z_last,
|
|
|
|
|
l_1,
|
|
|
|
|
l_last,
|
|
|
|
|
);
|
|
|
|
|
stark.eval_ext_recursively(builder, vars, &mut consumer);
|
|
|
|
|
let vanishing_polys_zeta = consumer.accumulators();
|
|
|
|
|
|
|
|
|
|
// Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta.
|
|
|
|
|
let quotient_polys_zeta = &proof.openings.quotient_polys;
|
|
|
|
|
let mut scale = ReducingFactorTarget::new(zeta_pow_deg);
|
|
|
|
|
for (i, chunk) in quotient_polys_zeta
|
|
|
|
|
.chunks(stark.quotient_degree_factor())
|
|
|
|
|
.enumerate()
|
2022-02-07 10:41:52 +01:00
|
|
|
{
|
2022-02-08 18:16:33 +01:00
|
|
|
let recombined_quotient = scale.reduce(chunk, builder);
|
|
|
|
|
let computed_vanishing_poly = builder.mul_extension(z_h_zeta, recombined_quotient);
|
|
|
|
|
builder.connect_extension(vanishing_polys_zeta[i], computed_vanishing_poly);
|
2022-02-07 10:41:52 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-08 18:16:33 +01:00
|
|
|
// TODO: Permutation polynomials.
|
|
|
|
|
let merkle_caps = &[proof.trace_cap, proof.quotient_polys_cap];
|
|
|
|
|
|
|
|
|
|
let fri_instance = stark.fri_instance_target(
|
|
|
|
|
builder,
|
|
|
|
|
challenges.stark_zeta,
|
|
|
|
|
F::primitive_root_of_unity(degree_bits),
|
|
|
|
|
inner_config.num_challenges,
|
|
|
|
|
);
|
|
|
|
|
builder.verify_fri_proof::<C>(
|
|
|
|
|
&fri_instance,
|
|
|
|
|
&proof.openings.to_fri_openings(),
|
|
|
|
|
&challenges.fri_challenges,
|
|
|
|
|
merkle_caps,
|
|
|
|
|
&proof.opening_proof,
|
|
|
|
|
&inner_config.fri_params(degree_bits),
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-02-07 10:41:52 +01:00
|
|
|
|
2022-02-08 18:16:33 +01:00
|
|
|
fn eval_l_1_and_l_last_recursively<F: RichField + Extendable<D>, const D: usize>(
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
log_n: usize,
|
|
|
|
|
x: ExtensionTarget<D>,
|
2022-02-08 18:24:28 +01:00
|
|
|
z_x: ExtensionTarget<D>,
|
2022-02-08 18:16:33 +01:00
|
|
|
) -> (ExtensionTarget<D>, ExtensionTarget<D>) {
|
|
|
|
|
let n = builder.constant_extension(F::Extension::from_canonical_usize(1 << log_n));
|
|
|
|
|
let g = builder.constant_extension(F::Extension::primitive_root_of_unity(log_n));
|
|
|
|
|
let one = builder.one_extension();
|
|
|
|
|
let l_1_deno = builder.mul_sub_extension(n, x, n);
|
|
|
|
|
let l_last_deno = builder.mul_sub_extension(g, x, one);
|
|
|
|
|
let l_last_deno = builder.mul_extension(n, l_last_deno);
|
|
|
|
|
|
|
|
|
|
(
|
|
|
|
|
builder.div_extension(z_x, l_1_deno),
|
|
|
|
|
builder.div_extension(z_x, l_last_deno),
|
|
|
|
|
)
|
2022-02-07 10:41:52 +01:00
|
|
|
}
|
2022-02-08 18:16:33 +01:00
|
|
|
|
|
|
|
|
// pub fn add_virtual_proof_with_pis<InnerC: GenericConfig<D, F = F>>(
|
|
|
|
|
// &mut self,
|
|
|
|
|
// common_data: &CommonCircuitData<F, InnerC, D>,
|
|
|
|
|
// ) -> ProofWithPublicInputsTarget<D> {
|
|
|
|
|
// let proof = self.add_virtual_proof(common_data);
|
|
|
|
|
// let public_inputs = self.add_virtual_targets(common_data.num_public_inputs);
|
|
|
|
|
// ProofWithPublicInputsTarget {
|
|
|
|
|
// proof,
|
|
|
|
|
// public_inputs,
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// fn add_virtual_proof<InnerC: GenericConfig<D, F = F>>(
|
|
|
|
|
// &mut self,
|
|
|
|
|
// common_data: &CommonCircuitData<F, InnerC, D>,
|
|
|
|
|
// ) -> ProofTarget<D> {
|
|
|
|
|
// let config = &common_data.config;
|
|
|
|
|
// let fri_params = &common_data.fri_params;
|
|
|
|
|
// let cap_height = fri_params.config.cap_height;
|
|
|
|
|
//
|
|
|
|
|
// let num_leaves_per_oracle = &[
|
|
|
|
|
// common_data.num_preprocessed_polys(),
|
|
|
|
|
// config.num_wires,
|
|
|
|
|
// common_data.num_zs_partial_products_polys(),
|
|
|
|
|
// common_data.num_quotient_polys(),
|
|
|
|
|
// ];
|
|
|
|
|
//
|
|
|
|
|
// ProofTarget {
|
|
|
|
|
// wires_cap: self.add_virtual_cap(cap_height),
|
|
|
|
|
// plonk_zs_partial_products_cap: self.add_virtual_cap(cap_height),
|
|
|
|
|
// quotient_polys_cap: self.add_virtual_cap(cap_height),
|
|
|
|
|
// openings: self.add_opening_set(common_data),
|
|
|
|
|
// opening_proof: self.add_virtual_fri_proof(num_leaves_per_oracle, fri_params),
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// fn add_opening_set<InnerC: GenericConfig<D, F = F>>(
|
|
|
|
|
// &mut self,
|
|
|
|
|
// common_data: &CommonCircuitData<F, InnerC, D>,
|
|
|
|
|
// ) -> OpeningSetTarget<D> {
|
|
|
|
|
// let config = &common_data.config;
|
|
|
|
|
// let num_challenges = config.num_challenges;
|
|
|
|
|
// let total_partial_products = num_challenges * common_data.num_partial_products;
|
|
|
|
|
// OpeningSetTarget {
|
|
|
|
|
// constants: self.add_virtual_extension_targets(common_data.num_constants),
|
|
|
|
|
// plonk_sigmas: self.add_virtual_extension_targets(config.num_routed_wires),
|
|
|
|
|
// wires: self.add_virtual_extension_targets(config.num_wires),
|
|
|
|
|
// plonk_zs: self.add_virtual_extension_targets(num_challenges),
|
|
|
|
|
// plonk_zs_right: self.add_virtual_extension_targets(num_challenges),
|
|
|
|
|
// partial_products: self.add_virtual_extension_targets(total_partial_products),
|
|
|
|
|
// quotient_polys: self.add_virtual_extension_targets(common_data.num_quotient_polys()),
|
|
|
|
|
// }
|
|
|
|
|
// }
|