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