[go: up one dir, main page]

rlnc/
lib.rs

1//! # rlnc: Random Linear Network Coding
2//!
3//! `rlnc` is a Rust library that provides an implementation of Random Linear Network Coding (RLNC) over finite field $GF(2^8)$.
4//!
5//! At source, data owner creates encoded (i.e. erasure-coded) pieces by computing random linear combinations of
6//! original data (always padded to ensure safe decoding) split into smaller pieces using random sampled coding coefficients.
7//! These erasure-coded pieces, tagged with random coding vectors, are forwarded to peers.
8//!
9//! Intermediate nodes in the network can combine any number of coded pieces to create new coded pieces, without
10//! ever decoding to original data. This is where recoder comes into play. And one of the reasons why RLNC shines
11//! as an advanced erasure-coding technique.
12//!
13//! Receiving nodes decode the original data by collecting enough linearly independent combinations to solve
14//! the linear system of equations i.e. nothing but the source pieces. This is the most compute-intensive part of RLNC.
15//! And this is also the slowest part of RLNC, orders of magnitude slower compared to encoder and recoder.
16//!
17//! RLNC enhances network throughput, robustness, and efficiency, particularly in lossy or dynamic networks.
18//! It can be used in applications like video streaming, distributed storage, and satellite communications,
19//! improving reliability and reducing latency. In RLNC each erasure-coded piece is equally important to the decoder,
20//! hence order of received pieces do not matter.
21//!
22//! ## How it Works
23//!
24//! At its core, RLNC works by mixing original data pieces into new "coded pieces"
25//! using random linear combinations over $GF(2^8)$.
26//!
27//! The main components of this library are:
28//!
29//! -   **`Encoder`**: Takes the original data, pads it properly, splits it into fixed-size pieces,
30//!     and generates new coded pieces by applying random linear combinations.
31//!     Each coded piece includes a coding vector and the linearly combined data.
32//!     The encoder handles necessary padding and a boundary marker is inserted to ensure
33//!     correct data recovery post decoding.
34//!
35//! -   **`Recoder`**: A crucial feature of network coding. A recoder takes
36//!     already coded pieces as input and generates *new* coded pieces from them.
37//!     This allows intermediate nodes in a network to participate in erasure-coding process,
38//!     recoding without first decoding it to the original form, significantly improving
39//!     throughput and robustness in complex network topologies.
40//!
41//! -   **`Decoder`**: Receives coded pieces and attempts to reconstruct the original data.
42//!     It employs repeated Gaussian elimination to decode received pieces. As soon as enough
43//!     linearly independent pieces are received, it can reconstruct the original data, regardless
44//!     of which specific pieces were lost or received, in whichever order.
45//!
46//! ## Features
47//!
48//! -   **Flexible data handling**: Supports arbitrary byte lengths for input
49//!     data, with internal padding and boundary markers for robust decoding.
50//! -   **Error Handling**: Comprehensive `RLNCError` enum for various failure scenarios.
51//!
52//! ## Example Usage
53//!
54//! A typical workflow involves creating an `Encoder` with your original data,
55//! generating arbitrary many coded pieces, sending them across a network (potentially through `Recoder`s),
56//! and finally, using a `Decoder` to reconstruct the original data.
57//!
58//! ```rust
59//! use rand::Rng;
60//! use rlnc::{
61//!     RLNCError,
62//!     full::{Decoder, Encoder, Recoder},
63//! };
64//!
65//! let mut rng = rand::rng();
66//!
67//! // 1. Define original data parameters
68//! let original_data_len = 10 * 1024;              // 10 KB
69//! let piece_count = 32;                           // Data will be split into 32 pieces
70//! let num_pieces_for_recoding = piece_count / 2;  // For recoding, 16 coded pieces to be used
71//! let original_data: Vec<u8> = (0..original_data_len).map(|_| rng.random()).collect();
72//! let original_data_copy = original_data.clone();
73//!
74//! // 2. Initialize the Encoder
75//! let encoder = Encoder::new(original_data, piece_count).expect("Failed to create RLNC encoder");
76//!
77//! // 3. Generate 16 coded-pieces, to be used by the Recoder for producing new coded pieces.
78//! let coded_pieces_for_recoding: Vec<u8> = (0..num_pieces_for_recoding).flat_map(|_| encoder.code(&mut rng)).collect();
79//!
80//! // 4. Initialize the Recoder with 16 coded pieces
81//! let mut recoder = Recoder::new(coded_pieces_for_recoding, encoder.get_full_coded_piece_byte_len(), encoder.get_piece_count()).expect("Failed to create RLNC recoder");
82//!
83//! // 5. Initialize the Decoder
84//! let mut decoder = Decoder::new(encoder.get_piece_byte_len(), encoder.get_piece_count()).expect("Failed to create RLNC decoder");
85//!
86//! // 6. Generate a recoded piece, this is the piece to be sent to the decoder as first piece.
87//! let recoded_piece = recoder.recode(&mut rng);
88//!
89//! // 7. First coded piece injected into the Decoder - it should be useful
90//! decoder.decode(&recoded_piece).expect("First coded piece should be useful");
91//!
92//! // 8. Generate coded pieces directly from the encoder and feed them to the decoder until decoding is complete
93//! while !decoder.is_already_decoded() {
94//!     let coded_piece = encoder.code(&mut rng);
95//!
96//!     match decoder.decode(&coded_piece) {
97//!         Ok(_) => {},                                // Piece was useful
98//!         Err(RLNCError::PieceNotUseful) => {},       // Piece was not useful (linearly dependent)
99//!         Err(RLNCError::ReceivedAllPieces) => break, // Already decoded
100//!         Err(e) => panic!("Unexpected error during decoding: {e:?}"),
101//!     }
102//! }
103//!
104//! // 5. Retrieve the decoded data
105//! let decoded_data = decoder.get_decoded_data().expect("Failed to retrieve decoded data even after all pieces are received");
106//!
107//! // 6. Verify that the decoded data matches the original data
108//! assert_eq!(original_data_copy, decoded_data);
109//! println!("RLNC workflow completed successfully! Original data matches decoded data.");
110//! ```
111//!
112//! ## Installation
113//!
114//! Add this to your `Cargo.toml`:
115//!
116//! ```toml
117//! [dependencies]
118//! rlnc = "=0.8.5"                                      # On x86_64 and aarch64 targets, it offers fast encoding, recoding and decoding, using SIMD intrinsics.
119//! # or
120//! rlnc = { version = "=0.8.5", features = "parallel" } # Uses `rayon`-based data-parallelism for fast encoding/ recoding. Decoding is not yet parallelized.
121//!
122//! rand = { version = "=0.9.1" } # Required for random number generation
123//! ```
124//!
125//! For more see README in `rlnc` repository @ <https://github.com/itzmeanjan/rlnc>.
126
127mod common;
128
129pub mod full;
130pub use crate::common::errors::RLNCError;