use crate::arithmetic::shift_left_then_reduce;
use crate::constants::BITS_IN_LOWER_PART_OF_T;
use crate::ntt::{
invert_ntt_montgomery,
ntt,
ntt_multiply_montgomery,
reduce,
};
use crate::polynomial::PolynomialRingElement;
use crate::simd::traits::Operations;
#[cfg_attr(tarpaulin, inline(never))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn compute_as1_plus_s2<SIMDUnit: Operations>(
rows_in_a: usize,
columns_in_a: usize,
a_as_ntt: &mut [PolynomialRingElement<SIMDUnit>],
s1_ntt: &[PolynomialRingElement<SIMDUnit>],
s1_s2: &[PolynomialRingElement<SIMDUnit>],
result: &mut [PolynomialRingElement<SIMDUnit>],
) {
for i in 0..rows_in_a {
for j in 0..columns_in_a {
let mut product = a_as_ntt[i * columns_in_a + j];
ntt_multiply_montgomery::<SIMDUnit>(&mut product, &s1_ntt[j]);
PolynomialRingElement::add(&mut result[i], &product);
}
}
for i in 0..result.len() {
reduce(&mut result[i]);
invert_ntt_montgomery::<SIMDUnit>(&mut result[i]);
PolynomialRingElement::add(&mut result[i], &s1_s2[columns_in_a + i]);
}
}
#[cfg_attr(tarpaulin, inline(never))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn compute_matrix_x_mask<SIMDUnit: Operations>(
rows_in_a: usize,
columns_in_a: usize,
matrix: &[PolynomialRingElement<SIMDUnit>],
mask: &[PolynomialRingElement<SIMDUnit>],
result: &mut [PolynomialRingElement<SIMDUnit>],
) {
for i in 0..rows_in_a {
for j in 0..columns_in_a {
let mut product = mask[j];
ntt_multiply_montgomery(&mut product, &matrix[i * columns_in_a + j]);
PolynomialRingElement::<SIMDUnit>::add(&mut result[i], &product);
}
reduce(&mut result[i]);
invert_ntt_montgomery(&mut result[i]);
}
}
#[cfg_attr(tarpaulin, inline(never))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn vector_times_ring_element<SIMDUnit: Operations>(
vector: &mut [PolynomialRingElement<SIMDUnit>],
ring_element: &PolynomialRingElement<SIMDUnit>,
) {
for element in vector {
ntt_multiply_montgomery(element, ring_element);
invert_ntt_montgomery(element);
}
}
#[cfg_attr(tarpaulin, inline(never))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn add_vectors<SIMDUnit: Operations>(
dimension: usize,
lhs: &mut [PolynomialRingElement<SIMDUnit>],
rhs: &[PolynomialRingElement<SIMDUnit>],
) {
for i in 0..dimension {
PolynomialRingElement::<SIMDUnit>::add(&mut lhs[i], &rhs[i]);
}
}
#[cfg_attr(tarpaulin, inline(never))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn subtract_vectors<SIMDUnit: Operations>(
dimension: usize,
lhs: &mut [PolynomialRingElement<SIMDUnit>],
rhs: &[PolynomialRingElement<SIMDUnit>],
) {
for i in 0..dimension {
PolynomialRingElement::<SIMDUnit>::subtract(&mut lhs[i], &rhs[i]);
}
}
#[cfg(feature = "hardened")]
#[cfg_attr(tarpaulin, inline(never))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn merge_masked_ntt_products<SIMDUnit: Operations>(
dimension: usize,
acc: &mut [PolynomialRingElement<SIMDUnit>],
rhs: &[PolynomialRingElement<SIMDUnit>],
) {
for i in 0..dimension {
PolynomialRingElement::<SIMDUnit>::add(&mut acc[i], &rhs[i]);
reduce(&mut acc[i]);
}
}
#[cfg_attr(tarpaulin, inline(never))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn compute_w_approx<SIMDUnit: Operations>(
rows_in_a: usize,
columns_in_a: usize,
matrix: &[PolynomialRingElement<SIMDUnit>],
signer_response: &[PolynomialRingElement<SIMDUnit>],
verifier_challenge_as_ntt: &PolynomialRingElement<SIMDUnit>,
t1: &mut [PolynomialRingElement<SIMDUnit>],
) {
for i in 0..rows_in_a {
let mut inner_result = PolynomialRingElement::<SIMDUnit>::zero();
for j in 0..columns_in_a {
let mut product = matrix[i * columns_in_a + j];
ntt_multiply_montgomery(&mut product, &signer_response[j]);
PolynomialRingElement::<SIMDUnit>::add(&mut inner_result, &product);
}
shift_left_then_reduce::<SIMDUnit, { BITS_IN_LOWER_PART_OF_T as i32 }>(&mut t1[i]);
ntt(&mut t1[i]);
ntt_multiply_montgomery(&mut t1[i], verifier_challenge_as_ntt);
PolynomialRingElement::<SIMDUnit>::subtract(&mut inner_result, &t1[i]);
t1[i] = inner_result;
reduce(&mut t1[i]);
invert_ntt_montgomery(&mut t1[i]);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::polynomial::PolynomialRingElement;
use crate::simd::portable::PortableSIMDUnit;
type P = PolynomialRingElement<PortableSIMDUnit>;
#[test]
fn compute_as1_plus_s2_2x2_zeros() {
let mut a = [P::zero(); 4];
let s1_ntt = [P::zero(); 2];
let s1_s2 = [P::zero(); 4];
let mut result = [P::zero(); 2];
compute_as1_plus_s2(2, 2, &mut a, &s1_ntt, &s1_s2, &mut result);
}
#[test]
fn matrix_x_mask_and_vector_ops_smoke() {
let matrix = [P::zero(); 4];
let mask = [P::zero(); 2];
let mut out = [P::zero(); 2];
compute_matrix_x_mask(2, 2, &matrix, &mask, &mut out);
let mut v = [P::zero(); 2];
let r = P::zero();
vector_times_ring_element(&mut v, &r);
let mut lhs = [P::zero(); 2];
let rhs = [P::zero(); 2];
add_vectors(2, &mut lhs, &rhs);
subtract_vectors(2, &mut lhs, &rhs);
}
#[test]
fn compute_w_approx_2x2_zeros() {
let matrix = [P::zero(); 4];
let signer = [P::zero(); 2];
let c = P::zero();
let mut t1 = [P::zero(); 2];
compute_w_approx(2, 2, &matrix, &signer, &c, &mut t1);
}
}