xref: /freebsd-src/crypto/openssl/include/internal/constant_time.h (revision 44096ebd22ddd0081a357011714eff8963614b65)
117f01e99SJung-uk Kim /*
2*44096ebdSEnji Cooper  * Copyright 2014-2024 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);
4517f01e99SJung-uk Kim /* Convenience method for uint64_t. */
4617f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b);
4717f01e99SJung-uk Kim 
4817f01e99SJung-uk Kim /* Returns 0xff..f if a >= b and 0 otherwise. */
4917f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_ge(unsigned int a,
5017f01e99SJung-uk Kim                                                  unsigned int b);
5117f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */
5217f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
5317f01e99SJung-uk Kim                                                     unsigned int b);
5417f01e99SJung-uk Kim 
5517f01e99SJung-uk Kim /* Returns 0xff..f if a == 0 and 0 otherwise. */
5617f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_is_zero(unsigned int a);
5717f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */
5817f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a);
5917f01e99SJung-uk Kim /* Convenience method for getting a 32-bit mask. */
6017f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a);
6117f01e99SJung-uk Kim 
6217f01e99SJung-uk Kim /* Returns 0xff..f if a == b and 0 otherwise. */
6317f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq(unsigned int a,
6417f01e99SJung-uk Kim                                                  unsigned int b);
6517f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */
6617f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
6717f01e99SJung-uk Kim                                                     unsigned int b);
6817f01e99SJung-uk Kim /* Signed integers. */
6917f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq_int(int a, int b);
7017f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */
7117f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_int_8(int a, int b);
7217f01e99SJung-uk Kim 
7317f01e99SJung-uk Kim /*-
7417f01e99SJung-uk Kim  * Returns (mask & a) | (~mask & b).
7517f01e99SJung-uk Kim  *
7617f01e99SJung-uk Kim  * When |mask| is all 1s or all 0s (as returned by the methods above),
7717f01e99SJung-uk Kim  * the select methods return either |a| (if |mask| is nonzero) or |b|
7817f01e99SJung-uk Kim  * (if |mask| is zero).
7917f01e99SJung-uk Kim  */
8017f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_select(unsigned int mask,
8117f01e99SJung-uk Kim                                                      unsigned int a,
8217f01e99SJung-uk Kim                                                      unsigned int b);
8317f01e99SJung-uk Kim /* Convenience method for unsigned chars. */
8417f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
8517f01e99SJung-uk Kim                                                         unsigned char a,
8617f01e99SJung-uk Kim                                                         unsigned char b);
8717f01e99SJung-uk Kim 
8817f01e99SJung-uk Kim /* Convenience method for uint32_t. */
8917f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,
9017f01e99SJung-uk Kim                                                     uint32_t b);
9117f01e99SJung-uk Kim 
9217f01e99SJung-uk Kim /* Convenience method for uint64_t. */
9317f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,
9417f01e99SJung-uk Kim                                                     uint64_t b);
9517f01e99SJung-uk Kim /* Convenience method for signed integers. */
9617f01e99SJung-uk Kim static ossl_inline int constant_time_select_int(unsigned int mask, int a,
9717f01e99SJung-uk Kim                                                 int b);
9817f01e99SJung-uk Kim 
9917f01e99SJung-uk Kim 
constant_time_msb(unsigned int a)10017f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_msb(unsigned int a)
10117f01e99SJung-uk Kim {
10217f01e99SJung-uk Kim     return 0 - (a >> (sizeof(a) * 8 - 1));
10317f01e99SJung-uk Kim }
10417f01e99SJung-uk Kim 
10517f01e99SJung-uk Kim 
constant_time_msb_32(uint32_t a)10617f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_msb_32(uint32_t a)
10717f01e99SJung-uk Kim {
10817f01e99SJung-uk Kim     return 0 - (a >> 31);
10917f01e99SJung-uk Kim }
11017f01e99SJung-uk Kim 
constant_time_msb_64(uint64_t a)11117f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_msb_64(uint64_t a)
11217f01e99SJung-uk Kim {
11317f01e99SJung-uk Kim     return 0 - (a >> 63);
11417f01e99SJung-uk Kim }
11517f01e99SJung-uk Kim 
constant_time_msb_s(size_t a)11617f01e99SJung-uk Kim static ossl_inline size_t constant_time_msb_s(size_t a)
11717f01e99SJung-uk Kim {
11817f01e99SJung-uk Kim     return 0 - (a >> (sizeof(a) * 8 - 1));
11917f01e99SJung-uk Kim }
12017f01e99SJung-uk Kim 
constant_time_lt(unsigned int a,unsigned int b)12117f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_lt(unsigned int a,
12217f01e99SJung-uk Kim                                                  unsigned int b)
12317f01e99SJung-uk Kim {
12417f01e99SJung-uk Kim     return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));
12517f01e99SJung-uk Kim }
12617f01e99SJung-uk Kim 
constant_time_lt_s(size_t a,size_t b)12717f01e99SJung-uk Kim static ossl_inline size_t constant_time_lt_s(size_t a, size_t b)
12817f01e99SJung-uk Kim {
12917f01e99SJung-uk Kim     return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b)));
13017f01e99SJung-uk Kim }
13117f01e99SJung-uk Kim 
constant_time_lt_8(unsigned int a,unsigned int b)13217f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_lt_8(unsigned int a,
13317f01e99SJung-uk Kim                                                     unsigned int b)
13417f01e99SJung-uk Kim {
13517f01e99SJung-uk Kim     return (unsigned char)constant_time_lt(a, b);
13617f01e99SJung-uk Kim }
13717f01e99SJung-uk Kim 
constant_time_lt_64(uint64_t a,uint64_t b)13817f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b)
13917f01e99SJung-uk Kim {
14017f01e99SJung-uk Kim     return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b)));
14117f01e99SJung-uk Kim }
14217f01e99SJung-uk Kim 
143*44096ebdSEnji Cooper #ifdef BN_ULONG
constant_time_msb_bn(BN_ULONG a)144*44096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a)
145*44096ebdSEnji Cooper {
146*44096ebdSEnji Cooper     return 0 - (a >> (sizeof(a) * 8 - 1));
147*44096ebdSEnji Cooper }
148*44096ebdSEnji Cooper 
constant_time_lt_bn(BN_ULONG a,BN_ULONG b)149*44096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b)
150*44096ebdSEnji Cooper {
151*44096ebdSEnji Cooper     return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b)));
152*44096ebdSEnji Cooper }
153*44096ebdSEnji Cooper 
constant_time_is_zero_bn(BN_ULONG a)154*44096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_is_zero_bn(BN_ULONG a)
155*44096ebdSEnji Cooper {
156*44096ebdSEnji Cooper     return constant_time_msb_bn(~a & (a - 1));
157*44096ebdSEnji Cooper }
158*44096ebdSEnji Cooper 
constant_time_eq_bn(BN_ULONG a,BN_ULONG b)159*44096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a,
160*44096ebdSEnji Cooper                                                 BN_ULONG b)
161*44096ebdSEnji Cooper {
162*44096ebdSEnji Cooper     return constant_time_is_zero_bn(a ^ b);
163*44096ebdSEnji Cooper }
164*44096ebdSEnji Cooper #endif
165*44096ebdSEnji Cooper 
constant_time_ge(unsigned int a,unsigned int b)16617f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_ge(unsigned int a,
16717f01e99SJung-uk Kim                                                  unsigned int b)
16817f01e99SJung-uk Kim {
16917f01e99SJung-uk Kim     return ~constant_time_lt(a, b);
17017f01e99SJung-uk Kim }
17117f01e99SJung-uk Kim 
constant_time_ge_s(size_t a,size_t b)17217f01e99SJung-uk Kim static ossl_inline size_t constant_time_ge_s(size_t a, size_t b)
17317f01e99SJung-uk Kim {
17417f01e99SJung-uk Kim     return ~constant_time_lt_s(a, b);
17517f01e99SJung-uk Kim }
17617f01e99SJung-uk Kim 
constant_time_ge_8(unsigned int a,unsigned int b)17717f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
17817f01e99SJung-uk Kim                                                     unsigned int b)
17917f01e99SJung-uk Kim {
18017f01e99SJung-uk Kim     return (unsigned char)constant_time_ge(a, b);
18117f01e99SJung-uk Kim }
18217f01e99SJung-uk Kim 
constant_time_ge_8_s(size_t a,size_t b)18317f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b)
18417f01e99SJung-uk Kim {
18517f01e99SJung-uk Kim     return (unsigned char)constant_time_ge_s(a, b);
18617f01e99SJung-uk Kim }
18717f01e99SJung-uk Kim 
constant_time_is_zero(unsigned int a)18817f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_is_zero(unsigned int a)
18917f01e99SJung-uk Kim {
19017f01e99SJung-uk Kim     return constant_time_msb(~a & (a - 1));
19117f01e99SJung-uk Kim }
19217f01e99SJung-uk Kim 
constant_time_is_zero_s(size_t a)19317f01e99SJung-uk Kim static ossl_inline size_t constant_time_is_zero_s(size_t a)
19417f01e99SJung-uk Kim {
19517f01e99SJung-uk Kim     return constant_time_msb_s(~a & (a - 1));
19617f01e99SJung-uk Kim }
19717f01e99SJung-uk Kim 
constant_time_is_zero_8(unsigned int a)19817f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a)
19917f01e99SJung-uk Kim {
20017f01e99SJung-uk Kim     return (unsigned char)constant_time_is_zero(a);
20117f01e99SJung-uk Kim }
20217f01e99SJung-uk Kim 
constant_time_is_zero_32(uint32_t a)20317f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a)
20417f01e99SJung-uk Kim {
20517f01e99SJung-uk Kim     return constant_time_msb_32(~a & (a - 1));
20617f01e99SJung-uk Kim }
20717f01e99SJung-uk Kim 
constant_time_is_zero_64(uint64_t a)208b077aed3SPierre Pronchery static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a)
209b077aed3SPierre Pronchery {
210b077aed3SPierre Pronchery     return constant_time_msb_64(~a & (a - 1));
211b077aed3SPierre Pronchery }
212b077aed3SPierre Pronchery 
constant_time_eq(unsigned int a,unsigned int b)21317f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq(unsigned int a,
21417f01e99SJung-uk Kim                                                  unsigned int b)
21517f01e99SJung-uk Kim {
21617f01e99SJung-uk Kim     return constant_time_is_zero(a ^ b);
21717f01e99SJung-uk Kim }
21817f01e99SJung-uk Kim 
constant_time_eq_s(size_t a,size_t b)21917f01e99SJung-uk Kim static ossl_inline size_t constant_time_eq_s(size_t a, size_t b)
22017f01e99SJung-uk Kim {
22117f01e99SJung-uk Kim     return constant_time_is_zero_s(a ^ b);
22217f01e99SJung-uk Kim }
22317f01e99SJung-uk Kim 
constant_time_eq_8(unsigned int a,unsigned int b)22417f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
22517f01e99SJung-uk Kim                                                     unsigned int b)
22617f01e99SJung-uk Kim {
22717f01e99SJung-uk Kim     return (unsigned char)constant_time_eq(a, b);
22817f01e99SJung-uk Kim }
22917f01e99SJung-uk Kim 
constant_time_eq_8_s(size_t a,size_t b)23017f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b)
23117f01e99SJung-uk Kim {
23217f01e99SJung-uk Kim     return (unsigned char)constant_time_eq_s(a, b);
23317f01e99SJung-uk Kim }
23417f01e99SJung-uk Kim 
constant_time_eq_int(int a,int b)23517f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq_int(int a, int b)
23617f01e99SJung-uk Kim {
23717f01e99SJung-uk Kim     return constant_time_eq((unsigned)(a), (unsigned)(b));
23817f01e99SJung-uk Kim }
23917f01e99SJung-uk Kim 
constant_time_eq_int_8(int a,int b)24017f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_int_8(int a, int b)
24117f01e99SJung-uk Kim {
24217f01e99SJung-uk Kim     return constant_time_eq_8((unsigned)(a), (unsigned)(b));
24317f01e99SJung-uk Kim }
24417f01e99SJung-uk Kim 
24517f01e99SJung-uk Kim /*
24617f01e99SJung-uk Kim  * Returns the value unmodified, but avoids optimizations.
24717f01e99SJung-uk Kim  * The barriers prevent the compiler from narrowing down the
24817f01e99SJung-uk Kim  * possible value range of the mask and ~mask in the select
24917f01e99SJung-uk Kim  * statements, which avoids the recognition of the select
25017f01e99SJung-uk Kim  * and turning it into a conditional load or branch.
25117f01e99SJung-uk Kim  */
value_barrier(unsigned int a)25217f01e99SJung-uk Kim static ossl_inline unsigned int value_barrier(unsigned int a)
25317f01e99SJung-uk Kim {
25417f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
25517f01e99SJung-uk Kim     unsigned int r;
25617f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
25717f01e99SJung-uk Kim #else
25817f01e99SJung-uk Kim     volatile unsigned int r = a;
25917f01e99SJung-uk Kim #endif
26017f01e99SJung-uk Kim     return r;
26117f01e99SJung-uk Kim }
26217f01e99SJung-uk Kim 
26317f01e99SJung-uk Kim /* Convenience method for uint32_t. */
value_barrier_32(uint32_t a)26417f01e99SJung-uk Kim static ossl_inline uint32_t value_barrier_32(uint32_t a)
26517f01e99SJung-uk Kim {
26617f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
26717f01e99SJung-uk Kim     uint32_t r;
26817f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
26917f01e99SJung-uk Kim #else
27017f01e99SJung-uk Kim     volatile uint32_t r = a;
27117f01e99SJung-uk Kim #endif
27217f01e99SJung-uk Kim     return r;
27317f01e99SJung-uk Kim }
27417f01e99SJung-uk Kim 
27517f01e99SJung-uk Kim /* Convenience method for uint64_t. */
value_barrier_64(uint64_t a)27617f01e99SJung-uk Kim static ossl_inline uint64_t value_barrier_64(uint64_t a)
27717f01e99SJung-uk Kim {
27817f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
27917f01e99SJung-uk Kim     uint64_t r;
28017f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
28117f01e99SJung-uk Kim #else
28217f01e99SJung-uk Kim     volatile uint64_t r = a;
28317f01e99SJung-uk Kim #endif
28417f01e99SJung-uk Kim     return r;
28517f01e99SJung-uk Kim }
28617f01e99SJung-uk Kim 
28717f01e99SJung-uk Kim /* Convenience method for size_t. */
value_barrier_s(size_t a)28817f01e99SJung-uk Kim static ossl_inline size_t value_barrier_s(size_t a)
28917f01e99SJung-uk Kim {
29017f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
29117f01e99SJung-uk Kim     size_t r;
29217f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
29317f01e99SJung-uk Kim #else
29417f01e99SJung-uk Kim     volatile size_t r = a;
29517f01e99SJung-uk Kim #endif
29617f01e99SJung-uk Kim     return r;
29717f01e99SJung-uk Kim }
29817f01e99SJung-uk Kim 
constant_time_select(unsigned int mask,unsigned int a,unsigned int b)29917f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_select(unsigned int mask,
30017f01e99SJung-uk Kim                                                      unsigned int a,
30117f01e99SJung-uk Kim                                                      unsigned int b)
30217f01e99SJung-uk Kim {
30317f01e99SJung-uk Kim     return (value_barrier(mask) & a) | (value_barrier(~mask) & b);
30417f01e99SJung-uk Kim }
30517f01e99SJung-uk Kim 
constant_time_select_s(size_t mask,size_t a,size_t b)30617f01e99SJung-uk Kim static ossl_inline size_t constant_time_select_s(size_t mask,
30717f01e99SJung-uk Kim                                                  size_t a,
30817f01e99SJung-uk Kim                                                  size_t b)
30917f01e99SJung-uk Kim {
31017f01e99SJung-uk Kim     return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b);
31117f01e99SJung-uk Kim }
31217f01e99SJung-uk Kim 
constant_time_select_8(unsigned char mask,unsigned char a,unsigned char b)31317f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
31417f01e99SJung-uk Kim                                                         unsigned char a,
31517f01e99SJung-uk Kim                                                         unsigned char b)
31617f01e99SJung-uk Kim {
31717f01e99SJung-uk Kim     return (unsigned char)constant_time_select(mask, a, b);
31817f01e99SJung-uk Kim }
31917f01e99SJung-uk Kim 
constant_time_select_int(unsigned int mask,int a,int b)32017f01e99SJung-uk Kim static ossl_inline int constant_time_select_int(unsigned int mask, int a,
32117f01e99SJung-uk Kim                                                 int b)
32217f01e99SJung-uk Kim {
32317f01e99SJung-uk Kim     return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b));
32417f01e99SJung-uk Kim }
32517f01e99SJung-uk Kim 
constant_time_select_int_s(size_t mask,int a,int b)32617f01e99SJung-uk Kim static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b)
32717f01e99SJung-uk Kim {
32817f01e99SJung-uk Kim     return (int)constant_time_select((unsigned)mask, (unsigned)(a),
32917f01e99SJung-uk Kim                                       (unsigned)(b));
33017f01e99SJung-uk Kim }
33117f01e99SJung-uk Kim 
constant_time_select_32(uint32_t mask,uint32_t a,uint32_t b)33217f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,
33317f01e99SJung-uk Kim                                                     uint32_t b)
33417f01e99SJung-uk Kim {
33517f01e99SJung-uk Kim     return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b);
33617f01e99SJung-uk Kim }
33717f01e99SJung-uk Kim 
constant_time_select_64(uint64_t mask,uint64_t a,uint64_t b)33817f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,
33917f01e99SJung-uk Kim                                                     uint64_t b)
34017f01e99SJung-uk Kim {
34117f01e99SJung-uk Kim     return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b);
34217f01e99SJung-uk Kim }
34317f01e99SJung-uk Kim 
34417f01e99SJung-uk Kim /*
34517f01e99SJung-uk Kim  * mask must be 0xFFFFFFFF or 0x00000000.
34617f01e99SJung-uk Kim  *
34717f01e99SJung-uk Kim  * if (mask) {
34817f01e99SJung-uk Kim  *     uint32_t tmp = *a;
34917f01e99SJung-uk Kim  *
35017f01e99SJung-uk Kim  *     *a = *b;
35117f01e99SJung-uk Kim  *     *b = tmp;
35217f01e99SJung-uk Kim  * }
35317f01e99SJung-uk Kim  */
constant_time_cond_swap_32(uint32_t mask,uint32_t * a,uint32_t * b)35417f01e99SJung-uk Kim static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a,
35517f01e99SJung-uk Kim                                                    uint32_t *b)
35617f01e99SJung-uk Kim {
35717f01e99SJung-uk Kim     uint32_t xor = *a ^ *b;
35817f01e99SJung-uk Kim 
35917f01e99SJung-uk Kim     xor &= mask;
36017f01e99SJung-uk Kim     *a ^= xor;
36117f01e99SJung-uk Kim     *b ^= xor;
36217f01e99SJung-uk Kim }
36317f01e99SJung-uk Kim 
36417f01e99SJung-uk Kim /*
36517f01e99SJung-uk Kim  * mask must be 0xFFFFFFFF or 0x00000000.
36617f01e99SJung-uk Kim  *
36717f01e99SJung-uk Kim  * if (mask) {
36817f01e99SJung-uk Kim  *     uint64_t tmp = *a;
36917f01e99SJung-uk Kim  *
37017f01e99SJung-uk Kim  *     *a = *b;
37117f01e99SJung-uk Kim  *     *b = tmp;
37217f01e99SJung-uk Kim  * }
37317f01e99SJung-uk Kim  */
constant_time_cond_swap_64(uint64_t mask,uint64_t * a,uint64_t * b)37417f01e99SJung-uk Kim static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a,
37517f01e99SJung-uk Kim                                                    uint64_t *b)
37617f01e99SJung-uk Kim {
37717f01e99SJung-uk Kim     uint64_t xor = *a ^ *b;
37817f01e99SJung-uk Kim 
37917f01e99SJung-uk Kim     xor &= mask;
38017f01e99SJung-uk Kim     *a ^= xor;
38117f01e99SJung-uk Kim     *b ^= xor;
38217f01e99SJung-uk Kim }
38317f01e99SJung-uk Kim 
38417f01e99SJung-uk Kim /*
385b077aed3SPierre Pronchery  * mask must be 0xFF or 0x00.
386b077aed3SPierre Pronchery  * "constant time" is per len.
387b077aed3SPierre Pronchery  *
388b077aed3SPierre Pronchery  * if (mask) {
389b077aed3SPierre Pronchery  *     unsigned char tmp[len];
390b077aed3SPierre Pronchery  *
391b077aed3SPierre Pronchery  *     memcpy(tmp, a, len);
392b077aed3SPierre Pronchery  *     memcpy(a, b);
393b077aed3SPierre Pronchery  *     memcpy(b, tmp);
394b077aed3SPierre Pronchery  * }
395b077aed3SPierre Pronchery  */
constant_time_cond_swap_buff(unsigned char mask,unsigned char * a,unsigned char * b,size_t len)396b077aed3SPierre Pronchery static ossl_inline void constant_time_cond_swap_buff(unsigned char mask,
397b077aed3SPierre Pronchery                                                      unsigned char *a,
398b077aed3SPierre Pronchery                                                      unsigned char *b,
399b077aed3SPierre Pronchery                                                      size_t len)
400b077aed3SPierre Pronchery {
401b077aed3SPierre Pronchery     size_t i;
402b077aed3SPierre Pronchery     unsigned char tmp;
403b077aed3SPierre Pronchery 
404b077aed3SPierre Pronchery     for (i = 0; i < len; i++) {
405b077aed3SPierre Pronchery         tmp = a[i] ^ b[i];
406b077aed3SPierre Pronchery         tmp &= mask;
407b077aed3SPierre Pronchery         a[i] ^= tmp;
408b077aed3SPierre Pronchery         b[i] ^= tmp;
409b077aed3SPierre Pronchery     }
410b077aed3SPierre Pronchery }
411b077aed3SPierre Pronchery 
412b077aed3SPierre Pronchery /*
41317f01e99SJung-uk Kim  * table is a two dimensional array of bytes. Each row has rowsize elements.
41417f01e99SJung-uk Kim  * Copies row number idx into out. rowsize and numrows are not considered
41517f01e99SJung-uk Kim  * private.
41617f01e99SJung-uk Kim  */
constant_time_lookup(void * out,const void * table,size_t rowsize,size_t numrows,size_t idx)41717f01e99SJung-uk Kim static ossl_inline void constant_time_lookup(void *out,
41817f01e99SJung-uk Kim                                              const void *table,
41917f01e99SJung-uk Kim                                              size_t rowsize,
42017f01e99SJung-uk Kim                                              size_t numrows,
42117f01e99SJung-uk Kim                                              size_t idx)
42217f01e99SJung-uk Kim {
42317f01e99SJung-uk Kim     size_t i, j;
42417f01e99SJung-uk Kim     const unsigned char *tablec = (const unsigned char *)table;
42517f01e99SJung-uk Kim     unsigned char *outc = (unsigned char *)out;
42617f01e99SJung-uk Kim     unsigned char mask;
42717f01e99SJung-uk Kim 
42817f01e99SJung-uk Kim     memset(out, 0, rowsize);
42917f01e99SJung-uk Kim 
43017f01e99SJung-uk Kim     /* Note idx may underflow - but that is well defined */
43117f01e99SJung-uk Kim     for (i = 0; i < numrows; i++, idx--) {
43217f01e99SJung-uk Kim         mask = (unsigned char)constant_time_is_zero_s(idx);
43317f01e99SJung-uk Kim         for (j = 0; j < rowsize; j++)
43417f01e99SJung-uk Kim             *(outc + j) |= constant_time_select_8(mask, *(tablec++), 0);
43517f01e99SJung-uk Kim     }
43617f01e99SJung-uk Kim }
43717f01e99SJung-uk Kim 
43817f01e99SJung-uk Kim /*
43917f01e99SJung-uk Kim  * Expected usage pattern is to unconditionally set error and then
44017f01e99SJung-uk Kim  * wipe it if there was no actual error. |clear| is 1 or 0.
44117f01e99SJung-uk Kim  */
44217f01e99SJung-uk Kim void err_clear_last_constant_time(int clear);
44317f01e99SJung-uk Kim 
44417f01e99SJung-uk Kim #endif                          /* OSSL_INTERNAL_CONSTANT_TIME_H */
445