From ebc1c263b44d084052ec1d7610f25632a19baee3 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 7 Sep 2026 21:03:22 +0200 Subject: [PATCH] crypto.ff: hide constant-time selection masks from optimizer Hide the selection mask so LLVM can't replace it with a branch around the calling loop. Fixes #37023 --- lib/std/crypto/ff.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/std/crypto/ff.zig b/lib/std/crypto/ff.zig index 4a465f433635179162db81870e7a3ec162027e4d..26e3ec82fc43e221927dd539e88c9ac5f9a1caac 100644 --- a/lib/std/crypto/ff.zig +++ b/lib/std/crypto/ff.zig @@ -1083,12 +1083,20 @@ pub fn Modulus(comptime max_bits: comptime_int) type { }; } +fn valueBarrier(x: Limb) Limb { + if (@inComptime() or builtin.zig_backend == .stage2_c) return x; + return asm ("" + : [ret] "=r" (-> Limb), + : [x] "0" (x), + ); +} + const ct = if (std.options.side_channels_mitigations == .none) ct_unprotected else ct_protected; const ct_protected = struct { // Returns x if on is true, otherwise y. fn select(on: bool, x: Limb, y: Limb) Limb { - const mask = @as(Limb, 0) -% @intFromBool(on); + const mask = valueBarrier(@as(Limb, 0) -% @intFromBool(on)); return y ^ (mask & (y ^ x)); } -- 2.54.0