Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 40 additions & 26 deletions ledger/src/proofs/accumulator_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,52 @@ use super::urs_utils;

pub fn accumulator_check(
urs: &SRS<Vesta>,
proof: &PicklesProofProofsVerified2ReprStableV2,
proofs: &[&PicklesProofProofsVerified2ReprStableV2],
) -> Result<bool, InvalidBigInt> {
// accumulator check
// https://github.com/MinaProtocol/mina/blob/fb1c3c0a408c344810140bdbcedacc532a11be91/src/lib/pickles/common.ml#L191-L204
// Note:
// comms: statement.proof_state.messages_for_next_wrap_proof.challenge_polynomial_commitment
// Array.of_list_map comm_chals ~f:(fun (comm, _) -> Or_infinity.Finite comm )
// chals: statement.proof_state.deferred_values.bulletproof_challenges
// Array.concat @@ List.map comm_chals ~f:(fun (_, chals) -> Vector.to_array chals)

let deferred_values = &proof.statement.proof_state.deferred_values;
let bulletproof_challenges = &deferred_values.bulletproof_challenges;
let bulletproof_challenges: Vec<Fp> = bulletproof_challenges
.iter()
.map(|chal| {
let prechallenge = &chal.prechallenge.inner;
let prechallenge: [u64; 2] = prechallenge.each_ref().map(|c| c.as_u64());

ScalarChallenge::limbs_to_field(&prechallenge)
})
.collect();

let of_coord =
|(x, y): &(BigInt, BigInt)| Ok(Vesta::of_coordinates(x.to_field()?, y.to_field()?));

// statement.proof_state.messages_for_next_wrap_proof.challenge_polynomial_commitment
let acc_comm = &proof
.statement
.proof_state
.messages_for_next_wrap_proof
.challenge_polynomial_commitment;
let acc_comm: Vesta = of_coord(acc_comm)?;

let acc_check =
urs_utils::batch_dlog_accumulator_check(urs, &[acc_comm], &bulletproof_challenges);
let mut comms = Vec::with_capacity(proofs.len());
let mut bulletproof_challenges = vec![];

for proof in proofs {
let chals = &proof
.statement
.proof_state
.deferred_values
.bulletproof_challenges;
let mut chals: Vec<Fp> = chals
.iter()
.map(|chal| {
let prechallenge = &chal.prechallenge.inner;
let prechallenge: [u64; 2] = prechallenge.each_ref().map(|c| c.as_u64());

ScalarChallenge::limbs_to_field(&prechallenge)
})
.collect();

bulletproof_challenges.append(&mut chals);

let of_coord =
|(x, y): &(BigInt, BigInt)| Ok(Vesta::of_coordinates(x.to_field()?, y.to_field()?));

// statement.proof_state.messages_for_next_wrap_proof.challenge_polynomial_commitment
let acc_comm = &proof
.statement
.proof_state
.messages_for_next_wrap_proof
.challenge_polynomial_commitment;
let acc_comm: Vesta = of_coord(acc_comm)?;

comms.push(acc_comm);
}

let acc_check = urs_utils::batch_dlog_accumulator_check(urs, &comms, &bulletproof_challenges);

if !acc_check {
println!("accumulator_check failed");
Expand Down
116 changes: 108 additions & 8 deletions ledger/src/proofs/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::rc::Rc;
use ark_ff::fields::arithmetic::InvalidBigInt;
use ark_poly::{EvaluationDomain, Radix2EvaluationDomain};
use ark_serialize::Write;
use itertools::Itertools;
use poly_commitment::srs::SRS;

use crate::{
Expand Down Expand Up @@ -519,6 +520,38 @@ fn verify_with(
)
}

pub struct VerificationContext<'a> {
pub verifier_index: &'a VerifierIndex<Fq>,
pub proof: &'a ProverProof<Fq>,
pub public_input: &'a [Fq],
}

fn batch_verify(proofs: &[VerificationContext]) -> Result<(), VerifyError> {
use kimchi::groupmap::GroupMap;
use kimchi::mina_curves::pasta::PallasParameters;
use kimchi::verifier::Context;
use mina_poseidon::sponge::{DefaultFqSponge, DefaultFrSponge};
use poly_commitment::evaluation_proof::OpeningProof;

type SpongeParams = mina_poseidon::constants::PlonkSpongeConstantsKimchi;
type EFqSponge = DefaultFqSponge<PallasParameters, SpongeParams>;
type EFrSponge = DefaultFrSponge<Fq, SpongeParams>;

let group_map = GroupMap::<Fp>::setup();
let proofs = proofs
.iter()
.map(|p| Context {
verifier_index: p.verifier_index,
proof: p.proof,
public_input: p.public_input,
})
.collect_vec();

kimchi::verifier::batch_verify::<Pallas, EFqSponge, EFrSponge, OpeningProof<Pallas>>(
&group_map, &proofs,
)
}

fn run_checks(
proof: &PicklesProofProofsVerified2ReprStableV2,
verifier_index: &VerifierIndex<Fq>,
Expand Down Expand Up @@ -713,7 +746,7 @@ pub fn verify_block(
let protocol_state_hash = MinaHash::hash(&protocol_state);

let accum_check =
accumulator_check::accumulator_check(srs, protocol_state_proof).unwrap_or(false);
accumulator_check::accumulator_check(srs, &[protocol_state_proof]).unwrap_or(false);
let verified = verify_impl(&protocol_state_hash, protocol_state_proof, &vk).unwrap_or(false);

accum_check && verified
Expand All @@ -730,12 +763,27 @@ pub fn verify_transaction<'a>(
data: (),
};

proofs.into_iter().all(|(statement, transaction_proof)| {
let accum_check =
accumulator_check::accumulator_check(srs, transaction_proof).unwrap_or(false);
let verified = verify_impl(statement, transaction_proof, &vk).unwrap_or(false);
accum_check && verified
})
let mut inputs: Vec<(
&Statement<SokDigest>,
&PicklesProofProofsVerified2ReprStableV2,
&VK,
)> = Vec::with_capacity(128);

let mut accum_check_proofs: Vec<&PicklesProofProofsVerified2ReprStableV2> =
Vec::with_capacity(128);

proofs
.into_iter()
.for_each(|(statement, transaction_proof)| {
accum_check_proofs.push(transaction_proof);
inputs.push((statement, transaction_proof, &vk));
});

let accum_check =
accumulator_check::accumulator_check(srs, &accum_check_proofs).unwrap_or(false);

let verified = batch_verify_impl(inputs.as_slice()).unwrap_or(false);
accum_check && verified
}

/// https://github.com/MinaProtocol/mina/blob/bfd1009abdbee78979ff0343cc73a3480e862f58/src/lib/crypto/kimchi_bindings/stubs/src/pasta_fq_plonk_proof.rs#L116
Expand All @@ -753,7 +801,8 @@ pub fn verify_zkapp(
data: (),
};

let accum_check = accumulator_check::accumulator_check(srs, sideloaded_proof).unwrap_or(false);
let accum_check =
accumulator_check::accumulator_check(srs, &[sideloaded_proof]).unwrap_or(false);
let verified = verify_impl(&zkapp_statement, sideloaded_proof, &vk).unwrap_or(false);

let ok = accum_check && verified;
Expand Down Expand Up @@ -811,6 +860,57 @@ where
Ok(result.is_ok() && checks)
}

fn batch_verify_impl<AppState>(
proofs: &[(&AppState, &PicklesProofProofsVerified2ReprStableV2, &VK)],
) -> Result<bool, InvalidBigInt>
where
AppState: ToFieldElements<Fp>,
{
let mut verification_contexts = Vec::with_capacity(proofs.len());
let mut checks = true;

for (app_state, proof, vk) in proofs {
let deferred_values = compute_deferred_values(proof)?;
checks = checks && run_checks(proof, vk.index);

let message_for_next_step_proof = get_message_for_next_step_proof(
&proof.statement.messages_for_next_step_proof,
&vk.commitments,
app_state,
)?;

let message_for_next_wrap_proof = get_message_for_next_wrap_proof(
&proof.statement.proof_state.messages_for_next_wrap_proof,
)?;

let prepared_statement = get_prepared_statement(
&message_for_next_step_proof,
&message_for_next_wrap_proof,
deferred_values,
&proof.statement.proof_state.sponge_digest_before_evaluations,
);

let npublic_input = vk.index.public;
let public_inputs = prepared_statement.to_public_input(npublic_input)?;
let proof_padded = make_padded_proof_from_p2p(proof)?;

verification_contexts.push((vk.index, proof_padded, public_inputs));
}

let proofs: Vec<VerificationContext> = verification_contexts
.iter()
.map(|(vk, proof, public_input)| VerificationContext {
verifier_index: vk,
proof,
public_input,
})
.collect();

let result = batch_verify(&proofs);

Ok(result.is_ok() && checks)
}

/// Dump data when it fails, to reproduce and compare in OCaml
fn dump_zkapp_verification(
verification_key: &VerificationKey,
Expand Down
6 changes: 5 additions & 1 deletion ledger/src/staged_ledger/staged_ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,12 +1247,16 @@ impl StagedLedger {
supercharge_coinbase: bool,
) -> Result<DiffResult, StagedLedgerError> {
let work = witness.completed_works();
let works_count = work.len();

let now = redux::Instant::now();
if skip_verification.is_none() {
Self::check_completed_works(logger, verifier, &self.scan_state, work)?;
}
eprintln!("verification time={:?}", now.elapsed());
eprintln!(
"verification time={:?} ({works_count} completed works)",
now.elapsed()
);

let prediff = witness.get(
|cmd| Self::check_commands(self.ledger.clone(), verifier, cmd, skip_verification),
Expand Down
Loading