From 187b122c622327fd4827ccafdf5e3f660c6453cc Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 27 Apr 2021 08:44:34 +0200 Subject: [PATCH] Fixes based on Daniel's PR comments. --- src/fri.rs | 78 +++++++++++++++++++++------------------------- src/merkle_tree.rs | 1 - src/proof.rs | 23 +++++--------- 3 files changed, 42 insertions(+), 60 deletions(-) diff --git a/src/fri.rs b/src/fri.rs index 052a7219..85843c44 100644 --- a/src/fri.rs +++ b/src/fri.rs @@ -5,8 +5,9 @@ use crate::hash::hash_n_to_1; use crate::merkle_proofs::verify_merkle_proof_subtree; use crate::merkle_tree::MerkleTree; use crate::plonk_challenger::Challenger; +use crate::plonk_common::reduce_with_powers; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; -use crate::proof::{FriEvaluations, FriMerkleProofs, FriProof, FriQueryRound, Hash}; +use crate::proof::{FriProof, FriQueryRound, FriQueryStep, Hash}; use crate::util::{log2_strict, reverse_bits}; use anyhow::{ensure, Result}; @@ -74,7 +75,7 @@ fn fri_proof( let pow_witness = fri_proof_of_work(current_hash, config); // Query phase - let query_round_proofs = fri_query_rounds(&trees, challenger, n, config); + let query_round_proofs = fri_prover_query_rounds(&trees, challenger, n, config); FriProof { commit_phase_merkle_roots: trees.iter().map(|t| t.root).collect(), @@ -110,7 +111,7 @@ fn fri_committed_trees( coeffs .coeffs .chunks_exact(arity) - .map(|chunk| chunk.iter().rev().fold(F::ZERO, |acc, &c| acc * beta + c)) + .map(|chunk| reduce_with_powers(chunk, beta)) .collect::>(), ); if i == num_reductions - 1 { @@ -172,28 +173,24 @@ fn fri_verify_proof_of_work( Ok(()) } -fn fri_query_rounds( +fn fri_prover_query_rounds( trees: &[MerkleTree], challenger: &mut Challenger, n: usize, config: &FriConfig, ) -> Vec> { - let mut query_round_proofs = Vec::new(); - for _ in 0..config.num_query_rounds { - fri_query_round(trees, challenger, n, &mut query_round_proofs, config); - } - query_round_proofs + (0..config.num_query_rounds) + .map(|_| fri_query_round(trees, challenger, n, config)) + .collect() } fn fri_query_round( trees: &[MerkleTree], challenger: &mut Challenger, n: usize, - query_round_proofs: &mut Vec>, config: &FriConfig, -) { - let mut merkle_proofs = FriMerkleProofs { proofs: Vec::new() }; - let mut evals = FriEvaluations { evals: Vec::new() }; +) -> FriQueryRound { + let mut query_steps = Vec::new(); // TODO: Challenger doesn't change between query rounds, so x is always the same. let x = challenger.get_challenge(); let mut domain_size = n; @@ -203,40 +200,35 @@ fn fri_query_round( let arity = 1 << arity_bits; let next_domain_size = domain_size >> arity_bits; x_index %= domain_size; - let roots_coset_indices = index_roots_coset(x_index, next_domain_size, domain_size, arity); - if i == 0 { + let roots_coset_indices = coset_indices(x_index, next_domain_size, domain_size, arity); + let evals = if i == 0 { // For the first layer, we need to send the evaluation at `x` too. - evals.evals.push( - roots_coset_indices - .iter() - .map(|&index| tree.get(index)[0]) - .collect(), - ); + roots_coset_indices + .iter() + .map(|&index| tree.get(index)[0]) + .collect() } 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. - evals.evals.push( - roots_coset_indices[1..] - .iter() - .map(|&index| tree.get(index)[0]) - .collect(), - ); - } - merkle_proofs.proofs.push(tree.prove_subtree( - x_index & ((1 << log2_strict(next_domain_size)) - 1), - arity_bits, - )); + roots_coset_indices[1..] + .iter() + .map(|&index| tree.get(index)[0]) + .collect() + }; + let merkle_proof = tree.prove_subtree(x_index & (next_domain_size - 1), arity_bits); + + query_steps.push(FriQueryStep { + merkle_proof, + evals, + }); domain_size = next_domain_size; } - query_round_proofs.push(FriQueryRound { - evals, - merkle_proofs, - }); + FriQueryRound { steps: query_steps } } /// Returns the indices in the domain of all `y` in `F` with `y^arity=x^arity`, starting with `x` itself. -fn index_roots_coset( +fn coset_indices( x_index: usize, next_domain_size: usize, domain_size: usize, @@ -250,12 +242,12 @@ fn index_roots_coset( /// 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. fn compute_evaluation(x: F, arity_bits: usize, last_evals: &[F], beta: F) -> F { + debug_assert_eq!(last_evals.len(), 1 << arity_bits); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. let g = F::primitive_root_of_unity(arity_bits); let points = g .powers() .zip(last_evals) - .take(1 << arity_bits) .map(|(y, &e)| (x * y, e)) .collect::>(); let barycentric_weights = barycentric_weights(&points); @@ -315,7 +307,7 @@ fn verify_fri_proof( x_index %= domain_size; let next_domain_size = domain_size >> arity_bits; if i == 0 { - let evals = round_proof.evals.evals[0].clone(); + let evals = round_proof.steps[0].evals.clone(); evaluations.push(evals); } else { let last_evals = &evaluations[i - 1]; @@ -326,14 +318,14 @@ fn verify_fri_proof( last_evals, betas[i - 1], ); - let mut evals = round_proof.evals.evals[i].clone(); + 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(0, e_x); evaluations.push(evals); }; let sorted_evals = { let roots_coset_indices = - index_roots_coset(x_index, next_domain_size, domain_size, arity); + coset_indices(x_index, next_domain_size, domain_size, arity); let mut sorted_evals_enumerate = evaluations[i].iter().enumerate().collect::>(); // We need to sort the evaluations so that they match their order in the Merkle tree. @@ -347,9 +339,9 @@ fn verify_fri_proof( }; verify_merkle_proof_subtree( sorted_evals, - x_index & ((1 << log2_strict(next_domain_size)) - 1), + x_index & (next_domain_size - 1), proof.commit_phase_merkle_roots[i], - &round_proof.merkle_proofs.proofs[i], + &round_proof.steps[i].merkle_proof, true, )?; diff --git a/src/merkle_tree.rs b/src/merkle_tree.rs index d0e65058..a74415a7 100644 --- a/src/merkle_tree.rs +++ b/src/merkle_tree.rs @@ -122,7 +122,6 @@ mod tests { use crate::field::crandall_field::CrandallField; use crate::merkle_proofs::{verify_merkle_proof, verify_merkle_proof_subtree}; - use crate::polynomial::division::divide_by_z_h; use super::*; diff --git a/src/proof.rs b/src/proof.rs index 5ed27c13..f37081c0 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -83,26 +83,17 @@ pub struct ProofTarget { pub fri_proofs: Vec, } -// TODO: Implement FriEvaluationsTarget -/// Evaluations of the FRI committed polynomials. -#[derive(Debug)] -pub struct FriEvaluations { - /// The first element of `evals` contains `arity` evaluations. - /// The other elements contain `arity-1` evaluations. - pub evals: Vec>, -} - -// TODO: Implement FriEvaluationsTarget -/// Merkle proofs corresponding to the evaluations in a `FriEvaluation`. -/// These proofs are actually Merkle subtree proofs, for subtrees of height `arity_bits`. -pub struct FriMerkleProofs { - pub proofs: Vec>, +/// Evaluations and Merkle proof produced by the prover in a FRI query step. +// TODO: Implement FriQueryStepTarget +pub struct FriQueryStep { + pub evals: Vec, + pub merkle_proof: MerkleProof, } +/// Proof for a FRI query round. // TODO: Implement FriQueryRoundTarget pub struct FriQueryRound { - pub evals: FriEvaluations, - pub merkle_proofs: FriMerkleProofs, + pub steps: Vec>, } pub struct FriProof {