RS encoding/decoding base methods (#303)

* Add rs lib, implement encoding

* Implement decoding
This commit is contained in:
Daniel Sanchez 2023-08-17 09:05:52 +02:00 committed by GitHub
parent fe3d39071d
commit 61b587a4ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 0 deletions

View File

@ -9,6 +9,7 @@ members = [
"nomos-services/consensus",
"nomos-services/mempool",
"nomos-services/http",
"nomos-da-core/reed-solomon",
"nodes/nomos-node",
"simulations",
"consensus-engine",

View File

@ -0,0 +1,9 @@
[package]
name = "reed-solomon"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reed-solomon-erasure = "6.0"

View File

@ -0,0 +1,73 @@
use reed_solomon_erasure::{galois_8::ReedSolomon, Error};
/// Reed Sololomon encode the elements with a custom parity ratio
/// # Arguments
/// * `parity_ratio` - Ratio of parity elements over original elements size
/// * `elements` - Elements to encode
pub fn encode_elements(parity_ratio: usize, elements: &[u8]) -> Result<Vec<u8>, Error> {
let mut encoded = vec![vec![0]; elements.len() * (parity_ratio + 1)];
for (i, &e) in elements.iter().enumerate() {
// review bytes encoding
encoded[i] = e.to_be_bytes().to_vec();
}
let encoder = ReedSolomon::new(elements.len(), elements.len() * parity_ratio)?;
encoder.encode(&mut encoded)?;
Ok(encoded.into_iter().flatten().collect())
}
/// Reed solomon decode the elements with a custom parity ratio
/// # Arguments
/// * `original_size` - Original size of encoded elements
/// * `parity_ratio` - Ratio of parity elements over original elements size (must be the same as the one used for encoding)
/// * `elements` - Elements to decode
pub fn decode_from_elements(
original_size: usize,
parity_ratio: usize,
elements: &[Option<u8>],
) -> Result<Vec<u8>, Error> {
let mut elements: Vec<_> = elements
.iter()
.map(|e| e.map(|n| n.to_be_bytes().to_vec()))
.collect();
let decoder = ReedSolomon::new(original_size, parity_ratio * original_size)?;
decoder.reconstruct(&mut elements)?;
Ok(elements
.into_iter()
.filter_map(|e: Option<Vec<u8>>| e.map(|n| u8::from_be_bytes(n.try_into().unwrap())))
.collect())
}
#[cfg(test)]
mod test {
use reed_solomon_erasure::Error;
#[test]
fn encode_with_ratio() {
let elements = vec![1, 2, 3, 4, 5, 6, 7, 8];
let encoded = super::encode_elements(1, &elements).unwrap();
// check intended size
assert_eq!(encoded.len(), 16);
// check elements
assert_eq!(&encoded[0..8], &elements);
}
#[test]
fn decode_with_ratio() {
let elements = vec![1, 2, 3, 4, 5, 6, 7, 8];
let encoded = super::encode_elements(1, &elements).unwrap();
let mut encoded: Vec<_> = encoded.into_iter().map(Some).collect();
encoded[4..12].copy_from_slice(&[None; 8]);
let decoded = super::decode_from_elements(8, 1, &encoded).unwrap();
assert_eq!(decoded[0..8], elements);
}
#[test]
fn decode_fails_with_insufficient_shards() {
let elements = vec![1, 2, 3, 4, 5, 6, 7, 8];
let encoded = super::encode_elements(1, &elements).unwrap();
let mut encoded: Vec<_> = encoded.into_iter().map(Some).collect();
encoded[7..].copy_from_slice(&[None; 9]);
let decoded = super::decode_from_elements(8, 1, &encoded);
assert!(matches!(decoded, Err(Error::TooFewShardsPresent)));
}
}