Module fountain

Module fountain 

Source
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.