2021-05-14 07:33:46 -07:00
|
|
|
use anyhow::Result;
|
|
|
|
|
use rayon::prelude::*;
|
|
|
|
|
|
2021-05-18 15:22:06 +02:00
|
|
|
use crate::field::extension_field::FieldExtension;
|
2021-05-27 17:20:26 +02:00
|
|
|
use crate::field::extension_field::{Extendable, OEF};
|
2021-04-30 15:07:54 +02:00
|
|
|
use crate::field::field::Field;
|
2021-05-04 19:56:34 +02:00
|
|
|
use crate::field::lagrange::interpolant;
|
2021-05-05 18:23:59 +02:00
|
|
|
use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig};
|
2021-04-30 15:07:54 +02:00
|
|
|
use crate::merkle_tree::MerkleTree;
|
2021-05-03 15:17:05 +02:00
|
|
|
use crate::plonk_challenger::Challenger;
|
2021-05-27 17:20:26 +02:00
|
|
|
use crate::plonk_common::{reduce_polys_with_powers, reduce_with_powers};
|
2021-05-04 19:56:34 +02:00
|
|
|
use crate::polynomial::polynomial::PolynomialCoeffs;
|
2021-05-31 17:49:04 +02:00
|
|
|
use crate::proof::{FriInitialTreeProof, FriProof, Hash, OpeningSet};
|
2021-05-14 07:33:46 -07:00
|
|
|
use crate::timed;
|
2021-05-04 17:48:26 +02:00
|
|
|
use crate::util::{log2_strict, reverse_index_bits_in_place, transpose};
|
2021-04-30 15:07:54 +02:00
|
|
|
|
2021-05-06 17:09:55 +02:00
|
|
|
pub const SALT_SIZE: usize = 2;
|
|
|
|
|
|
2021-05-06 23:14:37 +02:00
|
|
|
pub struct ListPolynomialCommitment<F: Field> {
|
2021-05-03 15:17:05 +02:00
|
|
|
pub polynomials: Vec<PolynomialCoeffs<F>>,
|
2021-04-30 15:07:54 +02:00
|
|
|
pub merkle_tree: MerkleTree<F>,
|
2021-05-03 15:17:05 +02:00
|
|
|
pub degree: usize,
|
2021-05-11 09:56:21 +02:00
|
|
|
pub rate_bits: usize,
|
|
|
|
|
pub blinding: bool,
|
2021-04-30 15:07:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<F: Field> ListPolynomialCommitment<F> {
|
2021-05-11 09:56:21 +02:00
|
|
|
pub fn new(polynomials: Vec<PolynomialCoeffs<F>>, rate_bits: usize, blinding: bool) -> Self {
|
2021-05-03 15:17:05 +02:00
|
|
|
let degree = polynomials[0].len();
|
2021-05-14 07:33:46 -07:00
|
|
|
let lde_values = timed!(
|
|
|
|
|
Self::lde_values(&polynomials, rate_bits, blinding),
|
|
|
|
|
"to compute LDE"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let mut leaves = timed!(transpose(&lde_values), "to transpose LDEs");
|
|
|
|
|
reverse_index_bits_in_place(&mut leaves);
|
|
|
|
|
let merkle_tree = timed!(MerkleTree::new(leaves, false), "to build Merkle tree");
|
|
|
|
|
|
|
|
|
|
Self {
|
|
|
|
|
polynomials,
|
|
|
|
|
merkle_tree,
|
|
|
|
|
degree,
|
|
|
|
|
rate_bits,
|
|
|
|
|
blinding,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn lde_values(
|
|
|
|
|
polynomials: &[PolynomialCoeffs<F>],
|
|
|
|
|
rate_bits: usize,
|
|
|
|
|
blinding: bool,
|
|
|
|
|
) -> Vec<Vec<F>> {
|
|
|
|
|
let degree = polynomials[0].len();
|
|
|
|
|
polynomials
|
2021-05-07 16:49:27 +02:00
|
|
|
.par_iter()
|
2021-05-03 15:17:05 +02:00
|
|
|
.map(|p| {
|
|
|
|
|
assert_eq!(p.len(), degree, "Polynomial degree invalid.");
|
|
|
|
|
p.clone()
|
2021-05-11 09:56:21 +02:00
|
|
|
.lde(rate_bits)
|
2021-05-03 15:17:05 +02:00
|
|
|
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR)
|
|
|
|
|
.values
|
|
|
|
|
})
|
2021-05-11 09:56:21 +02:00
|
|
|
.chain(if blinding {
|
2021-05-06 00:00:08 +02:00
|
|
|
// If blinding, salt with two random elements to each leaf vector.
|
2021-05-06 17:09:55 +02:00
|
|
|
(0..SALT_SIZE)
|
2021-05-11 09:56:21 +02:00
|
|
|
.map(|_| F::rand_vec(degree << rate_bits))
|
2021-05-03 15:17:05 +02:00
|
|
|
.collect()
|
2021-05-06 00:00:08 +02:00
|
|
|
} else {
|
|
|
|
|
Vec::new()
|
|
|
|
|
})
|
2021-05-14 07:33:46 -07:00
|
|
|
.collect()
|
2021-04-30 15:07:54 +02:00
|
|
|
}
|
2021-05-03 15:17:05 +02:00
|
|
|
|
2021-05-07 16:22:13 +02:00
|
|
|
pub fn leaf(&self, index: usize) -> &[F] {
|
|
|
|
|
let leaf = &self.merkle_tree.leaves[index];
|
2021-05-11 09:56:21 +02:00
|
|
|
&leaf[0..leaf.len() - if self.blinding { SALT_SIZE } else { 0 }]
|
2021-05-07 16:22:13 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-18 15:44:50 +02:00
|
|
|
pub fn open<const D: usize>(
|
2021-05-05 22:58:15 +02:00
|
|
|
&self,
|
2021-05-18 15:22:06 +02:00
|
|
|
points: &[F::Extension],
|
2021-05-05 22:58:15 +02:00
|
|
|
challenger: &mut Challenger<F>,
|
2021-05-11 09:56:21 +02:00
|
|
|
config: &FriConfig,
|
2021-05-18 15:44:50 +02:00
|
|
|
) -> (OpeningProof<F, D>, Vec<Vec<F::Extension>>)
|
2021-05-18 15:22:06 +02:00
|
|
|
where
|
2021-05-18 15:44:50 +02:00
|
|
|
F: Extendable<D>,
|
2021-05-18 15:22:06 +02:00
|
|
|
{
|
2021-05-11 09:56:21 +02:00
|
|
|
assert_eq!(self.rate_bits, config.rate_bits);
|
2021-05-27 17:20:26 +02:00
|
|
|
assert_eq!(config.check_basefield.len(), 1);
|
2021-05-11 09:56:21 +02:00
|
|
|
assert_eq!(config.blinding.len(), 1);
|
|
|
|
|
assert_eq!(self.blinding, config.blinding[0]);
|
2021-05-03 15:17:05 +02:00
|
|
|
for p in points {
|
|
|
|
|
assert_ne!(
|
2021-05-19 12:17:43 +02:00
|
|
|
p.exp(self.degree as u64),
|
2021-05-18 15:22:06 +02:00
|
|
|
F::Extension::ONE,
|
2021-05-03 15:17:05 +02:00
|
|
|
"Opening point is in the subgroup."
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let evaluations = points
|
2021-05-07 16:49:27 +02:00
|
|
|
.par_iter()
|
2021-05-03 15:17:05 +02:00
|
|
|
.map(|&x| {
|
|
|
|
|
self.polynomials
|
|
|
|
|
.iter()
|
2021-05-18 15:22:06 +02:00
|
|
|
.map(|p| p.to_extension().eval(x))
|
2021-05-03 15:17:05 +02:00
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
})
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
for evals in &evaluations {
|
2021-05-18 15:22:06 +02:00
|
|
|
for e in evals {
|
|
|
|
|
challenger.observe_extension_element(e);
|
|
|
|
|
}
|
2021-05-03 15:17:05 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-18 15:22:06 +02:00
|
|
|
let alpha = challenger.get_extension_challenge();
|
2021-05-03 15:17:05 +02:00
|
|
|
|
2021-05-05 18:32:24 +02:00
|
|
|
// Scale polynomials by `alpha`.
|
2021-05-27 17:20:26 +02:00
|
|
|
let composition_poly = reduce_polys_with_powers(&self.polynomials, alpha);
|
2021-05-05 18:32:24 +02:00
|
|
|
// Scale evaluations by `alpha`.
|
2021-05-05 22:58:15 +02:00
|
|
|
let composition_evals = evaluations
|
2021-05-07 16:49:27 +02:00
|
|
|
.par_iter()
|
2021-05-03 15:17:05 +02:00
|
|
|
.map(|e| reduce_with_powers(e, alpha))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
2021-05-05 22:58:15 +02:00
|
|
|
let quotient = Self::compute_quotient(points, &composition_evals, &composition_poly);
|
2021-05-04 17:48:26 +02:00
|
|
|
|
2021-05-27 17:20:26 +02:00
|
|
|
let quotient = if config.check_basefield[0] {
|
|
|
|
|
let composition_poly_conj = PolynomialCoeffs::<F>::frobenius(&composition_poly);
|
|
|
|
|
// This equality holds iff the polynomials in `self.polynomials` are defined over `F` and not `F::Extension`.
|
|
|
|
|
debug_assert_eq!(
|
|
|
|
|
composition_poly_conj.eval(points[0].frobenius()),
|
|
|
|
|
composition_evals[0].frobenius()
|
|
|
|
|
);
|
|
|
|
|
let quotient_conj = Self::compute_quotient(
|
|
|
|
|
&[points[0].frobenius()],
|
|
|
|
|
&[composition_evals[0].frobenius()],
|
|
|
|
|
&composition_poly_conj,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
&("ient_conj * alpha.exp(self.polynomials.len() as u64)) + "ient
|
|
|
|
|
} else {
|
|
|
|
|
quotient
|
|
|
|
|
};
|
|
|
|
|
|
2021-05-11 09:56:21 +02:00
|
|
|
let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(self.rate_bits);
|
2021-05-04 19:56:34 +02:00
|
|
|
let lde_quotient_values = lde_quotient
|
|
|
|
|
.clone()
|
2021-05-18 15:22:06 +02:00
|
|
|
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR.into());
|
2021-05-04 17:48:26 +02:00
|
|
|
|
2021-05-03 15:17:05 +02:00
|
|
|
let fri_proof = fri_proof(
|
2021-05-06 17:09:55 +02:00
|
|
|
&[&self.merkle_tree],
|
2021-05-04 17:48:26 +02:00
|
|
|
&lde_quotient,
|
|
|
|
|
&lde_quotient_values,
|
2021-05-03 15:17:05 +02:00
|
|
|
challenger,
|
2021-05-11 09:56:21 +02:00
|
|
|
&config,
|
2021-05-03 15:17:05 +02:00
|
|
|
);
|
2021-05-04 17:48:26 +02:00
|
|
|
|
2021-05-05 22:58:15 +02:00
|
|
|
(
|
|
|
|
|
OpeningProof {
|
|
|
|
|
fri_proof,
|
|
|
|
|
quotient_degree: quotient.len(),
|
|
|
|
|
},
|
2021-05-04 17:48:26 +02:00
|
|
|
evaluations,
|
2021-05-05 22:58:15 +02:00
|
|
|
)
|
2021-05-03 15:17:05 +02:00
|
|
|
}
|
2021-05-05 18:32:24 +02:00
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
// pub fn batch_open<const D: usize>(
|
|
|
|
|
// commitments: &[&Self],
|
|
|
|
|
// opening_config: &OpeningConfig<F, D>,
|
|
|
|
|
// fri_config: &FriConfig,
|
|
|
|
|
// challenger: &mut Challenger<F>,
|
|
|
|
|
// ) -> (OpeningProof<F, D>, Vec<Vec<Vec<Vec<F::Extension>>>>)
|
|
|
|
|
// where
|
|
|
|
|
// F: Extendable<D>,
|
|
|
|
|
// {
|
|
|
|
|
// let degree = commitments[0].degree;
|
|
|
|
|
// assert_eq!(fri_config.blinding.len(), commitments.len());
|
|
|
|
|
// for (i, commitment) in commitments.iter().enumerate() {
|
|
|
|
|
// assert_eq!(commitment.rate_bits, fri_config.rate_bits, "Invalid rate.");
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
// commitment.blinding, fri_config.blinding[i],
|
|
|
|
|
// "Invalid blinding paramater."
|
|
|
|
|
// );
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
// commitment.degree, degree,
|
|
|
|
|
// "Trying to open polynomial commitments of different degrees."
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// for &p in opening_config.points.iter().flat_map(|(v, _)| v) {
|
|
|
|
|
// assert_ne!(
|
|
|
|
|
// p.exp(degree as u64),
|
|
|
|
|
// F::Extension::ONE,
|
|
|
|
|
// "Opening point is in the subgroup."
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// let evaluations = opening_config
|
|
|
|
|
// .points
|
|
|
|
|
// .iter()
|
|
|
|
|
// .map(|(xs, is)| {
|
|
|
|
|
// xs.iter()
|
|
|
|
|
// .map(|&x| {
|
|
|
|
|
// is.iter()
|
|
|
|
|
// .map(|&i| {
|
|
|
|
|
// commitments[i]
|
|
|
|
|
// .polynomials
|
|
|
|
|
// .iter()
|
|
|
|
|
// .map(|p| p.to_extension().eval(x))
|
|
|
|
|
// .collect::<Vec<_>>()
|
|
|
|
|
// })
|
|
|
|
|
// .collect::<Vec<_>>()
|
|
|
|
|
// })
|
|
|
|
|
// .collect::<Vec<_>>()
|
|
|
|
|
// })
|
|
|
|
|
// .collect::<Vec<_>>();
|
|
|
|
|
// for evals_per_point_vec in &evaluations {
|
|
|
|
|
// for evals_per_point in evals_per_point_vec {
|
|
|
|
|
// for evals in evals_per_point {
|
|
|
|
|
// challenger.observe_extension_elements(evals);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// let alpha = challenger.get_extension_challenge();
|
|
|
|
|
// let mut cur_alpha = F::Extension::ONE;
|
|
|
|
|
//
|
|
|
|
|
// // Final low-degree polynomial that goes into FRI.
|
|
|
|
|
// let mut final_poly = PolynomialCoeffs::empty();
|
|
|
|
|
//
|
|
|
|
|
// for ((ps, is), evals) in opening_config.points.iter().zip(&evaluations) {
|
|
|
|
|
// let mut poly_count = 0;
|
|
|
|
|
// // Scale polynomials by `alpha`.
|
|
|
|
|
// let composition_poly = is
|
|
|
|
|
// .iter()
|
|
|
|
|
// .flat_map(|&i| &commitments[i].polynomials)
|
|
|
|
|
// .rev()
|
|
|
|
|
// .fold(PolynomialCoeffs::zero(degree), |acc, p| {
|
|
|
|
|
// poly_count += 1;
|
|
|
|
|
// &(&acc * alpha) + &p.to_extension()
|
|
|
|
|
// });
|
|
|
|
|
// // Scale evaluations by `alpha`.
|
|
|
|
|
// let composition_evals = &evals
|
|
|
|
|
// .iter()
|
|
|
|
|
// .map(|v| {
|
|
|
|
|
// v.iter()
|
|
|
|
|
// .flatten()
|
|
|
|
|
// .rev()
|
|
|
|
|
// .fold(F::Extension::ZERO, |acc, &e| acc * alpha + e)
|
|
|
|
|
// })
|
|
|
|
|
// .collect::<Vec<_>>();
|
|
|
|
|
//
|
|
|
|
|
// let quotient = Self::compute_quotient(ps, &composition_evals, &composition_poly);
|
|
|
|
|
// final_poly = &final_poly + &("ient * cur_alpha);
|
|
|
|
|
// cur_alpha *= alpha.exp(poly_count);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// for &i in &opening_config.check_base_field {
|
|
|
|
|
// let commitment = commitments[i];
|
|
|
|
|
// let x = opening_config
|
|
|
|
|
// .points
|
|
|
|
|
// .iter()
|
|
|
|
|
// .find(|(xs, is)| is.contains(&i))
|
|
|
|
|
// .expect("Polynomial is never opened.")
|
|
|
|
|
// .0[0];
|
|
|
|
|
// let x_conj = x.frobenius();
|
|
|
|
|
// let mut poly_count = 0;
|
|
|
|
|
// let poly = commitment.polynomials.iter().rev().fold(
|
|
|
|
|
// PolynomialCoeffs::zero(degree),
|
|
|
|
|
// |acc, p| {
|
|
|
|
|
// poly_count += 1;
|
|
|
|
|
// &(&acc * alpha) + &p.to_extension()
|
|
|
|
|
// },
|
|
|
|
|
// );
|
|
|
|
|
// let e = poly.eval(x_conj);
|
|
|
|
|
// let quotient = Self::compute_quotient(&[x_conj], &[e], &poly);
|
|
|
|
|
// final_poly = &final_poly + &("ient * cur_alpha);
|
|
|
|
|
// cur_alpha *= alpha.exp(poly_count);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// let lde_final_poly = final_poly.lde(fri_config.rate_bits);
|
|
|
|
|
// let lde_final_values = lde_final_poly
|
|
|
|
|
// .clone()
|
|
|
|
|
// .coset_fft(F::Extension::from_basefield(
|
|
|
|
|
// F::MULTIPLICATIVE_GROUP_GENERATOR,
|
|
|
|
|
// ));
|
|
|
|
|
//
|
|
|
|
|
// let fri_proof = fri_proof(
|
|
|
|
|
// &commitments
|
|
|
|
|
// .par_iter()
|
|
|
|
|
// .map(|c| &c.merkle_tree)
|
|
|
|
|
// .collect::<Vec<_>>(),
|
|
|
|
|
// &lde_final_poly,
|
|
|
|
|
// &lde_final_values,
|
|
|
|
|
// challenger,
|
|
|
|
|
// &fri_config,
|
|
|
|
|
// );
|
|
|
|
|
//
|
|
|
|
|
// (
|
|
|
|
|
// OpeningProof {
|
|
|
|
|
// fri_proof,
|
|
|
|
|
// quotient_degree: final_poly.len(),
|
|
|
|
|
// },
|
|
|
|
|
// evaluations,
|
|
|
|
|
// )
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
pub fn open_plonk<const D: usize>(
|
|
|
|
|
commitments: &[&Self; 5],
|
|
|
|
|
zeta: F::Extension,
|
|
|
|
|
degree_log: usize,
|
2021-05-06 17:09:55 +02:00
|
|
|
challenger: &mut Challenger<F>,
|
2021-05-11 09:56:21 +02:00
|
|
|
config: &FriConfig,
|
2021-05-31 17:49:04 +02:00
|
|
|
) -> (OpeningProof<F, D>, OpeningSet<F, D>)
|
2021-05-18 15:22:06 +02:00
|
|
|
where
|
2021-05-18 15:44:50 +02:00
|
|
|
F: Extendable<D>,
|
2021-05-18 15:22:06 +02:00
|
|
|
{
|
2021-05-31 17:49:04 +02:00
|
|
|
let g = F::Extension::primitive_root_of_unity(degree_log);
|
|
|
|
|
dbg!(degree_log);
|
|
|
|
|
for &p in &[zeta, g * zeta] {
|
2021-05-06 17:09:55 +02:00
|
|
|
assert_ne!(
|
2021-05-31 17:49:04 +02:00
|
|
|
p.exp(1 << degree_log as u64),
|
2021-05-18 15:22:06 +02:00
|
|
|
F::Extension::ONE,
|
2021-05-06 17:09:55 +02:00
|
|
|
"Opening point is in the subgroup."
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
let os = OpeningSet::new(
|
|
|
|
|
zeta,
|
|
|
|
|
g,
|
|
|
|
|
commitments[0],
|
|
|
|
|
commitments[1],
|
|
|
|
|
commitments[2],
|
|
|
|
|
commitments[3],
|
|
|
|
|
commitments[4],
|
|
|
|
|
);
|
|
|
|
|
challenger.observe_opening_set(&os);
|
2021-05-06 17:09:55 +02:00
|
|
|
|
2021-05-18 15:22:06 +02:00
|
|
|
let alpha = challenger.get_extension_challenge();
|
2021-05-31 17:49:04 +02:00
|
|
|
dbg!(alpha);
|
|
|
|
|
let mut cur_alpha = F::Extension::ONE;
|
2021-05-06 17:09:55 +02:00
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
// Final low-degree polynomial that goes into FRI.
|
|
|
|
|
let mut final_poly = PolynomialCoeffs::empty();
|
|
|
|
|
// Count the total number of polynomials accumulated into `final_poly`.
|
|
|
|
|
let mut poly_count = 0;
|
|
|
|
|
|
|
|
|
|
let composition_poly = [0, 1, 4]
|
2021-05-06 17:09:55 +02:00
|
|
|
.iter()
|
2021-05-31 17:49:04 +02:00
|
|
|
.flat_map(|&i| &commitments[i].polynomials)
|
2021-05-06 17:09:55 +02:00
|
|
|
.rev()
|
2021-05-31 17:49:04 +02:00
|
|
|
.fold(PolynomialCoeffs::empty(), |acc, p| {
|
|
|
|
|
poly_count += 1;
|
2021-05-18 15:22:06 +02:00
|
|
|
&(&acc * alpha) + &p.to_extension()
|
2021-05-12 11:26:21 -07:00
|
|
|
});
|
2021-05-31 17:49:04 +02:00
|
|
|
let composition_eval = [&os.constants, &os.plonk_sigmas, &os.quotient_polys]
|
|
|
|
|
.iter()
|
|
|
|
|
.flat_map(|v| v.iter())
|
|
|
|
|
.rev()
|
|
|
|
|
.fold(F::Extension::ZERO, |acc, &e| acc * alpha + e);
|
|
|
|
|
|
|
|
|
|
let quotient = Self::compute_quotient(&[zeta], &[composition_eval], &composition_poly);
|
|
|
|
|
final_poly = &final_poly + &("ient * cur_alpha);
|
|
|
|
|
{
|
|
|
|
|
let lde_final_poly = final_poly.lde(config.rate_bits);
|
|
|
|
|
let lde_final_values = lde_final_poly
|
|
|
|
|
.clone()
|
|
|
|
|
.coset_fft(F::Extension::from_basefield(
|
|
|
|
|
F::MULTIPLICATIVE_GROUP_GENERATOR,
|
|
|
|
|
));
|
|
|
|
|
dbg!(lde_final_values);
|
|
|
|
|
}
|
|
|
|
|
cur_alpha = alpha.exp(poly_count);
|
|
|
|
|
|
|
|
|
|
let zs_composition_poly =
|
|
|
|
|
commitments[3]
|
|
|
|
|
.polynomials
|
|
|
|
|
.iter()
|
|
|
|
|
.rev()
|
|
|
|
|
.fold(PolynomialCoeffs::empty(), |acc, p| {
|
|
|
|
|
poly_count += 1;
|
|
|
|
|
&(&acc * alpha) + &p.to_extension()
|
|
|
|
|
});
|
|
|
|
|
let zs_composition_evals = [
|
|
|
|
|
reduce_with_powers(&os.plonk_zs, alpha),
|
|
|
|
|
reduce_with_powers(&os.plonk_zs_right, alpha),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let zs_quotient = Self::compute_quotient(
|
|
|
|
|
&[zeta, g * zeta],
|
|
|
|
|
&zs_composition_evals,
|
|
|
|
|
&zs_composition_poly,
|
|
|
|
|
);
|
|
|
|
|
final_poly = &final_poly + &(&zs_quotient * cur_alpha);
|
|
|
|
|
{
|
|
|
|
|
let lde_final_poly = final_poly.lde(config.rate_bits);
|
|
|
|
|
let lde_final_values = lde_final_poly
|
|
|
|
|
.clone()
|
|
|
|
|
.coset_fft(F::Extension::from_basefield(
|
|
|
|
|
F::MULTIPLICATIVE_GROUP_GENERATOR,
|
|
|
|
|
));
|
|
|
|
|
dbg!(lde_final_values);
|
|
|
|
|
dbg!(cur_alpha);
|
|
|
|
|
}
|
|
|
|
|
cur_alpha = alpha.exp(poly_count);
|
|
|
|
|
|
|
|
|
|
let wires_composition_poly =
|
|
|
|
|
commitments[2]
|
|
|
|
|
.polynomials
|
|
|
|
|
.iter()
|
|
|
|
|
.rev()
|
|
|
|
|
.fold(PolynomialCoeffs::empty(), |acc, p| {
|
|
|
|
|
poly_count += 1;
|
|
|
|
|
&(&acc * alpha) + &p.to_extension()
|
|
|
|
|
});
|
|
|
|
|
let wire_evals_frob = os.wires.iter().map(|e| e.frobenius()).collect::<Vec<_>>();
|
|
|
|
|
let wires_composition_evals = [
|
|
|
|
|
reduce_with_powers(&os.wires, alpha),
|
|
|
|
|
reduce_with_powers(&wire_evals_frob, alpha),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let wires_quotient = Self::compute_quotient(
|
|
|
|
|
&[zeta, zeta.frobenius()],
|
|
|
|
|
&wires_composition_evals,
|
|
|
|
|
&wires_composition_poly,
|
|
|
|
|
);
|
|
|
|
|
final_poly = &final_poly + &(&wires_quotient * cur_alpha);
|
2021-05-06 17:09:55 +02:00
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
dbg!(final_poly.coeffs.len());
|
|
|
|
|
let lde_final_poly = final_poly.lde(config.rate_bits);
|
|
|
|
|
let lde_final_values = lde_final_poly
|
|
|
|
|
.clone()
|
|
|
|
|
.coset_fft(F::Extension::from_basefield(
|
|
|
|
|
F::MULTIPLICATIVE_GROUP_GENERATOR,
|
|
|
|
|
));
|
2021-05-06 17:09:55 +02:00
|
|
|
|
|
|
|
|
let fri_proof = fri_proof(
|
|
|
|
|
&commitments
|
2021-05-07 16:49:27 +02:00
|
|
|
.par_iter()
|
2021-05-06 17:09:55 +02:00
|
|
|
.map(|c| &c.merkle_tree)
|
|
|
|
|
.collect::<Vec<_>>(),
|
2021-05-31 17:49:04 +02:00
|
|
|
&lde_final_poly,
|
|
|
|
|
&lde_final_values,
|
2021-05-06 17:09:55 +02:00
|
|
|
challenger,
|
2021-05-11 09:56:21 +02:00
|
|
|
&config,
|
2021-05-06 17:09:55 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
(
|
|
|
|
|
OpeningProof {
|
|
|
|
|
fri_proof,
|
2021-05-31 17:49:04 +02:00
|
|
|
quotient_degree: final_poly.len(),
|
2021-05-06 17:09:55 +02:00
|
|
|
},
|
2021-05-31 17:49:04 +02:00
|
|
|
os,
|
2021-05-06 17:09:55 +02:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 18:32:24 +02:00
|
|
|
/// Given `points=(x_i)`, `evals=(y_i)` and `poly=P` with `P(x_i)=y_i`, computes the polynomial
|
|
|
|
|
/// `Q=(P-I)/Z` where `I` interpolates `(x_i, y_i)` and `Z` is the vanishing polynomial on `(x_i)`.
|
2021-05-18 15:44:50 +02:00
|
|
|
fn compute_quotient<const D: usize>(
|
2021-05-18 15:22:06 +02:00
|
|
|
points: &[F::Extension],
|
|
|
|
|
evals: &[F::Extension],
|
|
|
|
|
poly: &PolynomialCoeffs<F::Extension>,
|
|
|
|
|
) -> PolynomialCoeffs<F::Extension>
|
|
|
|
|
where
|
2021-05-18 15:44:50 +02:00
|
|
|
F: Extendable<D>,
|
2021-05-18 15:22:06 +02:00
|
|
|
{
|
2021-05-05 18:32:24 +02:00
|
|
|
let pairs = points
|
|
|
|
|
.iter()
|
|
|
|
|
.zip(evals)
|
|
|
|
|
.map(|(&x, &e)| (x, e))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
debug_assert!(pairs.iter().all(|&(x, e)| poly.eval(x) == e));
|
|
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
dbg!(&pairs);
|
2021-05-10 12:58:58 -07:00
|
|
|
let interpolant = interpolant(&pairs);
|
|
|
|
|
let denominator = points.iter().fold(PolynomialCoeffs::one(), |acc, &x| {
|
2021-05-18 15:22:06 +02:00
|
|
|
&acc * &PolynomialCoeffs::new(vec![-x, F::Extension::ONE])
|
2021-05-10 12:58:58 -07:00
|
|
|
});
|
|
|
|
|
let numerator = poly - &interpolant;
|
|
|
|
|
let (mut quotient, rem) = numerator.div_rem(&denominator);
|
2021-05-05 18:32:24 +02:00
|
|
|
debug_assert!(rem.is_zero());
|
|
|
|
|
|
2021-05-10 12:58:58 -07:00
|
|
|
quotient.padded(quotient.degree_plus_one().next_power_of_two())
|
2021-05-05 18:32:24 +02:00
|
|
|
}
|
2021-05-03 15:17:05 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-18 15:44:50 +02:00
|
|
|
pub struct OpeningProof<F: Field + Extendable<D>, const D: usize> {
|
|
|
|
|
fri_proof: FriProof<F, D>,
|
2021-05-06 15:14:43 +02:00
|
|
|
// TODO: Get the degree from `CommonCircuitData` instead.
|
2021-05-04 17:48:26 +02:00
|
|
|
quotient_degree: usize,
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-18 15:44:50 +02:00
|
|
|
impl<F: Field + Extendable<D>, const D: usize> OpeningProof<F, D> {
|
2021-05-04 17:48:26 +02:00
|
|
|
pub fn verify(
|
|
|
|
|
&self,
|
2021-05-31 17:49:04 +02:00
|
|
|
zeta: F::Extension,
|
|
|
|
|
os: &OpeningSet<F, D>,
|
2021-05-06 17:09:55 +02:00
|
|
|
merkle_roots: &[Hash<F>],
|
2021-05-04 17:48:26 +02:00
|
|
|
challenger: &mut Challenger<F>,
|
|
|
|
|
fri_config: &FriConfig,
|
|
|
|
|
) -> Result<()> {
|
2021-05-31 17:49:04 +02:00
|
|
|
challenger.observe_opening_set(os);
|
2021-05-04 17:48:26 +02:00
|
|
|
|
2021-05-18 15:22:06 +02:00
|
|
|
let alpha = challenger.get_extension_challenge();
|
2021-05-31 17:49:04 +02:00
|
|
|
dbg!(alpha);
|
2021-05-04 17:48:26 +02:00
|
|
|
|
|
|
|
|
verify_fri_proof(
|
|
|
|
|
log2_strict(self.quotient_degree),
|
2021-05-31 17:49:04 +02:00
|
|
|
&os,
|
|
|
|
|
zeta,
|
2021-05-04 17:48:26 +02:00
|
|
|
alpha,
|
2021-05-06 17:09:55 +02:00
|
|
|
merkle_roots,
|
2021-05-04 17:48:26 +02:00
|
|
|
&self.fri_proof,
|
|
|
|
|
challenger,
|
|
|
|
|
fri_config,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use anyhow::Result;
|
|
|
|
|
|
2021-05-14 07:33:46 -07:00
|
|
|
use crate::field::crandall_field::CrandallField;
|
|
|
|
|
|
|
|
|
|
use super::*;
|
2021-05-31 17:49:04 +02:00
|
|
|
use std::convert::TryInto;
|
2021-05-14 07:33:46 -07:00
|
|
|
|
2021-05-18 15:44:50 +02:00
|
|
|
fn gen_random_test_case<F: Field + Extendable<D>, const D: usize>(
|
2021-05-05 17:00:47 +02:00
|
|
|
k: usize,
|
|
|
|
|
degree_log: usize,
|
2021-05-31 17:49:04 +02:00
|
|
|
) -> Vec<PolynomialCoeffs<F>> {
|
2021-05-05 17:00:47 +02:00
|
|
|
let degree = 1 << degree_log;
|
|
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
(0..k)
|
2021-05-06 15:14:43 +02:00
|
|
|
.map(|_| PolynomialCoeffs::new(F::rand_vec(degree)))
|
2021-05-31 17:49:04 +02:00
|
|
|
.collect()
|
2021-05-05 17:00:47 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
fn gen_random_point<F: Field + Extendable<D>, const D: usize>(
|
|
|
|
|
degree_log: usize,
|
|
|
|
|
) -> F::Extension {
|
|
|
|
|
let degree = 1 << degree_log;
|
2021-05-04 17:48:26 +02:00
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
let mut point = F::Extension::rand();
|
|
|
|
|
while point.exp(degree as u64).is_one() {
|
|
|
|
|
point = F::Extension::rand();
|
|
|
|
|
}
|
2021-05-04 17:48:26 +02:00
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
point
|
2021-05-06 17:09:55 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-18 16:06:47 +02:00
|
|
|
fn check_batch_polynomial_commitment<F: Field + Extendable<D>, const D: usize>() -> Result<()> {
|
2021-05-31 17:49:04 +02:00
|
|
|
let ks = [1, 2, 3, 5, 8];
|
|
|
|
|
let degree_log = 2;
|
2021-05-06 17:09:55 +02:00
|
|
|
let fri_config = FriConfig {
|
|
|
|
|
proof_of_work_bits: 2,
|
2021-05-31 17:49:04 +02:00
|
|
|
rate_bits: 1,
|
|
|
|
|
// reduction_arity_bits: vec![2, 3, 1, 2],
|
|
|
|
|
reduction_arity_bits: vec![1],
|
2021-05-06 17:09:55 +02:00
|
|
|
num_query_rounds: 3,
|
2021-05-31 17:49:04 +02:00
|
|
|
blinding: vec![false, false, false, false, false],
|
2021-05-27 17:20:26 +02:00
|
|
|
check_basefield: vec![false, false, false],
|
2021-05-06 17:09:55 +02:00
|
|
|
};
|
|
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
let lpcs = ks
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|&k| {
|
|
|
|
|
ListPolynomialCommitment::<F>::new(
|
|
|
|
|
gen_random_test_case(k, degree_log),
|
|
|
|
|
fri_config.rate_bits,
|
|
|
|
|
false,
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.collect::<Vec<_>>();
|
2021-05-06 17:09:55 +02:00
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
let zeta = gen_random_point::<F, D>(degree_log);
|
|
|
|
|
let (proof, os) = ListPolynomialCommitment::open_plonk::<D>(
|
|
|
|
|
&[&lpcs[0], &lpcs[1], &lpcs[2], &lpcs[3], &lpcs[4]],
|
|
|
|
|
zeta,
|
|
|
|
|
degree_log,
|
2021-05-06 17:09:55 +02:00
|
|
|
&mut Challenger::new(),
|
2021-05-11 09:56:21 +02:00
|
|
|
&fri_config,
|
2021-05-06 17:09:55 +02:00
|
|
|
);
|
2021-05-31 17:49:04 +02:00
|
|
|
let os = OpeningSet::new(
|
|
|
|
|
zeta,
|
|
|
|
|
F::Extension::primitive_root_of_unity(degree_log),
|
|
|
|
|
&lpcs[0],
|
|
|
|
|
&lpcs[1],
|
|
|
|
|
&lpcs[2],
|
|
|
|
|
&lpcs[3],
|
|
|
|
|
&lpcs[4],
|
2021-05-06 17:09:55 +02:00
|
|
|
);
|
|
|
|
|
proof.verify(
|
2021-05-31 17:49:04 +02:00
|
|
|
zeta,
|
|
|
|
|
&os,
|
2021-05-06 17:09:55 +02:00
|
|
|
&[
|
2021-05-31 17:49:04 +02:00
|
|
|
lpcs[0].merkle_tree.root,
|
|
|
|
|
lpcs[1].merkle_tree.root,
|
|
|
|
|
lpcs[2].merkle_tree.root,
|
|
|
|
|
lpcs[3].merkle_tree.root,
|
|
|
|
|
lpcs[4].merkle_tree.root,
|
2021-05-06 17:09:55 +02:00
|
|
|
],
|
2021-05-06 15:19:06 +02:00
|
|
|
&mut Challenger::new(),
|
|
|
|
|
&fri_config,
|
|
|
|
|
)
|
2021-05-04 17:48:26 +02:00
|
|
|
}
|
2021-05-18 16:06:47 +02:00
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
// fn check_batch_polynomial_commitment_blinding<F: Field + Extendable<D>, const D: usize>(
|
|
|
|
|
// ) -> Result<()> {
|
|
|
|
|
// let k0 = 10;
|
|
|
|
|
// let k1 = 3;
|
|
|
|
|
// let k2 = 7;
|
|
|
|
|
// let degree_log = 11;
|
|
|
|
|
// let num_points = 5;
|
|
|
|
|
// let fri_config = FriConfig {
|
|
|
|
|
// proof_of_work_bits: 2,
|
|
|
|
|
// rate_bits: 2,
|
|
|
|
|
// reduction_arity_bits: vec![2, 3, 1, 2],
|
|
|
|
|
// num_query_rounds: 3,
|
|
|
|
|
// blinding: vec![true, false, true],
|
|
|
|
|
// check_basefield: vec![true, false, true],
|
|
|
|
|
// };
|
|
|
|
|
// let (polys0, _) = gen_random_test_case::<F, D>(k0, degree_log, num_points);
|
|
|
|
|
// let (polys1, _) = gen_random_test_case::<F, D>(k1, degree_log, num_points);
|
|
|
|
|
// let (polys2, points) = gen_random_test_case::<F, D>(k2, degree_log, num_points);
|
|
|
|
|
//
|
|
|
|
|
// let lpc0 = ListPolynomialCommitment::new(polys0, fri_config.rate_bits, true);
|
|
|
|
|
// let lpc1 = ListPolynomialCommitment::new(polys1, fri_config.rate_bits, false);
|
|
|
|
|
// let lpc2 = ListPolynomialCommitment::new(polys2, fri_config.rate_bits, true);
|
|
|
|
|
//
|
|
|
|
|
// let (proof, evaluations) = ListPolynomialCommitment::batch_open::<D>(
|
|
|
|
|
// &[&lpc0, &lpc1, &lpc2],
|
|
|
|
|
// &points,
|
|
|
|
|
// &fri_config,
|
|
|
|
|
// &mut Challenger::new(),
|
|
|
|
|
// );
|
|
|
|
|
// proof.verify(
|
|
|
|
|
// &points,
|
|
|
|
|
// &evaluations,
|
|
|
|
|
// &[
|
|
|
|
|
// lpc0.merkle_tree.root,
|
|
|
|
|
// lpc1.merkle_tree.root,
|
|
|
|
|
// lpc2.merkle_tree.root,
|
|
|
|
|
// ],
|
|
|
|
|
// &mut Challenger::new(),
|
|
|
|
|
// &fri_config,
|
|
|
|
|
// )
|
|
|
|
|
// }
|
|
|
|
|
|
2021-05-18 16:23:44 +02:00
|
|
|
macro_rules! tests_commitments {
|
|
|
|
|
($F:ty, $D:expr) => {
|
|
|
|
|
use super::*;
|
2021-05-18 16:06:47 +02:00
|
|
|
|
2021-05-18 16:23:44 +02:00
|
|
|
#[test]
|
|
|
|
|
fn test_batch_polynomial_commitment() -> Result<()> {
|
|
|
|
|
check_batch_polynomial_commitment::<$F, $D>()
|
|
|
|
|
}
|
2021-05-18 16:06:47 +02:00
|
|
|
|
2021-05-31 17:49:04 +02:00
|
|
|
// #[test]
|
|
|
|
|
// fn test_batch_polynomial_commitment_blinding() -> Result<()> {
|
|
|
|
|
// check_batch_polynomial_commitment_blinding::<$F, $D>()
|
|
|
|
|
// }
|
2021-05-18 16:23:44 +02:00
|
|
|
};
|
2021-05-18 16:06:47 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-18 16:23:44 +02:00
|
|
|
mod base {
|
|
|
|
|
tests_commitments!(crate::field::crandall_field::CrandallField, 1);
|
|
|
|
|
}
|
2021-05-18 16:06:47 +02:00
|
|
|
|
2021-05-18 16:23:44 +02:00
|
|
|
mod quadratic {
|
|
|
|
|
tests_commitments!(crate::field::crandall_field::CrandallField, 2);
|
2021-05-18 16:06:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod quartic {
|
|
|
|
|
use super::*;
|
2021-05-18 16:23:44 +02:00
|
|
|
tests_commitments!(crate::field::crandall_field::CrandallField, 4);
|
2021-05-18 16:06:47 +02:00
|
|
|
}
|
2021-04-30 15:07:54 +02:00
|
|
|
}
|