kdt/dilithium/src/poly.rs

621 lines
20 KiB
Rust

use crate::{
fips202::*, ntt::*, params::*, reduce::*, rounding::*, symmetric::*,
};
const D_SHL: i32 = 1i32 << (D - 1);
#[derive(Copy, Clone)]
pub struct Poly {
pub coeffs: [i32; N],
}
impl Default for Poly {
fn default() -> Self {
Poly { coeffs: [0i32; N] }
}
}
/// Inplace reduction of all coefficients of polynomial to
/// representative in [0,2*Q].
pub fn poly_reduce(a: &mut Poly) {
for i in 0..N {
a.coeffs[i] = reduce32(a.coeffs[i]);
}
}
/// For all coefficients of in/out polynomial add Q if
/// coefficient is negative.
pub fn poly_caddq(a: &mut Poly) {
for i in 0..N {
a.coeffs[i] = caddq(a.coeffs[i]);
}
}
/// Add polynomials. No modular reduction is performed.
pub fn poly_add(c: &mut Poly, b: &Poly) {
for i in 0..N {
c.coeffs[i] = c.coeffs[i] + b.coeffs[i];
}
}
/// Subtract polynomials. Assumes coefficients of second input
/// polynomial to be less than 2*Q. No modular reduction is
/// performed.
pub fn poly_sub(c: &mut Poly, b: &Poly) {
for i in 0..N {
c.coeffs[i] = c.coeffs[i] - b.coeffs[i];
}
}
/// Multiply polynomial by 2^D without modular reduction. Assumes
/// input coefficients to be less than 2^{32-D}.
pub fn poly_shiftl(a: &mut Poly) {
for i in 0..N {
a.coeffs[i] <<= D;
}
}
/// Inplace forward NTT. Output coefficients can be up to
/// 16*Q larger than input coefficients.
pub fn poly_ntt(a: &mut Poly) {
ntt(&mut a.coeffs);
}
/// Inplace inverse NTT and multiplication by 2^{32}.
/// Input coefficients need to be less than 2*Q.
/// Output coefficients are less than 2*Q.
pub fn poly_invntt_tomont(a: &mut Poly) {
invntt_tomont(&mut a.coeffs);
}
/// Pointwise multiplication of polynomials in NTT domain
/// representation and multiplication of resulting polynomial
/// by 2^{-32}. Output coefficients are less than 2*Q if input
/// coefficient are less than 22*Q.
pub fn poly_pointwise_montgomery(c: &mut Poly, a: &Poly, b: &Poly) {
for i in 0..N {
c.coeffs[i] = montgomery_reduce((a.coeffs[i] as i64) * b.coeffs[i] as i64);
}
}
/// For all coefficients c of the input polynomial,
/// compute c0, c1 such that c mod Q = c1*2^D + c0
/// with -2^{D-1} < c0 <= 2^{D-1}. Assumes coefficients to be
/// standard representatives.
pub fn poly_power2round(a1: &mut Poly, a0: &mut Poly) {
for i in 0..N {
a1.coeffs[i] = power2round(a1.coeffs[i], &mut a0.coeffs[i]);
}
}
/// For all coefficients c of the input polynomial,
/// compute high and low bits c0, c1 such c mod Q = c1*ALPHA + c0
/// with -ALPHA/2 < c0 <= ALPHA/2 except c1 = (Q-1)/ALPHA where we
/// set c1 = 0 and -ALPHA/2 <= c0 = c mod Q - Q < 0.
/// Assumes coefficients to be standard representatives.
pub fn poly_decompose(a1: &mut Poly, a0: &mut Poly) {
for i in 0..N {
a1.coeffs[i] = decompose(&mut a0.coeffs[i], a1.coeffs[i]);
}
}
/// Compute hint polynomial. The coefficients of which indicate
/// whether the low bits of the corresponding coefficient of
/// the input polynomial overflow into the high bits.
pub fn poly_make_hint(h: &mut Poly, a0: &Poly, a1: &Poly) -> i32 {
let mut s = 0i32;
for i in 0..N {
h.coeffs[i] = make_hint(a0.coeffs[i], a1.coeffs[i]) as i32;
s += h.coeffs[i];
}
s
}
/// Use hint polynomial to correct the high bits of a polynomial.
///
/// Arguments: - poly *b: pointer to output polynomial with corrected high bits
/// - const poly *a: pointer to input polynomial
/// - const poly *h: pointer to input hint polynomial
pub fn poly_use_hint(b: &mut Poly, h: &Poly) {
for i in 0..N {
b.coeffs[i] = use_hint(b.coeffs[i], h.coeffs[i] as u8);
}
}
/// Check infinity norm of polynomial against given bound.
/// Assumes input coefficients to be standard representatives.
/// Returns 0 if norm is strictly smaller than B and 1 otherwise.
pub fn poly_chknorm(a: &Poly, b: i32) -> u8 {
// It is ok to leak which coefficient violates the bound since
// the probability for each coefficient is independent of secret
// data but we must not leak the sign of the centralized representative.
let mut t;
if b > (Q_I32 - 1) / 8 {
return 1;
}
for i in 0..N {
// Absolute value of centralized representative
t = a.coeffs[i] >> 31;
t = a.coeffs[i] - (t & 2 * a.coeffs[i]);
if t >= b {
return 1;
}
}
return 0;
}
/// Sample uniformly random coefficients in [0, Q-1] by
/// performing rejection sampling on array of random bytes.
/// Returns number of sampled coefficients. Can be smaller than len if not enough
/// random bytes were given.
pub fn rej_uniform(a: &mut [i32], len: u32, buf: &[u8], buflen: usize) -> u32 {
let (mut ctr, mut pos) = (0usize, 0usize);
let mut t;
while ctr < len as usize && pos + 3 <= buflen {
t = buf[pos] as u32;
pos += 1;
t |= (buf[pos] as u32) << 8;
pos += 1;
t |= (buf[pos] as u32) << 16;
pos += 1;
t &= 0x7FFFFF;
if t < Q as u32 {
a[ctr] = t as i32;
ctr += 1;
}
}
ctr as u32
}
const POLY_UNIFORM_NBLOCKS: usize =
(768 + STREAM128_BLOCKBYTES - 1) / STREAM128_BLOCKBYTES;
/// Sample polynomial with uniformly random coefficients
/// in [0, Q-1] by performing rejection sampling using the
/// output stream of SHAKE256(seed|nonce) or AES256CTR(seed,nonce).
pub fn poly_uniform(a: &mut Poly, seed: &[u8], nonce: u16) {
let mut buflen = POLY_UNIFORM_NBLOCKS * STREAM128_BLOCKBYTES;
let mut buf = [0u8; POLY_UNIFORM_NBLOCKS * STREAM128_BLOCKBYTES + 2];
let mut state = Stream128State::default();
stream128_init(&mut state, seed, nonce);
stream128_squeezeblocks(&mut buf, POLY_UNIFORM_NBLOCKS as u64, &mut state);
let mut ctr = rej_uniform(&mut a.coeffs, N_U32, &mut buf, buflen);
let mut off;
while ctr < N_U32 {
off = buflen % 3;
for i in 0..off {
buf[i] = buf[buflen - off + i];
}
buflen = STREAM128_BLOCKBYTES + off;
stream128_squeezeblocks(&mut buf[off..], 1, &mut state);
ctr += rej_uniform(
&mut a.coeffs[(ctr as usize)..],
N_U32 - ctr,
&mut buf,
buflen,
);
}
}
/// Sample uniformly random coefficients in [-ETA, ETA] by
/// performing rejection sampling using array of random bytes.
pub fn rej_eta(a: &mut [i32], len: usize, buf: &[u8], buflen: usize) -> u32 {
let (mut ctr, mut pos) = (0usize, 0usize);
let (mut t0, mut t1);
while ctr < len && pos < buflen {
t0 = (buf[pos] & 0x0F) as u32;
t1 = (buf[pos] >> 4) as u32;
pos += 1;
if ETA == 2 {
if t0 < 15 {
t0 = t0 - (205 * t0 >> 10) * 5;
a[ctr] = 2 - t0 as i32;
ctr += 1;
}
if t1 < 15 && ctr < len {
t1 = t1 - (205 * t1 >> 10) * 5;
a[ctr] = 2 - t1 as i32;
ctr += 1;
}
} else if ETA == 4 {
if t0 < 9 {
a[ctr] = 4 - t0 as i32;
ctr += 1;
}
if t1 < 9 && ctr < len {
a[ctr] = 4 - t1 as i32;
ctr += 1;
}
}
}
ctr as u32
}
/// Sample polynomial with uniformly random coefficients
/// in [-ETA,ETA] by performing rejection sampling using the
/// output stream from SHAKE256(seed|nonce) or AES256CTR(seed,nonce).
const POLY_UNIFORM_ETA_NBLOCKS: usize = if ETA == 2 {
(136 + STREAM256_BLOCKBYTES - 1) / STREAM256_BLOCKBYTES
} else {
(227 + STREAM256_BLOCKBYTES - 1) / STREAM256_BLOCKBYTES
};
pub fn poly_uniform_eta(a: &mut Poly, seed: &[u8], nonce: u16) {
let buflen = POLY_UNIFORM_ETA_NBLOCKS * STREAM256_BLOCKBYTES;
let mut buf = [0u8; POLY_UNIFORM_ETA_NBLOCKS * STREAM256_BLOCKBYTES];
let mut state = Stream256State::default();
stream256_init(&mut state, seed, nonce);
stream256_squeezeblocks(
&mut buf,
POLY_UNIFORM_ETA_NBLOCKS as u64,
&mut state,
);
let mut ctr = rej_eta(&mut a.coeffs, N, &buf, buflen);
while ctr < N_U32 {
stream256_squeezeblocks(&mut buf, 1, &mut state);
ctr += rej_eta(
&mut a.coeffs[ctr as usize..],
N - ctr as usize,
&buf,
STREAM256_BLOCKBYTES,
);
}
}
const POLY_UNIFORM_GAMMA1_NBLOCKS: usize =
(POLYZ_PACKEDBYTES + STREAM256_BLOCKBYTES - 1) / STREAM256_BLOCKBYTES;
/// Sample polynomial with uniformly random coefficients
/// in [-(GAMMA1 - 1), GAMMA1 - 1] by performing rejection
/// sampling on output stream of SHAKE256(seed|nonce)
/// or AES256CTR(seed,nonce).
pub fn poly_uniform_gamma1(a: &mut Poly, seed: &[u8], nonce: u16) {
let mut buf = [0u8; POLY_UNIFORM_GAMMA1_NBLOCKS * STREAM256_BLOCKBYTES];
let mut state = Stream256State::default();
stream256_init(&mut state, seed, nonce);
stream256_squeezeblocks(
&mut buf,
POLY_UNIFORM_GAMMA1_NBLOCKS as u64,
&mut state,
);
polyz_unpack(a, &mut buf);
}
/// Implementation of H. Samples polynomial with TAU nonzero
/// coefficients in {-1,1} using the output stream of
/// SHAKE256(seed).
pub fn poly_challenge(c: &mut Poly, seed: &[u8]) {
let mut _signs = 0u64;
let mut buf = [0u8; SHAKE256_RATE];
let mut state = KeccakState::default(); //shake256_init
shake256_absorb(&mut state, seed, SEEDBYTES);
shake256_finalize(&mut state);
shake256_squeezeblocks(&mut buf, 1, &mut state);
for i in 0..8 {
_signs |= (buf[i] as u64) << 8 * i;
}
let mut pos: usize = 8;
// let mut b = buf[pos];
let mut b;
c.coeffs.fill(0);
for i in N - TAU..N {
loop {
if pos >= SHAKE256_RATE {
shake256_squeezeblocks(&mut buf, 1, &mut state);
pos = 0;
}
b = buf[pos] as usize;
pos += 1;
if b <= i {
break;
}
}
c.coeffs[i] = c.coeffs[b as usize];
c.coeffs[b as usize] = 1i32 - 2 * (_signs & 1) as i32;
_signs >>= 1;
}
}
/// Bit-pack polynomial with coefficients in [-ETA,ETA].
/// Input coefficients are assumed to lie in [Q-ETA,Q+ETA].
pub fn polyeta_pack(r: &mut [u8], a: &Poly) {
let mut t = [0u8; 8];
if ETA == 2 {
for i in 0..N / 8 {
t[0] = (ETA_I32 - a.coeffs[8 * i + 0]) as u8;
t[1] = (ETA_I32 - a.coeffs[8 * i + 1]) as u8;
t[2] = (ETA_I32 - a.coeffs[8 * i + 2]) as u8;
t[3] = (ETA_I32 - a.coeffs[8 * i + 3]) as u8;
t[4] = (ETA_I32 - a.coeffs[8 * i + 4]) as u8;
t[5] = (ETA_I32 - a.coeffs[8 * i + 5]) as u8;
t[6] = (ETA_I32 - a.coeffs[8 * i + 6]) as u8;
t[7] = (ETA_I32 - a.coeffs[8 * i + 7]) as u8;
r[3 * i + 0] = (t[0] >> 0) | (t[1] << 3) | (t[2] << 6);
r[3 * i + 1] = (t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7);
r[3 * i + 2] = (t[5] >> 1) | (t[6] << 2) | (t[7] << 5);
}
} else {
for i in 0..N / 2 {
t[0] = (ETA_I32 - a.coeffs[2 * i + 0]) as u8;
t[1] = (ETA_I32 - a.coeffs[2 * i + 1]) as u8;
r[i] = t[0] | (t[1] << 4);
}
}
}
/// Unpack polynomial with coefficients in [-ETA,ETA].
pub fn polyeta_unpack(r: &mut Poly, a: &[u8]) {
if ETA == 2 {
for i in 0..N / 8 {
r.coeffs[8 * i + 0] = (a[3 * i + 0] & 0x07) as i32;
r.coeffs[8 * i + 1] = ((a[3 * i + 0] >> 3) & 0x07) as i32;
r.coeffs[8 * i + 2] =
(((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 0x07) as i32;
r.coeffs[8 * i + 3] = ((a[3 * i + 1] >> 1) & 0x07) as i32;
r.coeffs[8 * i + 4] = ((a[3 * i + 1] >> 4) & 0x07) as i32;
r.coeffs[8 * i + 5] =
(((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 0x07) as i32;
r.coeffs[8 * i + 6] = ((a[3 * i + 2] >> 2) & 0x07) as i32;
r.coeffs[8 * i + 7] = ((a[3 * i + 2] >> 5) & 0x07) as i32;
r.coeffs[8 * i + 0] = (ETA_I32 - r.coeffs[8 * i + 0]) as i32;
r.coeffs[8 * i + 1] = (ETA_I32 - r.coeffs[8 * i + 1]) as i32;
r.coeffs[8 * i + 2] = (ETA_I32 - r.coeffs[8 * i + 2]) as i32;
r.coeffs[8 * i + 3] = (ETA_I32 - r.coeffs[8 * i + 3]) as i32;
r.coeffs[8 * i + 4] = (ETA_I32 - r.coeffs[8 * i + 4]) as i32;
r.coeffs[8 * i + 5] = (ETA_I32 - r.coeffs[8 * i + 5]) as i32;
r.coeffs[8 * i + 6] = (ETA_I32 - r.coeffs[8 * i + 6]) as i32;
r.coeffs[8 * i + 7] = (ETA_I32 - r.coeffs[8 * i + 7]) as i32;
}
} else {
for i in 0..N / 2 {
r.coeffs[2 * i + 0] = (a[i] & 0x0F) as i32;
r.coeffs[2 * i + 1] = (a[i] >> 4) as i32;
r.coeffs[2 * i + 0] = (ETA_I32 - r.coeffs[2 * i + 0]) as i32;
r.coeffs[2 * i + 1] = (ETA_I32 - r.coeffs[2 * i + 1]) as i32;
}
}
}
/// Bit-pack polynomial t1 with coefficients fitting in 10 bits.
/// Input coefficients are assumed to be standard representatives.
pub fn polyt1_pack(r: &mut [u8], a: &Poly) {
for i in 0..N / 4 {
r[5 * i + 0] = (a.coeffs[4 * i + 0] >> 0) as u8;
r[5 * i + 1] =
((a.coeffs[4 * i + 0] >> 8) | (a.coeffs[4 * i + 1] << 2)) as u8;
r[5 * i + 2] =
((a.coeffs[4 * i + 1] >> 6) | (a.coeffs[4 * i + 2] << 4)) as u8;
r[5 * i + 3] =
((a.coeffs[4 * i + 2] >> 4) | (a.coeffs[4 * i + 3] << 6)) as u8;
r[5 * i + 4] = (a.coeffs[4 * i + 3] >> 2) as u8;
}
}
/// Unpack polynomial t1 with 9-bit coefficients.
/// Output coefficients are standard representatives.
pub fn polyt1_unpack(r: &mut Poly, a: &[u8]) {
for i in 0..N / 4 {
r.coeffs[4 * i + 0] = (((a[5 * i + 0] >> 0) as u32
| (a[5 * i + 1] as u32) << 8)
& 0x3FF) as i32;
r.coeffs[4 * i + 1] = (((a[5 * i + 1] >> 2) as u32
| (a[5 * i + 2] as u32) << 6)
& 0x3FF) as i32;
r.coeffs[4 * i + 2] = (((a[5 * i + 2] >> 4) as u32
| (a[5 * i + 3] as u32) << 4)
& 0x3FF) as i32;
r.coeffs[4 * i + 3] = (((a[5 * i + 3] >> 6) as u32
| (a[5 * i + 4] as u32) << 2)
& 0x3FF) as i32;
}
}
/// Bit-pack polynomial t0 with coefficients in [-2^{D-1}, 2^{D-1}].
pub fn polyt0_pack(r: &mut [u8], a: &Poly) {
let mut t = [0i32; 8];
for i in 0..N / 8 {
t[0] = D_SHL - a.coeffs[8 * i + 0];
t[1] = D_SHL - a.coeffs[8 * i + 1];
t[2] = D_SHL - a.coeffs[8 * i + 2];
t[3] = D_SHL - a.coeffs[8 * i + 3];
t[4] = D_SHL - a.coeffs[8 * i + 4];
t[5] = D_SHL - a.coeffs[8 * i + 5];
t[6] = D_SHL - a.coeffs[8 * i + 6];
t[7] = D_SHL - a.coeffs[8 * i + 7];
r[13 * i + 0] = (t[0]) as u8;
r[13 * i + 1] = (t[0] >> 8) as u8;
r[13 * i + 1] |= (t[1] << 5) as u8;
r[13 * i + 2] = (t[1] >> 3) as u8;
r[13 * i + 3] = (t[1] >> 11) as u8;
r[13 * i + 3] |= (t[2] << 2) as u8;
r[13 * i + 4] = (t[2] >> 6) as u8;
r[13 * i + 4] |= (t[3] << 7) as u8;
r[13 * i + 5] = (t[3] >> 1) as u8;
r[13 * i + 6] = (t[3] >> 9) as u8;
r[13 * i + 6] |= (t[4] << 4) as u8;
r[13 * i + 7] = (t[4] >> 4) as u8;
r[13 * i + 8] = (t[4] >> 12) as u8;
r[13 * i + 8] |= (t[5] << 1) as u8;
r[13 * i + 9] = (t[5] >> 7) as u8;
r[13 * i + 9] |= (t[6] << 6) as u8;
r[13 * i + 10] = (t[6] >> 2) as u8;
r[13 * i + 11] = (t[6] >> 10) as u8;
r[13 * i + 11] |= (t[7] << 3) as u8;
r[13 * i + 12] = (t[7] >> 5) as u8;
}
}
/// Unpack polynomial t0 with coefficients in ]-2^{D-1}, 2^{D-1}].
/// Output coefficients lie in ]Q-2^{D-1},Q+2^{D-1}].
pub fn polyt0_unpack(r: &mut Poly, a: &[u8]) {
for i in 0..N / 8 {
r.coeffs[8 * i + 0] = a[13 * i + 0] as i32;
r.coeffs[8 * i + 0] |= (a[13 * i + 1] as i32) << 8;
r.coeffs[8 * i + 0] &= 0x1FFF;
r.coeffs[8 * i + 1] = (a[13 * i + 1] as i32) >> 5;
r.coeffs[8 * i + 1] |= (a[13 * i + 2] as i32) << 3;
r.coeffs[8 * i + 1] |= (a[13 * i + 3] as i32) << 11;
r.coeffs[8 * i + 1] &= 0x1FFF;
r.coeffs[8 * i + 2] = (a[13 * i + 3] as i32) >> 2;
r.coeffs[8 * i + 2] |= (a[13 * i + 4] as i32) << 6;
r.coeffs[8 * i + 2] &= 0x1FFF;
r.coeffs[8 * i + 3] = (a[13 * i + 4] as i32) >> 7;
r.coeffs[8 * i + 3] |= (a[13 * i + 5] as i32) << 1;
r.coeffs[8 * i + 3] |= (a[13 * i + 6] as i32) << 9;
r.coeffs[8 * i + 3] &= 0x1FFF;
r.coeffs[8 * i + 4] = (a[13 * i + 6] as i32) >> 4;
r.coeffs[8 * i + 4] |= (a[13 * i + 7] as i32) << 4;
r.coeffs[8 * i + 4] |= (a[13 * i + 8] as i32) << 12;
r.coeffs[8 * i + 4] &= 0x1FFF;
r.coeffs[8 * i + 5] = (a[13 * i + 8] as i32) >> 1;
r.coeffs[8 * i + 5] |= (a[13 * i + 9] as i32) << 7;
r.coeffs[8 * i + 5] &= 0x1FFF;
r.coeffs[8 * i + 6] = (a[13 * i + 9] as i32) >> 6;
r.coeffs[8 * i + 6] |= (a[13 * i + 10] as i32) << 2;
r.coeffs[8 * i + 6] |= (a[13 * i + 11] as i32) << 10;
r.coeffs[8 * i + 6] &= 0x1FFF;
r.coeffs[8 * i + 7] = (a[13 * i + 11] as i32) >> 3;
r.coeffs[8 * i + 7] |= (a[13 * i + 12] as i32) << 5;
r.coeffs[8 * i + 7] &= 0x1FFF; // TODO: Unnecessary mask?
r.coeffs[8 * i + 0] = D_SHL - r.coeffs[8 * i + 0];
r.coeffs[8 * i + 1] = D_SHL - r.coeffs[8 * i + 1];
r.coeffs[8 * i + 2] = D_SHL - r.coeffs[8 * i + 2];
r.coeffs[8 * i + 3] = D_SHL - r.coeffs[8 * i + 3];
r.coeffs[8 * i + 4] = D_SHL - r.coeffs[8 * i + 4];
r.coeffs[8 * i + 5] = D_SHL - r.coeffs[8 * i + 5];
r.coeffs[8 * i + 6] = D_SHL - r.coeffs[8 * i + 6];
r.coeffs[8 * i + 7] = D_SHL - r.coeffs[8 * i + 7];
}
}
/// Bit-pack polynomial z with coefficients
/// in [-(GAMMA1 - 1), GAMMA1 - 1].
/// Input coefficients are assumed to be standard representatives.*
pub fn polyz_pack(r: &mut [u8], a: &Poly) {
let mut t = [0i32; 4];
if GAMMA1 == (1 << 17) {
for i in 0..N / 4 {
t[0] = GAMMA1_I32 - a.coeffs[4 * i + 0];
t[1] = GAMMA1_I32 - a.coeffs[4 * i + 1];
t[2] = GAMMA1_I32 - a.coeffs[4 * i + 2];
t[3] = GAMMA1_I32 - a.coeffs[4 * i + 3];
r[9 * i + 0] = (t[0]) as u8;
r[9 * i + 1] = (t[0] >> 8) as u8;
r[9 * i + 2] = (t[0] >> 16) as u8;
r[9 * i + 2] |= (t[1] << 2) as u8;
r[9 * i + 3] = (t[1] >> 6) as u8;
r[9 * i + 4] = (t[1] >> 14) as u8;
r[9 * i + 4] |= (t[2] << 4) as u8;
r[9 * i + 5] = (t[2] >> 4) as u8;
r[9 * i + 6] = (t[2] >> 12) as u8;
r[9 * i + 6] |= (t[3] << 6) as u8;
r[9 * i + 7] = (t[3] >> 2) as u8;
r[9 * i + 8] = (t[3] >> 10) as u8;
}
} else if GAMMA1 == 1 << 19 {
for i in 0..N / 2 {
t[0] = GAMMA1_I32 - a.coeffs[2 * i + 0];
t[1] = GAMMA1_I32 - a.coeffs[2 * i + 1];
r[5 * i + 0] = (t[0]) as u8;
r[5 * i + 1] = (t[0] >> 8) as u8;
r[5 * i + 2] = (t[0] >> 16) as u8;
r[5 * i + 2] |= (t[1] << 4) as u8;
r[5 * i + 3] = (t[1] >> 4) as u8;
r[5 * i + 4] = (t[1] >> 12) as u8;
}
}
}
/// Unpack polynomial z with coefficients
/// in [-(GAMMA1 - 1), GAMMA1 - 1].
/// Output coefficients are standard representatives.
pub fn polyz_unpack(r: &mut Poly, a: &[u8]) {
if GAMMA1 == (1 << 17) {
for i in 0..N / 4 {
r.coeffs[4 * i + 0] = a[9 * i + 0] as i32;
r.coeffs[4 * i + 0] |= (a[9 * i + 1] as i32) << 8;
r.coeffs[4 * i + 0] |= (a[9 * i + 2] as i32) << 16;
r.coeffs[4 * i + 0] &= 0x3FFFF;
r.coeffs[4 * i + 1] = (a[9 * i + 2] as i32) >> 2;
r.coeffs[4 * i + 1] |= (a[9 * i + 3] as i32) << 6;
r.coeffs[4 * i + 1] |= (a[9 * i + 4] as i32) << 14;
r.coeffs[4 * i + 1] &= 0x3FFFF;
r.coeffs[4 * i + 2] = (a[9 * i + 4] as i32) >> 4;
r.coeffs[4 * i + 2] |= (a[9 * i + 5] as i32) << 4;
r.coeffs[4 * i + 2] |= (a[9 * i + 6] as i32) << 12;
r.coeffs[4 * i + 2] &= 0x3FFFF;
r.coeffs[4 * i + 3] = (a[9 * i + 6] as i32) >> 6;
r.coeffs[4 * i + 3] |= (a[9 * i + 7] as i32) << 2;
r.coeffs[4 * i + 3] |= (a[9 * i + 8] as i32) << 10;
r.coeffs[4 * i + 3] &= 0x3FFFF; // TODO: Unnecessary mask?
r.coeffs[4 * i + 0] = GAMMA1_I32 - r.coeffs[4 * i + 0];
r.coeffs[4 * i + 1] = GAMMA1_I32 - r.coeffs[4 * i + 1];
r.coeffs[4 * i + 2] = GAMMA1_I32 - r.coeffs[4 * i + 2];
r.coeffs[4 * i + 3] = GAMMA1_I32 - r.coeffs[4 * i + 3];
}
} else if GAMMA1 == 1 << 19 {
for i in 0..N / 2 {
r.coeffs[2 * i + 0] = a[5 * i + 0] as i32;
r.coeffs[2 * i + 0] |= (a[5 * i + 1] as i32) << 8;
r.coeffs[2 * i + 0] |= (a[5 * i + 2] as i32) << 16;
r.coeffs[2 * i + 0] &= 0xFFFFF;
r.coeffs[2 * i + 1] = (a[5 * i + 2] as i32) >> 4;
r.coeffs[2 * i + 1] |= (a[5 * i + 3] as i32) << 4;
r.coeffs[2 * i + 1] |= (a[5 * i + 4] as i32) << 12;
r.coeffs[2 * i + 0] &= 0xFFFFF; // TODO: Unnecessary mask?
r.coeffs[2 * i + 0] = GAMMA1_I32 - r.coeffs[2 * i + 0];
r.coeffs[2 * i + 1] = GAMMA1_I32 - r.coeffs[2 * i + 1];
}
}
}
/// Bit-pack polynomial w1 with coefficients in [0, 15].
/// Input coefficients are assumed to be standard representatives.
pub fn polyw1_pack(r: &mut [u8], a: &Poly) {
if GAMMA2 == (Q - 1) / 88 {
for i in 0..N / 4 {
r[3 * i + 0] = a.coeffs[4 * i + 0] as u8;
r[3 * i + 0] |= (a.coeffs[4 * i + 1] << 6) as u8;
r[3 * i + 1] = (a.coeffs[4 * i + 1] >> 2) as u8;
r[3 * i + 1] |= (a.coeffs[4 * i + 2] << 4) as u8;
r[3 * i + 2] = (a.coeffs[4 * i + 2] >> 4) as u8;
r[3 * i + 2] |= (a.coeffs[4 * i + 3] << 2) as u8;
}
} else {
for i in 0..N / 2 {
r[i] = (a.coeffs[2 * i + 0] | (a.coeffs[2 * i + 1] << 4)) as u8;
}
}
}