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_ECC
18
19 #include <stdint.h>
20 #include <stdbool.h>
21 #include "securec.h"
22 #include "bsl_err_internal.h"
23 #include "bsl_sal.h"
24 #include "crypt_errno.h"
25 #include "crypt_utils.h"
26 #include "bn_optimizer.h"
27 #include "crypt_bn.h"
28
29
GetExp(const BN_BigNum * bn)30 static uint32_t GetExp(const BN_BigNum *bn)
31 {
32 uint32_t s = 0;
33 while (!BN_GetBit(bn, s)) {
34 s++;
35 }
36 return s;
37 }
38
39 // p does not perform prime number check, but performs parity check.
CheckParam(const BN_BigNum * a,const BN_BigNum * p)40 static int32_t CheckParam(const BN_BigNum *a, const BN_BigNum *p)
41 {
42 if (BN_IsZero(p) || BN_IsOne(p)) {
43 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_SQRT_PARA);
44 return CRYPT_BN_ERR_SQRT_PARA;
45 }
46 if (!BN_GetBit(p, 0)) { // p must be odd prime
47 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_SQRT_PARA);
48 return CRYPT_BN_ERR_SQRT_PARA;
49 }
50 if (p->sign || a->sign) { // p、a must be positive
51 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_SQRT_PARA);
52 return CRYPT_BN_ERR_SQRT_PARA;
53 }
54 if (BN_Cmp(p, a) <= 0) {
55 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_SQRT_PARA);
56 return CRYPT_BN_ERR_SQRT_PARA;
57 }
58 return CRYPT_SUCCESS;
59 }
60
61 // r = +- a^((p + 1)/4)
CalculationRoot(BN_BigNum * r,const BN_BigNum * a,const BN_BigNum * p,BN_Mont * mont,BN_Optimizer * opt)62 static int32_t CalculationRoot(BN_BigNum *r, const BN_BigNum *a, const BN_BigNum *p, BN_Mont *mont, BN_Optimizer *opt)
63 {
64 int32_t ret = OptimizerStart(opt);
65 if (ret != CRYPT_SUCCESS) {
66 BSL_ERR_PUSH_ERROR(ret);
67 return ret;
68 }
69 BN_BigNum *temp = OptimizerGetBn(opt, p->size);
70 if (temp == NULL) {
71 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
72 ret = CRYPT_MEM_ALLOC_FAIL;
73 goto ERR;
74 }
75 GOTO_ERR_IF_EX(BN_AddLimb(temp, p, 1), ret); // p + 1
76 GOTO_ERR_IF_EX(BN_Rshift(temp, temp, 2), ret); // (p + 1) / 4 = (p + 1) >> 2
77 GOTO_ERR_IF(BN_MontExp(r, a, temp, mont, opt), ret);
78 ERR:
79 OptimizerEnd(opt);
80 return ret;
81 }
82
LegendreFastTempDataCheck(const BN_BigNum * a,const BN_BigNum * pp)83 static int32_t LegendreFastTempDataCheck(const BN_BigNum *a, const BN_BigNum *pp)
84 {
85 if (a == NULL || pp == NULL) {
86 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
87 return CRYPT_MEM_ALLOC_FAIL;
88 }
89 return CRYPT_SUCCESS;
90 }
91
LegendreFast(BN_BigNum * z,const BN_BigNum * p,int32_t * legendre,BN_Optimizer * opt)92 int32_t LegendreFast(BN_BigNum *z, const BN_BigNum *p, int32_t *legendre, BN_Optimizer *opt)
93 {
94 int32_t l = 1;
95 BN_BigNum *temp = NULL;
96 int32_t ret = OptimizerStart(opt);
97 if (ret != CRYPT_SUCCESS) {
98 BSL_ERR_PUSH_ERROR(ret);
99 return ret;
100 }
101 BN_BigNum *a = OptimizerGetBn(opt, p->size); // The variable has been checked for NULL in BN_Copy.
102 BN_BigNum *pp = OptimizerGetBn(opt, p->size);
103 GOTO_ERR_IF(LegendreFastTempDataCheck(a, pp), ret);
104 if (BN_IsOne(z)) {
105 *legendre = 1;
106 goto ERR;
107 }
108 if (BN_IsZero(z)) {
109 *legendre = 0;
110 goto ERR;
111 }
112 GOTO_ERR_IF_EX(BN_Copy(a, z), ret);
113 GOTO_ERR_IF_EX(BN_Copy(pp, p), ret);
114 while (true) {
115 if (BN_IsZero(a)) {
116 *legendre = BN_IsOne(pp) ? l : 0;
117 break;
118 }
119 // Theorem: p is an odd prime number, a and b are numbers that are not divisible by p. (a|p)(b|p) = (ab|p)
120 // a = aa * 2^exp
121 // (a|pp) = (2|pp)^exp * (aa|pp)
122 // If exp is an even number, (a|pp) = (aa|pp)
123 uint32_t exp = GetExp(a);
124 GOTO_ERR_IF_EX(BN_Rshift(a, a, exp), ret);
125 if ((exp & 1) != 0) {
126 // pp = +- 1 mod 8, 2 is its quadratic remainder. pp = +-3 mod 8, 2 is its non-quadric remainder.
127 if ((pp->data[0] & 1) != 0) {
128 // pp->data[0] % 8 = pp->data[0] & 7
129 // pp = +- 1 mod 8 = 7 or 1 mod
130 l = ((pp->data[0] & 7) == 1 || (pp->data[0] & 7) == 7) ? l : -l;
131 } else {
132 l = 0;
133 }
134 }
135 // pp->data[0] % 4 = pp->data[0] & 3
136 // K(a|pp) = K(pp|a) * (-1)^((a-1)*(pp-1)/4)
137 // (a-1)*(pp-1)/4 is an even number only when at least one of A and P mod 4 = 1;
138 // if both A and P mod 4 = 3, (a-1)*(pp-1)/4 is an odd number.
139 if (((pp->data[0] & 3) == 3) && ((a->data[0] & 3) == 3)) {
140 l = -l;
141 }
142 // K(pp|a) = K(pp%a|a), swap(a,pp)
143 GOTO_ERR_IF_EX(BN_Div(NULL, pp, pp, a, opt), ret);
144 temp = a;
145 a = pp;
146 pp = temp;
147 }
148 ret = CRYPT_SUCCESS;
149 ERR:
150 OptimizerEnd(opt);
151 return ret;
152 }
153
154 // Find z so that legendre(z / p) = z^((p-1)/2) mod p != 1
GetLegendreZ(BN_BigNum * z,const BN_BigNum * p,BN_Optimizer * opt)155 static int32_t GetLegendreZ(BN_BigNum *z, const BN_BigNum *p, BN_Optimizer *opt)
156 {
157 uint32_t maxCnt = 50; // A random number can be generated cyclically for a maximum of 50 times.
158 int32_t ret = OptimizerStart(opt);
159 if (ret != CRYPT_SUCCESS) {
160 BSL_ERR_PUSH_ERROR(ret);
161 return ret;
162 }
163 int32_t legendre;
164 BN_BigNum *exp = OptimizerGetBn(opt, p->size); // exp = (p - 1) / 2
165 if (exp == NULL) {
166 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
167 ret = CRYPT_MEM_ALLOC_FAIL;
168 goto ERR;
169 }
170 GOTO_ERR_IF_EX(BN_SubLimb(exp, p, 1), ret);
171 GOTO_ERR_IF_EX(BN_Rshift(exp, exp, 1), ret);
172
173 while (maxCnt > 0) {
174 GOTO_ERR_IF_EX(BN_RandRangeEx(opt->libCtx, z, p), ret);
175
176 maxCnt--;
177 if (BN_IsZero(z)) {
178 continue;
179 }
180
181 GOTO_ERR_IF_EX(LegendreFast(z, p, &legendre, opt), ret);
182 if (legendre == -1) {
183 ret = CRYPT_SUCCESS;
184 goto ERR;
185 }
186 }
187 ret = CRYPT_BN_ERR_LEGENDE_DATA;
188 ERR:
189 OptimizerEnd(opt);
190 return ret;
191 }
192
SetParaR(BN_BigNum * r,BN_BigNum * q,const BN_BigNum * a,BN_Mont * mont,BN_Optimizer * opt)193 static int32_t SetParaR(BN_BigNum *r, BN_BigNum *q, const BN_BigNum *a, BN_Mont *mont, BN_Optimizer *opt)
194 {
195 int32_t ret = OptimizerStart(opt);
196 if (ret != CRYPT_SUCCESS) {
197 BSL_ERR_PUSH_ERROR(ret);
198 return ret;
199 }
200 BN_BigNum *temp = OptimizerGetBn(opt, q->size);
201 if (temp == NULL) {
202 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
203 ret = CRYPT_MEM_ALLOC_FAIL;
204 goto ERR;
205 }
206 GOTO_ERR_IF_EX(BN_AddLimb(temp, q, 1), ret); // q + 1
207 GOTO_ERR_IF_EX(BN_Rshift(temp, temp, 1), ret); // (p + 1) / 2
208 GOTO_ERR_IF(BN_MontExp(r, a, temp, mont, opt), ret); // r = a^((q+1)/2) mod p
209 ERR:
210 OptimizerEnd(opt);
211 return ret;
212 }
213
TonelliShanksCalculation(BN_BigNum * r,BN_BigNum * c,BN_BigNum * t,uint32_t s,const BN_BigNum * p,BN_Optimizer * opt)214 static int32_t TonelliShanksCalculation(BN_BigNum *r, BN_BigNum *c, BN_BigNum *t,
215 uint32_t s, const BN_BigNum *p, BN_Optimizer *opt)
216 {
217 uint32_t m = s;
218 uint32_t i, j;
219 int32_t ret = OptimizerStart(opt);
220 if (ret != CRYPT_SUCCESS) {
221 BSL_ERR_PUSH_ERROR(ret);
222 return ret;
223 }
224 BN_BigNum *b = OptimizerGetBn(opt, p->size);
225 BN_BigNum *tempT = OptimizerGetBn(opt, p->size);
226 if (b == NULL || tempT == NULL) {
227 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
228 ret = CRYPT_MEM_ALLOC_FAIL;
229 goto ERR;
230 }
231 while (!BN_IsOne(t)) {
232 // Find an i (0 < i < s) so that t^(2^i) = 1
233 i = 1;
234 // repeat modulus square
235 GOTO_ERR_IF_EX(BN_ModSqr(tempT, t, p, opt), ret);
236 while (!BN_IsOne(tempT)) {
237 i++;
238 if (i >= m) {
239 ret = CRYPT_BN_ERR_NO_SQUARE_ROOT;
240 BSL_ERR_PUSH_ERROR(ret);
241 goto ERR;
242 }
243 GOTO_ERR_IF_EX(BN_ModSqr(tempT, tempT, p, opt), ret);
244 }
245
246 // b = c^(2^(m-i-1)), if m-i-1 == 0, b = c
247 GOTO_ERR_IF_EX(BN_Copy(b, c), ret);
248 for (j = m - i - 1; j > 0; j--) {
249 GOTO_ERR_IF_EX(BN_ModSqr(b, b, p, opt), ret);
250 }
251 GOTO_ERR_IF_EX(BN_ModMul(r, r, b, p, opt), ret); // r = r * b
252 GOTO_ERR_IF_EX(BN_ModSqr(c, b, p, opt), ret); // c = b*b
253 GOTO_ERR_IF_EX(BN_ModMul(t, t, c, p, opt), ret); // t = t * b * b = t * c
254 m = i;
255 }
256 ret = CRYPT_SUCCESS;
257 ERR:
258 OptimizerEnd(opt);
259 return ret;
260 }
261
SqrtVerify(BN_BigNum * r,const BN_BigNum * a,const BN_BigNum * p,BN_Optimizer * opt)262 static int32_t SqrtVerify(
263 BN_BigNum *r, const BN_BigNum *a, const BN_BigNum *p, BN_Optimizer *opt)
264 {
265 int32_t ret = OptimizerStart(opt);
266 if (ret != CRYPT_SUCCESS) {
267 BSL_ERR_PUSH_ERROR(ret);
268 return ret;
269 }
270 BN_BigNum *square = OptimizerGetBn(opt, p->size);
271 if (square == NULL) {
272 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
273 ret = CRYPT_MEM_ALLOC_FAIL;
274 goto ERR;
275 }
276
277 GOTO_ERR_IF_EX(BN_ModSqr(square, r, p, opt), ret);
278
279 if (BN_Cmp(square, a) != 0) {
280 ret = CRYPT_BN_ERR_NO_SQUARE_ROOT;
281 BSL_ERR_PUSH_ERROR(ret);
282 goto ERR;
283 }
284 ERR:
285 OptimizerEnd(opt);
286 return ret;
287 }
288
BN_ModSqrtTempDataCheck(const BN_BigNum * pSubOne,const BN_BigNum * q,const BN_BigNum * z,const BN_BigNum * c,const BN_BigNum * t)289 static int32_t BN_ModSqrtTempDataCheck(const BN_BigNum *pSubOne, const BN_BigNum *q,
290 const BN_BigNum *z, const BN_BigNum *c, const BN_BigNum *t)
291 {
292 if (pSubOne == NULL || q == NULL || z == NULL || c == NULL || t == NULL) {
293 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
294 return CRYPT_MEM_ALLOC_FAIL;
295 }
296 return CRYPT_SUCCESS;
297 }
298
299 /* 1. Input parameters a and p. p is an odd prime number, and a is an integer (0 <= a <= p-1)
300 2. For P-1 processing, let p-1 = q * 2^s
301 3. If s=1,r = a^((p + 1)/4)
302 4. Randomly select z (1<= z <= p-1) so that the Legendre symbol of z to p equals -1. (z, p) = 1, (z/p) = a^((p-1)/2)
303 5. Setting c = z^q, r = a^((q+1)/2), t = a^q, m = s
304 6. Circulation
305 1) If t = 1, return r.
306 2) Find an i (0 < i < m) so that t^(2^i) = 1.
307 3) b = c^(2^(m-i-1)), r = r * b, t = t*b*b, c = b*b, m = i
308 7. Verification */
BN_ModSqrt(BN_BigNum * r,const BN_BigNum * a,const BN_BigNum * p,BN_Optimizer * opt)309 int32_t BN_ModSqrt(BN_BigNum *r, const BN_BigNum *a, const BN_BigNum *p, BN_Optimizer *opt)
310 {
311 if (r == NULL || a == NULL || p == NULL || opt == NULL) {
312 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
313 return CRYPT_NULL_INPUT;
314 }
315 int32_t ret = OptimizerStart(opt);
316 if (ret != CRYPT_SUCCESS) {
317 BSL_ERR_PUSH_ERROR(ret);
318 return ret;
319 }
320 uint32_t s = 0;
321 BN_Mont *mont = NULL;
322 BN_BigNum *pSubOne = OptimizerGetBn(opt, p->size);
323 BN_BigNum *q = OptimizerGetBn(opt, p->size);
324 BN_BigNum *z = OptimizerGetBn(opt, p->size);
325 BN_BigNum *c = OptimizerGetBn(opt, p->size);
326 BN_BigNum *t = OptimizerGetBn(opt, p->size);
327 GOTO_ERR_IF(BN_ModSqrtTempDataCheck(pSubOne, q, z, c, t), ret);
328
329 GOTO_ERR_IF_EX(CheckParam(a, p), ret);
330
331 if (BN_IsZero(a) || BN_IsOne(a)) {
332 GOTO_ERR_IF_EX(BN_Copy(r, a), ret);
333 goto VERIFY;
334 }
335
336 mont = BN_MontCreate(p);
337 if (mont == NULL) {
338 ret = CRYPT_MEM_ALLOC_FAIL;
339 BSL_ERR_PUSH_ERROR(ret);
340 goto ERR;
341 }
342
343 GOTO_ERR_IF_EX(BN_SubLimb(pSubOne, p, 1), ret);
344
345 s = GetExp(pSubOne); // Obtains the power s of factor 2 in p-1.
346 GOTO_ERR_IF_EX(BN_Rshift(q, pSubOne, s), ret); // p - 1 = q * 2^s
347 if (s == 1) {
348 // s==1,r = +- n^((p + 1)/4)
349 GOTO_ERR_IF_EX(CalculationRoot(r, a, p, mont, opt), ret);
350 goto VERIFY;
351 }
352 // Randomly select z(1<= z <= p-1), so that the Legendre symbol of z to p equals -1. (z, p) = 1, (z/p) = a^((p-1)/2)
353 GOTO_ERR_IF(GetLegendreZ(z, p, opt), ret);
354
355 GOTO_ERR_IF(BN_MontExp(c, z, q, mont, opt), ret); // c = z^q mod p
356 GOTO_ERR_IF(BN_MontExp(t, a, q, mont, opt), ret); // t = a^q mod p
357 GOTO_ERR_IF_EX(SetParaR(r, q, a, mont, opt), ret); // r = a^((q+1)/2) mod p
358
359 // Circulation
360 // 1) If t = 1, return r.
361 // 2) Find an i (0 < i < m) so that t^(2^i) = 1
362 // 3) b = c^(2^(m-i-1)), r = r * b, t = t*b*b, c = b*b, m = i
363 GOTO_ERR_IF_EX(TonelliShanksCalculation(r, c, t, s, p, opt), ret);
364
365 VERIFY:
366 GOTO_ERR_IF_EX(SqrtVerify(r, a, p, opt), ret);
367
368 ERR:
369 OptimizerEnd(opt);
370 BN_MontDestroy(mont);
371 return ret;
372 }
373 #endif /* HITLS_CRYPTO_ECC */
374