fn tadd(a: i8, b: i8) -> i8 {
match (a, b) {
(-1, -1) => 1, (-1, 0) => -1, (-1, 1) => 0,
(0, -1) => -1, (0, 0) => 0, (0, 1) => 1,
(1, -1) => 0, (1, 0) => 1, (1, 1) => -1, _ => 0,
}
}
fn tmul(a: i8, b: i8) -> i8 {
match (a, b) {
(-1, -1) => 1, (-1, 1) => -1, (1, -1) => -1, (1, 1) => 1, _ => 0,
}
}
pub fn vec_add(a: &[i8], b: &[i8]) -> Vec<i8> {
a.iter().zip(b).map(|(&x, &y)| tadd(x, y)).collect()
}
pub fn inner_product(a: &[i8], b: &[i8]) -> i8 {
a.iter().zip(b).fold(0, |acc, (&x, &y)| tadd(acc, tmul(x, y)))
}
pub fn mat_vec_mul(mat: &[Vec<i8>], vec: &[i8]) -> Vec<i8> {
mat.iter().map(|row| inner_product(row, vec)).collect()
}
pub fn mat_mul(a: &[Vec<i8>], b: &[Vec<i8>]) -> Vec<Vec<i8>> {
let cols = b.get(0).map(|r| r.len()).unwrap_or(0);
(0..a.len()).map(|i| {
(0..cols).map(|j| {
let sum: i8 = (0..b.len()).fold(0, |acc, k| tadd(acc, tmul(a[i][k], b[k][j])));
sum
}).collect()
}).collect()
}
pub fn random_vec(len: usize, seed: u64) -> Vec<i8> {
let mut s = seed;
(0..len).map(|i| {
s = s.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
match (s.wrapping_add(i as u64)) % 3 { 0 => -1, 1 => 0, _ => 1 }
}).collect()
}
pub fn lwe_sample(secret: &[i8], seed: u64) -> (Vec<i8>, i8) {
let a = random_vec(secret.len(), seed);
let b = inner_product(&a, secret);
(a, b)
}
pub fn hamming_weight(v: &[i8]) -> usize { v.iter().filter(|&&x| x != 0).count() }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vec_add_closure() {
let r = vec_add(&[1, -1, 0], &[-1, 1, 0]);
assert!(r.iter().all(|&v| v >= -1 && v <= 1));
}
#[test]
fn test_vec_add_identity() {
let r = vec_add(&[1, -1, 0], &[0, 0, 0]);
assert_eq!(r, vec![1, -1, 0]);
}
#[test]
fn test_inner_product() {
assert_eq!(inner_product(&[1, 1], &[1, 1]), -1); }
#[test]
fn test_mat_vec_mul() {
let mat = vec![vec![1, 0], vec![0, 1]]; let v = vec![1, -1];
let r = mat_vec_mul(&mat, &v);
assert_eq!(r, vec![1, -1]);
}
#[test]
fn test_mat_mul_identity() {
let id = vec![vec![1, 0], vec![0, 1]];
let r = mat_mul(&id, &id);
assert_eq!(r, id);
}
#[test]
fn test_random_vec() {
let v = random_vec(10, 42);
assert_eq!(v.len(), 10);
assert!(v.iter().all(|&x| x >= -1 && x <= 1));
}
#[test]
fn test_lwe_sample() {
let secret = vec![1, -1, 0, 1];
let (a, b) = lwe_sample(&secret, 123);
assert_eq!(a.len(), 4);
}
#[test]
fn test_hamming_weight() {
assert_eq!(hamming_weight(&[1, -1, 0, 0, 1]), 3);
}
}