| ... | @@ -1020,8 +1020,15 @@ const Poly = struct { | ... | @@ -1020,8 +1020,15 @@ const Poly = struct { |
| 1020 | // = ⌊(2ᵈ/q)x+½⌋ mod⁺ 2ᵈ | 1020 | // = ⌊(2ᵈ/q)x+½⌋ mod⁺ 2ᵈ |
| 1021 | // = ⌊((x << d) + q/2) / q⌋ mod⁺ 2ᵈ | 1021 | // = ⌊((x << d) + q/2) / q⌋ mod⁺ 2ᵈ |
| 1022 | // = DIV((x << d) + q/2, q) & ((1<<d) - 1) | 1022 | // = DIV((x << d) + q/2, q) & ((1<<d) - 1) |
| 1023 | const t = @as(u32, @intCast(p.cs[in_off + i])) << d; | 1023 | const t = @as(u24, @intCast(p.cs[in_off + i])) << d; |
| 1024 | in[i] = @as(u16, @intCast(@divFloor(t + q_over_2, Q) & two_d_min_1)); | 1024 | // Division by invariant multiplication, equivalent to DIV(t + q/2, q). |
| | 1025 | // A division may not be a constant-time operation, even with a constant denominator. |
| | 1026 | // Here, side channels would leak information about the shared secret, see https://kyberslash.cr.yp.to |
| | 1027 | // Multiplication, on the other hand, is a constant-time operation on the CPUs we currently support. |
| | 1028 | comptime assert(d <= 11); |
| | 1029 | comptime assert(((20642679 * @as(u64, Q)) >> 36) == 1); |
| | 1030 | const u: u32 = @intCast((@as(u64, t + q_over_2) * 20642679) >> 36); |
| | 1031 | in[i] = @intCast(u & two_d_min_1); |
| 1025 | } | 1032 | } |
| 1026 | | 1033 | |
| 1027 | // Now we pack the d-bit integers from `in' into out as bytes. | 1034 | // Now we pack the d-bit integers from `in' into out as bytes. |