Skip to content

Commit

Permalink
Merge pull request #1 from PlayerData/off-stack-squashed
Browse files Browse the repository at this point in the history
Swap encoding to use less stack space and take 1 byte at a time
  • Loading branch information
saty9 authored Nov 7, 2024
2 parents bf02a82 + c101974 commit dba95d2
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 128 deletions.
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ license = "MIT"
keywords = ["cryptography", "ecc", "bch", "no_std"]
authors = ["Mike Lubinets <[email protected]>"]
version = "0.2.1"
edition = "2021"

[dependencies]
heapless = "0.8.0"

[dev-dependencies]
rustc-serialize = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[features]
unsafe_indexing = []
decoder = []
35 changes: 20 additions & 15 deletions examples/bandwidth.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
extern crate serde;
extern crate serde_json;
extern crate reed_solomon;
extern crate rustc_serialize;

use std::thread;
use std::time::Duration;
use std::sync::mpsc;

use serde::{Serialize};

use reed_solomon::Encoder;
use reed_solomon::Decoder;
Expand All @@ -24,19 +31,15 @@ impl Iterator for Generator {
}
}

use std::thread;
use std::time::Duration;
use std::sync::mpsc;

// Returns MB/s
fn encoder_bandwidth(data_len: usize, ecc_len: usize) -> f32 {
fn encoder_bandwidth(data_len: usize, ecc_len: usize) -> f32 {
// Measure encoding bandwidth
let (tx, thr_rx) = mpsc::channel();
let (thr_tx, rx) = mpsc::channel();

thread::spawn(move || {
let generator = Generator::new();
let encoder = Encoder::new(ecc_len);
let mut encoder = Encoder::<33>::new(ecc_len);

let buffer: Vec<u8> = generator.take(data_len).collect();
let mut bytes = 0;
Expand Down Expand Up @@ -64,19 +67,21 @@ fn decoder_bandwidth(data_len: usize, ecc_len: usize, errors: usize) -> f32 {

thread::spawn(move || {
let generator = Generator::new();
let encoder = Encoder::new(ecc_len);
let mut encoder = Encoder::<33>::new(ecc_len);
let decoder = Decoder::new(ecc_len);

let buffer: Vec<u8> = generator.take(data_len).collect();
let mut encoded = encoder.encode(&buffer);
for x in encoded.iter_mut().take(errors) {
let mut message = buffer.clone();
message.extend_from_slice(&encoded[..]);
for x in message.iter_mut().take(errors) {
*x = 0;
}

let mut bytes = 0;
while thr_rx.try_recv().is_err() {
if decoder.is_corrupted(&encoded) {
decoder.correct(&mut encoded, None).unwrap();
if decoder.is_corrupted(&message) {
decoder.correct(&mut message, None).unwrap();
}
bytes += data_len;
}
Expand All @@ -92,20 +97,20 @@ fn decoder_bandwidth(data_len: usize, ecc_len: usize, errors: usize) -> f32 {
kbytes / 1024.0
}

#[derive(RustcEncodable)]
#[derive(Serialize)]
struct BenchResult {
data_len: usize,
ecc_len: usize,
encoder: EncoderResult,
decoder: Vec<DecoderResult>
}

#[derive(RustcEncodable)]
#[derive(Serialize)]
struct EncoderResult {
bandwidth: f32
}

#[derive(RustcEncodable)]
#[derive(Serialize)]
struct DecoderResult {
errors: usize,
bandwidth: f32
Expand All @@ -129,6 +134,6 @@ fn main() {
}
}).collect();

let json = rustc_serialize::json::encode(&results).unwrap();
let json = serde_json::to_string(&results).unwrap();
println!("{}", json);
}
10 changes: 6 additions & 4 deletions examples/helloworld.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ fn main() {
let ecc_len = 8;

// Create encoder and decoder with
let enc = Encoder::new(ecc_len);
let mut enc = Encoder::<9>::new(ecc_len);
let dec = Decoder::new(ecc_len);

// Encode data
let encoded = enc.encode(&data[..]);

// Simulate some transmission errors
let mut corrupted = *encoded;
let mut corrupted = Vec::new();
corrupted.extend_from_slice(&data[..]);
corrupted.extend_from_slice(&encoded[..]);
for x in corrupted.iter_mut().take(4) {
*x = 0x0;
}
Expand All @@ -31,7 +33,7 @@ fn main() {

println!("message: {:?}", orig_str);
println!("original data: {:?}", data);
println!("error correction code: {:?}", encoded.ecc());
println!("error correction code: {:?}", encoded);
println!("corrupted: {:?}", corrupted);
println!("repaired: {:?}", recv_str);
}
}
3 changes: 2 additions & 1 deletion src/buffer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use ::gf::poly::Polynom;
use crate::gf::poly::Polynom;
use core::ops::{Deref, DerefMut};


/// Buffer for block encoded data
/// # Example
/// ```rust
Expand Down
83 changes: 48 additions & 35 deletions src/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use core;
use ::gf::poly_math::*;
use ::gf::poly::Polynom;
use ::buffer::Buffer;
use ::gf;
use crate::gf::poly_math::*;
use crate::gf::poly::Polynom;
use crate::gf;
use crate::buffer::Buffer;

/// Decoder error
#[derive(Debug, Copy, Clone)]
Expand Down Expand Up @@ -41,21 +41,23 @@ impl Decoder {
/// use reed_solomon::Decoder;
///
/// // Create encoder and decoder
/// let encoder = Encoder::new(4);
/// let mut encoder = Encoder::<5>::new(4);
/// let decoder = Decoder::new(4);
///
/// // Encode message
/// let mut encoded = encoder.encode(&[1, 2, 3, 4]);
/// let mut message = vec![1, 2, 3, 4];
/// message.extend_from_slice(&encoded[..]);
///
/// // Corrupt message
/// encoded[2] = 1;
/// encoded[3] = 2;
/// message[2] = 1;
/// message[3] = 2;
///
/// // Let's assume it's known that `encoded[3]` is an error
/// let known_erasures = [3];
///
/// // Decode and correct message,
/// let corrected = decoder.correct(&mut encoded, Some(&known_erasures)).unwrap();
/// let corrected = decoder.correct(&mut message, Some(&known_erasures)).unwrap();
///
/// // Check results
/// assert_eq!(&[1, 2, 3, 4], corrected.data())
Expand Down Expand Up @@ -89,8 +91,8 @@ impl Decoder {
}

let fsynd = self.forney_syndromes(&synd, erase_pos, msg.len());
let err_loc = try!(self.find_error_locator(&fsynd, None, erase_pos.len()));
let mut err_pos = try!(self.find_errors(&err_loc.reverse(), msg.len()));
let err_loc = self.find_error_locator(&fsynd, None, erase_pos.len())?;
let mut err_pos = self.find_errors(&err_loc.reverse(), msg.len())?;

// Append erase_pos to err_pos
for x in erase_pos.iter() {
Expand All @@ -115,21 +117,22 @@ impl Decoder {
/// use reed_solomon::Decoder;
///
/// // Create encoder and decoder
/// let encoder = Encoder::new(4);
/// let mut encoder = Encoder::<5>::new(4);
/// let decoder = Decoder::new(4);
///
/// // Encode message
/// let mut encoded = encoder.encode(&[1, 2, 3, 4]);
///
/// let mut message = vec![1, 2, 3, 4];
/// message.extend_from_slice(&encoded[..]);
/// // Corrupt message
/// encoded[2] = 1;
/// encoded[3] = 2;
/// message[2] = 1;
/// message[3] = 2;
///
/// // Let's assume it's known that `encoded[3]` is an error
/// let known_erasures = [3];
///
/// // Decode and correct message,
/// let corrected = decoder.correct(&mut encoded, Some(&known_erasures)).unwrap();
/// let corrected = decoder.correct(&mut message, Some(&known_erasures)).unwrap();
///
/// // Check results
/// assert_eq!(&[1, 2, 3, 4], corrected.data())
Expand All @@ -149,19 +152,21 @@ impl Decoder {
/// use reed_solomon::Decoder;
///
/// // Create encoder and decoder
/// let encoder = Encoder::new(4);
/// let mut encoder = Encoder::<5>::new(4);
/// let decoder = Decoder::new(4);
///
/// // Encode message
/// let mut encoded = encoder.encode(&[1, 2, 3, 4]);
/// let encoded = encoder.encode(&[1, 2, 3, 4]);
/// let mut message = vec![1, 2, 3, 4];
/// message.extend_from_slice(&encoded[..]);
///
/// assert_eq!(decoder.is_corrupted(&encoded), false);
/// assert_eq!(decoder.is_corrupted(&message), false);
///
/// // Corrupt message
/// encoded[2] = 1;
/// encoded[3] = 2;
/// message[2] = 1;
/// message[3] = 2;
///
/// assert_eq!(decoder.is_corrupted(&encoded), true);
/// assert_eq!(decoder.is_corrupted(&message), true);
/// ```
pub fn is_corrupted(&self, msg: &[u8]) -> bool {
(0..self.ecc_len).any(|x| msg.eval(gf::pow(2, x as i32)) != 0)
Expand Down Expand Up @@ -351,32 +356,38 @@ impl Decoder {

#[cfg(test)]
mod tests {
use std::vec::Vec;
use super::*;
use ::Encoder;
use crate::Encoder;

#[test]
fn calc_syndromes() {
let px = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut encoded = Encoder::new(8).encode(&px[..]);
let mut encoded = Encoder::<9>::new(8).encode(&px[..]);
let mut message = Vec::from(&px[..]);
message.extend_from_slice(&encoded[..]);

assert_eq!([0; 9], *Decoder::new(8).calc_syndromes(&encoded));
assert_eq!([0; 9], *Decoder::new(8).calc_syndromes(&message));

encoded[5] = 1;
message[5] = 1;

assert_eq!([0, 7, 162, 172, 245, 176, 71, 58, 180],
*Decoder::new(8).calc_syndromes(&encoded));
*Decoder::new(8).calc_syndromes(&message));
}

#[test]
fn is_corrupted() {
let px = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut encoded = Encoder::new(8).encode(&px[..]);
let mut encoded = Encoder::<9>::new(8).encode(&px[..]);
let mut message = Vec::new();
message.extend_from_slice(&px[..]);
message.extend_from_slice(&encoded[..]);

assert_eq!(false, Decoder::new(8).is_corrupted(&encoded));
assert_eq!(false, Decoder::new(8).is_corrupted(&message));

encoded[5] = 1;
message[5] = 1;

assert_eq!(true, Decoder::new(8).is_corrupted(&encoded));
assert_eq!(true, Decoder::new(8).is_corrupted(&message));
}

#[test]
Expand Down Expand Up @@ -410,15 +421,17 @@ mod tests {
#[test]
fn error_count() {
let msg = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoder = Encoder::new(10);
let mut encoder = Encoder::<11>::new(10);

let encoded = encoder.encode(&msg[..]);
let mut errd = *encoded;
let mut full_message = Vec::new();
full_message.extend_from_slice(&msg[..]);
full_message.extend_from_slice(&encoded[..]);

errd[0] = 255;
errd[3] = 255;
full_message[0] = 255;
full_message[3] = 255;

let (_correct,err) = Decoder::new(10).correct_err_count(&errd, None).unwrap();
let (_correct,err) = Decoder::new(10).correct_err_count(&full_message, None).unwrap();

assert_eq!(err, 2);
}
Expand Down
Loading

0 comments on commit dba95d2

Please sign in to comment.