xref: /freebsd/crypto/openssl/include/internal/constant_time.h (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
117f01e99SJung-uk Kim /*
2*b077aed3SPierre Pronchery  * Copyright 2014-2021 The OpenSSL Project Authors. All Rights Reserved.
317f01e99SJung-uk Kim  *
4*b077aed3SPierre 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
12*b077aed3SPierre 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 
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 
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 
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 
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 
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 
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 
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 
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 
14317f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_ge(unsigned int a,
14417f01e99SJung-uk Kim                                                  unsigned int b)
14517f01e99SJung-uk Kim {
14617f01e99SJung-uk Kim     return ~constant_time_lt(a, b);
14717f01e99SJung-uk Kim }
14817f01e99SJung-uk Kim 
14917f01e99SJung-uk Kim static ossl_inline size_t constant_time_ge_s(size_t a, size_t b)
15017f01e99SJung-uk Kim {
15117f01e99SJung-uk Kim     return ~constant_time_lt_s(a, b);
15217f01e99SJung-uk Kim }
15317f01e99SJung-uk Kim 
15417f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
15517f01e99SJung-uk Kim                                                     unsigned int b)
15617f01e99SJung-uk Kim {
15717f01e99SJung-uk Kim     return (unsigned char)constant_time_ge(a, b);
15817f01e99SJung-uk Kim }
15917f01e99SJung-uk Kim 
16017f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b)
16117f01e99SJung-uk Kim {
16217f01e99SJung-uk Kim     return (unsigned char)constant_time_ge_s(a, b);
16317f01e99SJung-uk Kim }
16417f01e99SJung-uk Kim 
16517f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_is_zero(unsigned int a)
16617f01e99SJung-uk Kim {
16717f01e99SJung-uk Kim     return constant_time_msb(~a & (a - 1));
16817f01e99SJung-uk Kim }
16917f01e99SJung-uk Kim 
17017f01e99SJung-uk Kim static ossl_inline size_t constant_time_is_zero_s(size_t a)
17117f01e99SJung-uk Kim {
17217f01e99SJung-uk Kim     return constant_time_msb_s(~a & (a - 1));
17317f01e99SJung-uk Kim }
17417f01e99SJung-uk Kim 
17517f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a)
17617f01e99SJung-uk Kim {
17717f01e99SJung-uk Kim     return (unsigned char)constant_time_is_zero(a);
17817f01e99SJung-uk Kim }
17917f01e99SJung-uk Kim 
18017f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a)
18117f01e99SJung-uk Kim {
18217f01e99SJung-uk Kim     return constant_time_msb_32(~a & (a - 1));
18317f01e99SJung-uk Kim }
18417f01e99SJung-uk Kim 
185*b077aed3SPierre Pronchery static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a)
186*b077aed3SPierre Pronchery {
187*b077aed3SPierre Pronchery     return constant_time_msb_64(~a & (a - 1));
188*b077aed3SPierre Pronchery }
189*b077aed3SPierre Pronchery 
19017f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq(unsigned int a,
19117f01e99SJung-uk Kim                                                  unsigned int b)
19217f01e99SJung-uk Kim {
19317f01e99SJung-uk Kim     return constant_time_is_zero(a ^ b);
19417f01e99SJung-uk Kim }
19517f01e99SJung-uk Kim 
19617f01e99SJung-uk Kim static ossl_inline size_t constant_time_eq_s(size_t a, size_t b)
19717f01e99SJung-uk Kim {
19817f01e99SJung-uk Kim     return constant_time_is_zero_s(a ^ b);
19917f01e99SJung-uk Kim }
20017f01e99SJung-uk Kim 
20117f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
20217f01e99SJung-uk Kim                                                     unsigned int b)
20317f01e99SJung-uk Kim {
20417f01e99SJung-uk Kim     return (unsigned char)constant_time_eq(a, b);
20517f01e99SJung-uk Kim }
20617f01e99SJung-uk Kim 
20717f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b)
20817f01e99SJung-uk Kim {
20917f01e99SJung-uk Kim     return (unsigned char)constant_time_eq_s(a, b);
21017f01e99SJung-uk Kim }
21117f01e99SJung-uk Kim 
21217f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq_int(int a, int b)
21317f01e99SJung-uk Kim {
21417f01e99SJung-uk Kim     return constant_time_eq((unsigned)(a), (unsigned)(b));
21517f01e99SJung-uk Kim }
21617f01e99SJung-uk Kim 
21717f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_int_8(int a, int b)
21817f01e99SJung-uk Kim {
21917f01e99SJung-uk Kim     return constant_time_eq_8((unsigned)(a), (unsigned)(b));
22017f01e99SJung-uk Kim }
22117f01e99SJung-uk Kim 
22217f01e99SJung-uk Kim /*
22317f01e99SJung-uk Kim  * Returns the value unmodified, but avoids optimizations.
22417f01e99SJung-uk Kim  * The barriers prevent the compiler from narrowing down the
22517f01e99SJung-uk Kim  * possible value range of the mask and ~mask in the select
22617f01e99SJung-uk Kim  * statements, which avoids the recognition of the select
22717f01e99SJung-uk Kim  * and turning it into a conditional load or branch.
22817f01e99SJung-uk Kim  */
22917f01e99SJung-uk Kim static ossl_inline unsigned int value_barrier(unsigned int a)
23017f01e99SJung-uk Kim {
23117f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
23217f01e99SJung-uk Kim     unsigned int r;
23317f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
23417f01e99SJung-uk Kim #else
23517f01e99SJung-uk Kim     volatile unsigned int r = a;
23617f01e99SJung-uk Kim #endif
23717f01e99SJung-uk Kim     return r;
23817f01e99SJung-uk Kim }
23917f01e99SJung-uk Kim 
24017f01e99SJung-uk Kim /* Convenience method for uint32_t. */
24117f01e99SJung-uk Kim static ossl_inline uint32_t value_barrier_32(uint32_t a)
24217f01e99SJung-uk Kim {
24317f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
24417f01e99SJung-uk Kim     uint32_t r;
24517f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
24617f01e99SJung-uk Kim #else
24717f01e99SJung-uk Kim     volatile uint32_t r = a;
24817f01e99SJung-uk Kim #endif
24917f01e99SJung-uk Kim     return r;
25017f01e99SJung-uk Kim }
25117f01e99SJung-uk Kim 
25217f01e99SJung-uk Kim /* Convenience method for uint64_t. */
25317f01e99SJung-uk Kim static ossl_inline uint64_t value_barrier_64(uint64_t a)
25417f01e99SJung-uk Kim {
25517f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
25617f01e99SJung-uk Kim     uint64_t r;
25717f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
25817f01e99SJung-uk Kim #else
25917f01e99SJung-uk Kim     volatile uint64_t r = a;
26017f01e99SJung-uk Kim #endif
26117f01e99SJung-uk Kim     return r;
26217f01e99SJung-uk Kim }
26317f01e99SJung-uk Kim 
26417f01e99SJung-uk Kim /* Convenience method for size_t. */
26517f01e99SJung-uk Kim static ossl_inline size_t value_barrier_s(size_t a)
26617f01e99SJung-uk Kim {
26717f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
26817f01e99SJung-uk Kim     size_t r;
26917f01e99SJung-uk Kim     __asm__("" : "=r"(r) : "0"(a));
27017f01e99SJung-uk Kim #else
27117f01e99SJung-uk Kim     volatile size_t r = a;
27217f01e99SJung-uk Kim #endif
27317f01e99SJung-uk Kim     return r;
27417f01e99SJung-uk Kim }
27517f01e99SJung-uk Kim 
27617f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_select(unsigned int mask,
27717f01e99SJung-uk Kim                                                      unsigned int a,
27817f01e99SJung-uk Kim                                                      unsigned int b)
27917f01e99SJung-uk Kim {
28017f01e99SJung-uk Kim     return (value_barrier(mask) & a) | (value_barrier(~mask) & b);
28117f01e99SJung-uk Kim }
28217f01e99SJung-uk Kim 
28317f01e99SJung-uk Kim static ossl_inline size_t constant_time_select_s(size_t mask,
28417f01e99SJung-uk Kim                                                  size_t a,
28517f01e99SJung-uk Kim                                                  size_t b)
28617f01e99SJung-uk Kim {
28717f01e99SJung-uk Kim     return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b);
28817f01e99SJung-uk Kim }
28917f01e99SJung-uk Kim 
29017f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
29117f01e99SJung-uk Kim                                                         unsigned char a,
29217f01e99SJung-uk Kim                                                         unsigned char b)
29317f01e99SJung-uk Kim {
29417f01e99SJung-uk Kim     return (unsigned char)constant_time_select(mask, a, b);
29517f01e99SJung-uk Kim }
29617f01e99SJung-uk Kim 
29717f01e99SJung-uk Kim static ossl_inline int constant_time_select_int(unsigned int mask, int a,
29817f01e99SJung-uk Kim                                                 int b)
29917f01e99SJung-uk Kim {
30017f01e99SJung-uk Kim     return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b));
30117f01e99SJung-uk Kim }
30217f01e99SJung-uk Kim 
30317f01e99SJung-uk Kim static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b)
30417f01e99SJung-uk Kim {
30517f01e99SJung-uk Kim     return (int)constant_time_select((unsigned)mask, (unsigned)(a),
30617f01e99SJung-uk Kim                                       (unsigned)(b));
30717f01e99SJung-uk Kim }
30817f01e99SJung-uk Kim 
30917f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,
31017f01e99SJung-uk Kim                                                     uint32_t b)
31117f01e99SJung-uk Kim {
31217f01e99SJung-uk Kim     return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b);
31317f01e99SJung-uk Kim }
31417f01e99SJung-uk Kim 
31517f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,
31617f01e99SJung-uk Kim                                                     uint64_t b)
31717f01e99SJung-uk Kim {
31817f01e99SJung-uk Kim     return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b);
31917f01e99SJung-uk Kim }
32017f01e99SJung-uk Kim 
32117f01e99SJung-uk Kim /*
32217f01e99SJung-uk Kim  * mask must be 0xFFFFFFFF or 0x00000000.
32317f01e99SJung-uk Kim  *
32417f01e99SJung-uk Kim  * if (mask) {
32517f01e99SJung-uk Kim  *     uint32_t tmp = *a;
32617f01e99SJung-uk Kim  *
32717f01e99SJung-uk Kim  *     *a = *b;
32817f01e99SJung-uk Kim  *     *b = tmp;
32917f01e99SJung-uk Kim  * }
33017f01e99SJung-uk Kim  */
33117f01e99SJung-uk Kim static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a,
33217f01e99SJung-uk Kim                                                    uint32_t *b)
33317f01e99SJung-uk Kim {
33417f01e99SJung-uk Kim     uint32_t xor = *a ^ *b;
33517f01e99SJung-uk Kim 
33617f01e99SJung-uk Kim     xor &= mask;
33717f01e99SJung-uk Kim     *a ^= xor;
33817f01e99SJung-uk Kim     *b ^= xor;
33917f01e99SJung-uk Kim }
34017f01e99SJung-uk Kim 
34117f01e99SJung-uk Kim /*
34217f01e99SJung-uk Kim  * mask must be 0xFFFFFFFF or 0x00000000.
34317f01e99SJung-uk Kim  *
34417f01e99SJung-uk Kim  * if (mask) {
34517f01e99SJung-uk Kim  *     uint64_t tmp = *a;
34617f01e99SJung-uk Kim  *
34717f01e99SJung-uk Kim  *     *a = *b;
34817f01e99SJung-uk Kim  *     *b = tmp;
34917f01e99SJung-uk Kim  * }
35017f01e99SJung-uk Kim  */
35117f01e99SJung-uk Kim static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a,
35217f01e99SJung-uk Kim                                                    uint64_t *b)
35317f01e99SJung-uk Kim {
35417f01e99SJung-uk Kim     uint64_t xor = *a ^ *b;
35517f01e99SJung-uk Kim 
35617f01e99SJung-uk Kim     xor &= mask;
35717f01e99SJung-uk Kim     *a ^= xor;
35817f01e99SJung-uk Kim     *b ^= xor;
35917f01e99SJung-uk Kim }
36017f01e99SJung-uk Kim 
36117f01e99SJung-uk Kim /*
362*b077aed3SPierre Pronchery  * mask must be 0xFF or 0x00.
363*b077aed3SPierre Pronchery  * "constant time" is per len.
364*b077aed3SPierre Pronchery  *
365*b077aed3SPierre Pronchery  * if (mask) {
366*b077aed3SPierre Pronchery  *     unsigned char tmp[len];
367*b077aed3SPierre Pronchery  *
368*b077aed3SPierre Pronchery  *     memcpy(tmp, a, len);
369*b077aed3SPierre Pronchery  *     memcpy(a, b);
370*b077aed3SPierre Pronchery  *     memcpy(b, tmp);
371*b077aed3SPierre Pronchery  * }
372*b077aed3SPierre Pronchery  */
373*b077aed3SPierre Pronchery static ossl_inline void constant_time_cond_swap_buff(unsigned char mask,
374*b077aed3SPierre Pronchery                                                      unsigned char *a,
375*b077aed3SPierre Pronchery                                                      unsigned char *b,
376*b077aed3SPierre Pronchery                                                      size_t len)
377*b077aed3SPierre Pronchery {
378*b077aed3SPierre Pronchery     size_t i;
379*b077aed3SPierre Pronchery     unsigned char tmp;
380*b077aed3SPierre Pronchery 
381*b077aed3SPierre Pronchery     for (i = 0; i < len; i++) {
382*b077aed3SPierre Pronchery         tmp = a[i] ^ b[i];
383*b077aed3SPierre Pronchery         tmp &= mask;
384*b077aed3SPierre Pronchery         a[i] ^= tmp;
385*b077aed3SPierre Pronchery         b[i] ^= tmp;
386*b077aed3SPierre Pronchery     }
387*b077aed3SPierre Pronchery }
388*b077aed3SPierre Pronchery 
389*b077aed3SPierre Pronchery /*
39017f01e99SJung-uk Kim  * table is a two dimensional array of bytes. Each row has rowsize elements.
39117f01e99SJung-uk Kim  * Copies row number idx into out. rowsize and numrows are not considered
39217f01e99SJung-uk Kim  * private.
39317f01e99SJung-uk Kim  */
39417f01e99SJung-uk Kim static ossl_inline void constant_time_lookup(void *out,
39517f01e99SJung-uk Kim                                              const void *table,
39617f01e99SJung-uk Kim                                              size_t rowsize,
39717f01e99SJung-uk Kim                                              size_t numrows,
39817f01e99SJung-uk Kim                                              size_t idx)
39917f01e99SJung-uk Kim {
40017f01e99SJung-uk Kim     size_t i, j;
40117f01e99SJung-uk Kim     const unsigned char *tablec = (const unsigned char *)table;
40217f01e99SJung-uk Kim     unsigned char *outc = (unsigned char *)out;
40317f01e99SJung-uk Kim     unsigned char mask;
40417f01e99SJung-uk Kim 
40517f01e99SJung-uk Kim     memset(out, 0, rowsize);
40617f01e99SJung-uk Kim 
40717f01e99SJung-uk Kim     /* Note idx may underflow - but that is well defined */
40817f01e99SJung-uk Kim     for (i = 0; i < numrows; i++, idx--) {
40917f01e99SJung-uk Kim         mask = (unsigned char)constant_time_is_zero_s(idx);
41017f01e99SJung-uk Kim         for (j = 0; j < rowsize; j++)
41117f01e99SJung-uk Kim             *(outc + j) |= constant_time_select_8(mask, *(tablec++), 0);
41217f01e99SJung-uk Kim     }
41317f01e99SJung-uk Kim }
41417f01e99SJung-uk Kim 
41517f01e99SJung-uk Kim /*
41617f01e99SJung-uk Kim  * Expected usage pattern is to unconditionally set error and then
41717f01e99SJung-uk Kim  * wipe it if there was no actual error. |clear| is 1 or 0.
41817f01e99SJung-uk Kim  */
41917f01e99SJung-uk Kim void err_clear_last_constant_time(int clear);
42017f01e99SJung-uk Kim 
42117f01e99SJung-uk Kim #endif                          /* OSSL_INTERNAL_CONSTANT_TIME_H */
422