Skip to content

Commit

Permalink
refactor(prover_keystore): Remove cached commitments function (#2805)
Browse files Browse the repository at this point in the history
## What ❔

- Removes `get_cached_commitments` function from keystore, as it didn't
in fact cache anything.
- Improve interfaces for commitment generation and checking the
scheduler vk hash.
- Generalizes the alignment check.
- Remove `zksync_types` from `zksync_prover_keystore` deps.

## Why ❔

Readability.
  • Loading branch information
popzxc authored Sep 5, 2024
1 parent 9821a20 commit 5c9186f
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 108 deletions.
2 changes: 1 addition & 1 deletion prover/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use anyhow::Context;
use zksync_prover_keystore::{commitment_utils::generate_commitments, keystore::Keystore};
use zksync_prover_keystore::keystore::Keystore;

use crate::vk_commitment_helper::{
get_toml_formatted_value, read_contract_toml, write_contract_toml,
};

pub fn read_and_update_contract_toml(keystore: &Keystore, dryrun: bool) -> anyhow::Result<()> {
let mut contract_doc = read_contract_toml().context("read_contract_toml()")?;
let vk_commitments = generate_commitments(keystore).context("generate_commitments()")?;
let vk_commitments = keystore
.generate_commitments()
.context("generate_commitments()")?;

contract_doc["contracts"]["FRI_RECURSION_LEAF_LEVEL_VK_HASH"] =
get_toml_formatted_value(vk_commitments.leaf);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use zksync_prover_fri_types::{
ProverServiceDataKey,
};
use zksync_prover_keystore::{
commitment_utils::generate_commitments,
keystore::Keystore,
setup_data_generator::{CPUSetupDataGenerator, GPUSetupDataGenerator, SetupDataGenerator},
};
Expand Down Expand Up @@ -98,7 +97,8 @@ fn generate_vks(keystore: &Keystore, jobs: usize, quiet: bool) -> anyhow::Result
}

// Let's also update the commitments file.
keystore.save_commitments(&generate_commitments(keystore)?)
let commitments = keystore.generate_commitments()?;
keystore.save_commitments(&commitments)
}

#[derive(Debug, Parser)]
Expand Down
74 changes: 46 additions & 28 deletions prover/crates/bin/witness_generator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ use zksync_env_config::object_store::ProverObjectStoreConfig;
use zksync_object_store::ObjectStoreFactory;
use zksync_prover_dal::{ConnectionPool, Prover, ProverDal};
use zksync_prover_fri_types::PROVER_PROTOCOL_SEMANTIC_VERSION;
use zksync_prover_keystore::commitment_utils::get_cached_commitments;
use zksync_prover_keystore::keystore::Keystore;
use zksync_queued_job_processor::JobProcessor;
use zksync_types::basic_fri_types::AggregationRound;
use zksync_types::{basic_fri_types::AggregationRound, protocol_version::ProtocolSemanticVersion};
use zksync_utils::wait_for_tasks::ManagedTasks;
use zksync_vlog::prometheus::PrometheusExporterConfig;
use zksync_witness_generator::{
Expand Down Expand Up @@ -54,6 +54,43 @@ struct Opt {
secrets_path: Option<std::path::PathBuf>,
}

/// Checks if the configuration locally matches the one in the database.
/// This function recalculates the commitment in order to check the exact code that
/// will run, instead of loading `commitments.json` (which also may correct misaligned
/// information).
async fn ensure_protocol_alignment(
prover_pool: &ConnectionPool<Prover>,
protocol_version: ProtocolSemanticVersion,
setup_data_path: String,
) -> anyhow::Result<()> {
tracing::info!("Verifying protocol alignment for {:?}", protocol_version);
let vk_commitments_in_db = match prover_pool
.connection()
.await
.unwrap()
.fri_protocol_versions_dal()
.vk_commitments_for(protocol_version)
.await
{
Some(commitments) => commitments,
None => {
panic!(
"No vk commitments available in database for a protocol version {:?}.",
protocol_version
);
}
};
let keystore = Keystore::new_with_setup_data_path(setup_data_path);
// `recursion_scheduler_level_vk_hash` actually stores `scheduler_vk_hash` for historical reasons.
let scheduler_vk_hash = vk_commitments_in_db.recursion_scheduler_level_vk_hash;
keystore
.verify_scheduler_vk_hash(scheduler_vk_hash)
.with_context(||
format!("VK commitments didn't match commitments from DB for protocol version {protocol_version:?}")
)?;
Ok(())
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let opt = Opt::from_args();
Expand Down Expand Up @@ -103,22 +140,13 @@ async fn main() -> anyhow::Result<()> {
let (stop_sender, stop_receiver) = watch::channel(false);

let protocol_version = PROVER_PROTOCOL_SEMANTIC_VERSION;
let vk_commitments_in_db = match prover_connection_pool
.connection()
.await
.unwrap()
.fri_protocol_versions_dal()
.vk_commitments_for(protocol_version)
.await
{
Some(commitments) => commitments,
None => {
panic!(
"No vk commitments available in database for a protocol version {:?}.",
protocol_version
);
}
};
ensure_protocol_alignment(
&prover_connection_pool,
protocol_version,
prover_config.setup_data_path.clone(),
)
.await
.unwrap_or_else(|err| panic!("Protocol alignment check failed: {:?}", err));

let rounds = match (opt.round, opt.all_rounds) {
(Some(round), false) => vec![round],
Expand Down Expand Up @@ -171,16 +199,6 @@ async fn main() -> anyhow::Result<()> {

let witness_generator_task = match round {
AggregationRound::BasicCircuits => {
let start = Instant::now();
let vk_commitments = get_cached_commitments(Some(setup_data_path.clone()));
let end = start.elapsed();
tracing::info!("Calculating commitment took: {:?}", end);
assert_eq!(
vk_commitments,
vk_commitments_in_db,
"VK commitments didn't match commitments from DB for protocol version {protocol_version:?}. Cached commitments: {vk_commitments:?}, commitments in database: {vk_commitments_in_db:?}"
);

let public_blob_store = match config.shall_save_to_public_bucket {
false => None,
true => Some(
Expand Down
2 changes: 1 addition & 1 deletion prover/crates/lib/keystore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ categories.workspace = true


[dependencies]
zksync_types.workspace = true
zksync_basic_types.workspace = true
zksync_utils.workspace = true
zksync_prover_fri_types.workspace = true
zkevm_test_harness.workspace = true
Expand Down
125 changes: 53 additions & 72 deletions prover/crates/lib/keystore/src/commitment_utils.rs
Original file line number Diff line number Diff line change
@@ -1,97 +1,78 @@
use std::{str::FromStr, sync::Mutex};
use std::str::FromStr;

use anyhow::Context as _;
use hex::ToHex;
use once_cell::sync::Lazy;
use zkevm_test_harness::witness::recursive_aggregation::{
compute_leaf_vks_and_params_commitment, compute_node_vk_commitment,
};
use zksync_basic_types::H256;
use zksync_prover_fri_types::circuit_definitions::{
boojum::field::goldilocks::GoldilocksField,
circuit_definitions::recursion_layer::ZkSyncRecursionLayerStorageType,
};
use zksync_types::{protocol_version::L1VerifierConfig, H256};

use crate::{
keystore::Keystore,
utils::{calculate_snark_vk_hash, get_leaf_vk_params},
VkCommitments,
};

static KEYSTORE: Lazy<Mutex<Option<Keystore>>> = Lazy::new(|| Mutex::new(None));
impl Keystore {
pub fn generate_commitments(&self) -> anyhow::Result<VkCommitments> {
let leaf_vk_params = get_leaf_vk_params(self).context("get_leaf_vk_params()")?;
let leaf_layer_params = leaf_vk_params
.iter()
.map(|el| el.1.clone())
.collect::<Vec<_>>()
.try_into()
.unwrap();
let leaf_vk_commitment = compute_leaf_vks_and_params_commitment(leaf_layer_params);

fn circuit_commitments(keystore: &Keystore) -> anyhow::Result<L1VerifierConfig> {
let commitments = generate_commitments(keystore).context("generate_commitments()")?;
Ok(L1VerifierConfig {
// Instead of loading the FRI scheduler verification key here,
// we load the SNARK-wrapper verification key.
// This is due to the fact that these keys are used only for picking the
// prover jobs / witgen jobs from the DB. The keys are matched with the ones in
// `prover_fri_protocol_versions` table, which has the SNARK-wrapper verification key.
// This is OK because if the FRI VK changes, the SNARK-wrapper VK will change as well.
recursion_scheduler_level_vk_hash: H256::from_str(&commitments.snark_wrapper)
.context("invalid SNARK wrapper VK")?,
})
}

pub fn generate_commitments(keystore: &Keystore) -> anyhow::Result<VkCommitments> {
let leaf_vk_params = get_leaf_vk_params(keystore).context("get_leaf_vk_params()")?;
let leaf_layer_params = leaf_vk_params
.iter()
.map(|el| el.1.clone())
.collect::<Vec<_>>()
.try_into()
.unwrap();
let leaf_vk_commitment = compute_leaf_vks_and_params_commitment(leaf_layer_params);
let node_vk = self
.load_recursive_layer_verification_key(
ZkSyncRecursionLayerStorageType::NodeLayerCircuit as u8,
)
.context("get_recursive_layer_vk_for_circuit_type(NodeLayerCircuit)")?;
let node_vk_commitment = compute_node_vk_commitment(node_vk.clone());

let node_vk = keystore
.load_recursive_layer_verification_key(
ZkSyncRecursionLayerStorageType::NodeLayerCircuit as u8,
)
.context("get_recursive_layer_vk_for_circuit_type(NodeLayerCircuit)")?;
let node_vk_commitment = compute_node_vk_commitment(node_vk.clone());
let scheduler_vk = self
.load_recursive_layer_verification_key(
ZkSyncRecursionLayerStorageType::SchedulerCircuit as u8,
)
.context("get_recursive_layer_vk_for_circuit_type(SchedulerCircuit)")?;
let scheduler_vk_commitment = compute_node_vk_commitment(scheduler_vk.clone());

let scheduler_vk = keystore
.load_recursive_layer_verification_key(
ZkSyncRecursionLayerStorageType::SchedulerCircuit as u8,
)
.context("get_recursive_layer_vk_for_circuit_type(SchedulerCircuit)")?;
let scheduler_vk_commitment = compute_node_vk_commitment(scheduler_vk.clone());
let hex_concatenator = |hex_array: [GoldilocksField; 4]| {
"0x".to_owned()
+ &hex_array
.iter()
.map(|x| format!("{:016x}", x.0))
.collect::<Vec<_>>()
.join("")
};

let hex_concatenator = |hex_array: [GoldilocksField; 4]| {
"0x".to_owned()
+ &hex_array
.iter()
.map(|x| format!("{:016x}", x.0))
.collect::<Vec<_>>()
.join("")
};
let leaf_aggregation_commitment_hex = hex_concatenator(leaf_vk_commitment);
let node_aggregation_commitment_hex = hex_concatenator(node_vk_commitment);
let scheduler_commitment_hex = hex_concatenator(scheduler_vk_commitment);
let snark_vk_hash: String = calculate_snark_vk_hash(self)?.encode_hex();

let leaf_aggregation_commitment_hex = hex_concatenator(leaf_vk_commitment);
let node_aggregation_commitment_hex = hex_concatenator(node_vk_commitment);
let scheduler_commitment_hex = hex_concatenator(scheduler_vk_commitment);
let snark_vk_hash: String = calculate_snark_vk_hash(keystore)?.encode_hex();

let result = VkCommitments {
leaf: leaf_aggregation_commitment_hex,
node: node_aggregation_commitment_hex,
scheduler: scheduler_commitment_hex,
snark_wrapper: format!("0x{}", snark_vk_hash),
};
tracing::info!("Commitments: {:?}", result);
Ok(result)
}

pub fn get_cached_commitments(setup_data_path: Option<String>) -> L1VerifierConfig {
if let Some(setup_data_path) = setup_data_path {
let keystore = Keystore::new_with_setup_data_path(setup_data_path);
let mut keystore_lock = KEYSTORE.lock().unwrap();
*keystore_lock = Some(keystore);
let result = VkCommitments {
leaf: leaf_aggregation_commitment_hex,
node: node_aggregation_commitment_hex,
scheduler: scheduler_commitment_hex,
snark_wrapper: format!("0x{}", snark_vk_hash),
};
tracing::info!("Commitments: {:?}", result);
Ok(result)
}

let keystore = KEYSTORE.lock().unwrap().clone().unwrap_or_default();
let commitments = circuit_commitments(&keystore).unwrap();

tracing::info!("Using cached commitments {:?}", commitments);
commitments
pub fn verify_scheduler_vk_hash(&self, expected_hash: H256) -> anyhow::Result<()> {
let commitments = self
.generate_commitments()
.context("generate_commitments()")?;
let calculated_hash =
H256::from_str(&commitments.snark_wrapper).context("invalid SNARK wrapper VK")?;
anyhow::ensure!(expected_hash == calculated_hash, "Invalid SNARK wrapper VK hash. Calculated locally: {calculated_hash:?}, provided: {expected_hash:?}");
Ok(())
}
}
2 changes: 1 addition & 1 deletion prover/crates/lib/keystore/src/keystore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ use circuit_definitions::{
};
use serde::{Deserialize, Serialize};
use zkevm_test_harness::data_source::{in_memory_data_source::InMemoryDataSource, SetupDataSource};
use zksync_basic_types::basic_fri_types::AggregationRound;
use zksync_config::configs::FriProverConfig;
use zksync_env_config::FromEnv;
use zksync_prover_fri_types::ProverServiceDataKey;
use zksync_types::basic_fri_types::AggregationRound;

#[cfg(feature = "gpu")]
use crate::GoldilocksGpuProverSetupData;
Expand Down
2 changes: 1 addition & 1 deletion prover/crates/lib/keystore/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use zkevm_test_harness::{
franklin_crypto::bellman::{CurveAffine, PrimeField, PrimeFieldRepr},
witness::recursive_aggregation::compute_leaf_params,
};
use zksync_basic_types::H256;
use zksync_prover_fri_types::circuit_definitions::{
boojum::field::goldilocks::GoldilocksField,
circuit_definitions::recursion_layer::base_circuit_type_into_recursive_leaf_circuit_type,
Expand All @@ -21,7 +22,6 @@ use zksync_prover_fri_types::circuit_definitions::{
scheduler::aux::BaseLayerCircuitType,
},
};
use zksync_types::H256;
use zksync_utils::locate_workspace;

use crate::keystore::Keystore;
Expand Down

0 comments on commit 5c9186f

Please sign in to comment.