#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Gf256;
impl Gf256 {
pub const POLY: u16 = 0x11B;
#[inline]
pub fn add(a: u8, b: u8) -> u8 {
a ^ b
}
#[inline]
pub fn sub(a: u8, b: u8) -> u8 {
a ^ b
}
pub fn mul(mut a: u8, mut b: u8) -> u8 {
let mut p: u8 = 0;
for _ in 0..8 {
if (b & 1) != 0 {
p ^= a;
}
let carry = (a & 0x80) != 0;
a <<= 1;
if carry {
a ^= (Self::POLY & 0xFF) as u8;
}
b >>= 1;
}
p
}
pub fn inv(a: u8) -> u8 {
if a == 0 {
return 0;
}
let mut res: u8 = 1;
let mut base = a;
let mut exp: u8 = 254;
while exp > 0 {
if (exp & 1) != 0 {
res = Self::mul(res, base);
}
base = Self::mul(base, base);
exp >>= 1;
}
res
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CodedPacket {
pub coefficients: Vec<u8>,
pub payload: Vec<u8>,
}
impl CodedPacket {
pub fn new(coefficients: Vec<u8>, payload: Vec<u8>) -> Self {
Self {
coefficients,
payload,
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(1 + self.coefficients.len() + self.payload.len());
buf.push(self.coefficients.len() as u8);
buf.extend_from_slice(&self.coefficients);
buf.extend_from_slice(&self.payload);
buf
}
pub fn from_bytes(raw: &[u8]) -> Result<Self, String> {
if raw.is_empty() {
return Err("Empty buffer".to_string());
}
let coeff_len = raw[0] as usize;
if raw.len() < 1 + coeff_len {
return Err("Truncated coded packet coefficients".to_string());
}
let coefficients = raw[1..1 + coeff_len].to_vec();
let payload = raw[1 + coeff_len..].to_vec();
Ok(Self {
coefficients,
payload,
})
}
}
pub struct FecEncoder {
pub k: usize,
pub chunk_size: usize,
pub original_chunks: Vec<Vec<u8>>,
}
impl FecEncoder {
pub fn new(data: &[u8], k: usize) -> Self {
assert!(k > 0, "k must be at least 1");
let chunk_size = (data.len() + k - 1) / k;
let mut original_chunks = Vec::with_capacity(k);
for i in 0..k {
let start = i * chunk_size;
let end = (start + chunk_size).min(data.len());
let mut chunk = Vec::with_capacity(chunk_size);
if start < data.len() {
chunk.extend_from_slice(&data[start..end]);
}
chunk.resize(chunk_size, 0u8);
original_chunks.push(chunk);
}
Self {
k,
chunk_size,
original_chunks,
}
}
pub fn systematic_packet(&self, index: usize) -> Option<CodedPacket> {
if index >= self.k {
return None;
}
let mut coeffs = vec![0u8; self.k];
coeffs[index] = 1;
Some(CodedPacket::new(coeffs, self.original_chunks[index].clone()))
}
pub fn generate_coded_packet(&self, seed: u64) -> CodedPacket {
let mut state = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
let mut coeffs = Vec::with_capacity(self.k);
for _ in 0..self.k {
state = state.wrapping_mul(6364136223846793005).wrapping_add(1);
let mut c = (state >> 33) as u8;
if c == 0 {
c = 1;
}
coeffs.push(c);
}
let mut payload = vec![0u8; self.chunk_size];
for (i, c) in coeffs.iter().enumerate() {
let chunk = &self.original_chunks[i];
for (byte_idx, &b) in chunk.iter().enumerate() {
payload[byte_idx] = Gf256::add(payload[byte_idx], Gf256::mul(*c, b));
}
}
CodedPacket::new(coeffs, payload)
}
pub fn generate_fec_block(&self, m: usize) -> Vec<CodedPacket> {
let mut packets = Vec::with_capacity(self.k + m);
for i in 0..self.k {
if let Some(pkt) = self.systematic_packet(i) {
packets.push(pkt);
}
}
for j in 0..m {
packets.push(self.generate_coded_packet((j as u64 + 1).wrapping_mul(0x9E3779B97F4A7C15)));
}
packets
}
}
pub struct FecDecoder {
pub k: usize,
pub chunk_size: usize,
pub original_len: usize,
matrix: Vec<Vec<u8>>,
payloads: Vec<Vec<u8>>,
}
impl FecDecoder {
pub fn new(k: usize, original_len: usize) -> Self {
let chunk_size = (original_len + k - 1) / k;
Self {
k,
chunk_size,
original_len,
matrix: Vec::new(),
payloads: Vec::new(),
}
}
pub fn rank(&self) -> usize {
self.matrix.len()
}
pub fn is_complete(&self) -> bool {
self.rank() == self.k
}
pub fn add_packet(&mut self, packet: CodedPacket) -> bool {
if self.is_complete() || packet.coefficients.len() != self.k {
return false;
}
let mut row = packet.coefficients;
let mut payload = packet.payload;
if payload.len() < self.chunk_size {
payload.resize(self.chunk_size, 0);
}
for i in 0..self.matrix.len() {
let lead_col = match self.matrix[i].iter().position(|&x| x != 0) {
Some(pos) => pos,
None => continue,
};
let factor = row[lead_col];
if factor != 0 {
for c in 0..self.k {
let term = Gf256::mul(factor, self.matrix[i][c]);
row[c] = Gf256::add(row[c], term);
}
for b in 0..self.chunk_size {
let term = Gf256::mul(factor, self.payloads[i][b]);
payload[b] = Gf256::add(payload[b], term);
}
}
}
if let Some(pivot_col) = row.iter().position(|&x| x != 0) {
let inv_pivot = Gf256::inv(row[pivot_col]);
for c in 0..self.k {
row[c] = Gf256::mul(row[c], inv_pivot);
}
for b in 0..self.chunk_size {
payload[b] = Gf256::mul(payload[b], inv_pivot);
}
for i in 0..self.matrix.len() {
let factor = self.matrix[i][pivot_col];
if factor != 0 {
for c in 0..self.k {
let term = Gf256::mul(factor, row[c]);
self.matrix[i][c] = Gf256::add(self.matrix[i][c], term);
}
for b in 0..self.chunk_size {
let term = Gf256::mul(factor, payload[b]);
self.payloads[i][b] = Gf256::add(self.payloads[i][b], term);
}
}
}
self.matrix.push(row);
self.payloads.push(payload);
true
} else {
false
}
}
pub fn decode(&self) -> Option<Vec<u8>> {
if !self.is_complete() {
return None;
}
let mut ordered_chunks = vec![vec![0u8; self.chunk_size]; self.k];
for i in 0..self.k {
if let Some(col) = self.matrix[i].iter().position(|&x| x != 0) {
if col < self.k {
ordered_chunks[col] = self.payloads[i].clone();
}
}
}
let mut result = Vec::with_capacity(self.original_len);
for chunk in ordered_chunks {
result.extend_from_slice(&chunk);
}
result.truncate(self.original_len);
Some(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gf256_basic_arithmetic() {
assert_eq!(Gf256::add(0x57, 0x83), 0xD4);
assert_eq!(Gf256::mul(0x57, 0x83), 0xC1);
let inv = Gf256::inv(0x57);
assert_eq!(Gf256::mul(0x57, inv), 1);
}
#[test]
fn test_fec_recovery_from_dropped_packets() {
let original_data = b"Sovereign peer-to-peer payload resilient against random loss.".to_vec();
let k = 4;
let m = 2;
let encoder = FecEncoder::new(&original_data, k);
let packets = encoder.generate_fec_block(m);
assert_eq!(packets.len(), 6);
let surviving_packets = vec![
packets[1].clone(),
packets[3].clone(),
packets[4].clone(),
packets[5].clone(),
];
let mut decoder = FecDecoder::new(k, original_data.len());
for pkt in surviving_packets {
decoder.add_packet(pkt);
}
assert!(decoder.is_complete());
let recovered = decoder.decode().expect("Decoding should succeed");
assert_eq!(recovered, original_data);
}
}