/src/boringssl/crypto/fipsmodule/bn/cmp.cc.inc
Line | Count | Source |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/bn.h> |
16 | | |
17 | | #include <assert.h> |
18 | | |
19 | | #include <openssl/mem.h> |
20 | | |
21 | | #include "internal.h" |
22 | | #include "../../internal.h" |
23 | | |
24 | | |
25 | | using namespace bssl; |
26 | | |
27 | | static int bn_cmp_words_consttime(const BN_ULONG *a, size_t a_len, |
28 | 642k | const BN_ULONG *b, size_t b_len) { |
29 | 642k | static_assert(sizeof(BN_ULONG) <= sizeof(crypto_word_t), |
30 | 642k | "crypto_word_t is too small"); |
31 | 642k | int ret = 0; |
32 | | // Process the common words in little-endian order. |
33 | 642k | size_t min = a_len < b_len ? a_len : b_len; |
34 | 7.99M | for (size_t i = 0; i < min; i++) { |
35 | 7.35M | crypto_word_t eq = constant_time_eq_w(a[i], b[i]); |
36 | 7.35M | crypto_word_t lt = constant_time_lt_w(a[i], b[i]); |
37 | 7.35M | ret = |
38 | 7.35M | constant_time_select_int(eq, ret, constant_time_select_int(lt, -1, 1)); |
39 | 7.35M | } |
40 | | |
41 | | // If `a` or `b` has non-zero words beyond `min`, they take precedence. |
42 | 642k | if (a_len < b_len) { |
43 | 69.5k | crypto_word_t mask = 0; |
44 | 1.07M | for (size_t i = a_len; i < b_len; i++) { |
45 | 1.00M | mask |= b[i]; |
46 | 1.00M | } |
47 | 69.5k | ret = constant_time_select_int(constant_time_is_zero_w(mask), ret, -1); |
48 | 572k | } else if (b_len < a_len) { |
49 | 165k | crypto_word_t mask = 0; |
50 | 4.06M | for (size_t i = b_len; i < a_len; i++) { |
51 | 3.89M | mask |= a[i]; |
52 | 3.89M | } |
53 | 165k | ret = constant_time_select_int(constant_time_is_zero_w(mask), ret, 1); |
54 | 165k | } |
55 | | |
56 | 642k | return ret; |
57 | 642k | } |
58 | | |
59 | 421k | int BN_ucmp(const BIGNUM *a, const BIGNUM *b) { |
60 | 421k | return bn_cmp_words_consttime(a->d, a->width, b->d, b->width); |
61 | 421k | } |
62 | | |
63 | 80.8k | int BN_cmp(const BIGNUM *a, const BIGNUM *b) { |
64 | 80.8k | if ((a == nullptr) || (b == nullptr)) { |
65 | 0 | if (a != nullptr) { |
66 | 0 | return -1; |
67 | 0 | } else if (b != nullptr) { |
68 | 0 | return 1; |
69 | 0 | } else { |
70 | 0 | return 0; |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | // We do not attempt to process the sign bit in constant time. Negative |
75 | | // `BIGNUM`s should never occur in crypto, only calculators. |
76 | 80.8k | if (a->neg != b->neg) { |
77 | 0 | if (a->neg) { |
78 | 0 | return -1; |
79 | 0 | } |
80 | 0 | return 1; |
81 | 0 | } |
82 | | |
83 | 80.8k | int ret = BN_ucmp(a, b); |
84 | 80.8k | return a->neg ? -ret : ret; |
85 | 80.8k | } |
86 | | |
87 | 221k | int bssl::bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) { |
88 | 221k | return bn_cmp_words_consttime(a, len, b, len) < 0; |
89 | 221k | } |
90 | | |
91 | 5.42M | int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) { |
92 | 5.42M | if (bn->width == 0) { |
93 | 0 | return w == 0; |
94 | 0 | } |
95 | 5.42M | BN_ULONG mask = bn->d[0] ^ w; |
96 | 21.3M | for (int i = 1; i < bn->width; i++) { |
97 | 15.8M | mask |= bn->d[i]; |
98 | 15.8M | } |
99 | 5.42M | return mask == 0; |
100 | 5.42M | } |
101 | | |
102 | 0 | int BN_cmp_word(const BIGNUM *a, BN_ULONG b) { |
103 | 0 | BIGNUM b_bn; |
104 | 0 | BN_init(&b_bn); |
105 | |
|
106 | 0 | b_bn.d = &b; |
107 | 0 | b_bn.width = b > 0; |
108 | 0 | b_bn.dmax = 1; |
109 | 0 | b_bn.flags = BN_FLG_STATIC_DATA; |
110 | 0 | return BN_cmp(a, &b_bn); |
111 | 0 | } |
112 | | |
113 | 6.65M | int BN_is_zero(const BIGNUM *bn) { |
114 | 6.65M | return bn_fits_in_words(bn, 0); |
115 | 6.65M | } |
116 | | |
117 | 5.42M | int BN_is_one(const BIGNUM *bn) { |
118 | 5.42M | return bn->neg == 0 && BN_abs_is_word(bn, 1); |
119 | 5.42M | } |
120 | | |
121 | 0 | int BN_is_word(const BIGNUM *bn, BN_ULONG w) { |
122 | 0 | return BN_abs_is_word(bn, w) && (w == 0 || bn->neg == 0); |
123 | 0 | } |
124 | | |
125 | 764k | int BN_is_odd(const BIGNUM *bn) { |
126 | 764k | return bn->width > 0 && (bn->d[0] & 1) == 1; |
127 | 764k | } |
128 | | |
129 | 0 | int BN_is_pow2(const BIGNUM *bn) { |
130 | 0 | int width = bn_minimal_width(bn); |
131 | 0 | if (width == 0 || bn->neg) { |
132 | 0 | return 0; |
133 | 0 | } |
134 | | |
135 | 0 | for (int i = 0; i < width - 1; i++) { |
136 | 0 | if (bn->d[i] != 0) { |
137 | 0 | return 0; |
138 | 0 | } |
139 | 0 | } |
140 | | |
141 | 0 | return 0 == (bn->d[width-1] & (bn->d[width-1] - 1)); |
142 | 0 | } |
143 | | |
144 | 21.1k | int BN_equal_consttime(const BIGNUM *a, const BIGNUM *b) { |
145 | 21.1k | BN_ULONG mask = 0; |
146 | | // If `a` or `b` has more words than the other, all those words must be zero. |
147 | 21.1k | for (int i = a->width; i < b->width; i++) { |
148 | 0 | mask |= b->d[i]; |
149 | 0 | } |
150 | 21.1k | for (int i = b->width; i < a->width; i++) { |
151 | 0 | mask |= a->d[i]; |
152 | 0 | } |
153 | | // Common words must match. |
154 | 21.1k | int min = a->width < b->width ? a->width : b->width; |
155 | 698k | for (int i = 0; i < min; i++) { |
156 | 677k | mask |= (a->d[i] ^ b->d[i]); |
157 | 677k | } |
158 | | // The sign bit must match. |
159 | 21.1k | mask |= (a->neg ^ b->neg); |
160 | 21.1k | return mask == 0; |
161 | 21.1k | } |