1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #ifdef HITLS_CRYPTO_BN
18
19 #include <stdbool.h>
20 #include "securec.h"
21 #include "bsl_sal.h"
22 #include "bsl_err_internal.h"
23 #include "crypt_errno.h"
24 #include "bn_basic.h"
25 #include "bn_bincal.h"
26 #include "bn_optimizer.h"
27
28
29 /* Euclidean algorithm */
BnGcdDiv(BN_BigNum * r,BN_BigNum * max,BN_BigNum * min,BN_Optimizer * opt)30 static int32_t BnGcdDiv(BN_BigNum *r, BN_BigNum *max, BN_BigNum *min, BN_Optimizer *opt)
31 {
32 int32_t ret = CRYPT_SUCCESS;
33 BN_BigNum *tmp = NULL;
34 BN_BigNum *big = max;
35 BN_BigNum *small = min;
36 do {
37 ret = BN_Div(NULL, big, big, small, opt);
38 if (ret != CRYPT_SUCCESS) {
39 BSL_ERR_PUSH_ERROR(ret);
40 return ret;
41 }
42 if (BN_IsOne(big)) {
43 return BN_Copy(r, big);
44 }
45 if (BN_IsZero(big)) {
46 return BN_Copy(r, small);
47 }
48 /* ensure that big > small in the next calculation of remainder */
49 tmp = big;
50 big = small;
51 small = tmp;
52 } while (true);
53 return CRYPT_SUCCESS;
54 }
55
BnGcdCheckInput(BN_BigNum * r,const BN_BigNum * a,const BN_BigNum * b,const BN_Optimizer * opt)56 int32_t BnGcdCheckInput(BN_BigNum *r, const BN_BigNum *a, const BN_BigNum *b, const BN_Optimizer *opt)
57 {
58 bool invalidInput = (a == NULL || b == NULL || r == NULL || opt == NULL);
59 if (invalidInput) {
60 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
61 return CRYPT_NULL_INPUT;
62 }
63 /* The GCD may be the minimum value between a and b. Ensure the r space before calculation. */
64 uint32_t needSize = (a->size < b->size) ? a->size : b->size;
65 int32_t ret = BnExtend(r, needSize);
66 if (ret != CRYPT_SUCCESS) {
67 return ret;
68 }
69 // a and b cannot be 0
70 if (BN_IsZero(a) || BN_IsZero(b)) {
71 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_GCD_NO_ZERO);
72 return CRYPT_BN_ERR_GCD_NO_ZERO;
73 }
74 return CRYPT_SUCCESS;
75 }
76
BN_Gcd(BN_BigNum * r,const BN_BigNum * a,const BN_BigNum * b,BN_Optimizer * opt)77 int32_t BN_Gcd(BN_BigNum *r, const BN_BigNum *a, const BN_BigNum *b, BN_Optimizer *opt)
78 {
79 int32_t ret = BnGcdCheckInput(r, a, b, opt);
80 if (ret != CRYPT_SUCCESS) {
81 return ret;
82 }
83 ret = BinCmp(a->data, a->size, b->data, b->size);
84 if (ret == 0) { // For example, a == b is the greatest common divisor of itself
85 ret = BN_Copy(r, a);
86 if (ret != CRYPT_SUCCESS) {
87 BSL_ERR_PUSH_ERROR(ret);
88 return ret;
89 }
90 r->sign = false; // the greatest common divisor is a positive integer
91 return CRYPT_SUCCESS;
92 }
93 const BN_BigNum *bigNum = (ret > 0) ? a : b;
94 const BN_BigNum *smallNum = (ret > 0) ? b : a;
95 ret = OptimizerStart(opt); // use the optimizer
96 if (ret != CRYPT_SUCCESS) {
97 BSL_ERR_PUSH_ERROR(ret);
98 return ret;
99 }
100 /* Apply for temporary space of BN objects a and b. */
101 BN_BigNum *max = OptimizerGetBn(opt, bigNum->size);
102 BN_BigNum *min = OptimizerGetBn(opt, smallNum->size);
103 if (max == NULL || min == NULL) {
104 OptimizerEnd(opt);
105 BSL_ERR_PUSH_ERROR(CRYPT_BN_OPTIMIZER_GET_FAIL);
106 return CRYPT_BN_OPTIMIZER_GET_FAIL;
107 }
108 ret = BN_Copy(max, bigNum);
109 if (ret != CRYPT_SUCCESS) {
110 OptimizerEnd(opt);
111 BSL_ERR_PUSH_ERROR(ret);
112 return ret;
113 }
114 ret = BN_Copy(min, smallNum);
115 if (ret != CRYPT_SUCCESS) {
116 OptimizerEnd(opt);
117 BSL_ERR_PUSH_ERROR(ret);
118 return ret;
119 }
120 // obtain the GCD, ensure that input parameter max > min
121 ret = BnGcdDiv(r, max, min, opt);
122 if (ret == CRYPT_SUCCESS) {
123 r->sign = false; // The GCD is a positive integer
124 }
125 OptimizerEnd(opt); // release occupation from the optimizer
126 return ret;
127 }
128
InverseReady(BN_BigNum * a,BN_BigNum * b,const BN_BigNum * x,const BN_BigNum * m,BN_Optimizer * opt)129 static int32_t InverseReady(BN_BigNum *a, BN_BigNum *b, const BN_BigNum *x, const BN_BigNum *m, BN_Optimizer *opt)
130 {
131 int32_t ret = BN_Copy(a, m);
132 if (ret != CRYPT_SUCCESS) {
133 BSL_ERR_PUSH_ERROR(ret);
134 return ret;
135 }
136 a->sign = false;
137 ret = BN_Mod(b, x, m, opt); // b must be a positive number and do not need to convert symbols.
138 if (ret != CRYPT_SUCCESS) {
139 BSL_ERR_PUSH_ERROR(ret);
140 return ret;
141 }
142 if (BN_IsZero(b)) { // does not satisfy x and m interprime, so it cannot obtain the inverse module.
143 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_NO_INVERSE);
144 return CRYPT_BN_ERR_NO_INVERSE;
145 }
146 return CRYPT_SUCCESS;
147 }
148
InverseCore(BN_BigNum * r,BN_BigNum * x,BN_BigNum * y,uint32_t mSize,BN_Optimizer * opt)149 static int32_t InverseCore(BN_BigNum *r, BN_BigNum *x, BN_BigNum *y, uint32_t mSize, BN_Optimizer *opt)
150 {
151 BN_BigNum *a = x;
152 BN_BigNum *b = y;
153 BN_BigNum *c = OptimizerGetBn(opt, mSize); // One more bit is reserved for addition and subtraction.
154 BN_BigNum *d = OptimizerGetBn(opt, mSize);
155 BN_BigNum *e = OptimizerGetBn(opt, mSize * 2); // multiplication of c requires 2x space
156 BN_BigNum *t = OptimizerGetBn(opt, mSize);
157 if (c == NULL || d == NULL || e == NULL || t == NULL) {
158 BSL_ERR_PUSH_ERROR(CRYPT_BN_OPTIMIZER_GET_FAIL);
159 return CRYPT_BN_OPTIMIZER_GET_FAIL;
160 }
161 (void)BN_SetBit(d, 0); // can ignore the return value
162 do {
163 int32_t ret = BN_Div(t, a, a, b, opt);
164 if (ret != CRYPT_SUCCESS) {
165 BSL_ERR_PUSH_ERROR(ret);
166 return ret;
167 }
168 if (BN_IsZero(a)) {
169 if (BN_IsOne(b)) { // b is 1
170 return BN_SetLimb(r, 1); // obtains the inverse modulus value 1
171 }
172 break; // Failed to obtain the inverse modulus value.
173 }
174 t->sign = !t->sign;
175 ret = BN_Mul(e, t, d, opt);
176 if (ret != CRYPT_SUCCESS) {
177 BSL_ERR_PUSH_ERROR(ret);
178 return ret;
179 }
180 ret = BN_Add(c, c, e);
181 if (ret != CRYPT_SUCCESS) {
182 BSL_ERR_PUSH_ERROR(ret);
183 return ret;
184 }
185 if (BN_IsOne(a)) {
186 return BN_Copy(r, c); // Obtain the module inverse.
187 }
188 // Switch a b
189 BN_BigNum *tmp = a;
190 a = b;
191 b = tmp;
192 // Switch c d
193 tmp = c;
194 c = d;
195 d = tmp;
196 } while (true);
197 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_NO_INVERSE);
198 return CRYPT_BN_ERR_NO_INVERSE;
199 }
200
InverseInputCheck(BN_BigNum * r,const BN_BigNum * x,const BN_BigNum * m,const BN_Optimizer * opt)201 int32_t InverseInputCheck(BN_BigNum *r, const BN_BigNum *x, const BN_BigNum *m, const BN_Optimizer *opt)
202 {
203 bool invalidInput = (r == NULL || x == NULL || m == NULL || opt == NULL);
204 if (invalidInput) {
205 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
206 return CRYPT_NULL_INPUT;
207 }
208 /* cannot be 0 */
209 if (BN_IsZero(x) || BN_IsZero(m)) {
210 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_DIVISOR_ZERO);
211 return CRYPT_BN_ERR_DIVISOR_ZERO;
212 }
213 return BnExtend(r, m->size);
214 }
215
BN_ModInv(BN_BigNum * r,const BN_BigNum * x,const BN_BigNum * m,BN_Optimizer * opt)216 int32_t BN_ModInv(BN_BigNum *r, const BN_BigNum *x, const BN_BigNum *m, BN_Optimizer *opt)
217 {
218 int32_t ret = InverseInputCheck(r, x, m, opt);
219 if (ret != CRYPT_SUCCESS) {
220 BSL_ERR_PUSH_ERROR(ret);
221 return ret;
222 }
223 ret = OptimizerStart(opt); // use the optimizer
224 if (ret != CRYPT_SUCCESS) {
225 BSL_ERR_PUSH_ERROR(ret);
226 return ret;
227 }
228 BN_BigNum *a = OptimizerGetBn(opt, m->size);
229 BN_BigNum *b = OptimizerGetBn(opt, m->size);
230 BN_BigNum *t = OptimizerGetBn(opt, m->size);
231 bool invalidInput = (a == NULL || b == NULL || t == NULL);
232 if (invalidInput) {
233 BSL_ERR_PUSH_ERROR(CRYPT_BN_OPTIMIZER_GET_FAIL);
234 ret = CRYPT_BN_OPTIMIZER_GET_FAIL;
235 goto ERR;
236 }
237 /* Take positive numbers a and b first. */
238 ret = InverseReady(a, b, x, m, opt);
239 if (ret != CRYPT_SUCCESS) {
240 BSL_ERR_PUSH_ERROR(ret);
241 goto ERR;
242 }
243 /* Extended Euclidean algorithm */
244 ret = InverseCore(t, a, b, m->size, opt);
245 if (ret != CRYPT_SUCCESS) {
246 BSL_ERR_PUSH_ERROR(ret);
247 goto ERR;
248 }
249 // Prevent the negative number.
250 ret = BN_Mod(r, t, m, opt);
251 if (ret != CRYPT_SUCCESS) {
252 BSL_ERR_PUSH_ERROR(ret);
253 goto ERR;
254 }
255 ERR:
256 OptimizerEnd(opt); // Release occupation from the optimizer.
257 return ret;
258 }
259 #endif /* HITLS_CRYPTO_BN */
260