11using System ;
22using System . Diagnostics ;
3+ using System . Runtime . CompilerServices ;
34
45using Org . BouncyCastle . Crypto . Parameters ;
56using 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