use crate::decode::{decode_layered, RsCodec};
pub struct EncodeParams {
pub k: usize,
pub m: usize,
pub n: usize,
pub q: usize,
pub t: usize,
pub nu: usize,
pub sub_chunk_no: usize,
pub original_count: usize,
}
pub fn encode(params: &EncodeParams, rs: &RsCodec, data: &[u8]) -> Vec<Vec<u8>> {
let min_sub_chunk_size = 2;
let min_size = params.k * params.sub_chunk_no * min_sub_chunk_size;
let padded_len = if data.is_empty() {
min_size
} else {
let aligned = ((data.len() + min_size - 1) / min_size) * min_size;
aligned.max(min_size)
};
let chunk_size = padded_len / params.k;
let sub_chunk_size = chunk_size / params.sub_chunk_no;
let total_nodes = params.q * params.t; let parity_start = params.k + params.nu;
let mut data_rows: Vec<Vec<u8>> = vec![vec![0u8; chunk_size]; params.k];
for i in 0..params.k {
let start = i * chunk_size;
if start >= data.len() {
break;
}
let end = data.len().min(start + chunk_size);
data_rows[i][..end - start].copy_from_slice(&data[start..end]);
}
let zero_row = vec![0u8; chunk_size];
let mut available_rows: Vec<Option<&[u8]>> = vec![None; total_nodes];
for i in 0..params.k {
available_rows[i] = Some(&data_rows[i]);
}
for i in params.k..parity_start {
available_rows[i] = Some(&zero_row);
}
let mut erased_rows: Vec<Vec<u8>> = Vec::with_capacity(total_nodes);
for node in 0..total_nodes {
if node < parity_start {
erased_rows.push(Vec::new());
} else {
erased_rows.push(vec![0u8; chunk_size]);
}
}
decode_layered(params, rs, &available_rows, &mut erased_rows, sub_chunk_size)
.expect("Encode failed: this indicates a bug in ClayCode");
let mut result = Vec::with_capacity(params.n);
for row in data_rows {
result.push(row);
}
for node in parity_start..total_nodes {
result.push(std::mem::take(&mut erased_rows[node]));
}
result
}
#[cfg(test)]
mod tests {
use super::*;
fn test_params() -> EncodeParams {
EncodeParams {
k: 4,
m: 2,
n: 6,
q: 2,
t: 3,
nu: 0,
sub_chunk_no: 8,
original_count: 4,
}
}
fn test_rs(params: &EncodeParams) -> RsCodec {
RsCodec::new(params.original_count, params.m).expect("test params should build a codec")
}
#[test]
fn chunk_count() {
let params = test_params();
let rs = test_rs(¶ms);
let chunks = encode(¶ms, &rs, b"Test data for encoding");
assert_eq!(chunks.len(), params.n);
}
#[test]
fn empty_data() {
let params = test_params();
let rs = test_rs(¶ms);
let chunks = encode(¶ms, &rs, &[]);
assert_eq!(chunks.len(), params.n);
let chunk_size = chunks[0].len();
for chunk in &chunks {
assert_eq!(chunk.len(), chunk_size);
}
}
#[test]
fn chunk_alignment() {
let params = test_params();
let rs = test_rs(¶ms);
let chunks = encode(¶ms, &rs, &vec![0xABu8; 100]);
for chunk in &chunks {
assert_eq!(chunk.len() % params.sub_chunk_no, 0);
}
}
}