mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 06:13:07 +00:00
Merge pull request #815 from mir-protocol/fri_pow_in_transcript
Include the FRI prover's PoW witness in the transcript
This commit is contained in:
commit
7720ff3799
@ -49,16 +49,8 @@ impl<F: RichField, H: Hasher<F>> Challenger<F, H> {
|
||||
|
||||
self.observe_extension_elements(&final_poly.coeffs);
|
||||
|
||||
let fri_pow_response = C::InnerHasher::hash_no_pad(
|
||||
&self
|
||||
.get_hash()
|
||||
.elements
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(Some(pow_witness))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.elements[0];
|
||||
self.observe_element(pow_witness);
|
||||
let fri_pow_response = self.get_challenge();
|
||||
|
||||
let fri_query_indices = (0..num_fri_queries)
|
||||
.map(|_| self.get_challenge().to_canonical_u64() as usize % lde_size)
|
||||
@ -105,16 +97,8 @@ impl<F: RichField + Extendable<D>, H: AlgebraicHasher<F>, const D: usize>
|
||||
|
||||
self.observe_extension_elements(&final_poly.0);
|
||||
|
||||
let pow_inputs = self
|
||||
.get_hash(builder)
|
||||
.elements
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(Some(pow_witness))
|
||||
.collect();
|
||||
let fri_pow_response = builder
|
||||
.hash_n_to_hash_no_pad::<C::InnerHasher>(pow_inputs)
|
||||
.elements[0];
|
||||
self.observe_element(pow_witness);
|
||||
let fri_pow_response = self.get_challenge(builder);
|
||||
|
||||
let fri_query_indices = (0..num_fri_queries)
|
||||
.map(|_| self.get_challenge(builder))
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
use itertools::Itertools;
|
||||
use maybe_rayon::*;
|
||||
use plonky2_field::extension::{flatten, unflatten, Extendable};
|
||||
use plonky2_field::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||
@ -6,7 +5,8 @@ use plonky2_util::reverse_index_bits_in_place;
|
||||
|
||||
use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound, FriQueryStep};
|
||||
use crate::fri::{FriConfig, FriParams};
|
||||
use crate::hash::hash_types::{HashOut, RichField};
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::hash::hashing::{PlonkyPermutation, SPONGE_RATE};
|
||||
use crate::hash::merkle_tree::MerkleTree;
|
||||
use crate::iop::challenger::Challenger;
|
||||
use crate::plonk::config::{GenericConfig, Hasher};
|
||||
@ -44,11 +44,10 @@ where
|
||||
);
|
||||
|
||||
// PoW phase
|
||||
let current_hash = challenger.get_hash();
|
||||
let pow_witness = timed!(
|
||||
timing,
|
||||
"find proof-of-work witness",
|
||||
fri_proof_of_work::<F, C, D>(current_hash, &fri_params.config)
|
||||
fri_proof_of_work::<F, C, D>(challenger, &fri_params.config)
|
||||
);
|
||||
|
||||
// Query phase
|
||||
@ -114,28 +113,55 @@ where
|
||||
(trees, coeffs)
|
||||
}
|
||||
|
||||
/// Performs the proof-of-work (a.k.a. grinding) step of the FRI protocol. Returns the PoW witness.
|
||||
fn fri_proof_of_work<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
current_hash: HashOut<F>,
|
||||
challenger: &mut Challenger<F, C::Hasher>,
|
||||
config: &FriConfig,
|
||||
) -> F {
|
||||
(0..=F::NEG_ONE.to_canonical_u64())
|
||||
let min_leading_zeros = config.proof_of_work_bits + (64 - F::order().bits()) as u32;
|
||||
|
||||
// The easiest implementation would be repeatedly clone our Challenger. With each clone, we'd
|
||||
// observe an incrementing PoW witness, then get the PoW response. If it contained sufficient
|
||||
// leading zeros, we'd end the search, and store this clone as our new challenger.
|
||||
//
|
||||
// However, performance is critical here. We want to avoid cloning Challenger, particularly
|
||||
// since it stores vectors, which means allocations. We'd like a more compact state to clone.
|
||||
//
|
||||
// We know that a duplex will be performed right after we send the PoW witness, so we can ignore
|
||||
// any output_buffer, which will be invalidated. We also know input_buffer.len() < SPONGE_WIDTH,
|
||||
// an invariant of Challenger.
|
||||
//
|
||||
// We separate the duplex operation into two steps, one which can be performed now, and the
|
||||
// other which depends on the PoW witness candidate. The first step is the overwrite our sponge
|
||||
// state with any inputs (excluding the PoW witness candidate). The second step is to overwrite
|
||||
// one more element of our sponge state with the candidate, then apply the permutation,
|
||||
// obtaining our duplex's post-state which contains the PoW response.
|
||||
let mut duplex_intermediate_state = challenger.sponge_state;
|
||||
let witness_input_pos = challenger.input_buffer.len();
|
||||
for (i, input) in challenger.input_buffer.iter().enumerate() {
|
||||
duplex_intermediate_state[i] = *input;
|
||||
}
|
||||
|
||||
let pow_witness = (0..=F::NEG_ONE.to_canonical_u64())
|
||||
.into_par_iter()
|
||||
.find_any(|&i| {
|
||||
C::InnerHasher::hash_no_pad(
|
||||
¤t_hash
|
||||
.elements
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(Some(F::from_canonical_u64(i)))
|
||||
.collect_vec(),
|
||||
)
|
||||
.elements[0]
|
||||
.to_canonical_u64()
|
||||
.leading_zeros()
|
||||
>= config.proof_of_work_bits + (64 - F::order().bits()) as u32
|
||||
.find_any(|&candidate| {
|
||||
let mut duplex_state = duplex_intermediate_state;
|
||||
duplex_state[witness_input_pos] = F::from_canonical_u64(candidate);
|
||||
duplex_state =
|
||||
<<C as GenericConfig<D>>::Hasher as Hasher<F>>::Permutation::permute(duplex_state);
|
||||
let pow_response = duplex_state[SPONGE_RATE - 1];
|
||||
let leading_zeros = pow_response.to_canonical_u64().leading_zeros();
|
||||
leading_zeros >= min_leading_zeros
|
||||
})
|
||||
.map(F::from_canonical_u64)
|
||||
.expect("Proof of work failed. This is highly unlikely!")
|
||||
.expect("Proof of work failed. This is highly unlikely!");
|
||||
|
||||
// Recompute pow_response using our normal Challenger code, and make sure it matches.
|
||||
challenger.observe_element(pow_witness);
|
||||
let pow_response = challenger.get_challenge();
|
||||
let leading_zeros = pow_response.to_canonical_u64().leading_zeros();
|
||||
assert!(leading_zeros >= min_leading_zeros);
|
||||
pow_witness
|
||||
}
|
||||
|
||||
fn fri_prover_query_rounds<
|
||||
|
||||
@ -15,8 +15,8 @@ use crate::plonk::config::{AlgebraicHasher, GenericHashOut, Hasher};
|
||||
/// Observes prover messages, and generates challenges by hashing the transcript, a la Fiat-Shamir.
|
||||
#[derive(Clone)]
|
||||
pub struct Challenger<F: RichField, H: Hasher<F>> {
|
||||
sponge_state: [F; SPONGE_WIDTH],
|
||||
input_buffer: Vec<F>,
|
||||
pub(crate) sponge_state: [F; SPONGE_WIDTH],
|
||||
pub(crate) input_buffer: Vec<F>,
|
||||
output_buffer: Vec<F>,
|
||||
_phantom: PhantomData<H>,
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user