• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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