decds_lib/
lib.rs

1//! # DECDS-lib: Decentralized Erasure-Coded Data Storage Library
2//!
3//! `decds-lib` provides functionalities for creating, storing, retrieving, and repairing arbitrary size data blobs
4//! using Random Linear Network Coding (RLNC) based erasure-coding and binary Merkle trees for data integrity verification.
5//!
6//! This library is designed to enable decentralized data storage solutions by breaking down
7//! large data into smaller, verifiable, and reconstructible chunks.
8//!
9//! ## How to Use
10//!
11//! ### 1. Create a Blob
12//!
13//! To store data, first create a `Blob` from a `Vec<u8>`. The `Blob::new` function
14//! takes your raw data, divides it into chunksets, applies erasure coding, and builds
15//! Merkle trees for both chunkset-level and blob-level integrity.
16//!
17//! ```rust
18//! use decds_lib::Blob;
19//! use rand::Rng; // Assuming `rand` is available in your project for example data
20//!
21//! let mut rng = rand::thread_rng();
22//! let original_data: Vec<u8> = (0..1024 * 1024 * 50).map(|_| rng.random()).collect(); // 50MB of random data
23//! let blob = Blob::new(original_data).expect("Failed to create blob");
24//! println!("Blob created with size: {} bytes", blob.get_blob_header().get_blob_size());
25//! ```
26//!
27//! ### 2. Retrieve Erasure-Coded Shares (Proof-Carrying Chunks)
28//!
29//! Once a `Blob` is created, you can retrieve its erasure-coded shares. Each share is a `Vec<ProofCarryingChunk>`,
30//! where each `ProofCarryingChunk` is a verifiable piece of data.
31//! You need `DECDS_NUM_ERASURE_CODED_SHARES` total shares per chunkset, but only `ChunkSet::NUM_ORIGINAL_CHUNKS`
32//! (which is 10) are needed to reconstruct the original data of that chunkset.
33//!
34//! ```rust
35//! use decds_lib::{Blob, DECDS_NUM_ERASURE_CODED_SHARES};
36//! use rand::Rng;
37//!
38//! let mut rng = rand::thread_rng();
39//! let original_data: Vec<u8> = (0..1024).map(|_| rng.random()).collect();
40//! let blob = Blob::new(original_data).expect("Failed to create blob");
41//!
42//! let first_share = blob.get_share(0).expect("Failed to get share");
43//! println!("Retrieved {} chunks for share 0.", first_share.len());
44//!
45//! // You can iterate through all available shares:
46//! for share_id in 0..DECDS_NUM_ERASURE_CODED_SHARES {
47//!     let share = blob.get_share(share_id).expect("Failed to get share");
48//!     // Do something with the share, e.g., send it to a storage node
49//! }
50//! ```
51//!
52//! ### 3. Repair/Reconstruct a Blob
53//!
54//! To reconstruct the original blob data, you need to collect enough `ProofCarryingChunk`s.
55//! You initialize a `RepairingBlob` with the `BlobHeader` (which can be serialized/deserialized),
56//! and then add chunks to it. Once enough chunks for a specific chunkset are collected,
57//! you can retrieve its repaired data.
58//!
59//! ```rust
60//! use decds_lib::{Blob, BlobHeader, ProofCarryingChunk, RepairingBlob, DECDS_NUM_ERASURE_CODED_SHARES, DecdsError};
61//! use rand::{Rng, seq::SliceRandom};
62//!
63//! let mut rng = rand::thread_rng();
64//! let original_data: Vec<u8> = (0..1024 * 1024 * 50).map(|_| rng.random()).collect(); // 50MB of random data
65//! let original_data_copy = original_data.clone();
66//!
67//! let blob = Blob::new(original_data).expect("Failed to create blob");
68//! let blob_header = blob.get_blob_header().clone();
69//!
70//! // Collect all chunks from the blob (simulate receiving them from storage)
71//! let mut all_chunks: Vec<ProofCarryingChunk> = (0..DECDS_NUM_ERASURE_CODED_SHARES)
72//!     .flat_map(|share_id| blob.get_share(share_id).unwrap())
73//!     .collect();
74//!
75//! // Simulate data loss by shuffling and taking only a subset (but enough for repair)
76//! // In a real scenario, you'd receive chunks from various sources
77//! all_chunks.shuffle(&mut rng);
78//!
79//! let mut repairer = RepairingBlob::new(blob_header.clone());
80//! let num_chunksets = blob_header.get_num_chunksets();
81//!
82//! // Add chunks to the repairer until all chunksets are repaired
83//! let mut chunk_idx = 0;
84//! let mut repaired_chunksets_count = 0;
85//!
86//! while repaired_chunksets_count < num_chunksets {
87//!     if chunk_idx >= all_chunks.len() {
88//!         println!("Not enough chunks to repair the entire blob!");
89//!         break;
90//!     }
91//!     let chunk = &all_chunks[chunk_idx];
92//!     let chunkset_id = chunk.get_chunkset_id();
93//!     // Try to add the chunk, handling various repair states
94//!     match repairer.add_chunk(chunk) {
95//!         Ok(_) => {
96//!             if repairer.is_chunkset_ready_to_repair(chunkset_id).expect("Failed to check chunkset repair status") {
97//!                 repaired_chunksets_count += 1;
98//!                 println!("Repaired chunkset {}!", chunkset_id);
99//!             }
100//!         },
101//!         Err(e) => {
102//!             // Handle cases where the chunk is not useful or chunkset is already repaired
103//!             match e {
104//!                 DecdsError::ChunksetReadyToRepair(_) | DecdsError::ChunksetAlreadyRepaired(_) | DecdsError::InvalidProofInChunk(_) => {
105//!                     // Chunk is redundant, already repaired, or invalid; simply skip it.
106//!                     // In a real system, invalid chunks would indicate a security issue.
107//!                 },
108//!                 _ => {
109//!                     eprintln!("Error adding chunk: {}", e);
110//!                     std::process::exit(1);
111//!                 },
112//!             }
113//!         },
114//!     }
115//!     chunk_idx += 1;
116//! }
117//!
118//! let final_repaired_data = (0..blob_header.get_num_chunksets()).flat_map(|chunkset_id| {
119//!     repairer.get_repaired_chunkset(chunkset_id).expect("Failed to get repaired chunkset")
120//! }).collect::<Vec<u8>>();
121//!
122//! assert_eq!(original_data_copy, final_repaired_data);
123//! println!("Blob successfully repaired and verified!");
124//! ```
125
126mod blob;
127mod chunk;
128mod chunkset;
129mod consts;
130mod errors;
131mod merkle_tree;
132
133#[cfg(test)]
134mod tests;
135
136pub use blob::{Blob, BlobHeader, RepairingBlob};
137pub use chunk::ProofCarryingChunk;
138pub use chunkset::RepairingChunkSet;
139pub use consts::DECDS_NUM_ERASURE_CODED_SHARES;
140pub use errors::DecdsError;