Merge pull request #55 from mir-protocol/check_base_field

Check base field
This commit is contained in:
wborgeaud 2021-06-02 09:59:00 +02:00 committed by GitHub
commit c24ad60688
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 320 additions and 515 deletions

View File

@ -14,6 +14,7 @@ default-run = "bench_recursion"
[dependencies]
env_logger = "0.8.3"
log = "0.4.14"
itertools = "0.10.0"
num = "0.3"
rand = "0.7.3"
rand_chacha = "0.2.2"

View File

@ -268,6 +268,7 @@ pub trait Field:
}
/// An iterator over the powers of a certain base element `b`: `b^0, b^1, b^2, ...`.
#[derive(Clone)]
pub struct Powers<F: Field> {
base: F,
current: F,

View File

@ -1,3 +1,5 @@
use crate::polynomial::commitment::SALT_SIZE;
pub mod prover;
pub mod verifier;
@ -25,6 +27,16 @@ pub struct FriConfig {
pub blinding: Vec<bool>,
}
impl FriConfig {
pub(crate) fn salt_size(&self, i: usize) -> usize {
if self.blinding[i] {
SALT_SIZE
} else {
0
}
}
}
fn fri_delta(rate_log: usize, conjecture: bool) -> f64 {
let rate = (1 << rate_log) as f64;
if conjecture {
@ -47,135 +59,3 @@ fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 {
1.0 / (2.0 * EPSILON * rate.sqrt())
}
}
#[cfg(test)]
mod tests {
use anyhow::Result;
use rand::rngs::ThreadRng;
use rand::Rng;
use crate::field::crandall_field::CrandallField;
use crate::field::extension_field::Extendable;
use crate::field::field::Field;
use crate::fri::prover::fri_proof;
use crate::fri::verifier::verify_fri_proof;
use crate::merkle_tree::MerkleTree;
use crate::plonk_challenger::Challenger;
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
use crate::util::reverse_index_bits_in_place;
use super::*;
fn check_fri<F: Field + Extendable<D>, const D: usize>(
degree_log: usize,
rate_bits: usize,
reduction_arity_bits: Vec<usize>,
num_query_rounds: usize,
) -> Result<()> {
let n = 1 << degree_log;
let coeffs = PolynomialCoeffs::new(F::rand_vec(n)).lde(rate_bits);
let coset_lde = coeffs.clone().coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR);
let config = FriConfig {
num_query_rounds,
rate_bits,
proof_of_work_bits: 2,
reduction_arity_bits,
blinding: vec![false],
};
let tree = {
let mut leaves = coset_lde
.values
.iter()
.map(|&x| vec![x])
.collect::<Vec<_>>();
reverse_index_bits_in_place(&mut leaves);
MerkleTree::new(leaves, false)
};
let coset_lde = PolynomialValues::new(
coset_lde
.values
.into_iter()
.map(F::Extension::from)
.collect(),
);
let root = tree.root;
let mut challenger = Challenger::new();
let proof = fri_proof::<F, D>(
&[&tree],
&coeffs.to_extension::<D>(),
&coset_lde,
&mut challenger,
&config,
);
let mut challenger = Challenger::new();
verify_fri_proof(
degree_log,
&[],
F::Extension::ONE,
&[root],
&proof,
&mut challenger,
&config,
)?;
Ok(())
}
fn gen_arities(degree_log: usize, rng: &mut ThreadRng) -> Vec<usize> {
let mut arities = Vec::new();
let mut remaining = degree_log;
while remaining > 0 {
let arity = rng.gen_range(0, remaining + 1);
arities.push(arity);
remaining -= arity;
}
arities
}
fn check_fri_multi_params<F: Field + Extendable<D>, const D: usize>() -> Result<()> {
let mut rng = rand::thread_rng();
for degree_log in 1..6 {
for rate_bits in 0..3 {
for num_query_round in 0..4 {
for _ in 0..3 {
check_fri::<F, D>(
degree_log,
rate_bits,
gen_arities(degree_log, &mut rng),
num_query_round,
)?;
}
}
}
}
Ok(())
}
mod base {
use super::*;
#[test]
fn test_fri_multi_params() -> Result<()> {
check_fri_multi_params::<CrandallField, 1>()
}
}
mod quadratic {
use super::*;
#[test]
fn test_fri_multi_params() -> Result<()> {
check_fri_multi_params::<CrandallField, 2>()
}
}
mod quartic {
use super::*;
#[test]
fn test_fri_multi_params() -> Result<()> {
check_fri_multi_params::<CrandallField, 4>()
}
}
}

View File

@ -1,15 +1,16 @@
use crate::field::extension_field::{flatten, Extendable, FieldExtension};
use anyhow::{ensure, Result};
use itertools::izip;
use crate::field::extension_field::{flatten, Extendable, FieldExtension, OEF};
use crate::field::field::Field;
use crate::field::lagrange::{barycentric_weights, interpolant, interpolate};
use crate::fri::FriConfig;
use crate::hash::hash_n_to_1;
use crate::merkle_proofs::verify_merkle_proof;
use crate::plonk_challenger::Challenger;
use crate::polynomial::commitment::SALT_SIZE;
use crate::polynomial::polynomial::PolynomialCoeffs;
use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash};
use crate::plonk_common::reduce_with_iter;
use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash, OpeningSet};
use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place};
use anyhow::{ensure, Result};
/// Computes P'(x^arity) from {P(x*g^i)}_(i=0..arity), where g is a `arity`-th root of unity
/// and P' is the FRI reduced polynomial.
@ -65,8 +66,10 @@ fn fri_verify_proof_of_work<F: Field + Extendable<D>, const D: usize>(
pub fn verify_fri_proof<F: Field + Extendable<D>, const D: usize>(
purported_degree_log: usize,
// Point-evaluation pairs for polynomial commitments.
points: &[(F::Extension, F::Extension)],
// Openings of the PLONK polynomials.
os: &OpeningSet<F, D>,
// Point at which the PLONK polynomials are opened.
zeta: F::Extension,
// Scaling factor to combine polynomials.
alpha: F::Extension,
initial_merkle_roots: &[Hash<F>],
@ -108,11 +111,10 @@ pub fn verify_fri_proof<F: Field + Extendable<D>, const D: usize>(
"Number of reductions should be non-zero."
);
let interpolant = interpolant(points);
for round_proof in &proof.query_round_proofs {
fri_verifier_query_round(
&interpolant,
points,
os,
zeta,
alpha,
initial_merkle_roots,
&proof,
@ -142,29 +144,77 @@ fn fri_verify_initial_proof<F: Field>(
fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
proof: &FriInitialTreeProof<F>,
alpha: F::Extension,
interpolant: &PolynomialCoeffs<F::Extension>,
points: &[(F::Extension, F::Extension)],
os: &OpeningSet<F, D>,
zeta: F::Extension,
subgroup_x: F,
config: &FriConfig,
) -> F::Extension {
let e = proof
.evals_proofs
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()
.enumerate()
.flat_map(|(i, (v, _))| &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }])
.rev()
.fold(F::Extension::ZERO, |acc, &e| alpha * acc + e.into());
let numerator = e - interpolant.eval(subgroup_x.into());
let denominator = points
.flat_map(|&i| proof.unsalted_evals(i, config))
.map(|&e| F::Extension::from_basefield(e));
let openings = os
.constants
.iter()
.map(|&(x, _)| F::Extension::from_basefield(subgroup_x) - x)
.product();
numerator / denominator
.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>(
interpolant: &PolynomialCoeffs<F::Extension>,
points: &[(F::Extension, F::Extension)],
os: &OpeningSet<F, D>,
zeta: F::Extension,
alpha: F::Extension,
initial_merkle_roots: &[Hash<F>],
proof: &FriProof<F, D>,
@ -195,8 +245,8 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
fri_combine_initial(
&round_proof.initial_trees_proof,
alpha,
interpolant,
points,
os,
zeta,
subgroup_x,
config,
)

View File

@ -2,7 +2,7 @@ use crate::circuit_builder::CircuitBuilder;
use crate::field::extension_field::{Extendable, FieldExtension};
use crate::field::field::Field;
use crate::hash::{permute, SPONGE_RATE, SPONGE_WIDTH};
use crate::proof::{Hash, HashTarget};
use crate::proof::{Hash, HashTarget, OpeningSet};
use crate::target::Target;
/// Observes prover messages, and generates challenges by hashing the transcript.
@ -61,6 +61,30 @@ impl<F: Field> Challenger<F> {
}
}
pub fn observe_opening_set<const D: usize>(&mut self, os: &OpeningSet<F, D>)
where
F: Extendable<D>,
{
let OpeningSet {
constants,
plonk_sigmas,
wires,
plonk_zs,
plonk_zs_right,
quotient_polys,
} = os;
for v in &[
constants,
plonk_sigmas,
wires,
plonk_zs,
plonk_zs_right,
quotient_polys,
] {
self.observe_extension_elements(v);
}
}
pub fn observe_hash(&mut self, hash: &Hash<F>) {
self.observe_elements(&hash.elements)
}

View File

@ -108,3 +108,14 @@ pub(crate) fn reduce_with_powers_recursive<F: Extendable<D>, const D: usize>(
) -> Target {
todo!()
}
pub(crate) fn reduce_with_iter<F: Field, I>(terms: &[F], coeffs: I) -> F
where
I: IntoIterator<Item = F>,
{
let mut sum = F::ZERO;
for (&term, coeff) in terms.iter().zip(coeffs) {
sum += coeff * term;
}
sum
}

View File

@ -1,8 +1,8 @@
use anyhow::Result;
use rayon::prelude::*;
use crate::field::extension_field::Extendable;
use crate::field::extension_field::FieldExtension;
use crate::field::extension_field::{Extendable, OEF};
use crate::field::field::Field;
use crate::field::lagrange::interpolant;
use crate::fri::{prover::fri_proof, verifier::verify_fri_proof, FriConfig};
@ -76,166 +76,128 @@ impl<F: Field> ListPolynomialCommitment<F> {
&leaf[0..leaf.len() - if self.blinding { SALT_SIZE } else { 0 }]
}
pub fn open<const D: usize>(
&self,
points: &[F::Extension],
/// Takes the commitments to the constants - sigmas - wires - zs - quotient — polynomials,
/// and an opening point `zeta` and produces a batched opening proof + opening set.
pub fn open_plonk<const D: usize>(
commitments: &[&Self; 5],
zeta: F::Extension,
challenger: &mut Challenger<F>,
config: &FriConfig,
) -> (OpeningProof<F, D>, Vec<Vec<F::Extension>>)
) -> (OpeningProof<F, D>, OpeningSet<F, D>)
where
F: Extendable<D>,
{
assert_eq!(self.rate_bits, config.rate_bits);
assert_eq!(config.blinding.len(), 1);
assert_eq!(self.blinding, config.blinding[0]);
for p in points {
assert!(D > 1, "Not implemented for D=1.");
let degree_log = log2_strict(commitments[0].degree);
let g = F::Extension::primitive_root_of_unity(degree_log);
for &p in &[zeta, g * zeta] {
assert_ne!(
p.exp(self.degree as u64),
p.exp(1 << degree_log as u64),
F::Extension::ONE,
"Opening point is in the subgroup."
);
}
let evaluations = points
.par_iter()
.map(|&x| {
self.polynomials
.iter()
.map(|p| p.to_extension().eval(x))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
for evals in &evaluations {
for e in evals {
challenger.observe_extension_element(e);
}
}
let alpha = challenger.get_extension_challenge();
// Scale polynomials by `alpha`.
let composition_poly = self
.polynomials
.iter()
.rev()
.fold(PolynomialCoeffs::zero(self.degree), |acc, p| {
&(&acc * alpha) + &p.to_extension()
});
// Scale evaluations by `alpha`.
let composition_evals = evaluations
.par_iter()
.map(|e| reduce_with_powers(e, alpha))
.collect::<Vec<_>>();
let quotient = Self::compute_quotient(points, &composition_evals, &composition_poly);
let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(self.rate_bits);
let lde_quotient_values = lde_quotient
.clone()
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR.into());
let fri_proof = fri_proof(
&[&self.merkle_tree],
&lde_quotient,
&lde_quotient_values,
challenger,
&config,
let os = OpeningSet::new(
zeta,
g,
commitments[0],
commitments[1],
commitments[2],
commitments[3],
commitments[4],
);
(
OpeningProof {
fri_proof,
quotient_degree: quotient.len(),
},
evaluations,
)
}
pub fn batch_open<const D: usize>(
commitments: &[&Self],
points: &[F::Extension],
challenger: &mut Challenger<F>,
config: &FriConfig,
) -> (OpeningProof<F, D>, Vec<Vec<Vec<F::Extension>>>)
where
F: Extendable<D>,
{
let degree = commitments[0].degree;
assert_eq!(config.blinding.len(), commitments.len());
for (i, commitment) in commitments.iter().enumerate() {
assert_eq!(commitment.rate_bits, config.rate_bits, "Invalid rate.");
assert_eq!(
commitment.blinding, config.blinding[i],
"Invalid blinding paramater."
);
assert_eq!(
commitment.degree, degree,
"Trying to open polynomial commitments of different degrees."
);
}
for p in points {
assert_ne!(
p.exp(degree as u64),
F::Extension::ONE,
"Opening point is in the subgroup."
);
}
let evaluations = points
.par_iter()
.map(|&x| {
commitments
.iter()
.map(move |c| {
c.polynomials
.iter()
.map(|p| p.to_extension().eval(x))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
for evals_per_point in &evaluations {
for evals in evals_per_point {
challenger.observe_extension_elements(evals);
}
}
challenger.observe_opening_set(&os);
let alpha = challenger.get_extension_challenge();
let mut cur_alpha = F::Extension::ONE;
// Scale polynomials by `alpha`.
let composition_poly = commitments
// 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;
// Polynomials opened at a single point.
let composition_poly = [0, 1, 4]
.iter()
.flat_map(|c| &c.polynomials)
.flat_map(|&i| &commitments[i].polynomials)
.rev()
.fold(PolynomialCoeffs::zero(degree), |acc, p| {
.fold(PolynomialCoeffs::empty(), |acc, p| {
poly_count += 1;
&(&acc * alpha) + &p.to_extension()
});
// Scale evaluations by `alpha`.
let composition_evals = &evaluations
.par_iter()
.map(|v| {
v.iter()
.flatten()
.rev()
.fold(F::Extension::ZERO, |acc, &e| acc * alpha + e)
})
.collect::<Vec<_>>();
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(points, &composition_evals, &composition_poly);
let quotient = Self::compute_quotient(&[zeta], &[composition_eval], &composition_poly);
final_poly = &final_poly + &(&quotient * cur_alpha);
cur_alpha = alpha.exp(poly_count);
let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(config.rate_bits);
let lde_quotient_values = lde_quotient.clone().coset_fft(F::Extension::from_basefield(
F::MULTIPLICATIVE_GROUP_GENERATOR,
));
// Zs polynomials are opened at `zeta` and `g*zeta`.
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);
cur_alpha = alpha.exp(poly_count);
// When working in an extension field, need to check that wires are in the base field.
// Check this by opening the wires polynomials at `zeta` and `zeta.frobenius()` and using the fact that
// a polynomial `f` is over the base field iff `f(z).frobenius()=f(z.frobenius())` with high probability.
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);
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,
));
let fri_proof = fri_proof(
&commitments
.par_iter()
.map(|c| &c.merkle_tree)
.collect::<Vec<_>>(),
&lde_quotient,
&lde_quotient_values,
&lde_final_poly,
&lde_final_values,
challenger,
&config,
);
@ -243,38 +205,12 @@ impl<F: Field> ListPolynomialCommitment<F> {
(
OpeningProof {
fri_proof,
quotient_degree: quotient.len(),
quotient_degree: final_poly.len(),
},
evaluations,
os,
)
}
pub fn batch_open_plonk<const D: usize>(
commitments: &[&Self; 5],
points: &[F::Extension],
challenger: &mut Challenger<F>,
config: &FriConfig,
) -> (OpeningProof<F, D>, Vec<OpeningSet<F::Extension>>)
where
F: Extendable<D>,
{
let (op, mut evaluations) = Self::batch_open(commitments, points, challenger, config);
let opening_sets = evaluations
.par_iter_mut()
.map(|evals| {
evals.reverse();
OpeningSet {
constants: evals.pop().unwrap(),
plonk_sigmas: evals.pop().unwrap(),
wires: evals.pop().unwrap(),
plonk_zs: evals.pop().unwrap(),
quotient_polys: evals.pop().unwrap(),
}
})
.collect();
(op, opening_sets)
}
/// 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)`.
fn compute_quotient<const D: usize>(
@ -297,7 +233,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
&acc * &PolynomialCoeffs::new(vec![-x, F::Extension::ONE])
});
let numerator = poly - &interpolant;
let (mut quotient, rem) = numerator.div_rem(&denominator);
let (quotient, rem) = numerator.div_rem(&denominator);
debug_assert!(rem.is_zero());
quotient.padded(quotient.degree_plus_one().next_power_of_two())
@ -313,39 +249,20 @@ pub struct OpeningProof<F: Field + Extendable<D>, const D: usize> {
impl<F: Field + Extendable<D>, const D: usize> OpeningProof<F, D> {
pub fn verify(
&self,
points: &[F::Extension],
evaluations: &[Vec<Vec<F::Extension>>],
zeta: F::Extension,
os: &OpeningSet<F, D>,
merkle_roots: &[Hash<F>],
challenger: &mut Challenger<F>,
fri_config: &FriConfig,
) -> Result<()> {
for evals_per_point in evaluations {
for evals in evals_per_point {
challenger.observe_extension_elements(evals);
}
}
challenger.observe_opening_set(os);
let alpha = challenger.get_extension_challenge();
let scaled_evals = evaluations
.par_iter()
.map(|v| {
v.iter()
.flatten()
.rev()
.fold(F::Extension::ZERO, |acc, &e| acc * alpha + e)
})
.collect::<Vec<_>>();
let pairs = points
.iter()
.zip(&scaled_evals)
.map(|(&x, &e)| (x, e))
.collect::<Vec<_>>();
verify_fri_proof(
log2_strict(self.quotient_degree),
&pairs,
&os,
zeta,
alpha,
merkle_roots,
&self.fri_proof,
@ -360,191 +277,102 @@ mod tests {
use anyhow::Result;
use super::*;
use rand::Rng;
fn gen_random_test_case<F: Field + Extendable<D>, const D: usize>(
k: usize,
degree_log: usize,
num_points: usize,
) -> (Vec<PolynomialCoeffs<F>>, Vec<F::Extension>) {
) -> Vec<PolynomialCoeffs<F>> {
let degree = 1 << degree_log;
let polys = (0..k)
(0..k)
.map(|_| PolynomialCoeffs::new(F::rand_vec(degree)))
.collect();
let mut points = F::Extension::rand_vec(num_points);
while points.iter().any(|&x| x.exp(degree as u64).is_one()) {
points = F::Extension::rand_vec(num_points);
.collect()
}
fn gen_random_point<F: Field + Extendable<D>, const D: usize>(
degree_log: usize,
) -> F::Extension {
let degree = 1 << degree_log;
let mut point = F::Extension::rand();
while point.exp(degree as u64).is_one() {
point = F::Extension::rand();
}
(polys, points)
point
}
fn check_polynomial_commitment<F: Field + Extendable<D>, const D: usize>() -> Result<()> {
let k = 10;
let degree_log = 11;
let num_points = 3;
let fri_config = FriConfig {
proof_of_work_bits: 2,
rate_bits: 2,
reduction_arity_bits: vec![3, 2, 1, 2],
num_query_rounds: 3,
blinding: vec![false],
};
let (polys, points) = gen_random_test_case::<F, D>(k, degree_log, num_points);
let lpc = ListPolynomialCommitment::new(polys, fri_config.rate_bits, false);
let (proof, evaluations) = lpc.open::<D>(&points, &mut Challenger::new(), &fri_config);
proof.verify(
&points,
&evaluations.into_iter().map(|e| vec![e]).collect::<Vec<_>>(),
&[lpc.merkle_tree.root],
&mut Challenger::new(),
&fri_config,
)
}
fn check_polynomial_commitment_blinding<F: Field + Extendable<D>, const D: usize>() -> Result<()>
{
let k = 10;
let degree_log = 11;
let num_points = 3;
let fri_config = FriConfig {
proof_of_work_bits: 2,
rate_bits: 2,
reduction_arity_bits: vec![3, 2, 1, 2],
num_query_rounds: 3,
blinding: vec![true],
};
let (polys, points) = gen_random_test_case::<F, D>(k, degree_log, num_points);
let lpc = ListPolynomialCommitment::new(polys, fri_config.rate_bits, true);
let (proof, evaluations) = lpc.open::<D>(&points, &mut Challenger::new(), &fri_config);
proof.verify(
&points,
&evaluations.into_iter().map(|e| vec![e]).collect::<Vec<_>>(),
&[lpc.merkle_tree.root],
&mut Challenger::new(),
&fri_config,
)
fn gen_random_blindings() -> Vec<bool> {
let mut rng = rand::thread_rng();
vec![
rng.gen_bool(0.5),
rng.gen_bool(0.5),
rng.gen_bool(0.5),
rng.gen_bool(0.5),
rng.gen_bool(0.5),
]
}
fn check_batch_polynomial_commitment<F: Field + Extendable<D>, const D: usize>() -> Result<()> {
let k0 = 10;
let k1 = 3;
let k2 = 7;
let ks = [1, 2, 3, 5, 8];
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![false, false, false],
blinding: gen_random_blindings(),
};
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, false);
let lpc1 = ListPolynomialCommitment::new(polys1, fri_config.rate_bits, false);
let lpc2 = ListPolynomialCommitment::new(polys2, fri_config.rate_bits, false);
let lpcs = (0..5)
.map(|i| {
ListPolynomialCommitment::<F>::new(
gen_random_test_case(ks[i], degree_log),
fri_config.rate_bits,
fri_config.blinding[i],
)
})
.collect::<Vec<_>>();
let (proof, evaluations) = ListPolynomialCommitment::batch_open::<D>(
&[&lpc0, &lpc1, &lpc2],
&points,
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,
&mut Challenger::new(),
&fri_config,
);
proof.verify(
&points,
&evaluations,
zeta,
&os,
&[
lpc0.merkle_tree.root,
lpc1.merkle_tree.root,
lpc2.merkle_tree.root,
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,
],
&mut Challenger::new(),
&fri_config,
)
}
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],
};
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,
&mut Challenger::new(),
&fri_config,
);
proof.verify(
&points,
&evaluations,
&[
lpc0.merkle_tree.root,
lpc1.merkle_tree.root,
lpc2.merkle_tree.root,
],
&mut Challenger::new(),
&fri_config,
)
}
macro_rules! tests_commitments {
($F:ty, $D:expr) => {
use super::*;
#[test]
fn test_polynomial_commitment() -> Result<()> {
check_polynomial_commitment::<$F, $D>()
}
#[test]
fn test_polynomial_commitment_blinding() -> Result<()> {
check_polynomial_commitment_blinding::<$F, $D>()
}
#[test]
fn test_batch_polynomial_commitment() -> Result<()> {
check_batch_polynomial_commitment::<$F, $D>()
}
#[test]
fn test_batch_polynomial_commitment_blinding() -> Result<()> {
check_batch_polynomial_commitment_blinding::<$F, $D>()
}
};
}
mod base {
tests_commitments!(crate::field::crandall_field::CrandallField, 1);
}
mod quadratic {
tests_commitments!(crate::field::crandall_field::CrandallField, 2);
use super::*;
use crate::field::crandall_field::CrandallField;
#[test]
fn test_batch_polynomial_commitment() -> Result<()> {
check_batch_polynomial_commitment::<CrandallField, 2>()
}
}
mod quartic {
use super::*;
tests_commitments!(crate::field::crandall_field::CrandallField, 4);
use crate::field::crandall_field::CrandallField;
#[test]
fn test_batch_polynomial_commitment() -> Result<()> {
check_batch_polynomial_commitment::<CrandallField, 4>()
}
}
}

View File

@ -1,5 +1,6 @@
use crate::field::extension_field::Extendable;
use crate::field::field::Field;
use crate::fri::FriConfig;
use crate::merkle_proofs::{MerkleProof, MerkleProofTarget};
use crate::polynomial::commitment::{ListPolynomialCommitment, OpeningProof};
use crate::polynomial::polynomial::PolynomialCoeffs;
@ -63,8 +64,8 @@ pub struct Proof<F: Field + Extendable<D>, const D: usize> {
/// Merkle root of LDEs of the quotient polynomial components.
pub quotient_polys_root: Hash<F>,
/// Purported values of each polynomial at each challenge point.
pub openings: Vec<OpeningSet<F::Extension>>,
/// Purported values of each polynomial at the challenge point.
pub openings: OpeningSet<F, D>,
/// A FRI argument for each FRI query.
pub opening_proof: OpeningProof<F, D>,
@ -99,6 +100,13 @@ pub struct FriInitialTreeProof<F: Field> {
pub evals_proofs: Vec<(Vec<F>, MerkleProof<F>)>,
}
impl<F: Field> FriInitialTreeProof<F> {
pub(crate) fn unsalted_evals(&self, i: usize, config: &FriConfig) -> &[F] {
let evals = &self.evals_proofs[i].0;
&evals[..evals.len() - config.salt_size(i)]
}
}
/// Proof for a FRI query round.
// TODO: Implement FriQueryRoundTarget
pub struct FriQueryRound<F: Field + Extendable<D>, const D: usize> {
@ -130,31 +138,37 @@ pub struct FriProofTarget {
}
/// The purported values of each polynomial at a single point.
pub struct OpeningSet<F: Field> {
pub constants: Vec<F>,
pub plonk_sigmas: Vec<F>,
pub wires: Vec<F>,
pub plonk_zs: Vec<F>,
pub quotient_polys: Vec<F>,
pub struct OpeningSet<F: Field + Extendable<D>, const D: usize> {
pub constants: Vec<F::Extension>,
pub plonk_sigmas: Vec<F::Extension>,
pub wires: Vec<F::Extension>,
pub plonk_zs: Vec<F::Extension>,
pub plonk_zs_right: Vec<F::Extension>,
pub quotient_polys: Vec<F::Extension>,
}
impl<F: Field> OpeningSet<F> {
impl<F: Field + Extendable<D>, const D: usize> OpeningSet<F, D> {
pub fn new(
z: F,
z: F::Extension,
g: F::Extension,
constant_commitment: &ListPolynomialCommitment<F>,
plonk_sigmas_commitment: &ListPolynomialCommitment<F>,
wires_commitment: &ListPolynomialCommitment<F>,
plonk_zs_commitment: &ListPolynomialCommitment<F>,
quotient_polys_commitment: &ListPolynomialCommitment<F>,
) -> Self {
let eval_commitment = |z: F, c: &ListPolynomialCommitment<F>| {
c.polynomials.iter().map(|p| p.eval(z)).collect::<Vec<_>>()
let eval_commitment = |z: F::Extension, c: &ListPolynomialCommitment<F>| {
c.polynomials
.iter()
.map(|p| p.to_extension().eval(z))
.collect::<Vec<_>>()
};
Self {
constants: eval_commitment(z, constant_commitment),
plonk_sigmas: eval_commitment(z, plonk_sigmas_commitment),
wires: eval_commitment(z, wires_commitment),
plonk_zs: eval_commitment(z, plonk_zs_commitment),
plonk_zs_right: eval_commitment(g * z, plonk_zs_commitment),
quotient_polys: eval_commitment(z, quotient_polys_commitment),
}
}

View File

@ -116,7 +116,7 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
let zeta = challenger.get_extension_challenge();
let (opening_proof, openings) = timed!(
ListPolynomialCommitment::batch_open_plonk(
ListPolynomialCommitment::open_plonk(
&[
&prover_data.constants_commitment,
&prover_data.sigmas_commitment,
@ -124,7 +124,7 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
&plonk_zs_commitment,
&quotient_polys_commitment,
],
&[zeta],
zeta,
&mut challenger,
&common_data.config.fri_config
),

View File

@ -41,13 +41,9 @@ pub(crate) fn verify<F: Extendable<D>, const D: usize>(
proof.quotient_polys_root,
];
proof.opening_proof.verify(
&[zeta],
evaluations,
merkle_roots,
&mut challenger,
fri_config,
)?;
proof
.opening_proof
.verify(zeta, evaluations, merkle_roots, &mut challenger, fri_config)?;
Ok(())
}