Added recursive powers

This commit is contained in:
wborgeaud 2021-06-04 17:36:48 +02:00
parent eee117512b
commit f5dfe95b2e
5 changed files with 129 additions and 85 deletions

View File

@ -206,4 +206,11 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}
b
}
pub fn convert_to_ext(&mut self, t: Target) -> ExtensionTarget<D> {
let zero = self.zero();
let mut arr = [zero; D];
arr[0] = t;
ExtensionTarget(arr)
}
}

View File

@ -2,6 +2,7 @@ use anyhow::{ensure, Result};
use itertools::izip;
use crate::circuit_builder::CircuitBuilder;
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::{flatten, Extendable, FieldExtension, OEF};
use crate::field::field::Field;
use crate::field::lagrange::{barycentric_weights, interpolant, interpolate};
@ -11,8 +12,10 @@ use crate::merkle_proofs::verify_merkle_proof;
use crate::plonk_challenger::{Challenger, RecursiveChallenger};
use crate::plonk_common::reduce_with_iter;
use crate::proof::{
FriInitialTreeProof, FriProof, FriProofTarget, FriQueryRound, Hash, OpeningSet,
FriInitialTreeProof, FriInitialTreeProofTarget, FriProof, FriProofTarget, FriQueryRound, Hash,
HashTarget, OpeningSet, OpeningSetTarget,
};
use crate::target::Target;
use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place};
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
@ -119,88 +122,89 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
// Ok(())
// }
//
// fn fri_verify_initial_proof<F: Field>(
// x_index: usize,
// proof: &FriInitialTreeProof<F>,
// initial_merkle_roots: &[Hash<F>],
// ) -> Result<()> {
// for ((evals, merkle_proof), &root) in proof.evals_proofs.iter().zip(initial_merkle_roots) {
// verify_merkle_proof(evals.clone(), x_index, root, merkle_proof, false)?;
// }
//
// Ok(())
// }
//
// 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,
// config: &FriConfig,
// ) -> F::Extension {
// assert!(D > 1, "Not implemented for D=1.");
// let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits;
// let subgroup_x = F::Extension::from_basefield(subgroup_x);
// let mut alpha_powers = alpha.powers();
// let mut sum = F::Extension::ZERO;
//
// // We will add three terms to `sum`:
// // - one for polynomials opened at `x` only
// // - one for polynomials opened at `x` and `g x`
// // - one for polynomials opened at `x` and its conjugate
//
// let evals = [0, 1, 4]
// .iter()
// .flat_map(|&i| proof.unsalted_evals(i, config))
// .map(|&e| F::Extension::from_basefield(e));
// let openings = os
// .constants
// .iter()
// .chain(&os.plonk_sigmas)
// .chain(&os.quotient_polys);
// let numerator = izip!(evals, openings, &mut alpha_powers)
// .map(|(e, &o, a)| a * (e - o))
// .sum::<F::Extension>();
// let denominator = subgroup_x - zeta;
// sum += numerator / denominator;
//
// let ev: F::Extension = proof
// .unsalted_evals(3, config)
// .iter()
// .zip(alpha_powers.clone())
// .map(|(&e, a)| a * e.into())
// .sum();
// let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta;
// let zs_interpol = interpolant(&[
// (zeta, reduce_with_iter(&os.plonk_zs, alpha_powers.clone())),
// (
// zeta_right,
// reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers),
// ),
// ]);
// let numerator = ev - zs_interpol.eval(subgroup_x);
// let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right);
// sum += numerator / denominator;
//
// let ev: F::Extension = proof
// .unsalted_evals(2, config)
// .iter()
// .zip(alpha_powers.clone())
// .map(|(&e, a)| a * e.into())
// .sum();
// let zeta_frob = zeta.frobenius();
// let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::<Vec<_>>();
// let wires_interpol = interpolant(&[
// (zeta, reduce_with_iter(&os.wires, alpha_powers.clone())),
// (zeta_frob, reduce_with_iter(&wire_evals_frob, alpha_powers)),
// ]);
// let numerator = ev - wires_interpol.eval(subgroup_x);
// let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob);
// sum += numerator / denominator;
//
// sum
// }
fn fri_verify_initial_proof(
&mut self,
x_index: Target,
proof: &FriInitialTreeProofTarget,
initial_merkle_roots: &[HashTarget],
) {
for ((evals, merkle_proof), &root) in proof.evals_proofs.iter().zip(initial_merkle_roots) {
self.verify_merkle_proof(evals.clone(), x_index, root, merkle_proof);
}
}
fn fri_combine_initial(
&mut self,
proof: &FriInitialTreeProofTarget,
alpha: ExtensionTarget<D>,
os: &OpeningSetTarget<D>,
zeta: ExtensionTarget<D>,
subgroup_x: Target,
) -> ExtensionTarget<D> {
assert!(D > 1, "Not implemented for D=1.");
let config = &self.config.fri_config;
let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits;
let subgroup_x = self.convert_to_ext(subgroup_x);
let mut alpha_powers = self.powers(alpha);
let mut sum = self.zero_extension();
// We will add three terms to `sum`:
// - one for polynomials opened at `x` only
// - one for polynomials opened at `x` and `g x`
// - one for polynomials opened at `x` and its conjugate
let evals = [0, 1, 4]
.iter()
.flat_map(|&i| proof.unsalted_evals(i, config))
.map(|&e| F::Extension::from_basefield(e));
let openings = os
.constants
.iter()
.chain(&os.plonk_sigmas)
.chain(&os.quotient_polys);
let numerator = izip!(evals, openings, &mut alpha_powers)
.map(|(e, &o, a)| a * (e - o))
.sum::<F::Extension>();
let denominator = subgroup_x - zeta;
sum += numerator / denominator;
let ev: F::Extension = proof
.unsalted_evals(3, config)
.iter()
.zip(alpha_powers.clone())
.map(|(&e, a)| a * e.into())
.sum();
let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta;
let zs_interpol = interpolant(&[
(zeta, reduce_with_iter(&os.plonk_zs, alpha_powers.clone())),
(
zeta_right,
reduce_with_iter(&os.plonk_zs_right, &mut alpha_powers),
),
]);
let numerator = ev - zs_interpol.eval(subgroup_x);
let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_right);
sum += numerator / denominator;
let ev: F::Extension = proof
.unsalted_evals(2, config)
.iter()
.zip(alpha_powers.clone())
.map(|(&e, a)| a * e.into())
.sum();
let zeta_frob = zeta.frobenius();
let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::<Vec<_>>();
let wires_interpol = interpolant(&[
(zeta, reduce_with_iter(&os.wires, alpha_powers.clone())),
(zeta_frob, reduce_with_iter(&wire_evals_frob, alpha_powers)),
]);
let numerator = ev - wires_interpol.eval(subgroup_x);
let denominator = (subgroup_x - zeta) * (subgroup_x - zeta_frob);
sum += numerator / denominator;
sum
}
//
// fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
// os: &OpeningSet<F, D>,

View File

@ -1,4 +1,5 @@
use crate::circuit_builder::CircuitBuilder;
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::Extendable;
use crate::field::field::Field;
use crate::gates::arithmetic::ArithmeticGate;
@ -226,6 +227,30 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}
}
/// An iterator over the powers of a certain base element `b`: `b^0, b^1, b^2, ...`.
#[derive(Clone)]
pub struct PowersTarget<const D: usize> {
base: ExtensionTarget<D>,
current: ExtensionTarget<D>,
}
impl<F: Extendable<D>, const D: usize> PowersTarget<D> {
fn next(&mut self, builder: &mut CircuitBuilder<F, D>) -> Option<ExtensionTarget<D>> {
let result = self.current;
self.current = builder.mul_extension(self.base, self.current);
Some(result)
}
}
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
pub fn powers(&mut self, base: ExtensionTarget<D>) -> PowersTarget<D> {
PowersTarget {
base,
current: self.one_extension(),
}
}
}
struct QuotientGenerator {
numerator: Target,
denominator: Target,

View File

@ -62,7 +62,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
leaf_data: Vec<Target>,
leaf_index: Target,
merkle_root: HashTarget,
proof: MerkleProofTarget,
proof: &MerkleProofTarget,
) {
let zero = self.zero();
let height = proof.siblings.len();
@ -71,7 +71,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let mut state: HashTarget = self.hash_or_noop(leaf_data);
let mut acc_leaf_index = zero;
for (bit, sibling) in purported_index_bits.into_iter().zip(proof.siblings) {
for (bit, &sibling) in purported_index_bits.into_iter().zip(&proof.siblings) {
let gate = self
.add_gate_no_constants(GMiMCGate::<F, D, GMIMC_ROUNDS>::with_automatic_constants());

View File

@ -35,6 +35,7 @@ impl<F: Field> Hash<F> {
}
/// Represents a ~256 bit hash output.
#[derive(Copy, Clone, Debug)]
pub struct HashTarget {
pub(crate) elements: [Target; 4],
}
@ -107,6 +108,13 @@ pub struct FriInitialTreeProofTarget {
pub evals_proofs: Vec<(Vec<Target>, MerkleProofTarget)>,
}
impl FriInitialTreeProofTarget {
pub(crate) fn unsalted_evals(&self, i: usize, config: &FriConfig) -> &[Target] {
let evals = &self.evals_proofs[i].0;
&evals[..evals.len() - config.salt_size(i)]
}
}
/// Proof for a FRI query round.
pub struct FriQueryRound<F: Field + Extendable<D>, const D: usize> {
pub initial_trees_proof: FriInitialTreeProof<F>,