Merge pull request #481 from mir-protocol/fix_hash_or_noop_merkle_proof

Use `hash_or_noop` for Merkle tree leaves
This commit is contained in:
wborgeaud 2022-02-15 08:12:36 +01:00 committed by GitHub
commit f4640bb5a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 172 additions and 63 deletions

View File

@ -1,3 +1,5 @@
#![feature(generic_const_exprs)]
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::field::goldilocks_field::GoldilocksField;
use plonky2::hash::hash_types::RichField; use plonky2::hash::hash_types::RichField;
@ -9,7 +11,10 @@ use tynm::type_name;
const ELEMS_PER_LEAF: usize = 135; const ELEMS_PER_LEAF: usize = 135;
pub(crate) fn bench_merkle_tree<F: RichField, H: Hasher<F>>(c: &mut Criterion) { pub(crate) fn bench_merkle_tree<F: RichField, H: Hasher<F>>(c: &mut Criterion)
where
[(); H::HASH_SIZE]:,
{
let mut group = c.benchmark_group(&format!( let mut group = c.benchmark_group(&format!(
"merkle-tree<{}, {}>", "merkle-tree<{}, {}>",
type_name::<F>(), type_name::<F>(),

View File

@ -12,7 +12,7 @@ use crate::fri::FriParams;
use crate::hash::hash_types::RichField; use crate::hash::hash_types::RichField;
use crate::hash::merkle_tree::MerkleTree; use crate::hash::merkle_tree::MerkleTree;
use crate::iop::challenger::Challenger; use crate::iop::challenger::Challenger;
use crate::plonk::config::GenericConfig; use crate::plonk::config::{GenericConfig, Hasher};
use crate::timed; use crate::timed;
use crate::util::reducing::ReducingFactor; use crate::util::reducing::ReducingFactor;
use crate::util::reverse_bits; use crate::util::reverse_bits;
@ -43,7 +43,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
cap_height: usize, cap_height: usize,
timing: &mut TimingTree, timing: &mut TimingTree,
fft_root_table: Option<&FftRootTable<F>>, fft_root_table: Option<&FftRootTable<F>>,
) -> Self { ) -> Self
where
[(); C::Hasher::HASH_SIZE]:,
{
let coeffs = timed!( let coeffs = timed!(
timing, timing,
"IFFT", "IFFT",
@ -68,7 +71,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
cap_height: usize, cap_height: usize,
timing: &mut TimingTree, timing: &mut TimingTree,
fft_root_table: Option<&FftRootTable<F>>, fft_root_table: Option<&FftRootTable<F>>,
) -> Self { ) -> Self
where
[(); C::Hasher::HASH_SIZE]:,
{
let degree = polynomials[0].len(); let degree = polynomials[0].len();
let lde_values = timed!( let lde_values = timed!(
timing, timing,
@ -133,7 +139,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
challenger: &mut Challenger<F, C::Hasher>, challenger: &mut Challenger<F, C::Hasher>,
fri_params: &FriParams, fri_params: &FriParams,
timing: &mut TimingTree, timing: &mut TimingTree,
) -> FriProof<F, C::Hasher, D> { ) -> FriProof<F, C::Hasher, D>
where
[(); C::Hasher::HASH_SIZE]:,
{
assert!(D > 1, "Not implemented for D=1."); assert!(D > 1, "Not implemented for D=1.");
let alpha = challenger.get_extension_challenge::<D>(); let alpha = challenger.get_extension_challenge::<D>();
let mut alpha = ReducingFactor::new(alpha); let mut alpha = ReducingFactor::new(alpha);

View File

@ -245,7 +245,10 @@ impl<F: RichField + Extendable<D>, H: Hasher<F>, const D: usize> CompressedFriPr
challenges: &ProofChallenges<F, D>, challenges: &ProofChallenges<F, D>,
fri_inferred_elements: FriInferredElements<F, D>, fri_inferred_elements: FriInferredElements<F, D>,
params: &FriParams, params: &FriParams,
) -> FriProof<F, H, D> { ) -> FriProof<F, H, D>
where
[(); H::HASH_SIZE]:,
{
let CompressedFriProof { let CompressedFriProof {
commit_phase_merkle_caps, commit_phase_merkle_caps,
query_round_proofs, query_round_proofs,

View File

@ -24,7 +24,10 @@ pub fn fri_proof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const
challenger: &mut Challenger<F, C::Hasher>, challenger: &mut Challenger<F, C::Hasher>,
fri_params: &FriParams, fri_params: &FriParams,
timing: &mut TimingTree, timing: &mut TimingTree,
) -> FriProof<F, C::Hasher, D> { ) -> FriProof<F, C::Hasher, D>
where
[(); C::Hasher::HASH_SIZE]:,
{
let n = lde_polynomial_values.len(); let n = lde_polynomial_values.len();
assert_eq!(lde_polynomial_coeffs.len(), n); assert_eq!(lde_polynomial_coeffs.len(), n);
@ -68,7 +71,10 @@ fn fri_committed_trees<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>,
) -> ( ) -> (
Vec<MerkleTree<F, C::Hasher>>, Vec<MerkleTree<F, C::Hasher>>,
PolynomialCoeffs<F::Extension>, PolynomialCoeffs<F::Extension>,
) { )
where
[(); C::Hasher::HASH_SIZE]:,
{
let mut trees = Vec::new(); let mut trees = Vec::new();
let mut shift = F::MULTIPLICATIVE_GROUP_GENERATOR; let mut shift = F::MULTIPLICATIVE_GROUP_GENERATOR;

View File

@ -56,18 +56,17 @@ pub(crate) fn fri_verify_proof_of_work<F: RichField + Extendable<D>, const D: us
Ok(()) Ok(())
} }
pub fn verify_fri_proof< pub fn verify_fri_proof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
F: RichField + Extendable<D>,
C: GenericConfig<D, F = F>,
const D: usize,
>(
instance: &FriInstanceInfo<F, D>, instance: &FriInstanceInfo<F, D>,
openings: &FriOpenings<F, D>, openings: &FriOpenings<F, D>,
challenges: &FriChallenges<F, D>, challenges: &FriChallenges<F, D>,
initial_merkle_caps: &[MerkleCap<F, C::Hasher>], initial_merkle_caps: &[MerkleCap<F, C::Hasher>],
proof: &FriProof<F, C::Hasher, D>, proof: &FriProof<F, C::Hasher, D>,
params: &FriParams, params: &FriParams,
) -> Result<()> { ) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
ensure!( ensure!(
params.final_poly_len() == proof.final_poly.len(), params.final_poly_len() == proof.final_poly.len(),
"Final polynomial has wrong degree." "Final polynomial has wrong degree."
@ -112,7 +111,10 @@ fn fri_verify_initial_proof<F: RichField, H: Hasher<F>>(
x_index: usize, x_index: usize,
proof: &FriInitialTreeProof<F, H>, proof: &FriInitialTreeProof<F, H>,
initial_merkle_caps: &[MerkleCap<F, H>], initial_merkle_caps: &[MerkleCap<F, H>],
) -> Result<()> { ) -> Result<()>
where
[(); H::HASH_SIZE]:,
{
for ((evals, merkle_proof), cap) in proof.evals_proofs.iter().zip(initial_merkle_caps) { for ((evals, merkle_proof), cap) in proof.evals_proofs.iter().zip(initial_merkle_caps) {
verify_merkle_proof::<F, H>(evals.clone(), x_index, cap, merkle_proof)?; verify_merkle_proof::<F, H>(evals.clone(), x_index, cap, merkle_proof)?;
} }
@ -177,7 +179,10 @@ fn fri_verifier_query_round<
n: usize, n: usize,
round_proof: &FriQueryRound<F, C::Hasher, D>, round_proof: &FriQueryRound<F, C::Hasher, D>,
params: &FriParams, params: &FriParams,
) -> Result<()> { ) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
fri_verify_initial_proof::<F, C::Hasher>( fri_verify_initial_proof::<F, C::Hasher>(
x_index, x_index,
&round_proof.initial_trees_proof, &round_proof.initial_trees_proof,

View File

@ -10,7 +10,7 @@ use crate::hash::hash_types::RichField;
use crate::iop::witness::{PartialWitness, Witness}; use crate::iop::witness::{PartialWitness, Witness};
use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::circuit_data::CircuitConfig; use crate::plonk::circuit_data::CircuitConfig;
use crate::plonk::config::GenericConfig; use crate::plonk::config::{GenericConfig, Hasher};
use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBaseBatch}; use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBaseBatch};
use crate::plonk::verifier::verify; use crate::plonk::verifier::verify;
use crate::util::transpose; use crate::util::transpose;
@ -92,7 +92,10 @@ pub fn test_eval_fns<
const D: usize, const D: usize,
>( >(
gate: G, gate: G,
) -> Result<()> { ) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
// Test that `eval_unfiltered` and `eval_unfiltered_base` are coherent. // Test that `eval_unfiltered` and `eval_unfiltered_base` are coherent.
let wires_base = F::rand_vec(gate.num_wires()); let wires_base = F::rand_vec(gate.num_wires());
let constants_base = F::rand_vec(gate.num_constants()); let constants_base = F::rand_vec(gate.num_constants());

View File

@ -12,16 +12,6 @@ pub(crate) const SPONGE_RATE: usize = 8;
pub(crate) const SPONGE_CAPACITY: usize = 4; pub(crate) const SPONGE_CAPACITY: usize = 4;
pub const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; pub const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY;
/// Hash the slice if necessary to reduce its length to ~256 bits. If it already fits, this is a
/// no-op.
pub fn hash_or_noop<F: RichField, P: PlonkyPermutation<F>>(inputs: &[F]) -> HashOut<F> {
if inputs.len() <= 4 {
HashOut::from_partial(inputs)
} else {
hash_n_to_hash_no_pad::<F, P>(inputs)
}
}
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> { impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
pub fn hash_or_noop<H: AlgebraicHasher<F>>(&mut self, inputs: Vec<Target>) -> HashOutTarget { pub fn hash_or_noop<H: AlgebraicHasher<F>>(&mut self, inputs: Vec<Target>) -> HashOutTarget {
let zero = self.zero(); let zero = self.zero();

View File

@ -30,9 +30,12 @@ pub(crate) fn verify_merkle_proof<F: RichField, H: Hasher<F>>(
leaf_index: usize, leaf_index: usize,
merkle_cap: &MerkleCap<F, H>, merkle_cap: &MerkleCap<F, H>,
proof: &MerkleProof<F, H>, proof: &MerkleProof<F, H>,
) -> Result<()> { ) -> Result<()>
where
[(); H::HASH_SIZE]:,
{
let mut index = leaf_index; let mut index = leaf_index;
let mut current_digest = H::hash_no_pad(&leaf_data); let mut current_digest = H::hash_or_noop(&leaf_data);
for &sibling_digest in proof.siblings.iter() { for &sibling_digest in proof.siblings.iter() {
let bit = index & 1; let bit = index & 1;
index >>= 1; index >>= 1;

View File

@ -60,10 +60,13 @@ fn capacity_up_to_mut<T>(v: &mut Vec<T>, len: usize) -> &mut [MaybeUninit<T>] {
fn fill_subtree<F: RichField, H: Hasher<F>>( fn fill_subtree<F: RichField, H: Hasher<F>>(
digests_buf: &mut [MaybeUninit<H::Hash>], digests_buf: &mut [MaybeUninit<H::Hash>],
leaves: &[Vec<F>], leaves: &[Vec<F>],
) -> H::Hash { ) -> H::Hash
where
[(); H::HASH_SIZE]:,
{
assert_eq!(leaves.len(), digests_buf.len() / 2 + 1); assert_eq!(leaves.len(), digests_buf.len() / 2 + 1);
if digests_buf.is_empty() { if digests_buf.is_empty() {
H::hash_no_pad(&leaves[0]) H::hash_or_noop(&leaves[0])
} else { } else {
// Layout is: left recursive output || left child digest // Layout is: left recursive output || left child digest
// || right child digest || right recursive output. // || right child digest || right recursive output.
@ -89,7 +92,9 @@ fn fill_digests_buf<F: RichField, H: Hasher<F>>(
cap_buf: &mut [MaybeUninit<H::Hash>], cap_buf: &mut [MaybeUninit<H::Hash>],
leaves: &[Vec<F>], leaves: &[Vec<F>],
cap_height: usize, cap_height: usize,
) { ) where
[(); H::HASH_SIZE]:,
{
// Special case of a tree that's all cap. The usual case will panic because we'll try to split // Special case of a tree that's all cap. The usual case will panic because we'll try to split
// an empty slice into chunks of `0`. (We would not need this if there was a way to split into // an empty slice into chunks of `0`. (We would not need this if there was a way to split into
// `blah` chunks as opposed to chunks _of_ `blah`.) // `blah` chunks as opposed to chunks _of_ `blah`.)
@ -99,7 +104,7 @@ fn fill_digests_buf<F: RichField, H: Hasher<F>>(
.par_iter_mut() .par_iter_mut()
.zip(leaves) .zip(leaves)
.for_each(|(cap_buf, leaf)| { .for_each(|(cap_buf, leaf)| {
cap_buf.write(H::hash_no_pad(leaf)); cap_buf.write(H::hash_or_noop(leaf));
}); });
return; return;
} }
@ -121,7 +126,10 @@ fn fill_digests_buf<F: RichField, H: Hasher<F>>(
} }
impl<F: RichField, H: Hasher<F>> MerkleTree<F, H> { impl<F: RichField, H: Hasher<F>> MerkleTree<F, H> {
pub fn new(leaves: Vec<Vec<F>>, cap_height: usize) -> Self { pub fn new(leaves: Vec<Vec<F>>, cap_height: usize) -> Self
where
[(); H::HASH_SIZE]:,
{
let log2_leaves_len = log2_strict(leaves.len()); let log2_leaves_len = log2_strict(leaves.len());
assert!( assert!(
cap_height <= log2_leaves_len, cap_height <= log2_leaves_len,
@ -208,14 +216,13 @@ mod tests {
(0..n).map(|_| F::rand_vec(k)).collect() (0..n).map(|_| F::rand_vec(k)).collect()
} }
fn verify_all_leaves< fn verify_all_leaves<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
F: RichField + Extendable<D>,
C: GenericConfig<D, F = F>,
const D: usize,
>(
leaves: Vec<Vec<F>>, leaves: Vec<Vec<F>>,
cap_height: usize, cap_height: usize,
) -> Result<()> { ) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
let tree = MerkleTree::<F, C::Hasher>::new(leaves.clone(), cap_height); let tree = MerkleTree::<F, C::Hasher>::new(leaves.clone(), cap_height);
for (i, leaf) in leaves.into_iter().enumerate() { for (i, leaf) in leaves.into_iter().enumerate() {
let proof = tree.prove(i); let proof = tree.prove(i);

View File

@ -57,7 +57,10 @@ pub(crate) fn decompress_merkle_proofs<F: RichField, H: Hasher<F>>(
compressed_proofs: &[MerkleProof<F, H>], compressed_proofs: &[MerkleProof<F, H>],
height: usize, height: usize,
cap_height: usize, cap_height: usize,
) -> Vec<MerkleProof<F, H>> { ) -> Vec<MerkleProof<F, H>>
where
[(); H::HASH_SIZE]:,
{
let num_leaves = 1 << height; let num_leaves = 1 << height;
let compressed_proofs = compressed_proofs.to_vec(); let compressed_proofs = compressed_proofs.to_vec();
let mut decompressed_proofs = Vec::with_capacity(compressed_proofs.len()); let mut decompressed_proofs = Vec::with_capacity(compressed_proofs.len());
@ -66,7 +69,7 @@ pub(crate) fn decompress_merkle_proofs<F: RichField, H: Hasher<F>>(
for (&i, v) in leaves_indices.iter().zip(leaves_data) { for (&i, v) in leaves_indices.iter().zip(leaves_data) {
// Observe the leaves. // Observe the leaves.
seen.insert(i + num_leaves, H::hash_no_pad(v)); seen.insert(i + num_leaves, H::hash_or_noop(v));
} }
// Iterators over the siblings. // Iterators over the siblings.

View File

@ -610,7 +610,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
} }
/// Builds a "full circuit", with both prover and verifier data. /// Builds a "full circuit", with both prover and verifier data.
pub fn build<C: GenericConfig<D, F = F>>(mut self) -> CircuitData<F, C, D> { pub fn build<C: GenericConfig<D, F = F>>(mut self) -> CircuitData<F, C, D>
where
[(); C::Hasher::HASH_SIZE]:,
{
let mut timing = TimingTree::new("preprocess", Level::Trace); let mut timing = TimingTree::new("preprocess", Level::Trace);
let start = Instant::now(); let start = Instant::now();
let rate_bits = self.config.fri_config.rate_bits; let rate_bits = self.config.fri_config.rate_bits;
@ -776,7 +779,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
} }
/// Builds a "prover circuit", with data needed to generate proofs but not verify them. /// Builds a "prover circuit", with data needed to generate proofs but not verify them.
pub fn build_prover<C: GenericConfig<D, F = F>>(self) -> ProverCircuitData<F, C, D> { pub fn build_prover<C: GenericConfig<D, F = F>>(self) -> ProverCircuitData<F, C, D>
where
[(); C::Hasher::HASH_SIZE]:,
{
// TODO: Can skip parts of this. // TODO: Can skip parts of this.
let CircuitData { let CircuitData {
prover_only, prover_only,
@ -790,7 +796,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
} }
/// Builds a "verifier circuit", with data needed to verify proofs but not generate them. /// Builds a "verifier circuit", with data needed to verify proofs but not generate them.
pub fn build_verifier<C: GenericConfig<D, F = F>>(self) -> VerifierCircuitData<F, C, D> { pub fn build_verifier<C: GenericConfig<D, F = F>>(self) -> VerifierCircuitData<F, C, D>
where
[(); C::Hasher::HASH_SIZE]:,
{
// TODO: Can skip parts of this. // TODO: Can skip parts of this.
let CircuitData { let CircuitData {
verifier_only, verifier_only,

View File

@ -104,7 +104,10 @@ pub struct CircuitData<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>,
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
CircuitData<F, C, D> CircuitData<F, C, D>
{ {
pub fn prove(&self, inputs: PartialWitness<F>) -> Result<ProofWithPublicInputs<F, C, D>> { pub fn prove(&self, inputs: PartialWitness<F>) -> Result<ProofWithPublicInputs<F, C, D>>
where
[(); C::Hasher::HASH_SIZE]:,
{
prove( prove(
&self.prover_only, &self.prover_only,
&self.common, &self.common,
@ -113,14 +116,20 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
) )
} }
pub fn verify(&self, proof_with_pis: ProofWithPublicInputs<F, C, D>) -> Result<()> { pub fn verify(&self, proof_with_pis: ProofWithPublicInputs<F, C, D>) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
verify(proof_with_pis, &self.verifier_only, &self.common) verify(proof_with_pis, &self.verifier_only, &self.common)
} }
pub fn verify_compressed( pub fn verify_compressed(
&self, &self,
compressed_proof_with_pis: CompressedProofWithPublicInputs<F, C, D>, compressed_proof_with_pis: CompressedProofWithPublicInputs<F, C, D>,
) -> Result<()> { ) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
compressed_proof_with_pis.verify(&self.verifier_only, &self.common) compressed_proof_with_pis.verify(&self.verifier_only, &self.common)
} }
} }
@ -144,7 +153,10 @@ pub struct ProverCircuitData<
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
ProverCircuitData<F, C, D> ProverCircuitData<F, C, D>
{ {
pub fn prove(&self, inputs: PartialWitness<F>) -> Result<ProofWithPublicInputs<F, C, D>> { pub fn prove(&self, inputs: PartialWitness<F>) -> Result<ProofWithPublicInputs<F, C, D>>
where
[(); C::Hasher::HASH_SIZE]:,
{
prove( prove(
&self.prover_only, &self.prover_only,
&self.common, &self.common,
@ -168,14 +180,20 @@ pub struct VerifierCircuitData<
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
VerifierCircuitData<F, C, D> VerifierCircuitData<F, C, D>
{ {
pub fn verify(&self, proof_with_pis: ProofWithPublicInputs<F, C, D>) -> Result<()> { pub fn verify(&self, proof_with_pis: ProofWithPublicInputs<F, C, D>) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
verify(proof_with_pis, &self.verifier_only, &self.common) verify(proof_with_pis, &self.verifier_only, &self.common)
} }
pub fn verify_compressed( pub fn verify_compressed(
&self, &self,
compressed_proof_with_pis: CompressedProofWithPublicInputs<F, C, D>, compressed_proof_with_pis: CompressedProofWithPublicInputs<F, C, D>,
) -> Result<()> { ) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
compressed_proof_with_pis.verify(&self.verifier_only, &self.common) compressed_proof_with_pis.verify(&self.verifier_only, &self.common)
} }
} }

View File

@ -46,6 +46,24 @@ pub trait Hasher<F: RichField>: Sized + Clone + Debug + Eq + PartialEq {
Self::hash_no_pad(&padded_input) Self::hash_no_pad(&padded_input)
} }
/// Hash the slice if necessary to reduce its length to ~256 bits. If it already fits, this is a
/// no-op.
fn hash_or_noop(inputs: &[F]) -> Self::Hash
where
[(); Self::HASH_SIZE]:,
{
if inputs.len() <= 4 {
let mut inputs_bytes = [0u8; Self::HASH_SIZE];
for i in 0..inputs.len() {
inputs_bytes[i * 8..(i + 1) * 8]
.copy_from_slice(&inputs[i].to_canonical_u64().to_le_bytes());
}
Self::Hash::from_bytes(&inputs_bytes)
} else {
Self::hash_no_pad(inputs)
}
}
fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash; fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash;
} }

View File

@ -138,7 +138,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
challenges: &ProofChallenges<F, D>, challenges: &ProofChallenges<F, D>,
fri_inferred_elements: FriInferredElements<F, D>, fri_inferred_elements: FriInferredElements<F, D>,
params: &FriParams, params: &FriParams,
) -> Proof<F, C, D> { ) -> Proof<F, C, D>
where
[(); C::Hasher::HASH_SIZE]:,
{
let CompressedProof { let CompressedProof {
wires_cap, wires_cap,
plonk_zs_partial_products_cap, plonk_zs_partial_products_cap,
@ -174,7 +177,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
pub fn decompress( pub fn decompress(
self, self,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> anyhow::Result<ProofWithPublicInputs<F, C, D>> { ) -> anyhow::Result<ProofWithPublicInputs<F, C, D>>
where
[(); C::Hasher::HASH_SIZE]:,
{
let challenges = self.get_challenges(self.get_public_inputs_hash(), common_data)?; let challenges = self.get_challenges(self.get_public_inputs_hash(), common_data)?;
let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data); let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data);
let decompressed_proof = let decompressed_proof =
@ -190,7 +196,10 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
self, self,
verifier_data: &VerifierOnlyCircuitData<C, D>, verifier_data: &VerifierOnlyCircuitData<C, D>,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
ensure!( ensure!(
self.public_inputs.len() == common_data.num_public_inputs, self.public_inputs.len() == common_data.num_public_inputs,
"Number of public inputs doesn't match circuit data." "Number of public inputs doesn't match circuit data."

View File

@ -31,7 +31,10 @@ pub(crate) fn prove<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, co
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
inputs: PartialWitness<F>, inputs: PartialWitness<F>,
timing: &mut TimingTree, timing: &mut TimingTree,
) -> Result<ProofWithPublicInputs<F, C, D>> { ) -> Result<ProofWithPublicInputs<F, C, D>>
where
[(); C::Hasher::HASH_SIZE]:,
{
let config = &common_data.config; let config = &common_data.config;
let num_challenges = config.num_challenges; let num_challenges = config.num_challenges;
let quotient_degree = common_data.quotient_degree(); let quotient_degree = common_data.quotient_degree();

View File

@ -187,7 +187,9 @@ mod tests {
use crate::gates::noop::NoopGate; use crate::gates::noop::NoopGate;
use crate::iop::witness::{PartialWitness, Witness}; use crate::iop::witness::{PartialWitness, Witness};
use crate::plonk::circuit_data::{CircuitConfig, VerifierOnlyCircuitData}; use crate::plonk::circuit_data::{CircuitConfig, VerifierOnlyCircuitData};
use crate::plonk::config::{GenericConfig, KeccakGoldilocksConfig, PoseidonGoldilocksConfig}; use crate::plonk::config::{
GenericConfig, Hasher, KeccakGoldilocksConfig, PoseidonGoldilocksConfig,
};
use crate::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs}; use crate::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs};
use crate::plonk::prover::prove; use crate::plonk::prover::prove;
use crate::util::timing::TimingTree; use crate::util::timing::TimingTree;
@ -322,7 +324,10 @@ mod tests {
ProofWithPublicInputs<F, C, D>, ProofWithPublicInputs<F, C, D>,
VerifierOnlyCircuitData<C, D>, VerifierOnlyCircuitData<C, D>,
CommonCircuitData<F, C, D>, CommonCircuitData<F, C, D>,
)> { )>
where
[(); C::Hasher::HASH_SIZE]:,
{
let mut builder = CircuitBuilder::<F, D>::new(config.clone()); let mut builder = CircuitBuilder::<F, D>::new(config.clone());
for _ in 0..num_dummy_gates { for _ in 0..num_dummy_gates {
builder.add_gate(NoopGate, vec![]); builder.add_gate(NoopGate, vec![]);
@ -356,6 +361,7 @@ mod tests {
)> )>
where where
InnerC::Hasher: AlgebraicHasher<F>, InnerC::Hasher: AlgebraicHasher<F>,
[(); C::Hasher::HASH_SIZE]:,
{ {
let mut builder = CircuitBuilder::<F, D>::new(config.clone()); let mut builder = CircuitBuilder::<F, D>::new(config.clone());
let mut pw = PartialWitness::new(); let mut pw = PartialWitness::new();
@ -407,7 +413,10 @@ mod tests {
>( >(
proof: &ProofWithPublicInputs<F, C, D>, proof: &ProofWithPublicInputs<F, C, D>,
cd: &CommonCircuitData<F, C, D>, cd: &CommonCircuitData<F, C, D>,
) -> Result<()> { ) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
let proof_bytes = proof.to_bytes()?; let proof_bytes = proof.to_bytes()?;
info!("Proof length: {} bytes", proof_bytes.len()); info!("Proof length: {} bytes", proof_bytes.len());
let proof_from_bytes = ProofWithPublicInputs::from_bytes(proof_bytes, cd)?; let proof_from_bytes = ProofWithPublicInputs::from_bytes(proof_bytes, cd)?;

View File

@ -15,7 +15,10 @@ pub(crate) fn verify<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, c
proof_with_pis: ProofWithPublicInputs<F, C, D>, proof_with_pis: ProofWithPublicInputs<F, C, D>,
verifier_data: &VerifierOnlyCircuitData<C, D>, verifier_data: &VerifierOnlyCircuitData<C, D>,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> Result<()> { ) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
ensure!( ensure!(
proof_with_pis.public_inputs.len() == common_data.num_public_inputs, proof_with_pis.public_inputs.len() == common_data.num_public_inputs,
"Number of public inputs doesn't match circuit data." "Number of public inputs doesn't match circuit data."
@ -42,7 +45,10 @@ pub(crate) fn verify_with_challenges<
challenges: ProofChallenges<F, D>, challenges: ProofChallenges<F, D>,
verifier_data: &VerifierOnlyCircuitData<C, D>, verifier_data: &VerifierOnlyCircuitData<C, D>,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> Result<()> { ) -> Result<()>
where
[(); C::Hasher::HASH_SIZE]:,
{
let local_constants = &proof.openings.constants; let local_constants = &proof.openings.constants;
let local_wires = &proof.openings.wires; let local_wires = &proof.openings.wires;
let vars = EvaluationVars { let vars = EvaluationVars {

View File

@ -7,7 +7,7 @@ use plonky2::field::zero_poly_coset::ZeroPolyOnCoset;
use plonky2::fri::oracle::PolynomialBatch; use plonky2::fri::oracle::PolynomialBatch;
use plonky2::hash::hash_types::RichField; use plonky2::hash::hash_types::RichField;
use plonky2::iop::challenger::Challenger; use plonky2::iop::challenger::Challenger;
use plonky2::plonk::config::GenericConfig; use plonky2::plonk::config::{GenericConfig, Hasher};
use plonky2::timed; use plonky2::timed;
use plonky2::util::timing::TimingTree; use plonky2::util::timing::TimingTree;
use plonky2::util::transpose; use plonky2::util::transpose;
@ -33,6 +33,7 @@ where
S: Stark<F, D>, S: Stark<F, D>,
[(); S::COLUMNS]:, [(); S::COLUMNS]:,
[(); S::PUBLIC_INPUTS]:, [(); S::PUBLIC_INPUTS]:,
[(); C::Hasher::HASH_SIZE]:,
{ {
let degree = trace.len(); let degree = trace.len();
let degree_bits = log2_strict(degree); let degree_bits = log2_strict(degree);

View File

@ -3,7 +3,7 @@ use plonky2::field::extension_field::{Extendable, FieldExtension};
use plonky2::field::field_types::Field; use plonky2::field::field_types::Field;
use plonky2::fri::verifier::verify_fri_proof; use plonky2::fri::verifier::verify_fri_proof;
use plonky2::hash::hash_types::RichField; use plonky2::hash::hash_types::RichField;
use plonky2::plonk::config::GenericConfig; use plonky2::plonk::config::{GenericConfig, Hasher};
use plonky2::plonk::plonk_common::reduce_with_powers; use plonky2::plonk::plonk_common::reduce_with_powers;
use plonky2_util::log2_strict; use plonky2_util::log2_strict;
@ -26,6 +26,7 @@ pub fn verify<
where where
[(); S::COLUMNS]:, [(); S::COLUMNS]:,
[(); S::PUBLIC_INPUTS]:, [(); S::PUBLIC_INPUTS]:,
[(); C::Hasher::HASH_SIZE]:,
{ {
let degree_bits = log2_strict(recover_degree(&proof_with_pis.proof, config)); let degree_bits = log2_strict(recover_degree(&proof_with_pis.proof, config));
let challenges = proof_with_pis.get_challenges(config, degree_bits)?; let challenges = proof_with_pis.get_challenges(config, degree_bits)?;
@ -47,6 +48,7 @@ pub(crate) fn verify_with_challenges<
where where
[(); S::COLUMNS]:, [(); S::COLUMNS]:,
[(); S::PUBLIC_INPUTS]:, [(); S::PUBLIC_INPUTS]:,
[(); C::Hasher::HASH_SIZE]:,
{ {
let StarkProofWithPublicInputs { let StarkProofWithPublicInputs {
proof, proof,