plonky2/src/polynomial/commitment.rs

266 lines
7.9 KiB
Rust
Raw Normal View History

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;
use crate::plonk_common::reduce_with_powers;
use crate::polynomial::old_polynomial::Polynomial;
2021-05-04 19:56:34 +02:00
use crate::polynomial::polynomial::PolynomialCoeffs;
2021-05-04 17:48:26 +02:00
use crate::proof::{FriProof, Hash};
use crate::util::{log2_strict, reverse_index_bits_in_place, transpose};
use anyhow::Result;
2021-04-30 15:07:54 +02:00
struct ListPolynomialCommitment<F: Field> {
2021-05-03 15:17:05 +02:00
pub polynomials: Vec<PolynomialCoeffs<F>>,
pub fri_config: FriConfig,
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-04-30 15:07:54 +02:00
}
impl<F: Field> ListPolynomialCommitment<F> {
2021-05-05 17:00:47 +02:00
pub fn new(polynomials: Vec<PolynomialCoeffs<F>>, fri_config: &FriConfig) -> Self {
2021-05-03 15:17:05 +02:00
let degree = polynomials[0].len();
2021-05-04 19:56:34 +02:00
let lde_values = polynomials
2021-05-03 15:17:05 +02:00
.iter()
.map(|p| {
assert_eq!(p.len(), degree, "Polynomial degree invalid.");
p.clone()
.lde(fri_config.rate_bits)
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR)
.values
})
2021-05-06 00:00:08 +02:00
.chain(if fri_config.blinding {
// If blinding, salt with two random elements to each leaf vector.
(0..2)
2021-05-06 15:14:43 +02:00
.map(|_| F::rand_vec(degree << fri_config.rate_bits))
2021-05-03 15:17:05 +02:00
.collect()
2021-05-06 00:00:08 +02:00
} else {
Vec::new()
})
2021-04-30 15:07:54 +02:00
.collect::<Vec<_>>();
2021-05-03 15:17:05 +02:00
2021-05-04 17:48:26 +02:00
let mut leaves = transpose(&lde_values);
reverse_index_bits_in_place(&mut leaves);
let merkle_tree = MerkleTree::new(leaves, false);
2021-04-30 15:07:54 +02:00
Self {
2021-05-03 15:17:05 +02:00
polynomials,
fri_config: fri_config.clone(),
2021-04-30 15:07:54 +02:00
merkle_tree,
2021-05-03 15:17:05 +02:00
degree,
2021-04-30 15:07:54 +02:00
}
}
2021-05-03 15:17:05 +02:00
2021-05-05 22:58:15 +02:00
pub fn open(
&self,
points: &[F],
challenger: &mut Challenger<F>,
) -> (OpeningProof<F>, Vec<Vec<F>>) {
2021-05-03 15:17:05 +02:00
for p in points {
assert_ne!(
p.exp_usize(self.degree),
F::ONE,
"Opening point is in the subgroup."
);
}
let evaluations = points
.iter()
.map(|&x| {
self.polynomials
.iter()
.map(|p| p.eval(x))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
for evals in &evaluations {
challenger.observe_elements(evals);
}
let alpha = challenger.get_challenge();
2021-05-05 18:32:24 +02:00
// Scale polynomials by `alpha`.
2021-05-05 22:58:15 +02:00
let composition_poly = self
2021-05-03 15:17:05 +02:00
.polynomials
.iter()
.rev()
.map(|p| p.clone().into())
.fold(Polynomial::empty(), |acc, p| acc.scalar_mul(alpha).add(&p));
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-03 15:17:05 +02:00
.iter()
.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
let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(self.fri_config.rate_bits);
2021-05-04 19:56:34 +02:00
let lde_quotient_values = lde_quotient
.clone()
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR);
2021-05-04 17:48:26 +02:00
2021-05-03 15:17:05 +02:00
let fri_proof = fri_proof(
2021-05-04 17:48:26 +02:00
&[self.merkle_tree.clone()],
&lde_quotient,
&lde_quotient_values,
2021-05-03 15:17:05 +02:00
challenger,
&self.fri_config,
);
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
/// 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(points: &[F], evals: &[F], poly: &Polynomial<F>) -> Polynomial<F> {
let pairs = points
.iter()
.zip(evals)
.map(|(&x, &e)| (x, e))
.collect::<Vec<_>>();
debug_assert!(pairs.iter().all(|&(x, e)| poly.eval(x) == e));
let interpolant: Polynomial<F> = interpolant(&pairs).into();
let denominator = points
.iter()
.fold(Polynomial::from(vec![F::ONE]), |acc, &x| {
acc.mul(&vec![-x, F::ONE].into())
});
let numerator = poly.add(&interpolant.neg());
let (mut quotient, rem) = numerator.polynomial_division(&denominator);
debug_assert!(rem.is_zero());
quotient.pad((quotient.degree() + 1).next_power_of_two());
quotient
}
2021-05-03 15:17:05 +02:00
}
pub struct OpeningProof<F: Field> {
2021-05-04 17:48:26 +02:00
fri_proof: FriProof<F>,
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,
}
impl<F: Field> OpeningProof<F> {
pub fn verify(
&self,
points: &[F],
2021-05-05 22:58:15 +02:00
evaluations: &[Vec<F>],
2021-05-06 15:19:06 +02:00
merkle_root: Hash<F>,
2021-05-04 17:48:26 +02:00
challenger: &mut Challenger<F>,
fri_config: &FriConfig,
) -> Result<()> {
2021-05-05 22:58:15 +02:00
for evals in evaluations {
2021-05-04 17:48:26 +02:00
challenger.observe_elements(evals);
}
let alpha = challenger.get_challenge();
2021-05-05 22:58:15 +02:00
let scaled_evals = evaluations
2021-05-04 17:48:26 +02:00
.iter()
.map(|e| reduce_with_powers(e, alpha))
.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,
alpha,
2021-05-06 15:19:06 +02:00
&[merkle_root],
2021-05-04 17:48:26 +02:00
&self.fri_proof,
challenger,
fri_config,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::field::crandall_field::CrandallField;
use anyhow::Result;
2021-05-05 17:00:47 +02:00
fn gen_random_test_case<F: Field>(
k: usize,
degree_log: usize,
num_points: usize,
) -> (Vec<PolynomialCoeffs<F>>, Vec<F>) {
let degree = 1 << degree_log;
let polys = (0..k)
2021-05-06 15:14:43 +02:00
.map(|_| PolynomialCoeffs::new(F::rand_vec(degree)))
2021-05-05 17:00:47 +02:00
.collect();
2021-05-06 15:14:43 +02:00
let mut points = F::rand_vec(num_points);
2021-05-05 17:00:47 +02:00
while points.iter().any(|&x| x.exp_usize(degree).is_one()) {
2021-05-06 15:14:43 +02:00
points = F::rand_vec(num_points);
2021-05-05 17:00:47 +02:00
}
(polys, points)
}
2021-05-04 17:48:26 +02:00
#[test]
fn test_polynomial_commitment() -> Result<()> {
type F = CrandallField;
2021-05-04 19:56:34 +02:00
let k = 10;
let degree_log = 11;
2021-05-05 17:00:47 +02:00
let num_points = 3;
2021-05-04 17:48:26 +02:00
let fri_config = FriConfig {
proof_of_work_bits: 2,
rate_bits: 2,
2021-05-04 19:56:34 +02:00
reduction_arity_bits: vec![3, 2, 1, 2],
num_query_rounds: 3,
2021-05-05 17:00:47 +02:00
blinding: false,
2021-05-04 17:48:26 +02:00
};
2021-05-05 17:00:47 +02:00
let (polys, points) = gen_random_test_case::<F>(k, degree_log, num_points);
2021-05-04 17:48:26 +02:00
2021-05-05 17:00:47 +02:00
let lpc = ListPolynomialCommitment::new(polys, &fri_config);
2021-05-05 22:58:15 +02:00
let (proof, evaluations) = lpc.open(&points, &mut Challenger::new());
2021-05-06 15:19:06 +02:00
proof.verify(
&points,
&evaluations,
lpc.merkle_tree.root,
&mut Challenger::new(),
&fri_config,
)
2021-05-05 17:00:47 +02:00
}
2021-05-04 17:48:26 +02:00
2021-05-05 17:00:47 +02:00
#[test]
fn test_polynomial_commitment_blinding() -> Result<()> {
type F = CrandallField;
2021-05-04 17:48:26 +02:00
2021-05-05 17:00:47 +02:00
let k = 10;
let degree_log = 11;
2021-05-04 17:48:26 +02:00
let num_points = 3;
2021-05-05 17:00:47 +02:00
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: true,
};
let (polys, points) = gen_random_test_case::<F>(k, degree_log, num_points);
2021-05-04 17:48:26 +02:00
2021-05-05 17:00:47 +02:00
let lpc = ListPolynomialCommitment::new(polys, &fri_config);
2021-05-05 22:58:15 +02:00
let (proof, evaluations) = lpc.open(&points, &mut Challenger::new());
2021-05-06 15:19:06 +02:00
proof.verify(
&points,
&evaluations,
lpc.merkle_tree.root,
&mut Challenger::new(),
&fri_config,
)
2021-05-04 17:48:26 +02:00
}
2021-04-30 15:07:54 +02:00
}