mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 16:23:12 +00:00
More work on polynomial commitments
This commit is contained in:
parent
bb8a68e198
commit
eb3011b02a
188
src/fri.rs
188
src/fri.rs
@ -1,13 +1,13 @@
|
|||||||
use crate::field::fft::fft;
|
use crate::field::fft::fft;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::field::lagrange::{barycentric_weights, interpolate};
|
use crate::field::lagrange::{barycentric_weights, interpolant, interpolate};
|
||||||
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::merkle_tree::MerkleTree;
|
use crate::merkle_tree::MerkleTree;
|
||||||
use crate::plonk_challenger::Challenger;
|
use crate::plonk_challenger::Challenger;
|
||||||
use crate::plonk_common::reduce_with_powers;
|
use crate::plonk_common::reduce_with_powers;
|
||||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||||
use crate::proof::{FriProof, FriQueryRound, FriQueryStep, Hash};
|
use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, FriQueryStep, 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};
|
||||||
use anyhow::{ensure, Result};
|
use anyhow::{ensure, Result};
|
||||||
|
|
||||||
@ -56,32 +56,35 @@ fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 {
|
|||||||
|
|
||||||
/// Builds a FRI proof.
|
/// Builds a FRI proof.
|
||||||
pub fn fri_proof<F: Field>(
|
pub fn fri_proof<F: Field>(
|
||||||
// Coefficients of the polynomial on which the LDT is performed.
|
initial_merkle_trees: &[MerkleTree<F>],
|
||||||
// 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.
|
||||||
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.
|
||||||
polynomial_values: &PolynomialValues<F>,
|
lde_polynomial_values: &PolynomialValues<F>,
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
config: &FriConfig,
|
config: &FriConfig,
|
||||||
) -> FriProof<F> {
|
) -> FriProof<F> {
|
||||||
let n = polynomial_values.values.len();
|
let n = lde_polynomial_values.values.len();
|
||||||
assert_eq!(polynomial_coeffs.coeffs.len(), n);
|
assert_eq!(lde_polynomial_coeffs.coeffs.len(), n);
|
||||||
|
|
||||||
// Commit phase
|
// Commit phase
|
||||||
let (trees, final_coeffs) =
|
let (trees, final_coeffs) = fri_committed_trees(
|
||||||
fri_committed_trees(polynomial_coeffs, polynomial_values, challenger, config);
|
lde_polynomial_coeffs,
|
||||||
|
lde_polynomial_values,
|
||||||
|
challenger,
|
||||||
|
config,
|
||||||
|
);
|
||||||
|
|
||||||
// PoW phase
|
// PoW phase
|
||||||
let current_hash = challenger.get_hash();
|
let current_hash = challenger.get_hash();
|
||||||
let pow_witness = fri_proof_of_work(current_hash, config);
|
let pow_witness = fri_proof_of_work(current_hash, config);
|
||||||
|
|
||||||
// Query phase
|
// Query phase
|
||||||
let query_round_proofs = fri_prover_query_rounds(&trees, challenger, n, config);
|
let query_round_proofs =
|
||||||
|
fri_prover_query_rounds(initial_merkle_trees, &trees, challenger, n, config);
|
||||||
|
|
||||||
FriProof {
|
FriProof {
|
||||||
commit_phase_merkle_roots: trees.iter().map(|t| t.root).collect(),
|
commit_phase_merkle_roots: trees.iter().map(|t| t.root).collect(),
|
||||||
// TODO: Fix this
|
|
||||||
initial_merkle_proofs: vec![],
|
|
||||||
query_round_proofs,
|
query_round_proofs,
|
||||||
final_poly: final_coeffs,
|
final_poly: final_coeffs,
|
||||||
pow_witness,
|
pow_witness,
|
||||||
@ -180,17 +183,19 @@ fn fri_verify_proof_of_work<F: Field>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fri_prover_query_rounds<F: Field>(
|
fn fri_prover_query_rounds<F: Field>(
|
||||||
|
initial_merkle_trees: &[MerkleTree<F>],
|
||||||
trees: &[MerkleTree<F>],
|
trees: &[MerkleTree<F>],
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
n: usize,
|
n: usize,
|
||||||
config: &FriConfig,
|
config: &FriConfig,
|
||||||
) -> Vec<FriQueryRound<F>> {
|
) -> Vec<FriQueryRound<F>> {
|
||||||
(0..config.num_query_rounds)
|
(0..config.num_query_rounds)
|
||||||
.map(|_| fri_prover_query_round(trees, challenger, n, config))
|
.map(|_| fri_prover_query_round(initial_merkle_trees, trees, challenger, n, config))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fri_prover_query_round<F: Field>(
|
fn fri_prover_query_round<F: Field>(
|
||||||
|
initial_merkle_trees: &[MerkleTree<F>],
|
||||||
trees: &[MerkleTree<F>],
|
trees: &[MerkleTree<F>],
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
n: usize,
|
n: usize,
|
||||||
@ -201,20 +206,17 @@ fn fri_prover_query_round<F: Field>(
|
|||||||
let x = challenger.get_challenge();
|
let x = challenger.get_challenge();
|
||||||
let mut domain_size = n;
|
let mut domain_size = n;
|
||||||
let mut x_index = x.to_canonical_u64() as usize % n;
|
let mut x_index = x.to_canonical_u64() as usize % n;
|
||||||
|
let mut x_index = 0;
|
||||||
|
let initial_proof = initial_merkle_trees
|
||||||
|
.iter()
|
||||||
|
.map(|t| (t.get(x_index).to_vec(), t.prove(x_index)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
for (i, tree) in trees.iter().enumerate() {
|
for (i, tree) in trees.iter().enumerate() {
|
||||||
let arity_bits = config.reduction_arity_bits[i];
|
let arity_bits = config.reduction_arity_bits[i];
|
||||||
let arity = 1 << arity_bits;
|
let arity = 1 << arity_bits;
|
||||||
let next_domain_size = domain_size >> arity_bits;
|
let mut evals = tree.get(x_index >> arity_bits).to_vec();
|
||||||
let evals = if i == 0 {
|
dbg!(i, x_index, x_index & (arity - 1), &evals);
|
||||||
// For the first layer, we need to send the evaluation at `x` too.
|
evals.remove(x_index & (arity - 1));
|
||||||
tree.get(x_index >> arity_bits).to_vec()
|
|
||||||
} else {
|
|
||||||
// For the other layers, we don't need to send the evaluation at `x`, since it can
|
|
||||||
// be inferred by the verifier. See the `compute_evaluation` function.
|
|
||||||
let mut evals = tree.get(x_index >> arity_bits).to_vec();
|
|
||||||
evals.remove(x_index & (arity - 1));
|
|
||||||
evals
|
|
||||||
};
|
|
||||||
let merkle_proof = tree.prove(x_index >> arity_bits);
|
let merkle_proof = tree.prove(x_index >> arity_bits);
|
||||||
|
|
||||||
query_steps.push(FriQueryStep {
|
query_steps.push(FriQueryStep {
|
||||||
@ -222,10 +224,15 @@ fn fri_prover_query_round<F: Field>(
|
|||||||
merkle_proof,
|
merkle_proof,
|
||||||
});
|
});
|
||||||
|
|
||||||
domain_size = next_domain_size;
|
domain_size >>= arity_bits;
|
||||||
x_index >>= arity_bits;
|
x_index >>= arity_bits;
|
||||||
}
|
}
|
||||||
FriQueryRound { steps: query_steps }
|
FriQueryRound {
|
||||||
|
initial_trees_proof: FriInitialTreeProof {
|
||||||
|
evals_proofs: initial_proof,
|
||||||
|
},
|
||||||
|
steps: query_steps,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes P'(x^arity) from {P(x*g^i)}_(i=0..arity), where g is a `arity`-th root of unity
|
/// Computes P'(x^arity) from {P(x*g^i)}_(i=0..arity), where g is a `arity`-th root of unity
|
||||||
@ -256,13 +263,25 @@ fn compute_evaluation<F: Field>(
|
|||||||
interpolate(&points, beta, &barycentric_weights)
|
interpolate(&points, beta, &barycentric_weights)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_fri_proof<F: Field>(
|
pub fn verify_fri_proof<F: Field>(
|
||||||
purported_degree_log: usize,
|
purported_degree_log: usize,
|
||||||
|
// Point-evaluation pairs for polynomial commitments.
|
||||||
|
points: &[(F, F)],
|
||||||
|
// Scaling factor to combine polynomials.
|
||||||
|
alpha: F,
|
||||||
|
initial_merkle_roots: &[Hash<F>],
|
||||||
proof: &FriProof<F>,
|
proof: &FriProof<F>,
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
config: &FriConfig,
|
config: &FriConfig,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let total_arities = config.reduction_arity_bits.iter().sum::<usize>();
|
let total_arities = config.reduction_arity_bits.iter().sum::<usize>();
|
||||||
|
dbg!(
|
||||||
|
purported_degree_log,
|
||||||
|
log2_strict(proof.final_poly.len()) + total_arities - config.rate_bits,
|
||||||
|
log2_strict(proof.final_poly.len()),
|
||||||
|
total_arities,
|
||||||
|
config.rate_bits,
|
||||||
|
);
|
||||||
ensure!(
|
ensure!(
|
||||||
purported_degree_log
|
purported_degree_log
|
||||||
== log2_strict(proof.final_poly.len()) + total_arities - config.rate_bits,
|
== log2_strict(proof.final_poly.len()) + total_arities - config.rate_bits,
|
||||||
@ -296,14 +315,71 @@ fn verify_fri_proof<F: Field>(
|
|||||||
"Number of reductions should be non-zero."
|
"Number of reductions should be non-zero."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
dbg!(&points);
|
||||||
|
let interpolant = interpolant(points);
|
||||||
for round_proof in &proof.query_round_proofs {
|
for round_proof in &proof.query_round_proofs {
|
||||||
fri_verifier_query_round(&proof, challenger, n, &betas, round_proof, config)?;
|
fri_verifier_query_round(
|
||||||
|
&interpolant,
|
||||||
|
points,
|
||||||
|
alpha,
|
||||||
|
initial_merkle_roots,
|
||||||
|
&proof,
|
||||||
|
challenger,
|
||||||
|
n,
|
||||||
|
&betas,
|
||||||
|
round_proof,
|
||||||
|
config,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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>(
|
||||||
|
proof: &FriInitialTreeProof<F>,
|
||||||
|
alpha: F,
|
||||||
|
interpolant: &PolynomialCoeffs<F>,
|
||||||
|
points: &[(F, F)],
|
||||||
|
subgroup_x: F,
|
||||||
|
) -> F {
|
||||||
|
dbg!(proof
|
||||||
|
.evals_proofs
|
||||||
|
.iter()
|
||||||
|
.map(|(v, _)| v)
|
||||||
|
.collect::<Vec<_>>());
|
||||||
|
let e = proof
|
||||||
|
.evals_proofs
|
||||||
|
.iter()
|
||||||
|
.map(|(v, _)| v)
|
||||||
|
.flatten()
|
||||||
|
.rev()
|
||||||
|
.fold(F::ZERO, |acc, &e| alpha * acc + e);
|
||||||
|
dbg!(e);
|
||||||
|
let numerator = e - interpolant.eval(subgroup_x);
|
||||||
|
dbg!(numerator);
|
||||||
|
dbg!(&points);
|
||||||
|
let denominator = points.iter().fold(F::ONE, |acc, &(x, _)| subgroup_x - x);
|
||||||
|
dbg!(denominator);
|
||||||
|
numerator / denominator
|
||||||
|
}
|
||||||
|
|
||||||
fn fri_verifier_query_round<F: Field>(
|
fn fri_verifier_query_round<F: Field>(
|
||||||
|
interpolant: &PolynomialCoeffs<F>,
|
||||||
|
points: &[(F, F)],
|
||||||
|
alpha: F,
|
||||||
|
initial_merkle_roots: &[Hash<F>],
|
||||||
proof: &FriProof<F>,
|
proof: &FriProof<F>,
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
n: usize,
|
n: usize,
|
||||||
@ -311,10 +387,16 @@ fn fri_verifier_query_round<F: Field>(
|
|||||||
round_proof: &FriQueryRound<F>,
|
round_proof: &FriQueryRound<F>,
|
||||||
config: &FriConfig,
|
config: &FriConfig,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut evaluations = Vec::new();
|
let mut evaluations: Vec<Vec<F>> = Vec::new();
|
||||||
let x = challenger.get_challenge();
|
let x = challenger.get_challenge();
|
||||||
let mut domain_size = n;
|
let mut domain_size = n;
|
||||||
let mut x_index = x.to_canonical_u64() as usize % n;
|
let mut x_index = x.to_canonical_u64() as usize % n;
|
||||||
|
let mut x_index = 0;
|
||||||
|
fri_verify_initial_proof(
|
||||||
|
x_index,
|
||||||
|
&round_proof.initial_trees_proof,
|
||||||
|
initial_merkle_roots,
|
||||||
|
)?;
|
||||||
let mut old_x_index = 0;
|
let mut old_x_index = 0;
|
||||||
// `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain.
|
// `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain.
|
||||||
let log_n = log2_strict(n);
|
let log_n = log2_strict(n);
|
||||||
@ -323,24 +405,30 @@ fn fri_verifier_query_round<F: Field>(
|
|||||||
for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() {
|
for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() {
|
||||||
let arity = 1 << arity_bits;
|
let arity = 1 << arity_bits;
|
||||||
let next_domain_size = domain_size >> arity_bits;
|
let next_domain_size = domain_size >> arity_bits;
|
||||||
if i == 0 {
|
let e_x = if i == 0 {
|
||||||
let evals = round_proof.steps[0].evals.clone();
|
fri_combine_initial(
|
||||||
evaluations.push(evals);
|
&round_proof.initial_trees_proof,
|
||||||
|
alpha,
|
||||||
|
interpolant,
|
||||||
|
points,
|
||||||
|
subgroup_x,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let last_evals = &evaluations[i - 1];
|
let last_evals = &evaluations[i - 1];
|
||||||
// Infer P(y) from {P(x)}_{x^arity=y}.
|
// Infer P(y) from {P(x)}_{x^arity=y}.
|
||||||
let e_x = compute_evaluation(
|
compute_evaluation(
|
||||||
subgroup_x,
|
subgroup_x,
|
||||||
old_x_index,
|
old_x_index,
|
||||||
config.reduction_arity_bits[i - 1],
|
config.reduction_arity_bits[i - 1],
|
||||||
last_evals,
|
last_evals,
|
||||||
betas[i - 1],
|
betas[i - 1],
|
||||||
);
|
)
|
||||||
let mut evals = round_proof.steps[i].evals.clone();
|
|
||||||
// Insert P(y) into the evaluation vector, since it wasn't included by the prover.
|
|
||||||
evals.insert(x_index & (arity - 1), e_x);
|
|
||||||
evaluations.push(evals);
|
|
||||||
};
|
};
|
||||||
|
let mut evals = round_proof.steps[i].evals.clone();
|
||||||
|
// Insert P(y) into the evaluation vector, since it wasn't included by the prover.
|
||||||
|
evals.insert(x_index & (arity - 1), e_x);
|
||||||
|
evaluations.push(evals);
|
||||||
|
dbg!(i, &evaluations[i]);
|
||||||
verify_merkle_proof(
|
verify_merkle_proof(
|
||||||
evaluations[i].clone(),
|
evaluations[i].clone(),
|
||||||
x_index >> arity_bits,
|
x_index >> arity_bits,
|
||||||
@ -409,11 +497,29 @@ mod tests {
|
|||||||
proof_of_work_bits: 2,
|
proof_of_work_bits: 2,
|
||||||
reduction_arity_bits,
|
reduction_arity_bits,
|
||||||
};
|
};
|
||||||
|
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 root = tree.root;
|
||||||
let mut challenger = Challenger::new();
|
let mut challenger = Challenger::new();
|
||||||
let proof = fri_proof(&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(degree_log, &proof, &mut challenger, &config)?;
|
verify_fri_proof(
|
||||||
|
degree_log,
|
||||||
|
&[],
|
||||||
|
F::ONE,
|
||||||
|
&[root],
|
||||||
|
&proof,
|
||||||
|
&mut challenger,
|
||||||
|
&config,
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
use crate::field::fft::fft;
|
use crate::field::fft::fft;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::field::lagrange::{interpolant, interpolate};
|
use crate::field::lagrange::{interpolant, interpolate};
|
||||||
use crate::fri::{fri_proof, FriConfig};
|
use crate::fri::{fri_proof, verify_fri_proof, FriConfig};
|
||||||
|
use crate::merkle_proofs::verify_merkle_proof;
|
||||||
use crate::merkle_tree::MerkleTree;
|
use crate::merkle_tree::MerkleTree;
|
||||||
use crate::plonk_challenger::Challenger;
|
use crate::plonk_challenger::Challenger;
|
||||||
use crate::plonk_common::reduce_with_powers;
|
use crate::plonk_common::reduce_with_powers;
|
||||||
use crate::polynomial::old_polynomial::Polynomial;
|
use crate::polynomial::old_polynomial::Polynomial;
|
||||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||||
use crate::util::transpose;
|
use crate::proof::{FriProof, Hash};
|
||||||
|
use crate::util::{log2_strict, reverse_index_bits_in_place, transpose};
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
struct ListPolynomialCommitment<F: Field> {
|
struct ListPolynomialCommitment<F: Field> {
|
||||||
pub polynomials: Vec<PolynomialCoeffs<F>>,
|
pub polynomials: Vec<PolynomialCoeffs<F>>,
|
||||||
@ -40,7 +43,10 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
}))
|
}))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let merkle_tree = MerkleTree::new(transpose(&lde_values), false);
|
let mut leaves = transpose(&lde_values);
|
||||||
|
reverse_index_bits_in_place(&mut leaves);
|
||||||
|
// let merkle_tree = MerkleTree::new(transpose(&lde_values), false);
|
||||||
|
let merkle_tree = MerkleTree::new(leaves, false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
polynomials,
|
polynomials,
|
||||||
@ -73,14 +79,21 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
challenger.observe_elements(evals);
|
challenger.observe_elements(evals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
challenger.observe_hash(&self.merkle_tree.root);
|
||||||
let alpha = challenger.get_challenge();
|
let alpha = challenger.get_challenge();
|
||||||
|
|
||||||
|
dbg!(self
|
||||||
|
.polynomials
|
||||||
|
.iter()
|
||||||
|
.map(|p| p.eval(F::MULTIPLICATIVE_GROUP_GENERATOR))
|
||||||
|
.collect::<Vec<_>>());
|
||||||
let scaled_poly = self
|
let scaled_poly = self
|
||||||
.polynomials
|
.polynomials
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.map(|p| p.clone().into())
|
.map(|p| p.clone().into())
|
||||||
.fold(Polynomial::empty(), |acc, p| acc.scalar_mul(alpha).add(&p));
|
.fold(Polynomial::empty(), |acc, p| acc.scalar_mul(alpha).add(&p));
|
||||||
|
dbg!(scaled_poly.eval(F::MULTIPLICATIVE_GROUP_GENERATOR));
|
||||||
let scaled_evals = evaluations
|
let scaled_evals = evaluations
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| reduce_with_powers(e, alpha))
|
.map(|e| reduce_with_powers(e, alpha))
|
||||||
@ -93,25 +106,128 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
debug_assert!(pairs.iter().all(|&(x, e)| scaled_poly.eval(x) == e));
|
debug_assert!(pairs.iter().all(|&(x, e)| scaled_poly.eval(x) == e));
|
||||||
|
|
||||||
|
dbg!(&pairs);
|
||||||
let interpolant: Polynomial<F> = interpolant(&pairs).into();
|
let interpolant: Polynomial<F> = interpolant(&pairs).into();
|
||||||
let denominator = points.iter().fold(Polynomial::empty(), |acc, &x| {
|
let denominator = points
|
||||||
acc.mul(&vec![-x, F::ONE].into())
|
.iter()
|
||||||
});
|
.fold(Polynomial::from(vec![F::ONE]), |acc, &x| {
|
||||||
|
acc.mul(&vec![-x, F::ONE].into())
|
||||||
|
});
|
||||||
|
dbg!(&denominator);
|
||||||
let numerator = scaled_poly.add(&interpolant.neg());
|
let numerator = scaled_poly.add(&interpolant.neg());
|
||||||
let (mut quotient, rem) = numerator.polynomial_division(&denominator);
|
for x in points {
|
||||||
|
dbg!(numerator.eval(*x));
|
||||||
|
}
|
||||||
|
dbg!(numerator.eval(F::MULTIPLICATIVE_GROUP_GENERATOR));
|
||||||
|
dbg!(denominator.eval(F::MULTIPLICATIVE_GROUP_GENERATOR));
|
||||||
|
let (mut quotient, rem) = numerator.polynomial_long_division(&denominator);
|
||||||
|
dbg!(&numerator);
|
||||||
|
dbg!(quotient.mul(&denominator).add(&rem));
|
||||||
|
dbg!("ient);
|
||||||
|
dbg!(&rem);
|
||||||
debug_assert!(rem.is_zero());
|
debug_assert!(rem.is_zero());
|
||||||
|
|
||||||
quotient.pad(quotient.degree().next_power_of_two());
|
quotient.pad(quotient.degree().next_power_of_two());
|
||||||
let quotient_values = fft(quotient.clone().into());
|
let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(self.fri_config.rate_bits);
|
||||||
|
let lde_quotient_values = fft(lde_quotient.clone());
|
||||||
|
|
||||||
let fri_proof = fri_proof(
|
let fri_proof = fri_proof(
|
||||||
"ient.into(),
|
&[self.merkle_tree.clone()],
|
||||||
"ient_values,
|
&lde_quotient,
|
||||||
|
&lde_quotient_values,
|
||||||
challenger,
|
challenger,
|
||||||
&self.fri_config,
|
&self.fri_config,
|
||||||
);
|
);
|
||||||
todo!()
|
|
||||||
|
OpeningProof {
|
||||||
|
evaluations,
|
||||||
|
merkle_root: self.merkle_tree.root,
|
||||||
|
fri_proof,
|
||||||
|
quotient_degree: quotient.len(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OpeningProof<F: Field> {
|
pub struct OpeningProof<F: Field> {
|
||||||
evaluations: Vec<Vec<F>>,
|
evaluations: Vec<Vec<F>>,
|
||||||
|
merkle_root: Hash<F>,
|
||||||
|
fri_proof: FriProof<F>,
|
||||||
|
quotient_degree: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field> OpeningProof<F> {
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
points: &[F],
|
||||||
|
challenger: &mut Challenger<F>,
|
||||||
|
fri_config: &FriConfig,
|
||||||
|
) -> Result<()> {
|
||||||
|
for evals in &self.evaluations {
|
||||||
|
challenger.observe_elements(evals);
|
||||||
|
}
|
||||||
|
|
||||||
|
challenger.observe_hash(&self.merkle_root);
|
||||||
|
let alpha = challenger.get_challenge();
|
||||||
|
|
||||||
|
let scaled_evals = self
|
||||||
|
.evaluations
|
||||||
|
.iter()
|
||||||
|
.map(|e| reduce_with_powers(e, alpha))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let pairs = points
|
||||||
|
.iter()
|
||||||
|
.zip(&scaled_evals)
|
||||||
|
.map(|(&x, &e)| (x, e))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
dbg!(self.quotient_degree);
|
||||||
|
verify_fri_proof(
|
||||||
|
log2_strict(self.quotient_degree),
|
||||||
|
&pairs,
|
||||||
|
alpha,
|
||||||
|
&[self.merkle_root],
|
||||||
|
&self.fri_proof,
|
||||||
|
challenger,
|
||||||
|
fri_config,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::field::crandall_field::CrandallField;
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_polynomial_commitment() -> Result<()> {
|
||||||
|
type F = CrandallField;
|
||||||
|
|
||||||
|
let k = 1;
|
||||||
|
let degree_log = 3;
|
||||||
|
let degree = 1 << degree_log;
|
||||||
|
|
||||||
|
let fri_config = FriConfig {
|
||||||
|
proof_of_work_bits: 2,
|
||||||
|
rate_bits: 2,
|
||||||
|
reduction_arity_bits: vec![3, 2, 1],
|
||||||
|
num_query_rounds: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let polys = (0..k)
|
||||||
|
// .map(|_| PolynomialCoeffs::new((0..degree).map(|_| F::rand()).collect()))
|
||||||
|
.map(|_| PolynomialCoeffs::new((0..degree).map(|i| F::from_canonical_u64(i)).collect()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let lpc = ListPolynomialCommitment::new(polys, &fri_config, false);
|
||||||
|
|
||||||
|
let num_points = 3;
|
||||||
|
let points = (0..num_points).map(|_| F::rand()).collect::<Vec<_>>();
|
||||||
|
let points = vec![-F::TWO, -F::ONE - F::TWO, -F::TWO - F::TWO];
|
||||||
|
|
||||||
|
let proof = lpc.open(&points, &mut Challenger::new());
|
||||||
|
|
||||||
|
proof.verify(&points, &mut Challenger::new(), &fri_config)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -235,10 +235,11 @@ impl<F: Field> Polynomial<F> {
|
|||||||
}
|
}
|
||||||
let a_deg = self.degree();
|
let a_deg = self.degree();
|
||||||
let b_deg = b.degree();
|
let b_deg = b.degree();
|
||||||
let a_pad = self.padded(a_deg + b_deg + 1);
|
let new_deg = (a_deg + b_deg + 1).next_power_of_two();
|
||||||
let b_pad = b.padded(a_deg + b_deg + 1);
|
let a_pad = self.padded(new_deg);
|
||||||
|
let b_pad = b.padded(new_deg);
|
||||||
|
|
||||||
let precomputation = fft_precompute(a_deg + b_deg + 1);
|
let precomputation = fft_precompute(new_deg);
|
||||||
let a_evals = fft_with_precomputation_power_of_2(a_pad.0.to_vec().into(), &precomputation);
|
let a_evals = fft_with_precomputation_power_of_2(a_pad.0.to_vec().into(), &precomputation);
|
||||||
let b_evals = fft_with_precomputation_power_of_2(b_pad.0.to_vec().into(), &precomputation);
|
let b_evals = fft_with_precomputation_power_of_2(b_pad.0.to_vec().into(), &precomputation);
|
||||||
|
|
||||||
@ -275,11 +276,16 @@ impl<F: Field> Polynomial<F> {
|
|||||||
let cur_q_degree = remainder.degree() - b_degree;
|
let cur_q_degree = remainder.degree() - b_degree;
|
||||||
quotient[cur_q_degree] = cur_q_coeff;
|
quotient[cur_q_degree] = cur_q_coeff;
|
||||||
|
|
||||||
|
dbg!(cur_q_coeff, cur_q_degree);
|
||||||
|
dbg!(&b);
|
||||||
for (i, &div_coeff) in b.iter().enumerate() {
|
for (i, &div_coeff) in b.iter().enumerate() {
|
||||||
|
dbg!(i, div_coeff, remainder[cur_q_degree + i]);
|
||||||
remainder[cur_q_degree + i] =
|
remainder[cur_q_degree + i] =
|
||||||
remainder[cur_q_degree + i] - (cur_q_coeff * div_coeff);
|
remainder[cur_q_degree + i] - (cur_q_coeff * div_coeff);
|
||||||
|
dbg!(remainder[cur_q_degree + i]);
|
||||||
}
|
}
|
||||||
remainder.trim();
|
remainder.trim();
|
||||||
|
dbg!(&remainder);
|
||||||
}
|
}
|
||||||
(quotient, remainder)
|
(quotient, remainder)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,17 +90,22 @@ pub struct FriQueryStep<F: Field> {
|
|||||||
pub merkle_proof: MerkleProof<F>,
|
pub merkle_proof: MerkleProof<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluations and Merkle proof produced by the prover in a FRI query step.
|
||||||
|
// TODO: Implement FriInitialTreeProofTarget
|
||||||
|
pub struct FriInitialTreeProof<F: Field> {
|
||||||
|
pub evals_proofs: Vec<(Vec<F>, MerkleProof<F>)>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Proof for a FRI query round.
|
/// Proof for a FRI query round.
|
||||||
// TODO: Implement FriQueryRoundTarget
|
// TODO: Implement FriQueryRoundTarget
|
||||||
pub struct FriQueryRound<F: Field> {
|
pub struct FriQueryRound<F: Field> {
|
||||||
|
pub initial_trees_proof: FriInitialTreeProof<F>,
|
||||||
pub steps: Vec<FriQueryStep<F>>,
|
pub steps: Vec<FriQueryStep<F>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FriProof<F: Field> {
|
pub struct FriProof<F: Field> {
|
||||||
/// A Merkle root for each reduced polynomial in the commit phase.
|
/// A Merkle root for each reduced polynomial in the commit phase.
|
||||||
pub commit_phase_merkle_roots: Vec<Hash<F>>,
|
pub commit_phase_merkle_roots: Vec<Hash<F>>,
|
||||||
/// Merkle proofs for the original purported codewords, i.e. the subject of the LDT.
|
|
||||||
pub initial_merkle_proofs: Vec<MerkleProof<F>>,
|
|
||||||
/// Query rounds proofs
|
/// Query rounds proofs
|
||||||
pub query_round_proofs: Vec<FriQueryRound<F>>,
|
pub query_round_proofs: Vec<FriQueryRound<F>>,
|
||||||
/// The final polynomial in coefficient form.
|
/// The final polynomial in coefficient form.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user