Skip to content

Commit 060a9bb

Browse files
committed
Improve const-time code in MLKemEngine
1 parent dc05aa4 commit 060a9bb

1 file changed

Lines changed: 41 additions & 12 deletions

File tree

crypto/src/crypto/kems/mlkem/MLKemEngine.cs

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Diagnostics;
3+
using System.Runtime.CompilerServices;
34

45
using Org.BouncyCastle.Crypto.Parameters;
56
using Org.BouncyCastle.Security;
@@ -142,7 +143,7 @@ internal void KemDecrypt(Span<byte> secret, ReadOnlySpan<byte> encapsulation,
142143

143144
m_indCpa.Encrypt(cmp, buf[..SymBytes], pk, kr[SymBytes..]);
144145

145-
bool fail = !Arrays.FixedTimeEquals(cmp, encapsulation);
146+
int fail = ~FixedTimeEquals(cmp, encapsulation);
146147

147148
Symmetric.Hash_h(encapsulation, kr[SymBytes..]);
148149
secretKey.AsSpan(SecretKeyBytes - SymBytes, SymBytes).CopyTo(implicit_rejection);
@@ -173,16 +174,30 @@ internal void KemEncrypt(Span<byte> encapsulation, Span<byte> secret, MLKemPubli
173174
kr[..SharedSecretBytes].CopyTo(secret);
174175
}
175176

176-
private static void CMov(Span<byte> r, ReadOnlySpan<byte> x, int len, bool b)
177+
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
178+
private static void CMov(Span<byte> r, ReadOnlySpan<byte> x, int xLen, int cond)
177179
{
178-
if (b)
180+
Debug.Assert(0 == cond || -1 == cond);
181+
182+
for (int i = 0; i < xLen; ++i)
179183
{
180-
x[..len].CopyTo(r);
184+
int r_i = r[i], diff = r_i ^ x[i];
185+
r_i ^= diff & cond;
186+
r[i] = (byte)r_i;
181187
}
182-
else
188+
}
189+
190+
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
191+
public static int FixedTimeEquals(ReadOnlySpan<byte> a, ReadOnlySpan<byte> b)
192+
{
193+
int d = 0;
194+
for (int i = 0, len = a.Length; i < len; ++i)
183195
{
184-
r[..len].CopyTo(r);
196+
d |= a[i] ^ b[i];
185197
}
198+
d |= d >> 16;
199+
d &= 0xFFFF;
200+
return (d - 1) >> 31;
186201
}
187202
#else
188203
internal void KemDecrypt(byte[] secBuf, int secOff, byte[] encBuf, int encOff,
@@ -201,7 +216,7 @@ internal void KemDecrypt(byte[] secBuf, int secOff, byte[] encBuf, int encOff,
201216

202217
m_indCpa.Encrypt(cmp, 0, Arrays.CopyOf(buf, SymBytes), pk, Arrays.CopyOfRange(kr, SymBytes, kr.Length));
203218

204-
bool fail = !Arrays.FixedTimeEquals(cmp.Length, cmp, 0, encBuf, encOff);
219+
int fail = ~FixedTimeEquals(cmp.Length, cmp, 0, encBuf, encOff);
205220

206221
Symmetric.Hash_h(encBuf, encOff, CipherTextBytes, kr, SymBytes);
207222
Array.Copy(secretKey, SecretKeyBytes - SymBytes, implicit_rejection, 0, SymBytes);
@@ -233,16 +248,30 @@ internal void KemEncrypt(byte[] encBuf, int encOff, byte[] secBuf, int secOff,
233248
Array.Copy(kr, 0, secBuf, secOff, SharedSecretBytes);
234249
}
235250

236-
private static void CMov(byte[] r, byte[] x, int len, bool b)
251+
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
252+
private static void CMov(byte[] r, byte[] x, int xLen, int cond)
237253
{
238-
if (b)
254+
Debug.Assert(0 == cond || -1 == cond);
255+
256+
for (int i = 0; i < xLen; ++i)
239257
{
240-
Array.Copy(x, 0, r, 0, len);
258+
int r_i = r[i], diff = r_i ^ x[i];
259+
r_i ^= diff & cond;
260+
r[i] = (byte)r_i;
241261
}
242-
else
262+
}
263+
264+
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
265+
public static int FixedTimeEquals(int len, byte[] a, int aOff, byte[] b, int bOff)
266+
{
267+
int d = 0;
268+
for (int i = 0; i < len; ++i)
243269
{
244-
Array.Copy(r, 0, r, 0, len);
270+
d |= a[aOff + i] ^ b[bOff + i];
245271
}
272+
d |= d >> 16;
273+
d &= 0xFFFF;
274+
return (d - 1) >> 31;
246275
}
247276
#endif
248277
}

0 commit comments

Comments
 (0)