Skip to main content

zc_rlnc/
lib.rs

1//! # RLNC - Random Linear Network Coding
2//!
3//! This library provides an implementation of Random Linear Network Coding (RLNC)
4//! using BLS12-381 scalar arithmetic.
5
6pub mod commit;
7mod common;
8pub mod decode;
9pub mod encode;
10mod matrix;
11pub mod primitives;
12
13#[cfg(test)]
14mod tests {
15    use blstrs::G1Projective;
16    use group::ff::Field;
17    use rand::Rng;
18    use std::time::{Duration, Instant};
19
20    use crate::commit::PedersenCommitter;
21
22    use super::{decode::Decoder, encode::Encoder, primitives::field::Scalar};
23
24    #[test]
25    fn test_encode_decode_with_random_vectors() {
26        // 128KiB
27        let data_size = 1024 * 1024;
28        let original_data = rand::rng().random_iter().take(data_size).collect::<Vec<_>>();
29
30        let chunk_count = 5;
31
32        println!("Data size: {}KiB, chunk count: {}", data_size / 1024, chunk_count);
33
34        let encoder = Encoder::<Scalar>::new(original_data.clone(), chunk_count).unwrap();
35        println!("Chunk size: {}", encoder.chunk_size());
36
37        let mut coded_packets = Vec::with_capacity(chunk_count);
38
39        let now = Instant::now();
40        for _ in 0..chunk_count {
41            let packet = encoder.encode(rand::rng()).unwrap();
42            coded_packets.push(packet);
43        }
44
45        println!("Encoding time: {:?}", now.elapsed());
46
47        let mut decoder = Decoder::<Scalar>::new(encoder.chunk_size(), chunk_count).unwrap();
48
49        let now = Instant::now();
50        let decoded = loop {
51            if let Some(decoded) = decoder.decode(coded_packets.pop().unwrap()).unwrap() {
52                break decoded;
53            }
54        };
55
56        println!("Decoding time: {:?}", now.elapsed());
57
58        println!("Decoded length: {}", decoded.len());
59        println!("Original length: {}", original_data.len());
60        assert!(decoded.starts_with(&original_data));
61    }
62
63    #[test]
64    fn test_simple_commit_and_verify() {
65        let seed = [0u8; 32];
66
67        let data = rand::rng().random_iter().take(1024 * 512).collect::<Vec<_>>();
68        let chunk_count = 10;
69
70        let chunks = Encoder::<Scalar>::prepare(&data, chunk_count).unwrap();
71        let start = Instant::now();
72        let committer = PedersenCommitter::new(seed, chunks.inner()[0].symbols().len());
73        println!("Committer creation time: {:?}", start.elapsed());
74
75        let start = Instant::now();
76        let commitments =
77            chunks.inner().iter().map(|c| committer.commit(c.symbols())).collect::<Vec<_>>();
78        println!("Commitment time: {:?}", start.elapsed());
79
80        let encoder = Encoder::from_chunks(chunks);
81        let mut decoder = Decoder::<Scalar>::new(encoder.chunk_size(), chunk_count).unwrap();
82
83        let mut coded_packets =
84            (0..chunk_count).map(|_| encoder.encode(rand::rng()).unwrap()).collect::<Vec<_>>();
85
86        let mut verify_time = Duration::ZERO;
87
88        let decoded = loop {
89            let next = coded_packets.pop().unwrap();
90            // Verify:
91            // 1. MSM commitments with coefficients
92            // 2. Recompute commitment over encoded data
93            // 3. Compare
94            let start = Instant::now();
95            let msm = G1Projective::multi_exp(&commitments, &next.coding_vector);
96            let com = committer.commit(&next.data);
97            verify_time += start.elapsed();
98
99            assert_eq!(msm, com);
100            if let Some(decoded) = decoder.decode(next).unwrap() {
101                break decoded;
102            }
103        };
104
105        println!("Total verification time: {verify_time:?}");
106
107        assert!(decoded.starts_with(&data));
108    }
109
110    #[test]
111    fn test_single_byte_data() {
112        let original_data = b"A";
113        let chunk_count = 1;
114
115        let encoder = Encoder::<Scalar>::new(original_data, chunk_count).unwrap();
116        let packet = encoder.encode_with_vector(&[Scalar::ONE]).unwrap();
117
118        let mut decoder = Decoder::<Scalar>::new(encoder.chunk_size(), chunk_count).unwrap();
119        let decoded = decoder.decode(packet).unwrap();
120
121        assert!(decoded.is_some());
122        let decoded_data = decoded.unwrap();
123        assert!(decoded_data.starts_with(original_data));
124    }
125}