authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2023-12-22 16:57:16+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-12-22 15:57:16+00:00
log21ae64852a531c36ae3166aa2b6f1fbaaf76c6f9
tree0fe35730e2a4f73ae29b3c32df8115adcb12eeb8
parent42ddf592dd610dda3371cae2eba63ac3e8502c64
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std.crypto.kem.kyber: mitigate KyberSlash (#18316)

On some architectures, including AMD Zen CPUs, dividing a secret by a constant denominator may not be a constant-time operation. And most Kyber implementations, including ours, could leak the hamming weight of the shared secret because of this. See: https://kyberslash.cr.yp.to Multiplications aren't guaranteed to be constant-time either, but at least on the CPUs we currently support, it is.

1 files changed, 9 insertions(+), 2 deletions(-)

lib/std/crypto/kyber_d00.zig+9-2
...@@ -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 }
10261033
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.