use super::{
plan::Plan,
types::{Challenge, FieldElement, Proof},
};
use crate::{config, ledger::FileLedger, KontorPoRError, Result};
use ff::Field;
use tracing::{debug, info_span};
pub fn verify(challenges: &[Challenge], proof: &Proof, ledger: &FileLedger) -> Result<bool> {
let _span = info_span!(
"verify",
num_challenges = challenges.len(),
has_ledger = true
)
.entered();
if challenges.is_empty() {
return Err(KontorPoRError::InvalidInput(
"Must provide at least one challenge".to_string(),
));
}
let plan = Plan::make_plan(challenges, ledger)?;
let num_challenges = challenges[0].num_challenges;
if num_challenges == 0 || num_challenges > config::MAX_NUM_CHALLENGES {
return Err(KontorPoRError::InvalidChallengeCount {
count: num_challenges,
});
}
let params = crate::params::load_or_generate_params(
plan.files_per_step,
plan.file_tree_depth,
plan.aggregated_tree_depth,
)?;
debug!(
"verify() - Using shape: files_per_step={}, file_tree_depth={}, aggregated_tree_depth={}",
plan.files_per_step, plan.file_tree_depth, plan.aggregated_tree_depth
);
for challenge in challenges.iter() {
if challenge.num_challenges != num_challenges {
return Err(KontorPoRError::InvalidInput(
"All challenges must have the same num_challenges for verification".to_string(),
));
}
}
for challenge in challenges {
let file_depth = crate::api::tree_depth_from_metadata(&challenge.file_metadata);
if file_depth > plan.file_tree_depth {
return Err(KontorPoRError::InvalidInput(format!(
"File {} depth {} exceeds circuit shape depth {} - circuit cannot handle this file",
challenge.file_metadata.file_id, file_depth, plan.file_tree_depth
)));
}
}
debug!("Verify commitment calculation (from plan):");
debug!(
" - Number of sorted challenges: {}",
plan.sorted_challenges.len()
);
debug!(" - Depths: {:?}", plan.depths);
let z0_primary = plan.build_z0_primary();
debug!("VERIFIER z0_primary: {:?}", z0_primary);
let num_iterations = plan.sorted_challenges[0].num_challenges;
if plan.aggregated_tree_depth == 0 {
debug!("verify() - Single-file verification:");
} else {
debug!("verify() - Multi-file verification:");
}
debug!(" - Number of files: {}", plan.sorted_challenges.len());
debug!(" - Number of iterations to verify: {}", num_iterations);
debug!(
" - z0_primary[0] aggregated_root: {:?}",
plan.aggregated_root
);
debug!(" - z0_primary[1] initial_state: {:?}", FieldElement::ZERO);
for (i, idx) in plan.ledger_indices.iter().enumerate() {
debug!(" - z0_primary[{}] ledger_index_{}: {}", 2 + i, i, idx);
}
for (i, depth) in plan.depths.iter().enumerate() {
debug!(
" - z0_primary[{}] depth_{}: {}",
2 + plan.files_per_step + i,
i,
depth
);
}
for (i, seed) in plan.seeds.iter().enumerate() {
debug!(
" - z0_primary[{}] seed_{}: {:?}",
2 + plan.files_per_step + plan.files_per_step + i,
i,
seed
);
}
let result = proof
.compressed_snark
.verify(¶ms.keys.vk, num_iterations, &z0_primary);
match result {
Ok(_) => Ok(true),
Err(nova_snark::errors::NovaError::ProofVerifyError { reason: _ }) => Ok(false),
Err(e) => Err(KontorPoRError::Snark(format!(
"An unexpected error occurred during verification: {e:?}"
))),
}
}