ml: Properly implement ByteDecode with d=12

I've overlooked the "m = q if d = 12" note in the pseudo-code for
Algorithm 6.  The text further up in the section actually clarifies
this:

  For d = 12, ByteDecode produces integers modulo q as output...(it)
  converts each 12-bit segment of its input into an integer modulo 4096
  and then reduces the result modulo q. This is no longer a one-to-one
  operation.

This did not have any practical impact (other than accepting public keys
that are technically non-compliant) because the values would get properly
reduced anyway by the Barrett reduction used in `mul_modq()`.

Fixes: 89f4b345e3 ("ml: Add software implementation of ML-KEM")
This commit is contained in:
Tobias Brunner
2026-07-24 08:47:39 +02:00
parent b6ff363e1c
commit 4f3e572b5b
+8 -2
View File
@@ -402,18 +402,24 @@ static void encode_poly_arr(uint8_t k, ml_poly_t *a, uint8_t *out)
* Decode k polynomials from a byte array (12-bit version that unpacks 2
* coefficients from 3 bytes, not using ml_bitpacker_t for performance reasons).
*
* As described in section 4.2.1, d=12 is a special version of ByteDecode that
* does a reduction mod q.
*
* Algorithm 6 in FIPS 203.
*/
static void decode_poly_arr(uint8_t k, uint8_t *in, ml_poly_t *a)
{
uint16_t f0, f1;
int i, j;
for (i = 0; i < k; i++)
{
for (j = 0; j < ML_KEM_N / 2; j++)
{
a[i].f[2*j] = (in[3*j] | ((uint16_t)in[3*j+1] << 8)) & 0xfff;
a[i].f[2*j+1] = ((in[3*j+1] >> 4) | ((uint16_t)in[3*j+2] << 4)) & 0xfff;
f0 = ( in[3*j] | ((uint16_t)in[3*j+1] << 8)) & 0xfff;
f1 = ((in[3*j+1] >> 4) | ((uint16_t)in[3*j+2] << 4)) & 0xfff;
a[i].f[2*j] = ml_reduce_modq(f0);
a[i].f[2*j+1] = ml_reduce_modq(f1);
}
in += ML_KEM_POLY_LEN;
}