Sample p uniformly with coefficients of norm less than or equal to η, using the given seed and nonce with SHAKE-256. The polynomial will not be normalized, but will have coefficients in [q-η, q+η]. FIPS 204: ExpandS (Algorithm 27)
fn expandS(comptime eta: u8, seed: *const [64]u8, nonce: u16) Poly
fn expandS(comptime eta: u8, seed: *const [64]u8, nonce: u16) Poly {
comptime {
if (eta != 2 and eta != 4) {
@compileError("eta must be 2 or 4");
}
}
var p = Poly.zero;
var i: usize = 0;
var buf: [sha3.Shake256.block_length]u8 = undefined; // SHAKE-256 rate is 136 bytes
// Prepare input: seed || nonce (little-endian u16)
var input: [66]u8 = undefined;
@memcpy(input[0..64], seed);
input[64] = @truncate(nonce);
input[65] = @truncate(nonce >> 8);
var h = sha3.Shake256.init(.{});
h.update(&input);
while (i < N) {
h.squeeze(&buf);
// Process buffer: extract two samples per byte (4-bit nibbles)
var j: usize = 0;
while (j < buf.len and i < N) : (j += 1) {
var t1 = @as(u32, buf[j]) & 15;
var t2 = @as(u32, buf[j]) >> 4;
if (eta == 2) {
// For eta=2: reject if t > 14, then reduce mod 5
if (t1 <= 14) {
t1 -%= ((205 * t1) >> 10) * 5; // reduce mod 5
p.cs[i] = Q + eta - t1;
i += 1;
}
if (t2 <= 14 and i < N) {
t2 -%= ((205 * t2) >> 10) * 5; // reduce mod 5
p.cs[i] = Q + eta - t2;
i += 1;
}
} else if (eta == 4) {
// For eta=4: accept if t <= 2*eta = 8
if (t1 <= 2 * eta) {
p.cs[i] = Q + eta - t1;
i += 1;
}
if (t2 <= 2 * eta and i < N) {
p.cs[i] = Q + eta - t2;
i += 1;
}
}
}
}
return p;
}