1use chie_crypto::hash::{IncrementalHasher, hash};
43use serde::{Deserialize, Serialize};
44use std::collections::HashMap;
45use thiserror::Error;
46
47const MERKLE_CHUNK_SIZE: usize = 256 * 1024;
49
50#[derive(Debug, Error)]
52pub enum VerificationError {
53 #[error("Hash mismatch: expected {expected:?}, got {actual:?}")]
54 HashMismatch {
55 expected: [u8; 32],
56 actual: [u8; 32],
57 },
58
59 #[error("Incomplete verification: {0} bytes processed, {1} bytes expected")]
60 Incomplete(u64, u64),
61
62 #[error("Chunk {0} failed verification")]
63 ChunkFailed(u64),
64
65 #[error("Merkle tree error: {0}")]
66 MerkleError(String),
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct VerificationResult {
72 pub verified: bool,
74 pub bytes_verified: u64,
76 pub actual_hash: [u8; 32],
78 pub expected_hash: [u8; 32],
80 pub chunks_verified: u64,
82}
83
84impl VerificationResult {
85 #[must_use]
87 #[inline]
88 pub const fn is_verified(&self) -> bool {
89 self.verified
90 }
91
92 #[must_use]
94 #[inline]
95 pub fn hash_mismatch(&self) -> Option<([u8; 32], [u8; 32])> {
96 if !self.verified {
97 Some((self.expected_hash, self.actual_hash))
98 } else {
99 None
100 }
101 }
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct VerificationProgress {
107 pub bytes_processed: u64,
109 pub total_bytes: Option<u64>,
111 pub chunks_processed: u64,
113 pub percentage: f64,
115}
116
117impl VerificationProgress {
118 #[must_use]
120 #[inline]
121 pub fn is_complete(&self) -> bool {
122 if let Some(total) = self.total_bytes {
123 self.bytes_processed >= total
124 } else {
125 false
126 }
127 }
128}
129
130pub struct StreamingVerifier {
132 hasher: IncrementalHasher,
134 expected_hash: [u8; 32],
136 bytes_processed: u64,
138 total_bytes: Option<u64>,
140 chunks_processed: u64,
142}
143
144impl StreamingVerifier {
145 #[must_use]
147 pub fn new(expected_hash: [u8; 32]) -> Self {
148 Self {
149 hasher: IncrementalHasher::new(),
150 expected_hash,
151 bytes_processed: 0,
152 total_bytes: None,
153 chunks_processed: 0,
154 }
155 }
156
157 #[must_use]
159 pub fn with_size(expected_hash: [u8; 32], total_bytes: u64) -> Self {
160 Self {
161 hasher: IncrementalHasher::new(),
162 expected_hash,
163 bytes_processed: 0,
164 total_bytes: Some(total_bytes),
165 chunks_processed: 0,
166 }
167 }
168
169 pub fn update(&mut self, data: &[u8]) {
171 self.hasher.update(data);
172 self.bytes_processed += data.len() as u64;
173 self.chunks_processed += 1;
174 }
175
176 #[must_use]
178 #[inline]
179 pub fn progress(&self) -> VerificationProgress {
180 let percentage = if let Some(total) = self.total_bytes {
181 if total > 0 {
182 (self.bytes_processed as f64 / total as f64) * 100.0
183 } else {
184 100.0
185 }
186 } else {
187 0.0
188 };
189
190 VerificationProgress {
191 bytes_processed: self.bytes_processed,
192 total_bytes: self.total_bytes,
193 chunks_processed: self.chunks_processed,
194 percentage,
195 }
196 }
197
198 pub fn finalize(self) -> Result<VerificationResult, VerificationError> {
200 let actual_hash: [u8; 32] = self.hasher.finalize();
201 let verified = actual_hash == self.expected_hash;
202
203 if !verified {
204 return Err(VerificationError::HashMismatch {
205 expected: self.expected_hash,
206 actual: actual_hash,
207 });
208 }
209
210 Ok(VerificationResult {
211 verified,
212 bytes_verified: self.bytes_processed,
213 actual_hash,
214 expected_hash: self.expected_hash,
215 chunks_verified: self.chunks_processed,
216 })
217 }
218
219 pub fn reset(&mut self) {
221 self.hasher = IncrementalHasher::new();
222 self.bytes_processed = 0;
223 self.chunks_processed = 0;
224 }
225}
226
227pub struct MerkleVerifier {
229 expected_root: [u8; 32],
231 chunk_hashes: HashMap<u64, [u8; 32]>,
233 chunk_size: usize,
235 total_chunks: u64,
237}
238
239impl MerkleVerifier {
240 #[must_use]
242 pub fn new(expected_root: [u8; 32], chunk_size: usize, total_chunks: u64) -> Self {
243 Self {
244 expected_root,
245 chunk_hashes: HashMap::new(),
246 chunk_size,
247 total_chunks,
248 }
249 }
250
251 #[must_use]
253 pub fn with_default_chunk_size(expected_root: [u8; 32], total_chunks: u64) -> Self {
254 Self::new(expected_root, MERKLE_CHUNK_SIZE, total_chunks)
255 }
256
257 pub fn verify_chunk(&mut self, chunk_index: u64, data: &[u8]) -> Result<(), VerificationError> {
259 let chunk_hash: [u8; 32] = hash(data);
261
262 self.chunk_hashes.insert(chunk_index, chunk_hash);
264
265 Ok(())
266 }
267
268 pub fn verify_merkle_root(&self) -> Result<VerificationResult, VerificationError> {
270 if self.chunk_hashes.len() as u64 != self.total_chunks {
271 return Err(VerificationError::Incomplete(
272 self.chunk_hashes.len() as u64,
273 self.total_chunks,
274 ));
275 }
276
277 let mut current_level: Vec<[u8; 32]> = (0..self.total_chunks)
279 .map(|i| self.chunk_hashes.get(&i).copied().unwrap_or([0u8; 32]))
280 .collect();
281
282 while current_level.len() > 1 {
284 let mut next_level = Vec::new();
285
286 for chunk in current_level.chunks(2) {
287 let combined_hash = if chunk.len() == 2 {
288 let mut combined = [0u8; 64];
290 combined[..32].copy_from_slice(&chunk[0]);
291 combined[32..].copy_from_slice(&chunk[1]);
292 hash(&combined)
293 } else {
294 chunk[0]
296 };
297 next_level.push(combined_hash);
298 }
299
300 current_level = next_level;
301 }
302
303 let actual_root = current_level[0];
304 let verified = actual_root == self.expected_root;
305
306 if !verified {
307 return Err(VerificationError::HashMismatch {
308 expected: self.expected_root,
309 actual: actual_root,
310 });
311 }
312
313 Ok(VerificationResult {
314 verified,
315 bytes_verified: (self.total_chunks * self.chunk_size as u64),
316 actual_hash: actual_root,
317 expected_hash: self.expected_root,
318 chunks_verified: self.total_chunks,
319 })
320 }
321
322 #[must_use]
324 #[inline]
325 pub fn chunks_verified(&self) -> u64 {
326 self.chunk_hashes.len() as u64
327 }
328
329 #[must_use]
331 #[inline]
332 pub fn is_complete(&self) -> bool {
333 self.chunk_hashes.len() as u64 == self.total_chunks
334 }
335
336 #[must_use]
338 pub fn progress(&self) -> VerificationProgress {
339 let chunks_verified = self.chunk_hashes.len() as u64;
340 let percentage = if self.total_chunks > 0 {
341 (chunks_verified as f64 / self.total_chunks as f64) * 100.0
342 } else {
343 0.0
344 };
345
346 VerificationProgress {
347 bytes_processed: chunks_verified * self.chunk_size as u64,
348 total_bytes: Some(self.total_chunks * self.chunk_size as u64),
349 chunks_processed: chunks_verified,
350 percentage,
351 }
352 }
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize)]
357pub struct VerificationCheckpoint {
358 pub bytes_processed: u64,
360 pub chunks_processed: u64,
362 pub hash_state: Vec<u8>,
364}
365
366impl VerificationCheckpoint {
367 #[must_use]
369 pub fn new(bytes_processed: u64, chunks_processed: u64) -> Self {
370 Self {
371 bytes_processed,
372 chunks_processed,
373 hash_state: Vec::new(), }
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use super::*;
381
382 #[test]
383 fn test_streaming_verifier_success() {
384 let data = b"Hello, World!";
385 let expected_hash: [u8; 32] = hash(data);
386
387 let mut verifier = StreamingVerifier::new(expected_hash);
388 verifier.update(data);
389
390 let result = verifier.finalize().unwrap();
391 assert!(result.verified);
392 assert_eq!(result.bytes_verified, data.len() as u64);
393 }
394
395 #[test]
396 fn test_streaming_verifier_incremental() {
397 let part1 = b"Hello, ";
398 let part2 = b"World!";
399 let full_data = b"Hello, World!";
400 let expected_hash: [u8; 32] = hash(full_data);
401
402 let mut verifier = StreamingVerifier::new(expected_hash);
403 verifier.update(part1);
404 verifier.update(part2);
405
406 let result = verifier.finalize().unwrap();
407 assert!(result.verified);
408 assert_eq!(result.bytes_verified, full_data.len() as u64);
409 assert_eq!(result.chunks_verified, 2);
410 }
411
412 #[test]
413 fn test_streaming_verifier_mismatch() {
414 let data = b"Hello, World!";
415 let wrong_hash = [0u8; 32];
416
417 let mut verifier = StreamingVerifier::new(wrong_hash);
418 verifier.update(data);
419
420 let result = verifier.finalize();
421 assert!(result.is_err());
422 }
423
424 #[test]
425 fn test_streaming_verifier_progress() {
426 let data = b"Hello, World!";
427 let expected_hash: [u8; 32] = hash(data);
428
429 let mut verifier = StreamingVerifier::with_size(expected_hash, data.len() as u64);
430 verifier.update(&data[..5]);
431
432 let progress = verifier.progress();
433 assert_eq!(progress.bytes_processed, 5);
434 assert_eq!(progress.total_bytes, Some(data.len() as u64));
435 assert!(!progress.is_complete());
436
437 verifier.update(&data[5..]);
438
439 let progress = verifier.progress();
440 assert!(progress.is_complete());
441 assert_eq!(progress.percentage, 100.0);
442 }
443
444 #[test]
445 fn test_merkle_verifier_single_chunk() {
446 let data = b"Hello, World!";
447 let chunk_hash: [u8; 32] = hash(data);
448
449 let mut verifier = MerkleVerifier::new(chunk_hash, 1024, 1);
450 verifier.verify_chunk(0, data).unwrap();
451
452 assert!(verifier.is_complete());
453 let result = verifier.verify_merkle_root().unwrap();
454 assert!(result.verified);
455 }
456
457 #[test]
458 fn test_merkle_verifier_multiple_chunks() {
459 let chunk1 = b"Hello, ";
460 let chunk2 = b"World!";
461
462 let hash1: [u8; 32] = hash(chunk1);
464 let hash2: [u8; 32] = hash(chunk2);
465 let mut combined = [0u8; 64];
466 combined[..32].copy_from_slice(&hash1);
467 combined[32..].copy_from_slice(&hash2);
468 let root: [u8; 32] = hash(&combined);
469
470 let mut verifier = MerkleVerifier::new(root, 1024, 2);
471 verifier.verify_chunk(0, chunk1).unwrap();
472 verifier.verify_chunk(1, chunk2).unwrap();
473
474 assert_eq!(verifier.chunks_verified(), 2);
475 assert!(verifier.is_complete());
476
477 let result = verifier.verify_merkle_root().unwrap();
478 assert!(result.verified);
479 }
480
481 #[test]
482 fn test_merkle_verifier_incomplete() {
483 let data = b"Hello, World!";
484 let chunk_hash: [u8; 32] = hash(data);
485
486 let mut verifier = MerkleVerifier::new(chunk_hash, 1024, 2);
487 verifier.verify_chunk(0, data).unwrap();
488
489 assert!(!verifier.is_complete());
490 assert_eq!(verifier.chunks_verified(), 1);
491
492 let result = verifier.verify_merkle_root();
493 assert!(result.is_err());
494 }
495
496 #[test]
497 fn test_merkle_verifier_progress() {
498 let chunk1 = b"Hello";
499 let chunk_hash: [u8; 32] = hash(chunk1);
500
501 let mut verifier = MerkleVerifier::with_default_chunk_size(chunk_hash, 4);
502 verifier.verify_chunk(0, chunk1).unwrap();
503
504 let progress = verifier.progress();
505 assert_eq!(progress.chunks_processed, 1);
506 assert_eq!(progress.percentage, 25.0);
507 }
508
509 #[test]
510 fn test_streaming_verifier_reset() {
511 let data = b"Hello, World!";
512 let expected_hash: [u8; 32] = hash(data);
513
514 let mut verifier = StreamingVerifier::new(expected_hash);
515 verifier.update(data);
516
517 verifier.reset();
518
519 assert_eq!(verifier.bytes_processed, 0);
520 assert_eq!(verifier.chunks_processed, 0);
521 }
522
523 #[test]
524 fn test_verification_result_helpers() {
525 let result = VerificationResult {
526 verified: false,
527 bytes_verified: 100,
528 actual_hash: [1u8; 32],
529 expected_hash: [2u8; 32],
530 chunks_verified: 10,
531 };
532
533 assert!(!result.is_verified());
534 assert!(result.hash_mismatch().is_some());
535 let (expected, actual) = result.hash_mismatch().unwrap();
536 assert_eq!(expected, [2u8; 32]);
537 assert_eq!(actual, [1u8; 32]);
538 }
539}