1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/// Polynomial sampling algorithms for ML-KEM (FIPS 203 Section 4.2.2).
///
/// Two sampling methods are provided:
///
/// - [`sample_ntt`] -- Algorithm 7 (SampleNTT): rejection sampling from a SHAKE128
/// XOF to produce a uniformly random polynomial in NTT domain. Operates on
/// **public** data (the seed rho is public), so rejection branching does not
/// leak secret information.
///
/// - [`sample_poly_cbd`] -- Algorithm 8 (SamplePolyCBD): centered binomial
/// distribution sampling from PRF output. Used for secret and error
/// polynomials. Fully constant-time (no secret-dependent branches).
use ;
use sha3;
/// Sample a uniformly random NTT-domain polynomial (Algorithm 7: SampleNTT).
///
/// Uses SHAKE128 as an XOF (extendable output function) seeded with the
/// 34-byte input `seed = rho || j || i`. Pairs of 12-bit candidates are
/// extracted from each 3-byte block and accepted if less than q = 3329
/// (rejection sampling).
///
/// Since the seed rho is public data, the variable-time rejection loop
/// does not leak secret information through timing.
///
/// # Arguments
///
/// * `seed` - A 34-byte XOF seed: `rho (32 bytes) || column_index (1 byte) || row_index (1 byte)`.
///
/// # Returns
///
/// A 256-coefficient polynomial in NTT domain with coefficients in `[0, q-1]`.
/// Sample a polynomial from the centered binomial distribution CBD_eta (Algorithm 8).
///
/// For each of the 256 coefficients, sums `eta` random bits for `x` and
/// `eta` random bits for `y`, then computes `(x - y) mod q`. The result
/// lies in `[-eta, eta]` before reduction, corresponding to the centered
/// binomial distribution.
///
/// Fully constant-time: no branches depend on secret bit values. The
/// branchless modular reduction adds q when the difference is negative
/// using an arithmetic shift mask.
///
/// # Arguments
///
/// * `eta` - The CBD parameter (2 or 3 for ML-KEM).
/// * `bytes` - Exactly `64 * eta` bytes of PRF output.
///
/// # Returns
///
/// A 256-coefficient polynomial with coefficients in `[0, q-1]`.
///
/// # Panics
///
/// Debug-asserts that `bytes.len() == 64 * eta`.