Merge pull request #107 from mir-protocol/precomputed_reduced_evals

Precompute reduced evaluations
This commit is contained in:
wborgeaud 2021-07-20 18:26:45 +02:00 committed by GitHub
commit 8a6d0fe06c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 91 additions and 41 deletions

View File

@ -118,14 +118,16 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
"Number of reductions should be non-zero."
);
let precomputed_reduced_evals =
PrecomputedReducedEvalsTarget::from_os_and_alpha(os, alpha, self);
for (i, round_proof) in proof.query_round_proofs.iter().enumerate() {
context!(
self,
&format!("verify {}'th FRI query", i),
self.fri_verifier_query_round(
os,
zeta,
alpha,
precomputed_reduced_evals,
initial_merkle_roots,
proof,
challenger,
@ -162,9 +164,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
&mut self,
proof: &FriInitialTreeProofTarget,
alpha: ExtensionTarget<D>,
os: &OpeningSetTarget<D>,
zeta: ExtensionTarget<D>,
subgroup_x: Target,
precomputed_reduced_evals: PrecomputedReducedEvalsTarget<D>,
common_data: &CommonCircuitData<F, D>,
) -> ExtensionTarget<D> {
assert!(D > 1, "Not implemented for D=1.");
@ -192,19 +194,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
)
.map(|&e| self.convert_to_ext(e))
.collect::<Vec<_>>();
let single_openings = os
.constants
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.wires)
.chain(&os.quotient_polys)
.chain(&os.partial_products)
.copied()
.collect::<Vec<_>>();
let mut single_numerator = alpha.reduce(&single_evals, self);
// TODO: Precompute the rhs as it is the same in all FRI rounds.
let rhs = alpha.reduce(&single_openings, self);
single_numerator = self.sub_extension(single_numerator, rhs);
let single_composition_eval = alpha.reduce(&single_evals, self);
let single_numerator =
self.sub_extension(single_composition_eval, precomputed_reduced_evals.single);
let single_denominator = self.sub_extension(subgroup_x, zeta);
let quotient = self.div_unsafe_extension(single_numerator, single_denominator);
sum = self.add_extension(sum, quotient);
@ -217,14 +209,15 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
.take(common_data.zs_range().end)
.map(|&e| self.convert_to_ext(e))
.collect::<Vec<_>>();
let zs_composition_eval = alpha.clone().reduce(&zs_evals, self);
let zs_composition_eval = alpha.reduce(&zs_evals, self);
let g = self.constant_extension(F::Extension::primitive_root_of_unity(degree_log));
let zeta_right = self.mul_extension(g, zeta);
let zs_ev_zeta = alpha.clone().reduce(&os.plonk_zs, self);
let zs_ev_zeta_right = alpha.reduce(&os.plonk_zs_right, self);
let interpol_val = self.interpolate2(
[(zeta, zs_ev_zeta), (zeta_right, zs_ev_zeta_right)],
[
(zeta, precomputed_reduced_evals.zs),
(zeta_right, precomputed_reduced_evals.zs_right),
],
subgroup_x,
);
let zs_numerator = self.sub_extension(zs_composition_eval, interpol_val);
@ -240,9 +233,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
fn fri_verifier_query_round(
&mut self,
os: &OpeningSetTarget<D>,
zeta: ExtensionTarget<D>,
alpha: ExtensionTarget<D>,
precomputed_reduced_evals: PrecomputedReducedEvalsTarget<D>,
initial_merkle_roots: &[HashTarget],
proof: &FriProofTarget<D>,
challenger: &mut RecursiveChallenger,
@ -289,9 +282,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
self.fri_combine_initial(
&round_proof.initial_trees_proof,
alpha,
os,
zeta,
subgroup_x,
precomputed_reduced_evals,
common_data,
)
)
@ -366,3 +359,39 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
self.assert_equal_extension(eval, purported_eval);
}
}
#[derive(Copy, Clone)]
struct PrecomputedReducedEvalsTarget<const D: usize> {
pub single: ExtensionTarget<D>,
pub zs: ExtensionTarget<D>,
pub zs_right: ExtensionTarget<D>,
}
impl<const D: usize> PrecomputedReducedEvalsTarget<D> {
fn from_os_and_alpha<F: Extendable<D>>(
os: &OpeningSetTarget<D>,
alpha: ExtensionTarget<D>,
builder: &mut CircuitBuilder<F, D>,
) -> Self {
let mut alpha = ReducingFactorTarget::new(alpha);
let single = alpha.reduce(
&os.constants
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.wires)
.chain(&os.quotient_polys)
.chain(&os.partial_products)
.copied()
.collect::<Vec<_>>(),
builder,
);
let zs = alpha.reduce(&os.plonk_zs, builder);
let zs_right = alpha.reduce(&os.plonk_zs_right, builder);
Self {
single,
zs,
zs_right,
}
}
}

View File

@ -112,11 +112,12 @@ pub fn verify_fri_proof<F: Field + Extendable<D>, const D: usize>(
"Number of reductions should be non-zero."
);
let precomputed_reduced_evals = PrecomputedReducedEvals::from_os_and_alpha(os, alpha);
for round_proof in &proof.query_round_proofs {
fri_verifier_query_round(
os,
zeta,
alpha,
precomputed_reduced_evals,
initial_merkle_roots,
&proof,
challenger,
@ -142,12 +143,43 @@ fn fri_verify_initial_proof<F: Field>(
Ok(())
}
/// Holds the reduced (by `alpha`) evaluations at `zeta` for the polynomial opened just at
/// zeta, for `Z` at zeta and for `Z` at `g*zeta`.
#[derive(Copy, Clone)]
struct PrecomputedReducedEvals<F: Extendable<D>, const D: usize> {
pub single: F::Extension,
pub zs: F::Extension,
pub zs_right: F::Extension,
}
impl<F: Extendable<D>, const D: usize> PrecomputedReducedEvals<F, D> {
fn from_os_and_alpha(os: &OpeningSet<F, D>, alpha: F::Extension) -> Self {
let mut alpha = ReducingFactor::new(alpha);
let single = alpha.reduce(
os.constants
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.wires)
.chain(&os.quotient_polys)
.chain(&os.partial_products),
);
let zs = alpha.reduce(os.plonk_zs.iter());
let zs_right = alpha.reduce(os.plonk_zs_right.iter());
Self {
single,
zs,
zs_right,
}
}
}
fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
proof: &FriInitialTreeProof<F>,
alpha: F::Extension,
os: &OpeningSet<F, D>,
zeta: F::Extension,
subgroup_x: F,
precomputed_reduced_evals: PrecomputedReducedEvals<F, D>,
common_data: &CommonCircuitData<F, D>,
) -> F::Extension {
let config = &common_data.config;
@ -174,19 +206,8 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
[common_data.partial_products_range()],
)
.map(|&e| F::Extension::from_basefield(e));
let single_openings = os
.constants
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.wires)
.chain(&os.quotient_polys)
.chain(&os.partial_products);
let single_diffs = single_evals
.into_iter()
.zip(single_openings)
.map(|(e, &o)| e - o)
.collect::<Vec<_>>();
let single_numerator = alpha.reduce(single_diffs.iter());
let single_composition_eval = alpha.reduce(single_evals);
let single_numerator = single_composition_eval - precomputed_reduced_evals.single;
let single_denominator = subgroup_x - zeta;
sum += single_numerator / single_denominator;
alpha.reset();
@ -197,12 +218,12 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
.iter()
.map(|&e| F::Extension::from_basefield(e))
.take(common_data.zs_range().end);
let zs_composition_eval = alpha.clone().reduce(zs_evals);
let zs_composition_eval = alpha.reduce(zs_evals);
let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta;
let zs_interpol = interpolate2(
[
(zeta, alpha.clone().reduce(os.plonk_zs.iter())),
(zeta_right, alpha.reduce(os.plonk_zs_right.iter())),
(zeta, precomputed_reduced_evals.zs),
(zeta_right, precomputed_reduced_evals.zs_right),
],
subgroup_x,
);
@ -215,9 +236,9 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
}
fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
os: &OpeningSet<F, D>,
zeta: F::Extension,
alpha: F::Extension,
precomputed_reduced_evals: PrecomputedReducedEvals<F, D>,
initial_merkle_roots: &[Hash<F>],
proof: &FriProof<F, D>,
challenger: &mut Challenger<F>,
@ -248,9 +269,9 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
fri_combine_initial(
&round_proof.initial_trees_proof,
alpha,
os,
zeta,
subgroup_x,
precomputed_reduced_evals,
common_data,
)
} else {