• 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_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