Skip to main content

kontor_crypto/api/
system.rs

1//! PorSystem: Unified API entry point for the Nova-based Proof-of-Retrievability system.
2//!
3//! This module provides a single, consolidated interface that encapsulates all
4//! proving and verification operations, managing dependencies like the FileLedger
5//! and parameter caching internally.
6
7use super::types::{Challenge, FileMetadata, PreparedFile, Proof};
8use crate::{ledger::FileLedger, KontorPoRError, Result};
9use std::collections::BTreeMap;
10use tracing::debug;
11
12/// The unified API entry point for the Nova-based Proof-of-Retrievability system.
13///
14/// PorSystem encapsulates the FileLedger and provides methods for file preparation,
15/// proof generation, and verification. It manages parameter caching and shape
16/// derivation internally.
17pub struct PorSystem<'a> {
18    /// Reference to the file ledger containing the aggregated Merkle tree
19    ledger: &'a FileLedger,
20}
21
22impl<'a> PorSystem<'a> {
23    /// Create a new PorSystem with the given FileLedger.
24    pub fn new(ledger: &'a FileLedger) -> Self {
25        Self { ledger }
26    }
27
28    /// Prepare a file for proving by applying erasure coding, chunking, and building a Merkle tree.
29    ///
30    /// This method uses the fixed chunk size from config::CHUNK_SIZE_BYTES and stores
31    /// the filename in the FileMetadata for operator UX.
32    ///
33    /// # Arguments
34    ///
35    /// * `data` - The raw file data to be processed
36    /// * `erasure_config` - Reed-Solomon erasure coding configuration
37    /// * `filename` - Filename for identification and UX
38    ///
39    /// # Returns
40    ///
41    /// Returns a tuple of (PreparedFile, FileMetadata) where:
42    /// - PreparedFile contains the private Merkle tree and file identifiers
43    /// - FileMetadata contains the public commitment and reconstruction information
44    pub fn prepare_file(
45        &self,
46        data: &[u8],
47        filename: &str,
48        nonce: &[u8],
49    ) -> Result<(PreparedFile, FileMetadata)> {
50        // Use the existing prepare_file function from mod.rs
51        super::prepare_file(data, filename, nonce)
52    }
53
54    /// Generate a single compact proof for any set of open Challenges.
55    ///
56    /// This method accepts a `Vec<PreparedFile>` and internally maps it to the
57    /// BTreeMap structure required by the underlying proving logic. Seeds
58    /// must be identical across all challenges in the batch.
59    ///
60    /// # Arguments
61    ///
62    /// * `files` - Vector of prepared files to prove
63    /// * `challenges` - Slice of challenges to answer
64    ///
65    /// # Returns
66    ///
67    /// Returns a Proof containing the compressed SNARK and the challenge IDs
68    pub fn prove(&self, files: Vec<&PreparedFile>, challenges: &[Challenge]) -> Result<Proof> {
69        // Convert Vec<&PreparedFile> to BTreeMap<String, &PreparedFile>
70        let mut files_map = BTreeMap::new();
71        for file in files {
72            if files_map.insert(file.file_id.clone(), file).is_some() {
73                return Err(KontorPoRError::InvalidInput(format!(
74                    "Duplicate file_id provided: {}",
75                    file.file_id
76                )));
77            }
78        }
79
80        // Validate that all files referenced by challenges are present
81        for challenge in challenges {
82            if !files_map.contains_key(&challenge.file_metadata.file_id) {
83                return Err(KontorPoRError::FileNotFound {
84                    file_id: challenge.file_metadata.file_id.clone(),
85                });
86            }
87        }
88
89        debug!(
90            "PorSystem::prove - {} files, {} challenges",
91            files_map.len(),
92            challenges.len()
93        );
94
95        // Use the existing prove function from prove.rs
96        super::prove::prove(challenges, &files_map, self.ledger, None)
97    }
98
99    /// Verify a proof against the Challenges it claims to answer.
100    ///
101    /// This method validates that the proof's challenge_ids exactly match
102    /// the provided challenges and then performs SNARK verification.
103    ///
104    /// # Arguments
105    ///
106    /// * `proof` - The proof to verify
107    /// * `challenges` - The challenges that the proof claims to answer
108    ///
109    /// # Returns
110    ///
111    /// Returns Ok(true) if the proof is valid, Ok(false) if invalid,
112    /// or an error if verification fails unexpectedly.
113    pub fn verify(&self, proof: &Proof, challenges: &[Challenge]) -> Result<bool> {
114        // Validate that proof.challenge_ids matches the provided challenges
115        let expected_ids: Vec<_> = challenges.iter().map(|c| c.id()).collect();
116
117        if proof.challenge_ids.len() != expected_ids.len() {
118            return Err(KontorPoRError::InvalidInput(format!(
119                "Challenge count mismatch: proof covers {} challenges, provided {}",
120                proof.challenge_ids.len(),
121                expected_ids.len()
122            )));
123        }
124
125        // Check that all challenge IDs match (order matters for Nova)
126        for (i, (proof_id, expected_id)) in proof
127            .challenge_ids
128            .iter()
129            .zip(expected_ids.iter())
130            .enumerate()
131        {
132            if proof_id != expected_id {
133                return Err(KontorPoRError::InvalidInput(format!(
134                    "Challenge ID mismatch at position {}: proof has {:?}, expected {:?}",
135                    i, proof_id.0, expected_id.0
136                )));
137            }
138        }
139
140        debug!(
141            "PorSystem::verify - validated {} challenge IDs",
142            challenges.len()
143        );
144
145        // Use the existing verify function from verify.rs
146        super::verify::verify(challenges, proof, self.ledger)
147    }
148}