* mpi/longlong.h: Include "const-time.h" (add_ssaaaa, sub_ddmmss): Prevent optimization of carry handling to conditional branches in generic variant of double width addition and subtraction as was seen with GCC on riscv64. (umul_ppmm): Avoid conditional branch in generic 16x16=>32bit multiplication version of umul_ppmm. * src/const-time.h (CT_DEOPTIMIZE_VAR): New. --
RISC-V has "sltu" instruction for generating carry value and generic version of add_ssaaaa and sub_ddmmss typically used this instruction. However, sometimes compiler gets too clever and instead generates code with conditional branch, which is not good for constant time code. Commit changes add_ssaaaaa and sub_ddmmss to clobber high word of calculation in a way that prevents such optimizations. Signed-off-by: Jussi Kivilinna <jussi.kivili...@iki.fi> --- mpi/longlong.h | 47 +++++++++++++++++++++++++++++++---------------- src/const-time.h | 8 ++++++++ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/mpi/longlong.h b/mpi/longlong.h index 21bd1a7e..7dc67591 100644 --- a/mpi/longlong.h +++ b/mpi/longlong.h @@ -20,6 +20,8 @@ along with this file; see the file COPYING.LIB. If not, see <https://www.gnu.or SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "const-time.h" + /* On 32-bit, use 64-bit 'unsigned long long' for UDWtype, if available. */ #if !defined (UDWtype) && SIZEOF_UNSIGNED_LONG_LONG * 8 == W_TYPE_SIZE * 2 # define UDWtype unsigned long long @@ -1582,22 +1584,29 @@ typedef unsigned int UTItype __attribute__ ((mode (TI))); # define add_ssaaaa(sh, sl, ah, al, bh, bl) \ do { \ UDWtype __audw = (ah); \ + UWtype __auwh, __auwl; \ UDWtype __budw = (bh); \ __audw <<= W_TYPE_SIZE; \ __audw |= (al); \ __budw <<= W_TYPE_SIZE; \ __budw |= (bl); \ __audw += __budw; \ - (sh) = (UWtype)(__audw >> W_TYPE_SIZE); \ - (sl) = (UWtype)(__audw); \ + __auwh = (UWtype)(__audw >> W_TYPE_SIZE); \ + __auwl = (UWtype)(__audw); \ + CT_DEOPTIMIZE_VAR(__auwh); \ + (sh) = __auwh; \ + (sl) = __auwl; \ } while (0) #elif !defined (add_ssaaaa) # define add_ssaaaa(sh, sl, ah, al, bh, bl) \ do { \ - UWtype __x; \ - __x = (al) + (bl); \ - (sh) = (ah) + (bh) + (__x < (al)); \ - (sl) = __x; \ + UWtype __xl, __xh; \ + __xl = (al) + (bl); \ + __xh = __xl < (al); \ + __xh = (ah) + (bh) + __xh; \ + CT_DEOPTIMIZE_VAR(__xh); \ + (sh) = __xh; \ + (sl) = __xl; \ } while (0) #endif @@ -1606,22 +1615,29 @@ typedef unsigned int UTItype __attribute__ ((mode (TI))); # define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ UDWtype __audw = (ah); \ + UWtype __auwh, __auwl; \ UDWtype __budw = (bh); \ __audw <<= W_TYPE_SIZE; \ __audw |= (al); \ __budw <<= W_TYPE_SIZE; \ __budw |= (bl); \ __audw -= __budw; \ - (sh) = (UWtype)(__audw >> W_TYPE_SIZE); \ - (sl) = (UWtype)(__audw); \ + __auwh = (UWtype)(__audw >> W_TYPE_SIZE); \ + __auwl = (UWtype)(__audw); \ + CT_DEOPTIMIZE_VAR(__auwh); \ + (sh) = __auwh; \ + (sl) = __auwl; \ } while (0) #elif !defined (sub_ddmmss) # define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ - UWtype __x; \ - __x = (al) - (bl); \ - (sh) = (ah) - (bh) - (__x > (al)); \ - (sl) = __x; \ + UWtype __xl, __xh; \ + __xl = (al) - (bl); \ + __xh = (__xl > (al)); \ + __xh = (ah) - (bh) - __xh; \ + CT_DEOPTIMIZE_VAR(__xh); \ + (sh) = __xh; \ + (sl) = __xl; \ } while (0) #endif @@ -1651,10 +1667,9 @@ typedef unsigned int UTItype __attribute__ ((mode (TI))); __x3 = (UWtype) __uh * __vh; \ \ __x1 += __ll_highpart (__x0);/* this can't give carry */ \ - __x1 += __x2; /* but this indeed can */ \ - if (__x1 < __x2) /* did we get it? */ \ - __x3 += __ll_B; /* yes, add it in the proper pos. */ \ - \ + /* but this indeed can, and if so, add it in the proper pos: */ \ + add_ssaaaa(__x2, __x1, 0, __x1, 0, __x2); \ + __x3 += __x2 << (W_TYPE_SIZE / 2); \ (w1) = __x3 + __ll_highpart (__x1); \ (w0) = (__ll_lowpart (__x1) << W_TYPE_SIZE/2) + __ll_lowpart (__x0);\ } while (0) diff --git a/src/const-time.h b/src/const-time.h index 46eb187d..c2acbb73 100644 --- a/src/const-time.h +++ b/src/const-time.h @@ -82,6 +82,14 @@ unsigned int _gcry_ct_not_memequal (const void *b1, const void *b2, size_t len); any structure. */ unsigned int _gcry_ct_memequal (const void *b1, const void *b2, size_t len); +/* Prevent compiler from assuming value of variable and from making + non-constant time optimizations. */ +#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY +# define CT_DEOPTIMIZE_VAR(var) asm volatile ("\n" : "+r" (var) :: "memory") +#else +# define CT_DEOPTIMIZE_VAR(var) (void)((var) += _gcry_ct_vzero) +#endif + /* * Return all bits set if A is 1 and return 0 otherwise. */ -- 2.45.2 _______________________________________________ Gcrypt-devel mailing list Gcrypt-devel@gnupg.org https://lists.gnupg.org/mailman/listinfo/gcrypt-devel