xref: /freebsd/crypto/openssl/include/internal/constant_time.h (revision e7be843b4a162e68651d3911f0357ed464915629)
117f01e99SJung-uk Kim /*
2*e7be843bSPierre Pronchery  * Copyright 2014-2025 The OpenSSL Project Authors. All Rights Reserved.
317f01e99SJung-uk Kim  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
517f01e99SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
617f01e99SJung-uk Kim  * in the file LICENSE in the source distribution or at
717f01e99SJung-uk Kim  * https://www.openssl.org/source/license.html
817f01e99SJung-uk Kim  */
917f01e99SJung-uk Kim 
1017f01e99SJung-uk Kim #ifndef OSSL_INTERNAL_CONSTANT_TIME_H
1117f01e99SJung-uk Kim # define OSSL_INTERNAL_CONSTANT_TIME_H
12b077aed3SPierre Pronchery # pragma once
1317f01e99SJung-uk Kim 
1417f01e99SJung-uk Kim # include <stdlib.h>
1517f01e99SJung-uk Kim # include <string.h>
1617f01e99SJung-uk Kim # include <openssl/e_os2.h>              /* For 'ossl_inline' */
1717f01e99SJung-uk Kim 
1817f01e99SJung-uk Kim /*-
1917f01e99SJung-uk Kim  * The boolean methods return a bitmask of all ones (0xff...f) for true
2017f01e99SJung-uk Kim  * and 0 for false. This is useful for choosing a value based on the result
2117f01e99SJung-uk Kim  * of a conditional in constant time. For example,
2217f01e99SJung-uk Kim  *      if (a < b) {
2317f01e99SJung-uk Kim  *        c = a;
2417f01e99SJung-uk Kim  *      } else {
2517f01e99SJung-uk Kim  *        c = b;
2617f01e99SJung-uk Kim  *      }
2717f01e99SJung-uk Kim  * can be written as
2817f01e99SJung-uk Kim  *      unsigned int lt = constant_time_lt(a, b);
2917f01e99SJung-uk Kim  *      c = constant_time_select(lt, a, b);
3017f01e99SJung-uk Kim  */
3117f01e99SJung-uk Kim 
3217f01e99SJung-uk Kim /* Returns the given value with the MSB copied to all the other bits. */
3317f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_msb(unsigned int a);
3417f01e99SJung-uk Kim /* Convenience method for uint32_t. */
3517f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_msb_32(uint32_t a);
3617f01e99SJung-uk Kim /* Convenience method for uint64_t. */
3717f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_msb_64(uint64_t a);
3817f01e99SJung-uk Kim 
3917f01e99SJung-uk Kim /* Returns 0xff..f if a < b and 0 otherwise. */
4017f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_lt(unsigned int a,
4117f01e99SJung-uk Kim                                                  unsigned int b);
4217f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */
4317f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_lt_8(unsigned int a,
4417f01e99SJung-uk Kim                                                     unsigned int b);
45*e7be843bSPierre Pronchery /* Convenience method for uint32_t. */
46*e7be843bSPierre Pronchery static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b);
47*e7be843bSPierre Pronchery 
4817f01e99SJung-uk Kim /* Convenience method for uint64_t. */
4917f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b);
5017f01e99SJung-uk Kim 
5117f01e99SJung-uk Kim /* Returns 0xff..f if a >= b and 0 otherwise. */
5217f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_ge(unsigned int a,
5317f01e99SJung-uk Kim                                                  unsigned int b);
5417f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */
5517f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
5617f01e99SJung-uk Kim                                                     unsigned int b);
5717f01e99SJung-uk Kim 
5817f01e99SJung-uk Kim /* Returns 0xff..f if a == 0 and 0 otherwise. */
5917f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_is_zero(unsigned int a);
6017f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */
6117f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a);
6217f01e99SJung-uk Kim /* Convenience method for getting a 32-bit mask. */
6317f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a);
6417f01e99SJung-uk Kim 
6517f01e99SJung-uk Kim /* Returns 0xff..f if a == b and 0 otherwise. */
6617f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq(unsigned int a,
6717f01e99SJung-uk Kim                                                  unsigned int b);
6817f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */
6917f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
7017f01e99SJung-uk Kim                                                     unsigned int b);
7117f01e99SJung-uk Kim /* Signed integers. */
7217f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq_int(int a, int b);
7317f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */
7417f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_int_8(int a, int b);
7517f01e99SJung-uk Kim 
7617f01e99SJung-uk Kim /*-
7717f01e99SJung-uk Kim  * Returns (mask & a) | (~mask & b).
7817f01e99SJung-uk Kim  *
7917f01e99SJung-uk Kim  * When |mask| is all 1s or all 0s (as returned by the methods above),
8017f01e99SJung-uk Kim  * the select methods return either |a| (if |mask| is nonzero) or |b|
8117f01e99SJung-uk Kim  * (if |mask| is zero).
8217f01e99SJung-uk Kim  */
8317f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_select(unsigned int mask,
8417f01e99SJung-uk Kim                                                      unsigned int a,
8517f01e99SJung-uk Kim                                                      unsigned int b);
8617f01e99SJung-uk Kim /* Convenience method for unsigned chars. */
8717f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
8817f01e99SJung-uk Kim                                                         unsigned char a,
8917f01e99SJung-uk Kim                                                         unsigned char b);
9017f01e99SJung-uk Kim 
9117f01e99SJung-uk Kim /* Convenience method for uint32_t. */
9217f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,
9317f01e99SJung-uk Kim                                                     uint32_t b);
9417f01e99SJung-uk Kim 
9517f01e99SJung-uk Kim /* Convenience method for uint64_t. */
9617f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,
9717f01e99SJung-uk Kim                                                     uint64_t b);
9817f01e99SJung-uk Kim /* Convenience method for signed integers. */
9917f01e99SJung-uk Kim static ossl_inline int constant_time_select_int(unsigned int mask, int a,
10017f01e99SJung-uk Kim                                                 int b);
10117f01e99SJung-uk Kim 
10217f01e99SJung-uk Kim 
constant_time_msb(unsigned int a)10317f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_msb(unsigned int a)
10417f01e99SJung-uk Kim {
10517f01e99SJung-uk Kim     return 0 - (a >> (sizeof(a) * 8 - 1));
10617f01e99SJung-uk Kim }
10717f01e99SJung-uk Kim 
10817f01e99SJung-uk Kim 
constant_time_msb_32(uint32_t a)10917f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_msb_32(uint32_t a)
11017f01e99SJung-uk Kim {
11117f01e99SJung-uk Kim     return 0 - (a >> 31);
11217f01e99SJung-uk Kim }
11317f01e99SJung-uk Kim 
constant_time_msb_64(uint64_t a)11417f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_msb_64(uint64_t a)
11517f01e99SJung-uk Kim {
11617f01e99SJung-uk Kim     return 0 - (a >> 63);
11717f01e99SJung-uk Kim }
11817f01e99SJung-uk Kim 
constant_time_msb_s(size_t a)11917f01e99SJung-uk Kim static ossl_inline size_t constant_time_msb_s(size_t a)
12017f01e99SJung-uk Kim {
12117f01e99SJung-uk Kim     return 0 - (a >> (sizeof(a) * 8 - 1));
12217f01e99SJung-uk Kim }
12317f01e99SJung-uk Kim 
constant_time_lt(unsigned int a,unsigned int b)12417f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_lt(unsigned int a,
12517f01e99SJung-uk Kim                                                  unsigned int b)
12617f01e99SJung-uk Kim {
12717f01e99SJung-uk Kim     return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));
12817f01e99SJung-uk Kim }
12917f01e99SJung-uk Kim 
constant_time_lt_s(size_t a,size_t b)13017f01e99SJung-uk Kim static ossl_inline size_t constant_time_lt_s(size_t a, size_t b)
13117f01e99SJung-uk Kim {
13217f01e99SJung-uk Kim     return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b)));
13317f01e99SJung-uk Kim }
13417f01e99SJung-uk Kim 
constant_time_lt_8(unsigned int a,unsigned int b)13517f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_lt_8(unsigned int a,
13617f01e99SJung-uk Kim                                                     unsigned int b)
13717f01e99SJung-uk Kim {
13817f01e99SJung-uk Kim     return (unsigned char)constant_time_lt(a, b);
13917f01e99SJung-uk Kim }
14017f01e99SJung-uk Kim 
constant_time_lt_32(uint32_t a,uint32_t b)141*e7be843bSPierre Pronchery static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b)
142*e7be843bSPierre Pronchery {
143*e7be843bSPierre Pronchery     return constant_time_msb_32(a ^ ((a ^ b) | ((a - b) ^ b)));
144*e7be843bSPierre Pronchery }
145*e7be843bSPierre Pronchery 
constant_time_lt_64(uint64_t a,uint64_t b)14617f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b)
14717f01e99SJung-uk Kim {
14817f01e99SJung-uk Kim     return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b)));
14917f01e99SJung-uk Kim }
15017f01e99SJung-uk Kim 
15144096ebdSEnji Cooper #ifdef BN_ULONG
value_barrier_bn(BN_ULONG a)152*e7be843bSPierre Pronchery static ossl_inline BN_ULONG value_barrier_bn(BN_ULONG a)
153*e7be843bSPierre Pronchery {
154*e7be843bSPierre Pronchery #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
155*e7be843bSPierre Pronchery     BN_ULONG r;
156*e7be843bSPierre Pronchery     __asm__("" : "=r"(r) : "0"(a));
157*e7be843bSPierre Pronchery #else
158*e7be843bSPierre Pronchery     volatile BN_ULONG r = a;
159*e7be843bSPierre Pronchery #endif
160*e7be843bSPierre Pronchery     return r;
161*e7be843bSPierre Pronchery }
162*e7be843bSPierre Pronchery 
constant_time_msb_bn(BN_ULONG a)16344096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a)
16444096ebdSEnji Cooper {
16544096ebdSEnji Cooper     return 0 - (a >> (sizeof(a) * 8 - 1));
16644096ebdSEnji Cooper }
16744096ebdSEnji Cooper 
constant_time_lt_bn(BN_ULONG a,BN_ULONG b)16844096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b)
16944096ebdSEnji Cooper {
17044096ebdSEnji Cooper     return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b)));
17144096ebdSEnji Cooper }
17244096ebdSEnji Cooper 
constant_time_is_zero_bn(BN_ULONG a)17344096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_is_zero_bn(BN_ULONG a)
17444096ebdSEnji Cooper {
17544096ebdSEnji Cooper     return constant_time_msb_bn(~a & (a - 1));
17644096ebdSEnji Cooper }
17744096ebdSEnji Cooper 
constant_time_eq_bn(BN_ULONG a,BN_ULONG b)17844096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a,
17944096ebdSEnji Cooper                                                 BN_ULONG b)
18044096ebdSEnji Cooper {
18144096ebdSEnji Cooper     return constant_time_is_zero_bn(a ^ b);
18244096ebdSEnji Cooper }
183*e7be843bSPierre Pronchery 
constant_time_select_bn(BN_ULONG mask,BN_ULONG a,BN_ULONG b)184*e7be843bSPierre Pronchery static ossl_inline BN_ULONG constant_time_select_bn(BN_ULONG mask,
185*e7be843bSPierre Pronchery                                                     BN_ULONG a,
186*e7be843bSPierre Pronchery                                                     BN_ULONG b)
187*e7be843bSPierre Pronchery {
188*e7be843bSPierre Pronchery     return (value_barrier_bn(mask) & a) | (value_barrier_bn(~mask) & b);
189*e7be843bSPierre Pronchery }
19044096ebdSEnji Cooper #endif
19144096ebdSEnji Cooper 
constant_time_ge(unsigned int a,unsigned int b)19217f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_ge(unsigned int a,
19317f01e99SJung-uk Kim                                                  unsigned int b)
19417f01e99SJung-uk Kim {
19517f01e99SJung-uk Kim     return ~constant_time_lt(a, b);
19617f01e99SJung-uk Kim }
19717f01e99SJung-uk Kim 
constant_time_ge_s(size_t a,size_t b)19817f01e99SJung-uk Kim static ossl_inline size_t constant_time_ge_s(size_t a, size_t b)
19917f01e99SJung-uk Kim {
20017f01e99SJung-uk Kim     return ~constant_time_lt_s(a, b);
20117f01e99SJung-uk Kim }
20217f01e99SJung-uk Kim 
constant_time_ge_8(unsigned int a,unsigned int b)20317f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
20417f01e99SJung-uk Kim                                                     unsigned int b)
20517f01e99SJung-uk Kim {
20617f01e99SJung-uk Kim     return (unsigned char)constant_time_ge(a, b);
20717f01e99SJung-uk Kim }
20817f01e99SJung-uk Kim 
constant_time_ge_8_s(size_t a,size_t b)20917f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b)
21017f01e99SJung-uk Kim {
21117f01e99SJung-uk Kim     return (unsigned char)constant_time_ge_s(a, b);
21217f01e99SJung-uk Kim }
21317f01e99SJung-uk Kim 
constant_time_is_zero(unsigned int a)21417f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_is_zero(unsigned int a)
21517f01e99SJung-uk Kim {
21617f01e99SJung-uk Kim     return constant_time_msb(~a & (a - 1));
21717f01e99SJung-uk Kim }
21817f01e99SJung-uk Kim 
constant_time_is_zero_s(size_t a)21917f01e99SJung-uk Kim static ossl_inline size_t constant_time_is_zero_s(size_t a)
22017f01e99SJung-uk Kim {
22117f01e99SJung-uk Kim     return constant_time_msb_s(~a & (a - 1));
22217f01e99SJung-uk Kim }
22317f01e99SJung-uk Kim 
constant_time_is_zero_8(unsigned int a)22417f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a)
22517f01e99SJung-uk Kim {
22617f01e99SJung-uk Kim     return (unsigned char)constant_time_is_zero(a);
22717f01e99SJung-uk Kim }
22817f01e99SJung-uk Kim 
constant_time_is_zero_32(uint32_t a)22917f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a)
23017f01e99SJung-uk Kim {
23117f01e99SJung-uk Kim     return constant_time_msb_32(~a & (a - 1));
23217f01e99SJung-uk Kim }
23317f01e99SJung-uk Kim 
constant_time_is_zero_64(uint64_t a)234b077aed3SPierre Pronchery static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a)
235b077aed3SPierre Pronchery {
236b077aed3SPierre Pronchery     return constant_time_msb_64(~a & (a - 1));
237b077aed3SPierre Pronchery }
238b077aed3SPierre Pronchery 
constant_time_eq(unsigned int a,unsigned int b)23917f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq(unsigned int a,
24017f01e99SJung-uk Kim                                                  unsigned int b)
24117f01e99SJung-uk Kim {
24217f01e99SJung-uk Kim     return constant_time_is_zero(a ^ b);
24317f01e99SJung-uk Kim }
24417f01e99SJung-uk Kim 
constant_time_eq_s(size_t a,size_t b)24517f01e99SJung-uk Kim static ossl_inline size_t constant_time_eq_s(size_t a, size_t b)
24617f01e99SJung-uk Kim {
24717f01e99SJung-uk Kim     return constant_time_is_zero_s(a ^ b);
24817f01e99SJung-uk Kim }
24917f01e99SJung-uk Kim 
constant_time_eq_8(unsigned int a,unsigned int b)25017f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
25117f01e99SJung-uk Kim                                                     unsigned int b)
25217f01e99SJung-uk Kim {
25317f01e99SJung-uk Kim     return (unsigned char)constant_time_eq(a, b);
25417f01e99SJung-uk Kim }
25517f01e99SJung-uk Kim 
constant_time_eq_8_s(size_t a,size_t b)25617f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b)
25717f01e99SJung-uk Kim {
25817f01e99SJung-uk Kim     return (unsigned char)constant_time_eq_s(a, b);
25917f01e99SJung-uk Kim }
26017f01e99SJung-uk Kim 
constant_time_eq_int(int a,int b)26117f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq_int(int a, int b)
26217f01e99SJung-uk Kim {
26317f01e99SJung-uk Kim     return constant_time_eq((unsigned)(a), (unsigned)(b));
26417f01e99SJung-uk Kim }
26517f01e99SJung-uk Kim 
constant_time_eq_int_8(int a,int b)26617f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_int_8(int a, int b)
26717f01e99SJung-uk Kim {
26817f01e99SJung-uk Kim     return constant_time_eq_8((unsigned)(a), (unsigned)(b));
26917f01e99SJung-uk Kim }
27017f01e99SJung-uk Kim 
27117f01e99SJung-uk Kim /*
27217f01e99SJung-uk Kim  * Returns the value unmodified, but avoids optimizations.
27317f01e99SJung-uk Kim  * The barriers prevent the compiler from narrowing down the
27417f01e99SJung-uk Kim  * possible value range of the mask and ~mask in the select
27517f01e99SJung-uk Kim  * statements, which avoids the recognition of the select
27617f01e99SJung-uk Kim  * and turning it into a conditional load or branch.
27717f01e99SJung-uk Kim  */
value_barrier(unsigned int a)27817f01e99SJung-uk Kim static ossl_inline unsigned int value_barrier(unsigned int a)
27917f01e99SJung-uk Kim {
28017f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
28117f01e99SJung-uk Kim     unsigned int r;
28217f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
28317f01e99SJung-uk Kim #else
28417f01e99SJung-uk Kim     volatile unsigned int r = a;
28517f01e99SJung-uk Kim #endif
28617f01e99SJung-uk Kim     return r;
28717f01e99SJung-uk Kim }
28817f01e99SJung-uk Kim 
28917f01e99SJung-uk Kim /* Convenience method for uint32_t. */
value_barrier_32(uint32_t a)29017f01e99SJung-uk Kim static ossl_inline uint32_t value_barrier_32(uint32_t a)
29117f01e99SJung-uk Kim {
29217f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
29317f01e99SJung-uk Kim     uint32_t r;
29417f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
29517f01e99SJung-uk Kim #else
29617f01e99SJung-uk Kim     volatile uint32_t r = a;
29717f01e99SJung-uk Kim #endif
29817f01e99SJung-uk Kim     return r;
29917f01e99SJung-uk Kim }
30017f01e99SJung-uk Kim 
30117f01e99SJung-uk Kim /* Convenience method for uint64_t. */
value_barrier_64(uint64_t a)30217f01e99SJung-uk Kim static ossl_inline uint64_t value_barrier_64(uint64_t a)
30317f01e99SJung-uk Kim {
30417f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
30517f01e99SJung-uk Kim     uint64_t r;
30617f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
30717f01e99SJung-uk Kim #else
30817f01e99SJung-uk Kim     volatile uint64_t r = a;
30917f01e99SJung-uk Kim #endif
31017f01e99SJung-uk Kim     return r;
31117f01e99SJung-uk Kim }
31217f01e99SJung-uk Kim 
31317f01e99SJung-uk Kim /* Convenience method for size_t. */
value_barrier_s(size_t a)31417f01e99SJung-uk Kim static ossl_inline size_t value_barrier_s(size_t a)
31517f01e99SJung-uk Kim {
31617f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
31717f01e99SJung-uk Kim     size_t r;
31817f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
31917f01e99SJung-uk Kim #else
32017f01e99SJung-uk Kim     volatile size_t r = a;
32117f01e99SJung-uk Kim #endif
32217f01e99SJung-uk Kim     return r;
32317f01e99SJung-uk Kim }
32417f01e99SJung-uk Kim 
325*e7be843bSPierre Pronchery /* Convenience method for unsigned char. */
value_barrier_8(unsigned char a)326*e7be843bSPierre Pronchery static ossl_inline unsigned char value_barrier_8(unsigned char a)
327*e7be843bSPierre Pronchery {
328*e7be843bSPierre Pronchery #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
329*e7be843bSPierre Pronchery     unsigned char r;
330*e7be843bSPierre Pronchery     __asm__("" : "=r"(r) : "0"(a));
331*e7be843bSPierre Pronchery #else
332*e7be843bSPierre Pronchery     volatile unsigned char r = a;
333*e7be843bSPierre Pronchery #endif
334*e7be843bSPierre Pronchery     return r;
335*e7be843bSPierre Pronchery }
336*e7be843bSPierre Pronchery 
constant_time_select(unsigned int mask,unsigned int a,unsigned int b)33717f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_select(unsigned int mask,
33817f01e99SJung-uk Kim                                                      unsigned int a,
33917f01e99SJung-uk Kim                                                      unsigned int b)
34017f01e99SJung-uk Kim {
34117f01e99SJung-uk Kim     return (value_barrier(mask) & a) | (value_barrier(~mask) & b);
34217f01e99SJung-uk Kim }
34317f01e99SJung-uk Kim 
constant_time_select_s(size_t mask,size_t a,size_t b)34417f01e99SJung-uk Kim static ossl_inline size_t constant_time_select_s(size_t mask,
34517f01e99SJung-uk Kim                                                  size_t a,
34617f01e99SJung-uk Kim                                                  size_t b)
34717f01e99SJung-uk Kim {
34817f01e99SJung-uk Kim     return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b);
34917f01e99SJung-uk Kim }
35017f01e99SJung-uk Kim 
constant_time_select_8(unsigned char mask,unsigned char a,unsigned char b)35117f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
35217f01e99SJung-uk Kim                                                         unsigned char a,
35317f01e99SJung-uk Kim                                                         unsigned char b)
35417f01e99SJung-uk Kim {
35517f01e99SJung-uk Kim     return (unsigned char)constant_time_select(mask, a, b);
35617f01e99SJung-uk Kim }
35717f01e99SJung-uk Kim 
constant_time_select_int(unsigned int mask,int a,int b)35817f01e99SJung-uk Kim static ossl_inline int constant_time_select_int(unsigned int mask, int a,
35917f01e99SJung-uk Kim                                                 int b)
36017f01e99SJung-uk Kim {
36117f01e99SJung-uk Kim     return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b));
36217f01e99SJung-uk Kim }
36317f01e99SJung-uk Kim 
constant_time_select_int_s(size_t mask,int a,int b)36417f01e99SJung-uk Kim static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b)
36517f01e99SJung-uk Kim {
36617f01e99SJung-uk Kim     return (int)constant_time_select((unsigned)mask, (unsigned)(a),
36717f01e99SJung-uk Kim                                       (unsigned)(b));
36817f01e99SJung-uk Kim }
36917f01e99SJung-uk Kim 
constant_time_select_32(uint32_t mask,uint32_t a,uint32_t b)37017f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,
37117f01e99SJung-uk Kim                                                     uint32_t b)
37217f01e99SJung-uk Kim {
37317f01e99SJung-uk Kim     return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b);
37417f01e99SJung-uk Kim }
37517f01e99SJung-uk Kim 
constant_time_select_64(uint64_t mask,uint64_t a,uint64_t b)37617f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,
37717f01e99SJung-uk Kim                                                     uint64_t b)
37817f01e99SJung-uk Kim {
37917f01e99SJung-uk Kim     return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b);
38017f01e99SJung-uk Kim }
38117f01e99SJung-uk Kim 
38217f01e99SJung-uk Kim /*
38317f01e99SJung-uk Kim  * mask must be 0xFFFFFFFF or 0x00000000.
38417f01e99SJung-uk Kim  *
38517f01e99SJung-uk Kim  * if (mask) {
38617f01e99SJung-uk Kim  *     uint32_t tmp = *a;
38717f01e99SJung-uk Kim  *
38817f01e99SJung-uk Kim  *     *a = *b;
38917f01e99SJung-uk Kim  *     *b = tmp;
39017f01e99SJung-uk Kim  * }
39117f01e99SJung-uk Kim  */
constant_time_cond_swap_32(uint32_t mask,uint32_t * a,uint32_t * b)39217f01e99SJung-uk Kim static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a,
39317f01e99SJung-uk Kim                                                    uint32_t *b)
39417f01e99SJung-uk Kim {
39517f01e99SJung-uk Kim     uint32_t xor = *a ^ *b;
39617f01e99SJung-uk Kim 
397*e7be843bSPierre Pronchery     xor &= value_barrier_32(mask);
39817f01e99SJung-uk Kim     *a ^= xor;
39917f01e99SJung-uk Kim     *b ^= xor;
40017f01e99SJung-uk Kim }
40117f01e99SJung-uk Kim 
40217f01e99SJung-uk Kim /*
40317f01e99SJung-uk Kim  * mask must be 0xFFFFFFFF or 0x00000000.
40417f01e99SJung-uk Kim  *
40517f01e99SJung-uk Kim  * if (mask) {
40617f01e99SJung-uk Kim  *     uint64_t tmp = *a;
40717f01e99SJung-uk Kim  *
40817f01e99SJung-uk Kim  *     *a = *b;
40917f01e99SJung-uk Kim  *     *b = tmp;
41017f01e99SJung-uk Kim  * }
41117f01e99SJung-uk Kim  */
constant_time_cond_swap_64(uint64_t mask,uint64_t * a,uint64_t * b)41217f01e99SJung-uk Kim static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a,
41317f01e99SJung-uk Kim                                                    uint64_t *b)
41417f01e99SJung-uk Kim {
41517f01e99SJung-uk Kim     uint64_t xor = *a ^ *b;
41617f01e99SJung-uk Kim 
417*e7be843bSPierre Pronchery     xor &= value_barrier_64(mask);
41817f01e99SJung-uk Kim     *a ^= xor;
41917f01e99SJung-uk Kim     *b ^= xor;
42017f01e99SJung-uk Kim }
42117f01e99SJung-uk Kim 
42217f01e99SJung-uk Kim /*
423b077aed3SPierre Pronchery  * mask must be 0xFF or 0x00.
424b077aed3SPierre Pronchery  * "constant time" is per len.
425b077aed3SPierre Pronchery  *
426b077aed3SPierre Pronchery  * if (mask) {
427b077aed3SPierre Pronchery  *     unsigned char tmp[len];
428b077aed3SPierre Pronchery  *
429b077aed3SPierre Pronchery  *     memcpy(tmp, a, len);
430b077aed3SPierre Pronchery  *     memcpy(a, b);
431b077aed3SPierre Pronchery  *     memcpy(b, tmp);
432b077aed3SPierre Pronchery  * }
433b077aed3SPierre Pronchery  */
constant_time_cond_swap_buff(unsigned char mask,unsigned char * a,unsigned char * b,size_t len)434b077aed3SPierre Pronchery static ossl_inline void constant_time_cond_swap_buff(unsigned char mask,
435b077aed3SPierre Pronchery                                                      unsigned char *a,
436b077aed3SPierre Pronchery                                                      unsigned char *b,
437b077aed3SPierre Pronchery                                                      size_t len)
438b077aed3SPierre Pronchery {
439b077aed3SPierre Pronchery     size_t i;
440b077aed3SPierre Pronchery     unsigned char tmp;
441b077aed3SPierre Pronchery 
442b077aed3SPierre Pronchery     for (i = 0; i < len; i++) {
443b077aed3SPierre Pronchery         tmp = a[i] ^ b[i];
444*e7be843bSPierre Pronchery         tmp &= value_barrier_8(mask);
445b077aed3SPierre Pronchery         a[i] ^= tmp;
446b077aed3SPierre Pronchery         b[i] ^= tmp;
447b077aed3SPierre Pronchery     }
448b077aed3SPierre Pronchery }
449b077aed3SPierre Pronchery 
450b077aed3SPierre Pronchery /*
45117f01e99SJung-uk Kim  * table is a two dimensional array of bytes. Each row has rowsize elements.
45217f01e99SJung-uk Kim  * Copies row number idx into out. rowsize and numrows are not considered
45317f01e99SJung-uk Kim  * private.
45417f01e99SJung-uk Kim  */
constant_time_lookup(void * out,const void * table,size_t rowsize,size_t numrows,size_t idx)45517f01e99SJung-uk Kim static ossl_inline void constant_time_lookup(void *out,
45617f01e99SJung-uk Kim                                              const void *table,
45717f01e99SJung-uk Kim                                              size_t rowsize,
45817f01e99SJung-uk Kim                                              size_t numrows,
45917f01e99SJung-uk Kim                                              size_t idx)
46017f01e99SJung-uk Kim {
46117f01e99SJung-uk Kim     size_t i, j;
46217f01e99SJung-uk Kim     const unsigned char *tablec = (const unsigned char *)table;
46317f01e99SJung-uk Kim     unsigned char *outc = (unsigned char *)out;
46417f01e99SJung-uk Kim     unsigned char mask;
46517f01e99SJung-uk Kim 
46617f01e99SJung-uk Kim     memset(out, 0, rowsize);
46717f01e99SJung-uk Kim 
46817f01e99SJung-uk Kim     /* Note idx may underflow - but that is well defined */
46917f01e99SJung-uk Kim     for (i = 0; i < numrows; i++, idx--) {
47017f01e99SJung-uk Kim         mask = (unsigned char)constant_time_is_zero_s(idx);
47117f01e99SJung-uk Kim         for (j = 0; j < rowsize; j++)
47217f01e99SJung-uk Kim             *(outc + j) |= constant_time_select_8(mask, *(tablec++), 0);
47317f01e99SJung-uk Kim     }
47417f01e99SJung-uk Kim }
47517f01e99SJung-uk Kim 
47617f01e99SJung-uk Kim /*
47717f01e99SJung-uk Kim  * Expected usage pattern is to unconditionally set error and then
47817f01e99SJung-uk Kim  * wipe it if there was no actual error. |clear| is 1 or 0.
47917f01e99SJung-uk Kim  */
48017f01e99SJung-uk Kim void err_clear_last_constant_time(int clear);
48117f01e99SJung-uk Kim 
48217f01e99SJung-uk Kim #endif                          /* OSSL_INTERNAL_CONSTANT_TIME_H */
483