mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-08 00:33:06 +00:00
LPC batch opening
This commit is contained in:
parent
7617018d82
commit
0bae47bedb
@ -5,7 +5,7 @@ pub mod verifier;
|
|||||||
/// while increasing L, potentially requiring more challenge points.
|
/// while increasing L, potentially requiring more challenge points.
|
||||||
const EPSILON: f64 = 0.01;
|
const EPSILON: f64 = 0.01;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct FriConfig {
|
pub struct FriConfig {
|
||||||
pub proof_of_work_bits: u32,
|
pub proof_of_work_bits: u32,
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let root = tree.root;
|
let root = tree.root;
|
||||||
let mut challenger = Challenger::new();
|
let mut challenger = Challenger::new();
|
||||||
let proof = fri_proof(&[tree], &coeffs, &coset_lde, &mut challenger, &config);
|
let proof = fri_proof(&[&tree], &coeffs, &coset_lde, &mut challenger, &config);
|
||||||
|
|
||||||
let mut challenger = Challenger::new();
|
let mut challenger = Challenger::new();
|
||||||
verify_fri_proof(
|
verify_fri_proof(
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use crate::util::reverse_index_bits_in_place;
|
|||||||
|
|
||||||
/// Builds a FRI proof.
|
/// Builds a FRI proof.
|
||||||
pub fn fri_proof<F: Field>(
|
pub fn fri_proof<F: Field>(
|
||||||
initial_merkle_trees: &[MerkleTree<F>],
|
initial_merkle_trees: &[&MerkleTree<F>],
|
||||||
// Coefficients of the polynomial on which the LDT is performed. Only the first `1/rate` coefficients are non-zero.
|
// Coefficients of the polynomial on which the LDT is performed. Only the first `1/rate` coefficients are non-zero.
|
||||||
lde_polynomial_coeffs: &PolynomialCoeffs<F>,
|
lde_polynomial_coeffs: &PolynomialCoeffs<F>,
|
||||||
// Evaluation of the polynomial on the large domain.
|
// Evaluation of the polynomial on the large domain.
|
||||||
@ -113,7 +113,7 @@ fn fri_proof_of_work<F: Field>(current_hash: Hash<F>, config: &FriConfig) -> F {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fri_prover_query_rounds<F: Field>(
|
fn fri_prover_query_rounds<F: Field>(
|
||||||
initial_merkle_trees: &[MerkleTree<F>],
|
initial_merkle_trees: &[&MerkleTree<F>],
|
||||||
trees: &[MerkleTree<F>],
|
trees: &[MerkleTree<F>],
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
n: usize,
|
n: usize,
|
||||||
@ -125,7 +125,7 @@ fn fri_prover_query_rounds<F: Field>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fri_prover_query_round<F: Field>(
|
fn fri_prover_query_round<F: Field>(
|
||||||
initial_merkle_trees: &[MerkleTree<F>],
|
initial_merkle_trees: &[&MerkleTree<F>],
|
||||||
trees: &[MerkleTree<F>],
|
trees: &[MerkleTree<F>],
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
n: usize,
|
n: usize,
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use crate::fri::FriConfig;
|
|||||||
use crate::hash::hash_n_to_1;
|
use crate::hash::hash_n_to_1;
|
||||||
use crate::merkle_proofs::verify_merkle_proof;
|
use crate::merkle_proofs::verify_merkle_proof;
|
||||||
use crate::plonk_challenger::Challenger;
|
use crate::plonk_challenger::Challenger;
|
||||||
|
use crate::polynomial::commitment::SALT_SIZE;
|
||||||
use crate::polynomial::polynomial::PolynomialCoeffs;
|
use crate::polynomial::polynomial::PolynomialCoeffs;
|
||||||
use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash};
|
use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash};
|
||||||
use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place};
|
use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place};
|
||||||
@ -148,10 +149,8 @@ fn fri_combine_initial<F: Field>(
|
|||||||
let e = proof
|
let e = proof
|
||||||
.evals_proofs
|
.evals_proofs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(v, _)| v)
|
.flat_map(|(v, _)| &v[..v.len() - if config.blinding { SALT_SIZE } else { 0 }])
|
||||||
.flatten()
|
|
||||||
.rev()
|
.rev()
|
||||||
.skip(if config.blinding { 2 } else { 0 }) // If blinding, the last two element are salt.
|
|
||||||
.fold(F::ZERO, |acc, &e| alpha * acc + e);
|
.fold(F::ZERO, |acc, &e| alpha * acc + e);
|
||||||
let numerator = e - interpolant.eval(subgroup_x);
|
let numerator = e - interpolant.eval(subgroup_x);
|
||||||
let denominator = points.iter().map(|&(x, _)| subgroup_x - x).product();
|
let denominator = points.iter().map(|&(x, _)| subgroup_x - x).product();
|
||||||
|
|||||||
@ -10,6 +10,8 @@ use crate::proof::{FriProof, Hash};
|
|||||||
use crate::util::{log2_strict, reverse_index_bits_in_place, transpose};
|
use crate::util::{log2_strict, reverse_index_bits_in_place, transpose};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub const SALT_SIZE: usize = 2;
|
||||||
|
|
||||||
struct ListPolynomialCommitment<F: Field> {
|
struct ListPolynomialCommitment<F: Field> {
|
||||||
pub polynomials: Vec<PolynomialCoeffs<F>>,
|
pub polynomials: Vec<PolynomialCoeffs<F>>,
|
||||||
pub fri_config: FriConfig,
|
pub fri_config: FriConfig,
|
||||||
@ -31,7 +33,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
})
|
})
|
||||||
.chain(if fri_config.blinding {
|
.chain(if fri_config.blinding {
|
||||||
// If blinding, salt with two random elements to each leaf vector.
|
// If blinding, salt with two random elements to each leaf vector.
|
||||||
(0..2)
|
(0..SALT_SIZE)
|
||||||
.map(|_| F::rand_vec(degree << fri_config.rate_bits))
|
.map(|_| F::rand_vec(degree << fri_config.rate_bits))
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
@ -100,7 +102,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR);
|
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR);
|
||||||
|
|
||||||
let fri_proof = fri_proof(
|
let fri_proof = fri_proof(
|
||||||
&[self.merkle_tree.clone()],
|
&[&self.merkle_tree],
|
||||||
&lde_quotient,
|
&lde_quotient,
|
||||||
&lde_quotient_values,
|
&lde_quotient_values,
|
||||||
challenger,
|
challenger,
|
||||||
@ -116,6 +118,84 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn batch_open(
|
||||||
|
commitments: &[&Self],
|
||||||
|
points: &[F],
|
||||||
|
challenger: &mut Challenger<F>,
|
||||||
|
) -> (OpeningProof<F>, Vec<Vec<F>>) {
|
||||||
|
let degree = commitments[0].degree;
|
||||||
|
assert!(
|
||||||
|
commitments.iter().all(|c| c.degree == degree),
|
||||||
|
"Trying to open polynomial commitments of different degrees."
|
||||||
|
);
|
||||||
|
let fri_config = &commitments[0].fri_config;
|
||||||
|
assert!(
|
||||||
|
commitments.iter().all(|c| &c.fri_config == fri_config),
|
||||||
|
"Trying to open polynomial commitments with different config."
|
||||||
|
);
|
||||||
|
for p in points {
|
||||||
|
assert_ne!(
|
||||||
|
p.exp_usize(degree),
|
||||||
|
F::ONE,
|
||||||
|
"Opening point is in the subgroup."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let evaluations = points
|
||||||
|
.iter()
|
||||||
|
.map(|&x| {
|
||||||
|
commitments
|
||||||
|
.iter()
|
||||||
|
.flat_map(move |c| c.polynomials.iter().map(|p| p.eval(x)).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for evals in &evaluations {
|
||||||
|
challenger.observe_elements(evals);
|
||||||
|
}
|
||||||
|
|
||||||
|
let alpha = challenger.get_challenge();
|
||||||
|
|
||||||
|
// Scale polynomials by `alpha`.
|
||||||
|
let composition_poly = commitments
|
||||||
|
.iter()
|
||||||
|
.flat_map(|c| &c.polynomials)
|
||||||
|
.rev()
|
||||||
|
.map(|p| p.clone().into())
|
||||||
|
.fold(Polynomial::empty(), |acc, p| acc.scalar_mul(alpha).add(&p));
|
||||||
|
// Scale evaluations by `alpha`.
|
||||||
|
let composition_evals = evaluations
|
||||||
|
.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(fri_config.rate_bits);
|
||||||
|
let lde_quotient_values = lde_quotient
|
||||||
|
.clone()
|
||||||
|
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR);
|
||||||
|
|
||||||
|
let fri_proof = fri_proof(
|
||||||
|
&commitments
|
||||||
|
.iter()
|
||||||
|
.map(|c| &c.merkle_tree)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
&lde_quotient,
|
||||||
|
&lde_quotient_values,
|
||||||
|
challenger,
|
||||||
|
&fri_config,
|
||||||
|
);
|
||||||
|
|
||||||
|
(
|
||||||
|
OpeningProof {
|
||||||
|
fri_proof,
|
||||||
|
quotient_degree: quotient.len(),
|
||||||
|
},
|
||||||
|
evaluations,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Given `points=(x_i)`, `evals=(y_i)` and `poly=P` with `P(x_i)=y_i`, computes the polynomial
|
/// 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)`.
|
/// `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> {
|
fn compute_quotient(points: &[F], evals: &[F], poly: &Polynomial<F>) -> Polynomial<F> {
|
||||||
@ -152,7 +232,7 @@ impl<F: Field> OpeningProof<F> {
|
|||||||
&self,
|
&self,
|
||||||
points: &[F],
|
points: &[F],
|
||||||
evaluations: &[Vec<F>],
|
evaluations: &[Vec<F>],
|
||||||
merkle_root: Hash<F>,
|
merkle_roots: &[Hash<F>],
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
fri_config: &FriConfig,
|
fri_config: &FriConfig,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
@ -177,7 +257,7 @@ impl<F: Field> OpeningProof<F> {
|
|||||||
log2_strict(self.quotient_degree),
|
log2_strict(self.quotient_degree),
|
||||||
&pairs,
|
&pairs,
|
||||||
alpha,
|
alpha,
|
||||||
&[merkle_root],
|
merkle_roots,
|
||||||
&self.fri_proof,
|
&self.fri_proof,
|
||||||
challenger,
|
challenger,
|
||||||
fri_config,
|
fri_config,
|
||||||
@ -230,7 +310,7 @@ mod tests {
|
|||||||
proof.verify(
|
proof.verify(
|
||||||
&points,
|
&points,
|
||||||
&evaluations,
|
&evaluations,
|
||||||
lpc.merkle_tree.root,
|
&[lpc.merkle_tree.root],
|
||||||
&mut Challenger::new(),
|
&mut Challenger::new(),
|
||||||
&fri_config,
|
&fri_config,
|
||||||
)
|
)
|
||||||
@ -257,7 +337,91 @@ mod tests {
|
|||||||
proof.verify(
|
proof.verify(
|
||||||
&points,
|
&points,
|
||||||
&evaluations,
|
&evaluations,
|
||||||
lpc.merkle_tree.root,
|
&[lpc.merkle_tree.root],
|
||||||
|
&mut Challenger::new(),
|
||||||
|
&fri_config,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_batch_polynomial_commitment() -> Result<()> {
|
||||||
|
type F = CrandallField;
|
||||||
|
|
||||||
|
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: false,
|
||||||
|
};
|
||||||
|
let (polys0, _) = gen_random_test_case::<F>(k0, degree_log, num_points);
|
||||||
|
let (polys1, _) = gen_random_test_case::<F>(k0, degree_log, num_points);
|
||||||
|
let (polys2, points) = gen_random_test_case::<F>(k0, degree_log, num_points);
|
||||||
|
|
||||||
|
let lpc0 = ListPolynomialCommitment::new(polys0, &fri_config);
|
||||||
|
let lpc1 = ListPolynomialCommitment::new(polys1, &fri_config);
|
||||||
|
let lpc2 = ListPolynomialCommitment::new(polys2, &fri_config);
|
||||||
|
|
||||||
|
let (proof, evaluations) = ListPolynomialCommitment::batch_open(
|
||||||
|
&[&lpc0, &lpc1, &lpc2],
|
||||||
|
&points,
|
||||||
|
&mut Challenger::new(),
|
||||||
|
);
|
||||||
|
proof.verify(
|
||||||
|
&points,
|
||||||
|
&evaluations,
|
||||||
|
&[
|
||||||
|
lpc0.merkle_tree.root,
|
||||||
|
lpc1.merkle_tree.root,
|
||||||
|
lpc2.merkle_tree.root,
|
||||||
|
],
|
||||||
|
&mut Challenger::new(),
|
||||||
|
&fri_config,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_batch_polynomial_commitment_blinding() -> Result<()> {
|
||||||
|
type F = CrandallField;
|
||||||
|
|
||||||
|
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: true,
|
||||||
|
};
|
||||||
|
let (polys0, _) = gen_random_test_case::<F>(k0, degree_log, num_points);
|
||||||
|
let (polys1, _) = gen_random_test_case::<F>(k0, degree_log, num_points);
|
||||||
|
let (polys2, points) = gen_random_test_case::<F>(k0, degree_log, num_points);
|
||||||
|
|
||||||
|
let lpc0 = ListPolynomialCommitment::new(polys0, &fri_config);
|
||||||
|
let lpc1 = ListPolynomialCommitment::new(polys1, &fri_config);
|
||||||
|
let lpc2 = ListPolynomialCommitment::new(polys2, &fri_config);
|
||||||
|
|
||||||
|
let (proof, evaluations) = ListPolynomialCommitment::batch_open(
|
||||||
|
&[&lpc0, &lpc1, &lpc2],
|
||||||
|
&points,
|
||||||
|
&mut Challenger::new(),
|
||||||
|
);
|
||||||
|
proof.verify(
|
||||||
|
&points,
|
||||||
|
&evaluations,
|
||||||
|
&[
|
||||||
|
lpc0.merkle_tree.root,
|
||||||
|
lpc1.merkle_tree.root,
|
||||||
|
lpc2.merkle_tree.root,
|
||||||
|
],
|
||||||
&mut Challenger::new(),
|
&mut Challenger::new(),
|
||||||
&fri_config,
|
&fri_config,
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user