use reed_solomon_erasure::galois_8::{add as gf_add, mul as gf_mul, div as gf_div};
pub const GAMMA: u8 = 2;
#[inline]
pub fn gf_inv(a: u8) -> u8 {
gf_div(1, a)
}
pub fn prt_compute_both(c: &[u8], c_star: &[u8]) -> (Vec<u8>, Vec<u8>) {
let len = c.len();
let mut u = vec![0u8; len];
let mut u_star = vec![0u8; len];
for i in 0..len {
u[i] = gf_add(c[i], gf_mul(GAMMA, c_star[i]));
u_star[i] = gf_add(gf_mul(GAMMA, c[i]), c_star[i]);
}
(u, u_star)
}
pub fn prt_compute_both_oriented(c_xy: &[u8], c_sw: &[u8], xy_is_primary: bool) -> (Vec<u8>, Vec<u8>) {
let len = c_xy.len();
let mut u_xy = vec![0u8; len];
let mut u_sw = vec![0u8; len];
if xy_is_primary {
for i in 0..len {
u_xy[i] = gf_add(c_xy[i], gf_mul(GAMMA, c_sw[i]));
u_sw[i] = gf_add(gf_mul(GAMMA, c_xy[i]), c_sw[i]);
}
} else {
for i in 0..len {
u_xy[i] = gf_add(gf_mul(GAMMA, c_sw[i]), c_xy[i]);
u_sw[i] = gf_add(c_sw[i], gf_mul(GAMMA, c_xy[i]));
}
}
(u_xy, u_sw)
}
pub fn pft_compute_both(u: &[u8], u_star: &[u8]) -> (Vec<u8>, Vec<u8>) {
let len = u.len();
let mut c = vec![0u8; len];
let mut c_star = vec![0u8; len];
let det = gf_add(1, gf_mul(GAMMA, GAMMA));
let det_inv = gf_inv(det);
for i in 0..len {
c[i] = gf_mul(gf_add(u[i], gf_mul(GAMMA, u_star[i])), det_inv);
c_star[i] = gf_mul(gf_add(gf_mul(GAMMA, u[i]), u_star[i]), det_inv);
}
(c, c_star)
}
pub fn compute_c_from_u_and_cstar(u_xy: &[u8], c_companion: &[u8]) -> Vec<u8> {
let len = u_xy.len();
let mut c = vec![0u8; len];
for i in 0..len {
c[i] = gf_add(u_xy[i], gf_mul(GAMMA, c_companion[i]));
}
c
}
pub fn compute_cstar_from_c_and_u(c_helper: &[u8], u_helper: &[u8], helper_is_primary: bool) -> Vec<u8> {
let len = c_helper.len();
let mut companion_c = vec![0u8; len];
let gamma_inv = gf_inv(GAMMA);
if helper_is_primary {
for i in 0..len {
companion_c[i] = gf_add(u_helper[i], gf_mul(GAMMA, c_helper[i]));
}
} else {
for i in 0..len {
companion_c[i] = gf_mul(gf_add(u_helper[i], c_helper[i]), gamma_inv);
}
}
companion_c
}
pub fn compute_u_from_c_and_ustar(c_xy: &[u8], u_companion: &[u8]) -> Vec<u8> {
let len = c_xy.len();
let mut u = vec![0u8; len];
let det = gf_add(1, gf_mul(GAMMA, GAMMA));
for i in 0..len {
u[i] = gf_add(gf_mul(det, c_xy[i]), gf_mul(GAMMA, u_companion[i]));
}
u
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gamma_properties() {
assert_ne!(GAMMA, 0);
let gamma_sq = gf_mul(GAMMA, GAMMA);
assert_ne!(gamma_sq, 1);
}
#[test]
fn test_prt_pft_roundtrip() {
let c = vec![0x12, 0x34, 0x56, 0x78];
let c_star = vec![0xAB, 0xCD, 0xEF, 0x01];
let (u, u_star) = prt_compute_both(&c, &c_star);
let (c_back, c_star_back) = pft_compute_both(&u, &u_star);
assert_eq!(c, c_back);
assert_eq!(c_star, c_star_back);
}
#[test]
fn test_gf_arithmetic() {
assert_eq!(gf_add(5, 3), 6);
assert_eq!(gf_mul(2, 3), 6);
assert_eq!(gf_mul(gf_inv(2), 2), 1);
}
}