Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5a19d81
added proof_size function
Antonio95 Oct 7, 2025
5d27960
added function that returns the proof size given the Authorization
Antonio95 Oct 7, 2025
727b65f
created Authorization::number_of_input_records(); turned authorizatio…
Antonio95 Oct 7, 2025
68defa5
added consistency check between prepare_verifier_inputs and Authoriza…
Antonio95 Oct 7, 2025
99c00bd
switched execution tests to Varuna V2 and added proof-size checks to all
Antonio95 Oct 7, 2025
47acade
added 1 to the wrapper function to account for serialized version number
Antonio95 Oct 8, 2025
32f3ea1
Merge branch 'option_serialized_size_fix' into proof_size
Antonio95 Oct 8, 2025
3191b05
comment fixed and replaced magical 8 by size_of usize
Antonio95 Oct 8, 2025
532cd3d
Merge branch 'staging' into proof_size
Antonio95 Oct 8, 2025
6841b97
Update synthesizer/process/src/stack/authorization/mod.rs
Antonio95 Oct 8, 2025
49f0a3a
added reference to serialize_compressed in the documentation of proof…
Antonio95 Oct 8, 2025
1ee7a72
Update algorithms/src/snark/varuna/data_structures/proof.rs
vicsn Oct 14, 2025
d394f44
modified interface, added Authorisation::from_unchecked, added test c…
Antonio95 Oct 16, 2025
de62b52
restricted consensus version
Antonio95 Oct 16, 2025
edac4f1
addressed PR review comments; created proof_size for synthesizer Proof
Antonio95 Oct 16, 2025
5f966ad
merged staging
Antonio95 Oct 16, 2025
795df43
improved documentation of the two proof_size methods
Antonio95 Oct 16, 2025
1988927
changed original output type into the new semantic one
Antonio95 Oct 16, 2025
d63394f
Merge branch 'staging' into proof_size
Antonio95 Oct 16, 2025
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
88 changes: 85 additions & 3 deletions algorithms/src/snark/varuna/data_structures/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,22 @@

use crate::{
SNARKError,
polycommit::sonic_pc,
snark::varuna::{CircuitId, ahp},
polycommit::{kzg10::KZGCommitment, sonic_pc},
snark::varuna::{CircuitId, VarunaVersion, ahp},
};

use ahp::prover::{FourthMessage, ThirdMessage};
use snarkvm_curves::PairingEngine;
use snarkvm_fields::PrimeField;
use snarkvm_fields::{One, PrimeField};
use snarkvm_utilities::{FromBytes, ToBytes, into_io_error, serialize::*};

use std::{
collections::BTreeMap,
io::{self, Read, Write},
};

use std::mem::size_of;

#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Commitments<E: PairingEngine> {
pub witness_commitments: Vec<WitnessCommitments<E>>,
Expand Down Expand Up @@ -378,6 +380,86 @@ impl<E: PairingEngine> FromBytes for Proof<E> {
}
}

/// Computes the size of a Varuna proof in bytes without reciving the proof
/// itself.
///
/// *Arguments*:
/// - `batch_sizes`: the batch sizes of the circuits and instances being
/// proved.
/// - `hiding`: indicates whether the proof system is run in ZK mode
/// - `varuna_version`: the version of Varuna being used
///
/// *Returns*:
/// - `Some(size)` for `VarunaVersion::V2`, where `size` is the size of the
/// proof in bytes.
/// - `None` for `VarunaVersion::V1`.
pub fn proof_size<E: PairingEngine>(
batch_sizes: &[usize],
varuna_version: VarunaVersion,
hiding: bool,
) -> Option<usize> {
let n_circuits: usize = batch_sizes.len();
let n_instances: usize = batch_sizes.iter().sum();

match varuna_version {
VarunaVersion::V1 => None,
VarunaVersion::V2 => {
// All fields are serialised in Compressed mode The breakdown is as follows:
// - batch sizes: (boils down to CanonicalSerialize for [usize])
// + one u64 for the length (the number of circuits) followed that many
// usize This contains the size information for the vectors in all other
// fields, which are therefore serialised without their length
// - commitments:
// + witness_commitments: n_instances commitments
// + mask_poly: 1 byte to encode the enum tag (a bool) plus one commitment if
// the variant is Some (if and only if the proof system is run in ZK mode)
// + h_0, g_1, g_2, h_2: four commitments
// + g_a, g_b, g_c: 3 * n_circuits commitments
// - evaluations:
// + g_1_eval: one field element
// + g_a_evals, g_b_evals, g_c_evals: 3 * n_circuits field elements
// - third_msg:
// + 3 * n_instances field elements
// - fourth_msg:
// + 3 * n_circuits field elements
// - pc_proof:
// + one usize for the size of the vector (which is always 3)
// + three of [1 commitment + 1 bool (for the Option tag) + {1 field element
// if the variant is Some (if and only if the proof system is run in ZK
// mode)}]

let n_bool = 1;
let n_u64 = 1;
let n_field_elements = 1 + 6 * n_circuits + 3 * n_instances;
let n_commitments = 4 + n_instances + (if hiding { 1 } else { 0 }) + 3 * n_circuits;

// The next three sizes are const functions
let size_bool = size_of::<bool>();
let size_u64 = size_of::<u64>();
// The next two can be hard-coded if performance becomes critical and they
// are considered fully stable. They are 32 and 48 bytes at the time of
// writing, respectively (commitments are affine points written in compressed
// form).
let size_field_element = E::Fr::one().compressed_size();
let size_commitment = KZGCommitment::<E>::empty().compressed_size();

let size_pc_proof = 8 + 3 * (size_commitment + 1) + if hiding { size_field_element } else { 0 };

Some(
n_bool * size_bool
+ n_u64 * size_u64
+ size_of_val(batch_sizes)
+ n_field_elements * size_field_element
+ n_commitments * size_commitment
+ size_pc_proof,
)

// NB: "n_usize * size_usize" must be computed as
// size_of_val(batch_sizes) due to linting restrictions
}
}
}

#[cfg(test)]
mod test {
#![allow(non_camel_case_types)]
Expand Down
11 changes: 11 additions & 0 deletions algorithms/src/snark/varuna/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod varuna {
VarunaSNARK,
VarunaVersion,
mode::SNARKMode,
proof::proof_size,
test_circuit::TestCircuit,
},
traits::{AlgebraicSponge, SNARK},
Expand All @@ -33,6 +34,7 @@ mod varuna {

use snarkvm_curves::bls12_377::{Bls12_377, Fq, Fr};
use snarkvm_utilities::{
CanonicalSerialize,
ToBytes,
rand::{TestRng, Uniform},
};
Expand Down Expand Up @@ -131,6 +133,15 @@ mod varuna {
$snark_inst::prove_batch(universal_prover, &fs_parameters, varuna_version, &pks_to_constraints, rng).unwrap();
println!("Called prover");

if varuna_version == VarunaVersion::V2 {
let batch_sizes = proof.batch_sizes();
let mut proof_bytes = vec![];
proof.serialize_compressed(&mut proof_bytes).unwrap();
let actual_size = proof_size::<Bls12_377>(&batch_sizes, VarunaVersion::V2, $snark_mode::ZK).unwrap();
assert_eq!(proof_bytes.len(), actual_size);
println!("Compressed size is as expected ({actual_size} B)");
}

assert!(
$snark_inst::verify_batch(universal_verifier, &fs_parameters, varuna_version, &vks_to_inputs, &proof).unwrap(),
"Batch verification failed with {instance_batch_size} instances and {circuit_batch_size} circuits for circuits: {constraints:?}"
Expand Down
2 changes: 1 addition & 1 deletion ledger/block/src/transaction/execution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl<N: Network> Execution<N> {
}

/// Returns an iterator over the underlying transitions.
pub fn transitions(&self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = &Transition<N>> {
pub fn transitions(&self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = &Transition<N>> + Clone {
self.transitions.values()
}

Expand Down
63 changes: 62 additions & 1 deletion synthesizer/process/src/stack/authorization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ mod serialize;
mod string;

use console::{network::prelude::*, program::Request, types::Field};
use snarkvm_ledger_block::{Transaction, Transition};
use snarkvm_algorithms::snark::varuna::{VarunaVersion, proof_size};
use snarkvm_ledger_block::{Input, Transaction, Transition};
use snarkvm_synthesizer_program::StackTrait;

use indexmap::IndexMap;
Expand Down Expand Up @@ -285,6 +286,66 @@ impl<N: Network> PartialEq for Authorization<N> {

impl<N: Network> Eq for Authorization<N> {}

impl<N: Network> Authorization<N> {
/// Returns the (exact) predicted size of the Varuna proof of an Authorization
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Returns the (exact) predicted size of the Varuna proof of an Authorization
/// Returns the size of the Varuna proof of an `Authorization`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(function gone in later commits)

///
/// *Arguments*:
/// - `varuna_version`: the version of Varuna to use. Only `VarunaVersion::V2` is supported.
///
/// *Returns*:
/// - `Some(size)` for `VarunaVersion::V2`, where `size` is the size of the proof in bytes.
/// - `None` for `VarunaVersion::V1`.
pub fn proof_size(&self, varuna_version: VarunaVersion) -> Option<usize> {
match varuna_version {
VarunaVersion::V1 => None,
VarunaVersion::V2 => {
// The Varuna circuits that must be proved as part of an Authorization are:
// - the circuits of each function in the authorization
// - one the inclusion circuit for input records to *all* of those functions
// TODO: Dynamic dispatch, once implemented, will cause a third type
// of circuit to appear which needs to be accounted for here.

let mut circuit_frequencies = HashMap::new();

// In order to compute the frequencies of function circuits, we mimic the
// operation of Process::verify_execution:
for transition in self.transitions().values() {
let entry = circuit_frequencies
.entry((*transition.program_id(), *transition.function_name()))
.or_insert(0usize);
*entry += 1;
}

let mut batch_sizes: Vec<usize> = circuit_frequencies.values().cloned().collect();

// We now add the single inclusion circuit for input records, if any:
let n_input_records = Self::number_of_input_records(self.transitions().values());
if n_input_records > 0 {
batch_sizes.push(n_input_records);
}

// Varuna is always ran in hiding (i. e. ZK) mode when proving Executions
proof_size::<N::PairingCurve>(&batch_sizes, VarunaVersion::V2, true)
}
}
}

/// Total number of inputs to the passed `Transition`s that are of type
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Total number of inputs to the passed `Transition`s that are of type
/// Returns the total number of inputs to the passed `Transition`s that are of type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(addressed and also fixed other parts of the same documentation that had become outdated due to the interface change)

/// `Input::Record`.
// This method is used to ensure consistency between
// `prepare_verifier_inputs` and the batch-size calculation used in
// `Authorization::proof_size` above. The specifics of the former mean this
// method must receive an iterator of `Transition`s instead of the
// `Authorization` itself. Notably, the `transitions` argument can be
// `authorization.transitions().values()`.
#[inline]
pub(crate) fn number_of_input_records<'a>(transitions: impl ExactSizeIterator<Item = &'a Transition<N>>) -> usize {
transitions
.map(|transition| transition.inputs().iter().filter(|input| matches!(input, Input::Record(_, _))).count())
.sum()
}
}

/// Ensures the given request and transition correspond to one another.
fn ensure_request_and_transition_matches<N: Network>(
index: usize,
Expand Down
Loading