From b5b23a08cfdd98e6230b39b55e031e358e24c792 Mon Sep 17 00:00:00 2001 From: Ilya Lesokhin Date: Mon, 6 Jul 2026 14:42:10 +0300 Subject: [PATCH] refactor(multiverifier): move shared test fixtures to test_utils Move the config constants, target padding sizes, preprocessed roots, proof fixture path, and helpers shared by the multiverifier test modules out of verify_test.rs into test_utils.rs (PCS_CONFIG, LOG_BLOWUP_FACTOR, TARGET_PADDING_SIZES, CIRCUIT_N_PREPROCESSED_COLUMNS, PRIVACY_CAIRO_VERIFIER_OUTPUT_VALUES, PRIVACY_CAIRO_VERIFIER_PREPROCESSED_ROOT, MULTIVERIFIER_PREPROCESSED_ROOT, MULTIVERIFIER_OF_TWO_CAIRO_PROOFS_PATH, blake2s_u32s_host, multiverifier_preprocessed_column_log_sizes), so they can be reused by additional test modules without one test file depending on another. Co-Authored-By: Claude Opus 4.8 --- .../circuit_multiverifier/src/test_utils.rs | 99 +++++++++++++++++ .../circuit_multiverifier/src/verify_test.rs | 104 ++---------------- 2 files changed, 108 insertions(+), 95 deletions(-) diff --git a/crates/circuit_multiverifier/src/test_utils.rs b/crates/circuit_multiverifier/src/test_utils.rs index 94042080..f87afbf2 100644 --- a/crates/circuit_multiverifier/src/test_utils.rs +++ b/crates/circuit_multiverifier/src/test_utils.rs @@ -1,3 +1,5 @@ +use blake2::{Blake2s256, Digest}; +use circuit_cairo_verifier::privacy::get_pcs_config; use circuit_common::{ N_RESERVED, finalize::{ComponentSizes, pad_to_targets}, @@ -8,8 +10,10 @@ use circuit_verifier::{ verify::CircuitConfig, }; use circuits::{blake::HashValue, context::FinalizedContext, ivalue::NoValue}; +use circuits_stark_verifier::order_hash_map::OrderedHashMap; use circuits_stark_verifier::proof::{ProofConfig, empty_proof}; use stwo::core::{fields::qm31::QM31, pcs::PcsConfig}; +use stwo_constraint_framework::preprocessed_columns::PreProcessedColumnId; use crate::verify::{MultiverifierInput, SharedConfig, build_multiverifier_circuit}; use stwo::core::poly::circle::CanonicCoset; @@ -19,6 +23,101 @@ use stwo::prover::backend::simd::SimdBackend; use stwo::prover::mempool::BaseColumnPool; use stwo::prover::poly::circle::PolyOps; +// Shared test fixtures: config constants, target padding sizes, and helpers used by the +// multiverifier test modules (`verify_test` and `backward_compatibility_test`). + +const PRIVACY_CAIRO_VERIFIER_TRACE_LOG_SIZE: u32 = 21; +pub const LOG_BLOWUP_FACTOR: u32 = 3; +pub const PCS_CONFIG: PcsConfig = + get_pcs_config(PRIVACY_CAIRO_VERIFIER_TRACE_LOG_SIZE, LOG_BLOWUP_FACTOR); +pub const TARGET_PADDING_SIZES: ComponentSizes = ComponentSizes { + eq: 1 << 17, + qm31_ops: 1 << 21, + m31_to_u32: 1 << 18, + triple_xor: 1 << 17, + blake_g_gate: 1 << 20, +}; +/// The number of preprocessed columns in a trace of a circuit. +pub const CIRCUIT_N_PREPROCESSED_COLUMNS: usize = 45; +/// The Blake2s digest of the output in the privacy Cairo verifier proof fixture +/// (`test_data/circuit_multiverifier/proof_cairo.bin`). +pub const PRIVACY_CAIRO_VERIFIER_OUTPUT_VALUES: [u32; 8] = + [3035180123, 3555538090, 587798257, 1881776298, 3385462846, 2102605012, 3369268656, 403460632]; + +/// The preprocessed root of the privacy Cairo verifier circuit. +pub const PRIVACY_CAIRO_VERIFIER_PREPROCESSED_ROOT: [u32; 8] = + [3927153469, 2149409952, 1045374089, 2379944016, 2639147837, 600016285, 2135210114, 302122822]; + +/// The preprocessed root of the multiverifier circuit. +pub const MULTIVERIFIER_PREPROCESSED_ROOT: [u32; 8] = + [299245338, 3245106799, 2582894857, 1660971541, 1264978744, 3663378231, 505079882, 3077728512]; +/// A multiverifier proof verifying two identical Cairo verifier proofs. +pub const MULTIVERIFIER_OF_TWO_CAIRO_PROOFS_PATH: &str = + concat!(env!("CARGO_MANIFEST_DIR"), "/../../test_data/circuit_multiverifier/proof.bin"); + +/// Out-of-circuit implementation of [`circuits::blake::blake2s_u32s`]. +pub fn blake2s_u32s_host(words: &[u32]) -> [u32; 8] { + let mut hasher = Blake2s256::new(); + for word in words { + hasher.update(word.to_le_bytes()); + } + let hash: [u8; 32] = hasher.finalize().into(); + std::array::from_fn(|i| u32::from_le_bytes(hash[i * 4..i * 4 + 4].try_into().unwrap())) +} + +pub fn multiverifier_preprocessed_column_log_sizes() -> OrderedHashMap { + [ + ("bitwise_xor_4_0", 8), + ("bitwise_xor_4_1", 8), + ("bitwise_xor_4_2", 8), + ("bitwise_xor_7_0", 14), + ("bitwise_xor_7_1", 14), + ("bitwise_xor_7_2", 14), + ("seq_16", 16), + ("bitwise_xor_8_0", 16), + ("bitwise_xor_8_1", 16), + ("bitwise_xor_8_2", 16), + ("eq_in0_address", 17), + ("eq_in1_address", 17), + ("triple_xor_input_addr_0", 17), + ("triple_xor_input_addr_1", 17), + ("triple_xor_input_addr_2", 17), + ("triple_xor_output_addr", 17), + ("triple_xor_multiplicity", 17), + ("m31_to_u32_input_addr", 18), + ("m31_to_u32_output_addr", 18), + ("m31_to_u32_multiplicity", 18), + ("bitwise_xor_9_0", 18), + ("bitwise_xor_9_1", 18), + ("bitwise_xor_9_2", 18), + ("blake_g_gate_input_addr_a", 20), + ("blake_g_gate_input_addr_b", 20), + ("blake_g_gate_input_addr_c", 20), + ("blake_g_gate_input_addr_d", 20), + ("blake_g_gate_input_addr_f0", 20), + ("blake_g_gate_input_addr_f1", 20), + ("blake_g_gate_output_addr_a", 20), + ("blake_g_gate_output_addr_b", 20), + ("blake_g_gate_output_addr_c", 20), + ("blake_g_gate_output_addr_d", 20), + ("blake_g_gate_multiplicity", 20), + ("bitwise_xor_10_0", 20), + ("bitwise_xor_10_1", 20), + ("bitwise_xor_10_2", 20), + ("qm31_ops_add_flag", 21), + ("qm31_ops_sub_flag", 21), + ("qm31_ops_mul_flag", 21), + ("qm31_ops_pointwise_mul_flag", 21), + ("qm31_ops_in0_address", 21), + ("qm31_ops_in1_address", 21), + ("qm31_ops_out_address", 21), + ("qm31_ops_mults", 21), + ] + .into_iter() + .map(|(id, log_size)| (PreProcessedColumnId { id: id.to_string() }, log_size)) + .collect() +} + /// Builds a `NoValue` multiverifier and preprocesses it. The multiverifier is built by feeding it /// two identical proofs of a circuit. pub fn get_preprocessed_multiverifier_from_circuit( diff --git a/crates/circuit_multiverifier/src/verify_test.rs b/crates/circuit_multiverifier/src/verify_test.rs index 6cfbc770..d7de5dc3 100644 --- a/crates/circuit_multiverifier/src/verify_test.rs +++ b/crates/circuit_multiverifier/src/verify_test.rs @@ -1,12 +1,9 @@ use std::fs::File; use std::io::Write; -use blake2::{Blake2s256, Digest}; use cairo_air::utils::binary_deserialize_from_file; use circuit_cairo_serialize::prepare_circuit_proof_for_cairo_verifier; -use circuit_cairo_verifier::privacy::{ - get_pcs_config, privacy_cairo_verifier_config, privacy_components, -}; +use circuit_cairo_verifier::privacy::{privacy_cairo_verifier_config, privacy_components}; use circuit_cairo_verifier::utils::get_proof_file_path; use circuit_cairo_verifier::verify::build_cairo_verifier_circuit; use circuit_cairo_verifier::verify::verify_cairo_with_component_set; @@ -26,7 +23,6 @@ use circuit_verifier::verify::CircuitPublicData; use circuits::blake::HashValue; use circuits::context::FinalizedContext; use circuits::ivalue::{IValue, NoValue}; -use circuits_stark_verifier::order_hash_map::OrderedHashMap; use circuits_stark_verifier::proof::{Proof, ProofConfig}; use itertools::chain; use stwo::core::fields::qm31::QM31; @@ -34,39 +30,20 @@ use stwo::core::pcs::PcsConfig; use stwo::core::vcs_lifted::blake2_merkle::Blake2sMerkleChannel; use stwo::prover::backend::simd::SimdBackend; use stwo::prover::mempool::BaseColumnPool; -use stwo_constraint_framework::preprocessed_columns::PreProcessedColumnId; - -use crate::test_utils::{get_preprocessed_multiverifier_from_circuit, get_preprocessed_root}; -use crate::verify::{MultiverifierInput, SharedConfig, build_multiverifier_circuit}; -const PRIVACY_CAIRO_VERIFIER_TRACE_LOG_SIZE: u32 = 21; -const LOG_BLOWUP_FACTOR: u32 = 3; -const PCS_CONFIG: PcsConfig = - get_pcs_config(PRIVACY_CAIRO_VERIFIER_TRACE_LOG_SIZE, LOG_BLOWUP_FACTOR); -const TARGET_PADDING_SIZES: ComponentSizes = ComponentSizes { - eq: 1 << 17, - qm31_ops: 1 << 21, - m31_to_u32: 1 << 18, - triple_xor: 1 << 17, - blake_g_gate: 1 << 20, +use crate::test_utils::{ + CIRCUIT_N_PREPROCESSED_COLUMNS, LOG_BLOWUP_FACTOR, MULTIVERIFIER_OF_TWO_CAIRO_PROOFS_PATH, + MULTIVERIFIER_PREPROCESSED_ROOT, PCS_CONFIG, PRIVACY_CAIRO_VERIFIER_OUTPUT_VALUES, + PRIVACY_CAIRO_VERIFIER_PREPROCESSED_ROOT, TARGET_PADDING_SIZES, blake2s_u32s_host, + get_preprocessed_multiverifier_from_circuit, get_preprocessed_root, + multiverifier_preprocessed_column_log_sizes, }; -/// The number of preprocessed columns in a trace of a circuit. -const CIRCUIT_N_PREPROCESSED_COLUMNS: usize = 45; +use crate::verify::{MultiverifierInput, SharedConfig, build_multiverifier_circuit}; -/// Constants related to the cairo verifier circuit. -const PRIVACY_CAIRO_VERIFIER_PREPROCESSED_ROOT: [u32; 8] = - [3927153469, 2149409952, 1045374089, 2379944016, 2639147837, 600016285, 2135210114, 302122822]; +/// The Cairo verifier proof fixture (produced by [`test_cairo_proof_regression`]). const PRIVACY_CAIRO_VERIFIER_PROOF_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../test_data/circuit_multiverifier/proof_cairo.bin"); -/// The Blake2s digest of the output in the proof above. -const PRIVACY_CAIRO_VERIFIER_OUTPUT_VALUES: [u32; 8] = - [3035180123, 3555538090, 587798257, 1881776298, 3385462846, 2102605012, 3369268656, 403460632]; -/// Constants related to the multiverifier circuit. -const MULTIVERIFIER_PREPROCESSED_ROOT: [u32; 8] = - [299245338, 3245106799, 2582894857, 1660971541, 1264978744, 3663378231, 505079882, 3077728512]; -const MULTIVERIFIER_OF_TWO_CAIRO_PROOFS_PATH: &str = - concat!(env!("CARGO_MANIFEST_DIR"), "/../../test_data/circuit_multiverifier/proof.bin"); /// The same multiverifier proof, serialized as the felt252 `scarb execute --arguments-file` input /// consumed by the Cairo1 verifier program: a JSON array of hex-string felts produced via /// [`circuit_cairo_serialize`]. Regenerate with `FIX_PROOF=1`. @@ -79,69 +56,6 @@ fn hash_value_to_u32s(hash: &HashValue) -> [u32; 8] { std::array::from_fn(|i| hash[i].get().unpack_u32()) } -/// Out-of-circuit implementation of [`circuits::blake::blake2s_u32s`]. -fn blake2s_u32s_host(words: &[u32]) -> [u32; 8] { - let mut hasher = Blake2s256::new(); - for word in words { - hasher.update(word.to_le_bytes()); - } - let hash: [u8; 32] = hasher.finalize().into(); - std::array::from_fn(|i| u32::from_le_bytes(hash[i * 4..i * 4 + 4].try_into().unwrap())) -} - -fn multiverifier_preprocessed_column_log_sizes() -> OrderedHashMap { - [ - ("bitwise_xor_4_0", 8), - ("bitwise_xor_4_1", 8), - ("bitwise_xor_4_2", 8), - ("bitwise_xor_7_0", 14), - ("bitwise_xor_7_1", 14), - ("bitwise_xor_7_2", 14), - ("seq_16", 16), - ("bitwise_xor_8_0", 16), - ("bitwise_xor_8_1", 16), - ("bitwise_xor_8_2", 16), - ("eq_in0_address", 17), - ("eq_in1_address", 17), - ("triple_xor_input_addr_0", 17), - ("triple_xor_input_addr_1", 17), - ("triple_xor_input_addr_2", 17), - ("triple_xor_output_addr", 17), - ("triple_xor_multiplicity", 17), - ("m31_to_u32_input_addr", 18), - ("m31_to_u32_output_addr", 18), - ("m31_to_u32_multiplicity", 18), - ("bitwise_xor_9_0", 18), - ("bitwise_xor_9_1", 18), - ("bitwise_xor_9_2", 18), - ("blake_g_gate_input_addr_a", 20), - ("blake_g_gate_input_addr_b", 20), - ("blake_g_gate_input_addr_c", 20), - ("blake_g_gate_input_addr_d", 20), - ("blake_g_gate_input_addr_f0", 20), - ("blake_g_gate_input_addr_f1", 20), - ("blake_g_gate_output_addr_a", 20), - ("blake_g_gate_output_addr_b", 20), - ("blake_g_gate_output_addr_c", 20), - ("blake_g_gate_output_addr_d", 20), - ("blake_g_gate_multiplicity", 20), - ("bitwise_xor_10_0", 20), - ("bitwise_xor_10_1", 20), - ("bitwise_xor_10_2", 20), - ("qm31_ops_add_flag", 21), - ("qm31_ops_sub_flag", 21), - ("qm31_ops_mul_flag", 21), - ("qm31_ops_pointwise_mul_flag", 21), - ("qm31_ops_in0_address", 21), - ("qm31_ops_in1_address", 21), - ("qm31_ops_out_address", 21), - ("qm31_ops_mults", 21), - ] - .into_iter() - .map(|(id, log_size)| (PreProcessedColumnId { id: id.to_string() }, log_size)) - .collect() -} - /// Builds a `NoValue` Cairo verifier circuit (with configs of privacy) and preprocesses it. /// /// If `target_padding` is `None`, we don't pad the circuits (note that even in this case, the