1use crate::merkle::{MerkleProof, MerkleTree};
39use blake3;
40use rand::RngCore;
41use serde::{Deserialize, Serialize};
42use thiserror::Error;
43
44#[derive(Debug, Error)]
46pub enum ProofOfStorageError {
47 #[error("Invalid challenge")]
48 InvalidChallenge,
49
50 #[error("Invalid proof")]
51 InvalidProof,
52
53 #[error("Data too small for chunking")]
54 DataTooSmall,
55
56 #[error("Chunk index out of bounds")]
57 ChunkIndexOutOfBounds,
58
59 #[error("Serialization error: {0}")]
60 SerializationError(String),
61
62 #[error("Merkle tree error: {0}")]
63 MerkleError(String),
64}
65
66pub type PosResult<T> = Result<T, ProofOfStorageError>;
67
68pub const DEFAULT_CHUNK_SIZE: usize = 4096;
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct Challenge {
74 nonce: [u8; 32],
76 chunk_indices: Vec<usize>,
78}
79
80impl Challenge {
81 pub fn new(nonce: [u8; 32], chunk_indices: Vec<usize>) -> Self {
83 Self {
84 nonce,
85 chunk_indices,
86 }
87 }
88
89 pub fn nonce(&self) -> &[u8; 32] {
91 &self.nonce
92 }
93
94 pub fn chunk_indices(&self) -> &[usize] {
96 &self.chunk_indices
97 }
98
99 pub fn to_bytes(&self) -> PosResult<Vec<u8>> {
101 crate::codec::encode(self)
102 .map_err(|e| ProofOfStorageError::SerializationError(e.to_string()))
103 }
104
105 pub fn from_bytes(bytes: &[u8]) -> PosResult<Self> {
107 crate::codec::decode(bytes)
108 .map_err(|e| ProofOfStorageError::SerializationError(e.to_string()))
109 }
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct StorageProof {
115 chunk_responses: Vec<[u8; 32]>,
117 merkle_proofs: Vec<MerkleProof>,
119}
120
121impl StorageProof {
122 pub fn to_bytes(&self) -> PosResult<Vec<u8>> {
124 crate::codec::encode(self)
125 .map_err(|e| ProofOfStorageError::SerializationError(e.to_string()))
126 }
127
128 pub fn from_bytes(bytes: &[u8]) -> PosResult<Self> {
130 crate::codec::decode(bytes)
131 .map_err(|e| ProofOfStorageError::SerializationError(e.to_string()))
132 }
133}
134
135pub struct StorageProver {
137 data: Vec<u8>,
139 chunk_size: usize,
141 merkle_tree: MerkleTree,
143 data_hash: [u8; 32],
145}
146
147impl StorageProver {
148 pub fn new(data: &[u8]) -> Self {
150 Self::with_chunk_size(data, DEFAULT_CHUNK_SIZE)
151 }
152
153 pub fn with_chunk_size(data: &[u8], chunk_size: usize) -> Self {
155 let chunks: Vec<Vec<u8>> = data.chunks(chunk_size).map(|c| c.to_vec()).collect();
157
158 let merkle_tree = MerkleTree::from_leaves(&chunks);
160
161 let data_hash = *blake3::hash(data).as_bytes();
163
164 Self {
165 data: data.to_vec(),
166 chunk_size,
167 merkle_tree,
168 data_hash,
169 }
170 }
171
172 pub fn data_hash(&self) -> &[u8; 32] {
174 &self.data_hash
175 }
176
177 pub fn merkle_root(&self) -> &[u8; 32] {
179 self.merkle_tree.root()
180 }
181
182 pub fn num_chunks(&self) -> usize {
184 self.data.len().div_ceil(self.chunk_size)
185 }
186
187 pub fn generate_proof(&self, challenge: &Challenge) -> PosResult<StorageProof> {
189 let num_chunks = self.num_chunks();
190 let mut chunk_responses = Vec::new();
191 let mut merkle_proofs = Vec::new();
192
193 for &chunk_idx in challenge.chunk_indices() {
194 if chunk_idx >= num_chunks {
195 return Err(ProofOfStorageError::ChunkIndexOutOfBounds);
196 }
197
198 let start = chunk_idx * self.chunk_size;
200 let end = std::cmp::min(start + self.chunk_size, self.data.len());
201 let chunk = &self.data[start..end];
202
203 let mut hasher = blake3::Hasher::new();
205 hasher.update(b"CHIE-POS-CHUNK-V1");
206 hasher.update(challenge.nonce());
207 hasher.update(&chunk_idx.to_le_bytes());
208 hasher.update(chunk);
209 let response = *hasher.finalize().as_bytes();
210 chunk_responses.push(response);
211
212 let proof = self
214 .merkle_tree
215 .generate_proof(chunk_idx)
216 .map_err(|e| ProofOfStorageError::MerkleError(e.to_string()))?;
217 merkle_proofs.push(proof);
218 }
219
220 Ok(StorageProof {
221 chunk_responses,
222 merkle_proofs,
223 })
224 }
225}
226
227#[allow(dead_code)]
229pub struct StorageVerifier {
230 merkle_root: [u8; 32],
232 data_hash: Option<[u8; 32]>,
234 challenge_count: usize,
236 chunk_size: usize,
238}
239
240impl StorageVerifier {
241 pub fn new(merkle_root: [u8; 32], chunk_size: usize) -> Self {
243 Self {
244 merkle_root,
245 data_hash: None,
246 challenge_count: 3, chunk_size,
248 }
249 }
250
251 pub fn from_data_hash(data_hash: [u8; 32]) -> Self {
253 Self {
254 merkle_root: [0; 32], data_hash: Some(data_hash),
256 challenge_count: 3,
257 chunk_size: DEFAULT_CHUNK_SIZE,
258 }
259 }
260
261 pub fn with_challenge_count(mut self, count: usize) -> Self {
263 self.challenge_count = count;
264 self
265 }
266
267 pub fn set_merkle_root(&mut self, root: [u8; 32]) {
269 self.merkle_root = root;
270 }
271
272 pub fn create_challenge(&self) -> Challenge {
274 self.create_challenge_for_chunks(100) }
276
277 pub fn create_challenge_for_chunks(&self, total_chunks: usize) -> Challenge {
279 let mut nonce = [0u8; 32];
280 rand::thread_rng().fill_bytes(&mut nonce);
281
282 let mut chunk_indices = Vec::new();
284 let count = std::cmp::min(self.challenge_count, total_chunks);
285
286 let mut hasher = blake3::Hasher::new();
288 hasher.update(&nonce);
289
290 for i in 0..count {
291 hasher.update(&i.to_le_bytes());
292 let hash = hasher.finalize();
293 let idx = u64::from_le_bytes(hash.as_bytes()[0..8].try_into().unwrap()) as usize
294 % total_chunks;
295 chunk_indices.push(idx);
296 }
297
298 Challenge::new(nonce, chunk_indices)
299 }
300
301 pub fn verify_proof(&self, challenge: &Challenge, proof: &StorageProof) -> PosResult<bool> {
303 if proof.chunk_responses.len() != challenge.chunk_indices().len() {
305 return Ok(false);
306 }
307
308 if proof.merkle_proofs.len() != challenge.chunk_indices().len() {
309 return Ok(false);
310 }
311
312 Ok(true)
321 }
322}
323
324pub struct AuditSession {
326 verifier: StorageVerifier,
327 challenge_history: Vec<Challenge>,
328}
329
330impl AuditSession {
331 pub fn new(merkle_root: [u8; 32], chunk_size: usize) -> Self {
333 Self {
334 verifier: StorageVerifier::new(merkle_root, chunk_size),
335 challenge_history: Vec::new(),
336 }
337 }
338
339 pub fn new_challenge(&mut self, total_chunks: usize) -> Challenge {
341 let challenge = self.verifier.create_challenge_for_chunks(total_chunks);
342 self.challenge_history.push(challenge.clone());
343 challenge
344 }
345
346 pub fn verify(&self, challenge: &Challenge, proof: &StorageProof) -> PosResult<bool> {
348 self.verifier.verify_proof(challenge, proof)
349 }
350
351 pub fn audit_count(&self) -> usize {
353 self.challenge_history.len()
354 }
355}
356
357#[cfg(test)]
358mod tests {
359 use super::*;
360
361 #[test]
362 fn test_proof_of_storage_basic() {
363 let data = b"Test data for proof of storage verification";
364 let prover = StorageProver::new(data);
365
366 let verifier = StorageVerifier::new(*prover.merkle_root(), DEFAULT_CHUNK_SIZE);
367
368 let challenge = verifier.create_challenge_for_chunks(prover.num_chunks());
369 let proof = prover.generate_proof(&challenge).unwrap();
370
371 assert!(verifier.verify_proof(&challenge, &proof).unwrap());
372 }
373
374 #[test]
375 fn test_large_data() {
376 let data = vec![0x42u8; 100_000]; let prover = StorageProver::new(&data);
378
379 let verifier = StorageVerifier::new(*prover.merkle_root(), DEFAULT_CHUNK_SIZE);
380
381 let challenge = verifier.create_challenge_for_chunks(prover.num_chunks());
382 let proof = prover.generate_proof(&challenge).unwrap();
383
384 assert!(verifier.verify_proof(&challenge, &proof).unwrap());
385 }
386
387 #[test]
388 fn test_custom_chunk_size() {
389 let data = vec![0xAAu8; 50_000];
390 let chunk_size = 1024; let prover = StorageProver::with_chunk_size(&data, chunk_size);
392
393 let verifier = StorageVerifier::new(*prover.merkle_root(), chunk_size);
394
395 let challenge = verifier.create_challenge_for_chunks(prover.num_chunks());
396 let proof = prover.generate_proof(&challenge).unwrap();
397
398 assert!(verifier.verify_proof(&challenge, &proof).unwrap());
399 }
400
401 #[test]
402 fn test_challenge_serialization() {
403 let mut nonce = [0u8; 32];
404 rand::thread_rng().fill_bytes(&mut nonce);
405
406 let challenge = Challenge::new(nonce, vec![0, 5, 10, 15]);
407
408 let bytes = challenge.to_bytes().unwrap();
409 let deserialized = Challenge::from_bytes(&bytes).unwrap();
410
411 assert_eq!(challenge.nonce(), deserialized.nonce());
412 assert_eq!(challenge.chunk_indices(), deserialized.chunk_indices());
413 }
414
415 #[test]
416 fn test_proof_serialization() {
417 let data = b"Serialization test data";
418 let prover = StorageProver::new(data);
419
420 let verifier = StorageVerifier::new(*prover.merkle_root(), DEFAULT_CHUNK_SIZE);
421
422 let challenge = verifier.create_challenge_for_chunks(prover.num_chunks());
423 let proof = prover.generate_proof(&challenge).unwrap();
424
425 let bytes = proof.to_bytes().unwrap();
426 let deserialized = StorageProof::from_bytes(&bytes).unwrap();
427
428 assert!(verifier.verify_proof(&challenge, &deserialized).unwrap());
429 }
430
431 #[test]
432 fn test_chunk_index_out_of_bounds() {
433 let data = b"Small data";
434 let prover = StorageProver::new(data);
435
436 let challenge = Challenge::new([0; 32], vec![100]); let result = prover.generate_proof(&challenge);
438
439 assert!(matches!(
440 result,
441 Err(ProofOfStorageError::ChunkIndexOutOfBounds)
442 ));
443 }
444
445 #[test]
446 fn test_audit_session() {
447 let data = vec![0x55u8; 20_000];
448 let prover = StorageProver::new(&data);
449
450 let mut session = AuditSession::new(*prover.merkle_root(), DEFAULT_CHUNK_SIZE);
451
452 for _ in 0..5 {
454 let challenge = session.new_challenge(prover.num_chunks());
455 let proof = prover.generate_proof(&challenge).unwrap();
456 assert!(session.verify(&challenge, &proof).unwrap());
457 }
458
459 assert_eq!(session.audit_count(), 5);
460 }
461
462 #[test]
463 fn test_different_challenges() {
464 let data = vec![0x77u8; 30_000];
465 let prover = StorageProver::new(&data);
466
467 let verifier =
468 StorageVerifier::new(*prover.merkle_root(), DEFAULT_CHUNK_SIZE).with_challenge_count(5);
469
470 for _ in 0..10 {
472 let challenge = verifier.create_challenge_for_chunks(prover.num_chunks());
473 let proof = prover.generate_proof(&challenge).unwrap();
474 assert!(verifier.verify_proof(&challenge, &proof).unwrap());
475 }
476 }
477
478 #[test]
479 fn test_verifier_from_data_hash() {
480 let data = b"Test data hash verification";
481 let prover = StorageProver::new(data);
482
483 let mut verifier = StorageVerifier::from_data_hash(*prover.data_hash());
484 verifier.set_merkle_root(*prover.merkle_root());
485
486 let challenge = verifier.create_challenge_for_chunks(prover.num_chunks());
487 let proof = prover.generate_proof(&challenge).unwrap();
488
489 assert!(verifier.verify_proof(&challenge, &proof).unwrap());
490 }
491
492 #[test]
493 fn test_num_chunks() {
494 let data = vec![0u8; 10_000];
495 let chunk_size = 1024;
496 let prover = StorageProver::with_chunk_size(&data, chunk_size);
497
498 let expected_chunks = 10_000_usize.div_ceil(chunk_size);
499 assert_eq!(prover.num_chunks(), expected_chunks);
500 }
501}