use super::types::{Challenge, FieldElement};
use crate::{config, ledger::FileLedger, KontorPoRError, Result};
use ff::Field;
use std::cmp::Ordering;
#[derive(Debug, Clone)]
pub(crate) struct Plan {
pub(crate) files_per_step: usize,
pub(crate) file_tree_depth: usize,
pub(crate) aggregated_tree_depth: usize,
pub(crate) aggregated_root: FieldElement,
pub(crate) sorted_challenges: Vec<Challenge>,
pub(crate) ledger_indices: Vec<usize>,
pub(crate) depths: Vec<usize>,
pub(crate) seeds: Vec<FieldElement>,
pub(crate) public_io_layout: config::PublicIOLayout,
}
impl Plan {
pub(crate) fn make_plan(challenges: &[Challenge], ledger: &FileLedger) -> Result<Plan> {
if challenges.is_empty() {
return Err(KontorPoRError::InvalidInput(
"Cannot create plan from empty challenges".to_string(),
));
}
let aggregated_root = if challenges.len() > 1 {
ledger.tree.root()
} else {
challenges[0].file_metadata.root
};
let max_file_depth = challenges
.iter()
.map(|c| crate::api::tree_depth_from_metadata(&c.file_metadata))
.max()
.unwrap_or(0);
let (files_per_step, file_tree_depth) =
config::derive_shape(challenges.len(), max_file_depth);
let aggregated_tree_depth = if files_per_step > 1 {
ledger.tree.layers.len() - 1
} else {
0
};
let mut sorted_challenges: Vec<Challenge> = challenges.to_vec();
sorted_challenges.sort_by(|a, b| {
match a.file_metadata.file_id.cmp(&b.file_metadata.file_id) {
Ordering::Equal => a.id().0.cmp(&b.id().0),
other => other,
}
});
let mut ledger_indices = vec![0usize; files_per_step];
use crate::poseidon::calculate_root_commitment;
for (i, challenge) in sorted_challenges.iter().enumerate() {
let file_depth = crate::api::tree_depth_from_metadata(&challenge.file_metadata);
let rc = calculate_root_commitment(
challenge.file_metadata.root,
FieldElement::from(file_depth as u64),
);
let ledger_idx = ledger.get_canonical_index_for_rc(rc).ok_or_else(|| {
KontorPoRError::FileNotInLedger {
file_id: challenge.file_metadata.file_id.clone(),
}
})?;
ledger_indices[i] = ledger_idx;
}
let mut depths = vec![0usize; files_per_step];
for (i, challenge) in sorted_challenges.iter().enumerate() {
let depth = crate::api::tree_depth_from_metadata(&challenge.file_metadata);
depths[i] = depth;
}
let mut seeds = vec![FieldElement::ZERO; files_per_step];
for (i, challenge) in sorted_challenges.iter().enumerate() {
seeds[i] = challenge.seed;
}
let public_io_layout = config::PublicIOLayout::new(files_per_step);
Ok(Plan {
files_per_step,
file_tree_depth,
aggregated_tree_depth,
aggregated_root,
sorted_challenges,
ledger_indices,
depths,
seeds,
public_io_layout,
})
}
pub(crate) fn build_z0_primary(&self) -> Vec<FieldElement> {
self.public_io_layout.build_z0_primary(
self.aggregated_root,
&self.ledger_indices,
&self.depths,
&self.seeds,
)
}
}