Expand description
Split up big payloads into constantly sized chunks which can be recombined by a decoder.
The fountain module provides an implementation of a fountain encoder, which splits
up a byte payload into multiple segments and emits an unbounded stream of parts which
can be recombined at the receiving decoder site. The emitted parts are either original
payload segments, or constructed by xor-ing a certain set of payload segments.
A seeded Xoshiro RNG ensures that the receiver can reconstruct which segments
were combined into the part.
let xor = |a: &[u8], b: &[u8]| {
a.iter()
.zip(b.iter())
.map(|(&x1, &x2)| x1 ^ x2)
.collect::<Vec<_>>()
};
let data = String::from("Ten chars!");
let max_length = 4;
// note the padding
let (p1, p2, p3) = (b"Ten ", b"char", "s!\u{0}\u{0}".as_bytes());
let mut encoder = ur::fountain::Encoder::new(data.as_bytes(), max_length).unwrap();
let mut decoder = ur::fountain::Decoder::default();
// the fountain encoder first emits all original segments in order
let part1 = encoder.next_part();
assert_eq!(part1.data(), p1);
// receive the first part into the decoder
decoder.receive(part1).unwrap();
let part2 = encoder.next_part();
assert_eq!(part2.data(), p2);
// receive the second part into the decoder
decoder.receive(part2).unwrap();
// miss the third part
assert_eq!(encoder.next_part().data(), p3);
// the RNG then first selects the original third segment
assert_eq!(encoder.next_part().data(), p3);
// the RNG then selects all three segments to be xored
let xored = encoder.next_part();
assert_eq!(xored.data(), xor(&xor(p1, p2), p3));
// receive the xored part into the decoder
// since it already has p1 and p2, p3 can be computed
// from p1 xor p2 xor p3
decoder.receive(xored).unwrap();
assert!(decoder.complete());
assert_eq!(decoder.message().unwrap().as_deref(), Some(data.as_bytes()));The index selection is biased towards combining fewer segments.
let data = String::from("Fifty chars").repeat(5);
let max_length = 5;
let mut encoder = ur::fountain::Encoder::new(data.as_bytes(), max_length).unwrap();
// 40% of the emitted parts represent original message segments
assert_eq!(
(0..100)
.map(|_i| if encoder.next_part().is_simple() {
1
} else {
0
})
.sum::<usize>(),
39
);
let mut encoder = ur::fountain::Encoder::new(data.as_bytes(), max_length).unwrap();
// On average, 3.33 segments (out of ten total) are combined into a part
assert_eq!(
(0..100)
.map(|_i| encoder.next_part().indexes().len())
.sum::<usize>(),
333
);Structs§
- Decoder
- A decoder capable of receiving and recombining fountain-encoded transmissions.
- Encoder
- An encoder capable of emitting fountain-encoded transmissions.
- Part
- A part emitted by a fountain
Encoder.
Enums§
- Error
- Errors that can happen during fountain encoding and decoding.