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
18 #if defined(HITLS_CRYPTO_ECC) && defined(HITLS_CRYPTO_CURVE_MONT)
19
20 #include "securec.h"
21 #include "bsl_sal.h"
22 #include "bsl_err_internal.h"
23 #include "crypt_utils.h"
24 #include "crypt_errno.h"
25 #include "ecc_local.h"
26
27 #ifdef HITLS_CRYPTO_CURVE_MONT_NIST
28
29 // Jacobian coordinate double the point
ECP_NistPointDoubleMont(const ECC_Para * para,ECC_Point * r,const ECC_Point * a)30 int32_t ECP_NistPointDoubleMont(const ECC_Para *para, ECC_Point *r, const ECC_Point *a)
31 {
32 if (a == NULL || r == NULL || para == NULL) {
33 return CRYPT_NULL_INPUT;
34 }
35 BN_Optimizer *opt = BN_OptimizerCreate();
36 if (opt == NULL) {
37 return CRYPT_MEM_ALLOC_FAIL;
38 }
39 (void)OptimizerStart(opt);
40 int32_t ret;
41 BN_BigNum *halfP = ECP_HalfPGet(para->p);
42 BN_BigNum *t1 = OptimizerGetBn(opt, a->x->room);
43 BN_BigNum *t2 = OptimizerGetBn(opt, a->x->room);
44 BN_BigNum *t3 = OptimizerGetBn(opt, a->x->room);
45 if (t1 == NULL || t2 == NULL || t3 == NULL || halfP == NULL) {
46 ret = CRYPT_MEM_ALLOC_FAIL;
47 goto ERR;
48 }
49 GOTO_ERR_IF(para->method->bnMontEnc(halfP, para->montP, opt, false), ret);
50
51 GOTO_ERR_IF(para->method->bnModNistEccSqr(t1, a->z, para->montP, opt), ret);
52
53 GOTO_ERR_IF(BN_ModSubQuick(t2, a->x, t1, para->p, opt), ret);
54 GOTO_ERR_IF(BN_ModAddQuick(t1, a->x, t1, para->p, opt), ret);
55 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t2, t1, para->montP, opt), ret);
56 GOTO_ERR_IF(BN_ModAddQuick(t3, t2, t2, para->p, opt), ret);
57 GOTO_ERR_IF(BN_ModAddQuick(t2, t3, t2, para->p, opt), ret); // t2 = 3*t2
58 GOTO_ERR_IF(BN_ModAddQuick(r->y, a->y, a->y, para->p, opt), ret);
59 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, r->y, a->z, para->montP, opt), ret);
60 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->y, r->y, para->montP, opt), ret);
61 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, r->y, a->x, para->montP, opt), ret);
62
63 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->x, t2, para->montP, opt), ret);
64 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->y, r->y, para->montP, opt), ret);
65 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, r->y, halfP, para->montP, opt), ret);
66 GOTO_ERR_IF(BN_ModAddQuick(t1, t3, t3, para->p, opt), ret);
67 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t1, para->p, opt), ret);
68
69 GOTO_ERR_IF(BN_ModSubQuick(t1, t3, r->x, para->p, opt), ret);
70 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, t1, t2, para->montP, opt), ret);
71 GOTO_ERR_IF(BN_ModSubQuick(r->y, t1, r->y, para->p, opt), ret);
72 ERR:
73 BN_OptimizerDestroy(opt);
74 BN_Destroy(halfP);
75 return ret;
76 }
77
78 // Jacobian coordinate multi-double the point: r = (2^m) * pt
ECP_NistPointMultDoubleMont(const ECC_Para * para,ECC_Point * r,const ECC_Point * a,uint32_t m)79 int32_t ECP_NistPointMultDoubleMont(const ECC_Para *para, ECC_Point *r, const ECC_Point *a, uint32_t m)
80 {
81 if (a == NULL || r == NULL || para == NULL) {
82 return CRYPT_NULL_INPUT;
83 }
84 uint32_t tm = m;
85 BN_Optimizer *opt = BN_OptimizerCreate();
86 if (opt == NULL) {
87 return CRYPT_MEM_ALLOC_FAIL;
88 }
89 int32_t ret;
90 (void)OptimizerStart(opt);
91 BN_BigNum *ta = OptimizerGetBn(opt, a->x->room);
92 BN_BigNum *tb = OptimizerGetBn(opt, a->x->room);
93 BN_BigNum *tc = OptimizerGetBn(opt, a->x->room);
94 BN_BigNum *tw = OptimizerGetBn(opt, a->x->room);
95 BN_BigNum *halfP = ECP_HalfPGet(para->p);
96 if (ta == NULL || tb == NULL || tc == NULL || tw == NULL || halfP == NULL) {
97 ret = CRYPT_MEM_ALLOC_FAIL;
98 goto ERR;
99 }
100 GOTO_ERR_IF(BN_Copy(r->x, a->x), ret);
101 GOTO_ERR_IF(BN_ModAddQuick(r->y, a->y, a->y, para->p, opt), ret);
102 GOTO_ERR_IF(BN_Copy(r->z, a->z), ret);
103
104 GOTO_ERR_IF(para->method->bnModNistEccSqr(tw, a->z, para->montP, opt), ret);
105 GOTO_ERR_IF(para->method->bnModNistEccSqr(tw, tw, para->montP, opt), ret);
106 GOTO_ERR_IF(para->method->bnMontEnc(halfP, para->montP, opt, false), ret);
107
108 while (tm > 0) {
109 // 3.1
110 // ta = 3*(x^2 - tw)
111 GOTO_ERR_IF(para->method->bnModNistEccSqr(ta, r->x, para->montP, opt), ret);
112 GOTO_ERR_IF(BN_ModSubQuick(tc, ta, tw, para->p, opt), ret);
113 GOTO_ERR_IF(BN_ModAddQuick(ta, tc, tc, para->p, opt), ret);
114 GOTO_ERR_IF(BN_ModAddQuick(ta, ta, tc, para->p, opt), ret);
115 // tb = x*(y^2)
116 GOTO_ERR_IF(para->method->bnModNistEccSqr(tc, r->y, para->montP, opt), ret);
117 GOTO_ERR_IF(para->method->bnModNistEccMul(tb, tc, r->x, para->montP, opt), ret);
118
119 // 3.2
120 // x = ta^2 - 2*tb
121 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->x, ta, para->montP, opt), ret);
122 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, tb, para->p, opt), ret);
123 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, tb, para->p, opt), ret);
124 // z = zy
125 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, r->z, r->y, para->montP, opt), ret);
126
127 // 3.3
128 // tc = y^4
129 GOTO_ERR_IF(para->method->bnModNistEccSqr(tc, r->y, para->montP, opt), ret);
130 GOTO_ERR_IF(para->method->bnModNistEccSqr(tc, tc, para->montP, opt), ret);
131 // m = m - 1, if bit > 0, tw = tw * (y^4)
132 tm--;
133 if (tm > 0) {
134 GOTO_ERR_IF(para->method->bnModNistEccMul(tw, tw, tc, para->montP, opt), ret);
135 }
136 // 3.4
137 // y = 2*ta*(tb - x) - (y^4)
138 GOTO_ERR_IF(BN_ModSubQuick(r->y, tb, r->x, para->p, opt), ret);
139 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, r->y, ta, para->montP, opt), ret);
140 GOTO_ERR_IF(BN_ModAddQuick(r->y, r->y, r->y, para->p, opt), ret);
141 GOTO_ERR_IF(BN_ModSubQuick(r->y, r->y, tc, para->p, opt), ret);
142 }
143 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, r->y, halfP, para->montP, opt), ret);
144 ERR:
145 BN_Destroy(halfP);
146 BN_OptimizerDestroy(opt); // no need to end opt.
147 return ret;
148 }
149
150 // Point addition calculation (Jacobian point a plus Jacobian point b)
151 // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo
ECP_NistPointAddMont(const ECC_Para * para,ECC_Point * r,const ECC_Point * a,const ECC_Point * b)152 int32_t ECP_NistPointAddMont(const ECC_Para *para, ECC_Point *r, const ECC_Point *a, const ECC_Point *b)
153 {
154 if (para == NULL || r == NULL || a == NULL || b == NULL) {
155 return CRYPT_NULL_INPUT;
156 }
157 if (BN_IsZero(a->z)) {
158 // If point a is an infinity point, r = b
159 return ECC_CopyPoint(r, b);
160 }
161 if (BN_IsZero(b->z)) {
162 // If point b is an infinity point, r = a
163 return ECC_CopyPoint(r, a);
164 }
165 BN_Optimizer *opt = BN_OptimizerCreate();
166 if (opt == NULL) {
167 return CRYPT_MEM_ALLOC_FAIL;
168 }
169 (void)OptimizerStart(opt);
170 BN_BigNum *t1 = OptimizerGetBn(opt, a->x->room);
171 BN_BigNum *t2 = OptimizerGetBn(opt, a->x->room);
172 BN_BigNum *t3 = OptimizerGetBn(opt, a->x->room);
173 BN_BigNum *t4 = OptimizerGetBn(opt, a->x->room);
174 BN_BigNum *t5 = OptimizerGetBn(opt, a->x->room);
175 BN_BigNum *t6 = OptimizerGetBn(opt, a->x->room);
176 if (t1 == NULL || t2 == NULL || t3 == NULL || t4 == NULL || t5 == NULL || t6 == NULL) {
177 BN_OptimizerDestroy(opt); // no need to end opt.
178 return CRYPT_MEM_ALLOC_FAIL;
179 }
180
181 int32_t ret;
182 GOTO_ERR_IF(para->method->bnModNistEccSqr(t1, b->z, para->montP, opt), ret); // Z2^2
183 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t1, b->z, para->montP, opt), ret); // Z2^3
184 GOTO_ERR_IF(para->method->bnModNistEccMul(t5, t1, a->x, para->montP, opt), ret); // U1 = X1*Z2^2
185 GOTO_ERR_IF(para->method->bnModNistEccMul(t6, t2, a->y, para->montP, opt), ret); // S1 = Y1*Z2^3
186 GOTO_ERR_IF(para->method->bnModNistEccSqr(t3, a->z, para->montP, opt), ret); // T3 = Z1^2
187
188 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, a->z, b->y, para->montP, opt), ret); // r->y = Y2*Z1
189 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, a->z, b->z, para->montP, opt), ret); // r->z = Z2*Z1
190 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, t3, r->y, para->montP, opt), ret); // S2 = Y2 * Z1^3
191 GOTO_ERR_IF(para->method->bnModNistEccMul(r->x, t3, b->x, para->montP, opt), ret); // U2 = Z1^2 * X2
192
193 GOTO_ERR_IF(BN_ModSubQuick(t1, r->x, t5, para->p, opt), ret); // H = U2 - U1
194 GOTO_ERR_IF(BN_ModSubQuick(t2, r->y, t6, para->p, opt), ret); // r = S2 - S1
195 if (BN_IsZero(t1) && BN_IsZero(t2)) {
196 GOTO_ERR_IF(para->method->pointDouble(para, r, b), ret);
197 goto ERR;
198 }
199 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, t1, r->z, para->montP, opt), ret); // r->z = H * Z2*Z1
200 GOTO_ERR_IF(para->method->bnModNistEccSqr(t3, t1, para->montP, opt), ret); // t3 = H^2
201
202 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, t1, t3, para->montP, opt), ret); // t1 = H^3
203 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, t3, t5, para->montP, opt), ret); // t3 = H^2 * U1
204 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->x, t2, para->montP, opt), ret); // r->x = r ^ 2
205
206 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t3, para->p, opt), ret); // r ^ 2 - H^2*U1
207 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t3, para->p, opt), ret); // r ^ 2 - 2*H^2 * U1
208 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t1, para->p, opt), ret); // r ^ 2 - 2*H^2*U1 - H^3
209 GOTO_ERR_IF(BN_ModSubQuick(t3, t3, r->x, para->p, opt), ret); // H^2 * U1 - X3
210 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, t2, t3, para->montP, opt), ret); // r * (H^2 * U1 - X3)
211 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, t1, t6, para->montP, opt), ret); // t1 = H^3 * S1
212 GOTO_ERR_IF(BN_ModSubQuick(r->y, t3, t1, para->p, opt), ret); // r * (H^2 * U1 - X3) - H^3 * S1
213 ERR:
214 BN_OptimizerDestroy(opt); // no need to end opt.
215 return ret;
216 }
217
218 // cal r = a + b (b->z = 1)
219 // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-madd-2004-hmv
ECP_NistPointAddAffineMont(const ECC_Para * para,ECC_Point * r,const ECC_Point * a,const ECC_Point * b)220 int32_t ECP_NistPointAddAffineMont(const ECC_Para *para, ECC_Point *r, const ECC_Point *a, const ECC_Point *b)
221 {
222 int32_t ret;
223 if (a == NULL || b == NULL || r == NULL || para == NULL) {
224 return CRYPT_NULL_INPUT;
225 }
226 if (BN_IsZero(a->z)) { // if point a is an infinity point, r = b,
227 return ECC_CopyPoint(r, b);
228 }
229 BN_Optimizer *opt = BN_OptimizerCreate();
230 if (opt == NULL) {
231 return CRYPT_MEM_ALLOC_FAIL;
232 }
233 (void)OptimizerStart(opt);
234 BN_BigNum *t1 = OptimizerGetBn(opt, a->x->room);
235 BN_BigNum *t2 = OptimizerGetBn(opt, a->x->room);
236 BN_BigNum *t3 = OptimizerGetBn(opt, a->x->room);
237 BN_BigNum *t4 = OptimizerGetBn(opt, a->x->room);
238 if (t1 == NULL || t2 == NULL || t3 == NULL || t4 == NULL) {
239 ret = CRYPT_MEM_ALLOC_FAIL;
240 goto ERR;
241 }
242
243 GOTO_ERR_IF(para->method->bnModNistEccSqr(t1, a->z, para->montP, opt), ret); // T1 = Z1^2
244 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t1, a->z, para->montP, opt), ret); // T2 = Z1^3
245 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, t1, b->x, para->montP, opt), ret); // T1 = X2*T1
246 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t2, b->y, para->montP, opt), ret); // T2 = Y2*T2
247 GOTO_ERR_IF(BN_ModSubQuick(t1, t1, a->x, para->p, opt), ret); // T1 = T1-X1
248 GOTO_ERR_IF(BN_ModSubQuick(t2, t2, a->y, para->p, opt), ret); // T2 = T2-Y1
249
250 if (BN_IsZero(t1)) {
251 if (BN_IsZero(t2)) {
252 // If two points are equal, use double for calculation.
253 GOTO_ERR_IF(para->method->pointDouble(para, r, b), ret);
254 } else {
255 // Obtain the infinite point.
256 GOTO_ERR_IF(BN_SetLimb(r->z, 0), ret);
257 }
258 goto ERR;
259 }
260 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, a->z, t1, para->montP, opt), ret); // Z3 = Z1 * T1
261
262 GOTO_ERR_IF(para->method->bnModNistEccSqr(t3, t1, para->montP, opt), ret); // T3 = T1 ^ 2
263 GOTO_ERR_IF(para->method->bnModNistEccMul(t4, t1, t3, para->montP, opt), ret); // T4 = T3 * T1
264 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, t3, a->x, para->montP, opt), ret); // T3 = T3 * X1
265 GOTO_ERR_IF(BN_ModAddQuick(t1, t3, t3, para->p, opt), ret); // T1 = 2 * T3
266 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->x, t2, para->montP, opt), ret); // X3 = T2 ^ 2
267 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t1, para->p, opt), ret); // X3 = X3 - T1
268 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t4, para->p, opt), ret); // X3 = X3 - T4
269 GOTO_ERR_IF(BN_ModSubQuick(t3, t3, r->x, para->p, opt), ret); // T3 = T3 - X3
270 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, t3, t2, para->montP, opt), ret); // T3 = T3 * T2
271 GOTO_ERR_IF(para->method->bnModNistEccMul(t4, t4, a->y, para->montP, opt), ret); // T4 = T4 * Y1
272 GOTO_ERR_IF(BN_ModSubQuick(r->y, t3, t4, para->p, opt), ret); // Y3 = T3 - T4
273 ERR:
274 BN_OptimizerDestroy(opt); // no need to end opt.
275 return ret;
276 }
277 #endif
278
279 #ifdef HITLS_CRYPTO_CURVE_MONT_PRIME
280 /*
281 prime curves point multi-double r = (2^m)*a
282 Calculation procedure:
283 1. If the point is an infinity point, return the infinity point.
284 2. Y = 2*Y, W = Z^4
285 3. If m > 0, repeat the following steps:
286 A = 3*X^2 + a*W
287 B = X*Y^2
288 X = A^2 - 2*B
289 Z = Z*Y
290 m = m - 1
291 if m > 0 then W = W*Y^4
292 Y = 2*A*(B-X)-Y^4
293 4. Return (X, Y/2, Z)
294 */
ECP_PrimePointDoubleMont(const ECC_Para * para,ECC_Point * r,const ECC_Point * a)295 int32_t ECP_PrimePointDoubleMont(const ECC_Para *para, ECC_Point *r, const ECC_Point *a)
296 {
297 if (para == NULL || r == NULL || a == NULL) {
298 return CRYPT_NULL_INPUT;
299 }
300 BN_Optimizer *opt = BN_OptimizerCreate();
301 if (opt == NULL) {
302 return CRYPT_MEM_ALLOC_FAIL;
303 }
304 int32_t ret;
305 (void)OptimizerStart(opt);
306 BN_BigNum *t1 = OptimizerGetBn(opt, a->x->room);
307 BN_BigNum *t2 = OptimizerGetBn(opt, a->x->room);
308 BN_BigNum *t3 = OptimizerGetBn(opt, a->x->room);
309 BN_BigNum *halfP = ECP_HalfPGet(para->p);
310 if (t1 == NULL || t2 == NULL || t3 == NULL || halfP == NULL) {
311 ret = CRYPT_MEM_ALLOC_FAIL;
312 goto ERR;
313 }
314 GOTO_ERR_IF(para->method->bnMontEnc(halfP, para->montP, opt, false), ret);
315 GOTO_ERR_IF(para->method->bnModNistEccSqr(t1, a->z, para->montP, opt), ret); // Z1^2
316 GOTO_ERR_IF(para->method->bnModNistEccSqr(t2, t1, para->montP, opt), ret); // Z1^4
317 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, t2, para->a, para->montP, opt), ret); // a*Z1^4
318 GOTO_ERR_IF(para->method->bnModNistEccSqr(t2, a->x, para->montP, opt), ret); // X1^2
319 GOTO_ERR_IF(BN_ModAddQuick(t3, t2, t2, para->p, opt), ret); // 2*X1^2
320 GOTO_ERR_IF(BN_ModAddQuick(t2, t3, t2, para->p, opt), ret); // 3*X1^2
321 GOTO_ERR_IF(BN_ModAddQuick(t2, t1, t2, para->p, opt), ret); // t2 = 3*X1^2 + a*Z1^4
322 GOTO_ERR_IF(BN_ModAddQuick(r->y, a->y, a->y, para->p, opt), ret);
323 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, r->y, a->z, para->montP, opt), ret);
324 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->y, r->y, para->montP, opt), ret);
325 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, r->y, a->x, para->montP, opt), ret);
326
327 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->y, r->y, para->montP, opt), ret);
328 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, r->y, halfP, para->montP, opt), ret);
329 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->x, t2, para->montP, opt), ret);
330 GOTO_ERR_IF(BN_ModAddQuick(t1, t3, t3, para->p, opt), ret);
331 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t1, para->p, opt), ret);
332
333 GOTO_ERR_IF(BN_ModSubQuick(t1, t3, r->x, para->p, opt), ret);
334 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, t1, t2, para->montP, opt), ret);
335 GOTO_ERR_IF(BN_ModSubQuick(r->y, t1, r->y, para->p, opt), ret);
336 ERR:
337 BN_Destroy(halfP);
338 BN_OptimizerDestroy(opt); // no need to end opt.
339 return ret;
340 }
341
342 // Point addition calculation (Jacobian point a plus Jacobian point b)
343 // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl
ECP_PrimePointAddMont(const ECC_Para * para,ECC_Point * r,const ECC_Point * a,const ECC_Point * b)344 int32_t ECP_PrimePointAddMont(const ECC_Para *para, ECC_Point *r, const ECC_Point *a,
345 const ECC_Point *b)
346 {
347 bool flag = (para == NULL) || (r == NULL) || (a == NULL) || (b == NULL);
348 if (flag) {
349 return CRYPT_NULL_INPUT;
350 }
351 if (BN_IsZero(a->z)) {
352 return ECC_CopyPoint(r, b);
353 }
354 if (BN_IsZero(b->z)) {
355 return ECC_CopyPoint(r, a);
356 }
357 BN_Optimizer *opt = BN_OptimizerCreate();
358 if (opt == NULL) {
359 return CRYPT_MEM_ALLOC_FAIL;
360 }
361 (void)OptimizerStart(opt);
362 BN_BigNum *t0 = OptimizerGetBn(opt, para->p->size);
363 BN_BigNum *t1 = OptimizerGetBn(opt, para->p->size);
364 BN_BigNum *t2 = OptimizerGetBn(opt, para->p->size);
365 BN_BigNum *t3 = OptimizerGetBn(opt, para->p->size);
366 BN_BigNum *t4 = OptimizerGetBn(opt, para->p->size);
367 BN_BigNum *t5 = OptimizerGetBn(opt, para->p->size);
368 flag = (t0 == NULL) || (t1 == NULL) || (t2 == NULL) || (t3 == NULL) || (t4 == NULL) || (t5 == NULL);
369 if (flag) {
370 BN_OptimizerDestroy(opt); // no need to end opt.
371 return CRYPT_MEM_ALLOC_FAIL;
372 }
373
374 int32_t ret;
375 GOTO_ERR_IF(para->method->bnModNistEccSqr(t0, a->z, para->montP, opt), ret); // z1z1 = z1^2
376 GOTO_ERR_IF(para->method->bnModNistEccSqr(t5, b->z, para->montP, opt), ret); // z2z2 = z2^2
377 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, a->x, t5, para->montP, opt), ret); // u1 = x1*z2z2
378 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, b->x, t0, para->montP, opt), ret); // u2 = x2*z1z1
379
380 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, b->z, t5, para->montP, opt), ret); // z2 * z2z2
381 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, a->y, t2, para->montP, opt), ret); // s1 = y1 * z2 * z2z2
382
383 GOTO_ERR_IF(para->method->bnModNistEccMul(t4, a->z, t0, para->montP, opt), ret); // z1 * z1z1
384 GOTO_ERR_IF(para->method->bnModNistEccMul(t4, b->y, t4, para->montP, opt), ret); // s2 = y2 * z1 * z1z1
385
386 GOTO_ERR_IF(BN_ModAddQuick(t0, t0, t5, para->p, opt), ret); // z1z1 + z2z2
387 GOTO_ERR_IF(BN_ModSubQuick(t3, t3, t1, para->p, opt), ret); // h = u2 - u1
388 GOTO_ERR_IF(BN_ModSubQuick(t4, t4, t2, para->p, opt), ret); // s2 - s1
389 if (BN_IsZero(t3) && BN_IsZero(t4)) {
390 GOTO_ERR_IF(para->method->pointDouble(para, r, b), ret);
391 goto ERR;
392 }
393 GOTO_ERR_IF(BN_ModAddQuick(t5, t3, t3, para->p, opt), ret); // 2h
394 GOTO_ERR_IF(BN_ModAddQuick(r->y, t4, t4, para->p, opt), ret); // r = 2(s2 - s1)
395 GOTO_ERR_IF(para->method->bnModNistEccSqr(t5, t5, para->montP, opt), ret); // i = (2h)^2
396 GOTO_ERR_IF(para->method->bnModNistEccMul(t4, t3, t5, para->montP, opt), ret); // j = h*i
397
398 GOTO_ERR_IF(para->method->bnModNistEccMul(t5, t1, t5, para->montP, opt), ret); // v = u1 * i
399 GOTO_ERR_IF(BN_ModAddQuick(t1, t5, t5, para->p, opt), ret); // 2 * v
400 GOTO_ERR_IF(BN_ModAddQuick(t1, t1, t4, para->p, opt), ret); // 2 * v + j
401 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->x, r->y, para->montP, opt), ret); // rr ^ 2
402 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t1, para->p, opt), ret); // r->x = rr ^ 2 - j - z * v
403
404 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t2, t4, para->montP, opt), ret); // s1 * j
405 GOTO_ERR_IF(BN_ModAddQuick(t2, t2, t2, para->p, opt), ret); // 2 * s1 * j
406 GOTO_ERR_IF(BN_ModSubQuick(t5, t5, r->x, para->p, opt), ret); // v = v - x3
407 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, r->y, t5, para->montP, opt), ret); // r * (v - x3)
408 GOTO_ERR_IF(BN_ModSubQuick(r->y, r->y, t2, para->p, opt), ret); // r * (v - x3) - 2 * s1 * j
409
410 GOTO_ERR_IF(BN_ModAddQuick(r->z, a->z, b->z, para->p, opt), ret); // z1 + z2
411 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->z, r->z, para->montP, opt), ret); // (z1 + z2) ^ 2
412 GOTO_ERR_IF(BN_ModSubQuick(r->z, r->z, t0, para->p, opt), ret); // (z1 + z2) ^ 2 - z1z1 - z2z2
413 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, r->z, t3, para->montP, opt), ret); // r->z * h
414
415 ERR:
416 BN_OptimizerDestroy(opt); // no need to end opt.
417 return ret;
418 }
419
420 // Jacobian coordinate multi-double the point: r = (2^m) * pt
ECP_PrimePointMultDoubleMont(const ECC_Para * para,ECC_Point * r,const ECC_Point * a,uint32_t m)421 int32_t ECP_PrimePointMultDoubleMont(const ECC_Para *para, ECC_Point *r, const ECC_Point *a, uint32_t m)
422 {
423 if (para == NULL || r == NULL || a == NULL) {
424 return CRYPT_NULL_INPUT;
425 }
426 uint32_t tm = m;
427 int32_t ret;
428 BN_Optimizer *opt = BN_OptimizerCreate();
429 if (opt == NULL) {
430 return CRYPT_MEM_ALLOC_FAIL;
431 }
432 (void)OptimizerStart(opt);
433 BN_BigNum *t1 = OptimizerGetBn(opt, a->x->room);
434 BN_BigNum *t2 = OptimizerGetBn(opt, a->x->room);
435 BN_BigNum *ta = OptimizerGetBn(opt, a->x->room);
436 BN_BigNum *tb = OptimizerGetBn(opt, a->x->room);
437 BN_BigNum *tw = OptimizerGetBn(opt, a->x->room);
438 BN_BigNum *halfP = ECP_HalfPGet(para->p);
439 if (t1 == NULL || t2 == NULL || ta == NULL || tb == NULL || tw == NULL || halfP == NULL) {
440 ret = CRYPT_MEM_ALLOC_FAIL;
441 goto ERR;
442 }
443
444 GOTO_ERR_IF(BN_Copy(r->x, a->x), ret);
445 GOTO_ERR_IF(BN_ModAddQuick(r->y, a->y, a->y, para->p, opt), ret);
446 GOTO_ERR_IF(BN_Copy(r->z, a->z), ret);
447 GOTO_ERR_IF(para->method->bnMontEnc(halfP, para->montP, opt, false), ret);
448
449 GOTO_ERR_IF(para->method->bnModNistEccSqr(tw, a->z, para->montP, opt), ret);
450 GOTO_ERR_IF(para->method->bnModNistEccSqr(tw, tw, para->montP, opt), ret); // Z^4
451
452 while (tm > 0) {
453 // A = 3*X^2 + a*W
454 GOTO_ERR_IF(para->method->bnModNistEccSqr(t1, r->x, para->montP, opt), ret); // X^2
455 GOTO_ERR_IF(BN_ModAddQuick(ta, t1, t1, para->p, opt), ret);
456 GOTO_ERR_IF(BN_ModAddQuick(ta, ta, t1, para->p, opt), ret); // 3*X^2
457 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, para->a, tw, para->montP, opt), ret); // a*W
458 GOTO_ERR_IF(BN_ModAddQuick(ta, ta, t2, para->p, opt), ret); // A = 3*X^2 + a*W
459
460 GOTO_ERR_IF(para->method->bnModNistEccSqr(t1, r->y, para->montP, opt), ret); // t1 = Y^2
461 GOTO_ERR_IF(para->method->bnModNistEccMul(tb, t1, r->x, para->montP, opt), ret); // B = X*Y^2
462
463 GOTO_ERR_IF(para->method->bnModNistEccSqr(t1, t1, para->montP, opt), ret); // t1 = Y^4
464
465 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->x, ta, para->montP, opt), ret); // A^2
466 GOTO_ERR_IF(BN_ModAddQuick(t2, tb, tb, para->p, opt), ret); // 2*B
467 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t2, para->p, opt), ret); // X = A^2 - 2*B
468
469 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, r->z, r->y, para->montP, opt), ret);
470
471 // m = m - 1
472 tm--;
473 if (tm > 0) {
474 GOTO_ERR_IF(para->method->bnModNistEccMul(tw, tw, t1, para->montP, opt), ret);
475 }
476 GOTO_ERR_IF(BN_ModSubQuick(r->y, tb, r->x, para->p, opt), ret);
477 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, r->y, ta, para->montP, opt), ret);
478 GOTO_ERR_IF(BN_ModAddQuick(r->y, r->y, r->y, para->p, opt), ret);
479 GOTO_ERR_IF(BN_ModSubQuick(r->y, r->y, t1, para->p, opt), ret);
480 }
481 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, r->y, halfP, para->montP, opt), ret);
482 ERR:
483 BN_Destroy(halfP);
484 BN_OptimizerDestroy(opt);
485 return ret;
486 }
487
488 /*
489 prime curve point addition r = a + b, , depending on the method->pointDouble point operation.
490 Calculation formula:
491 X3 = (Y2*Z1^3-Y1)^2 - (X2*Z1^2-X1)^2 * (X1+X2*Z1^2)
492 Y3 = (Y2*Z1^3-Y1) * (X1*(X2*Z1^2-X1)^2-X3) - Y1 * (X2*Z1^2-X1)^3
493 Z3 = (X2*Z1^2-X1) * Z1
494 */
ECP_PrimePointAddAffineMont(const ECC_Para * para,ECC_Point * r,const ECC_Point * a,const ECC_Point * b)495 int32_t ECP_PrimePointAddAffineMont(const ECC_Para *para, ECC_Point *r, const ECC_Point *a, const ECC_Point *b)
496 {
497 if (para == NULL || r == NULL || a == NULL || b == NULL) {
498 return CRYPT_NULL_INPUT;
499 }
500 if (BN_IsZero(a->z)) { // if point a is an infinity point, r = b,
501 return ECC_CopyPoint(r, b);
502 }
503 BN_Optimizer *opt = BN_OptimizerCreate();
504 if (opt == NULL) {
505 return CRYPT_MEM_ALLOC_FAIL;
506 }
507 (void)OptimizerStart(opt);
508 BN_BigNum *t1 = OptimizerGetBn(opt, a->x->room);
509 BN_BigNum *t2 = OptimizerGetBn(opt, a->x->room);
510 BN_BigNum *t3 = OptimizerGetBn(opt, a->x->room);
511 BN_BigNum *t4 = OptimizerGetBn(opt, a->x->room);
512 if (t1 == NULL || t2 == NULL || t3 == NULL || t4 == NULL) {
513 BN_OptimizerDestroy(opt);
514 return CRYPT_MEM_ALLOC_FAIL;
515 }
516 int32_t ret;
517 GOTO_ERR_IF(para->method->bnModNistEccSqr(t1, a->z, para->montP, opt), ret); // Z1^2
518 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t1, a->z, para->montP, opt), ret); // Z1^3
519 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, t1, b->x, para->montP, opt), ret); // X2*Z1^2
520 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t2, b->y, para->montP, opt), ret); // Y2*Z1^3
521 GOTO_ERR_IF(BN_ModSubQuick(t1, t1, a->x, para->p, opt), ret); // X2*Z1^2 - X1
522 GOTO_ERR_IF(BN_ModSubQuick(t2, t2, a->y, para->p, opt), ret); // Y2*Z1^3 - Y1
523
524 if (BN_IsZero(t1)) {
525 if (BN_IsZero(t2)) {
526 // If two points are equal, use double for calculation.
527 GOTO_ERR_IF(para->method->pointDouble(para, r, b), ret);
528 } else {
529 // Obtain the infinite point.
530 GOTO_ERR_IF(BN_SetLimb(r->z, 0), ret);
531 }
532 goto ERR;
533 }
534 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, a->z, t1, para->montP, opt), ret); // Z3 = (X2*Z1^2 - X1)*Z1
535
536 GOTO_ERR_IF(para->method->bnModNistEccSqr(t3, t1, para->montP, opt), ret); // (X2*Z1^2 - X1)^2
537 GOTO_ERR_IF(para->method->bnModNistEccMul(t4, t1, t3, para->montP, opt), ret); // (X2*Z1^2 - X1)^3
538 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, t3, a->x, para->montP, opt), ret); // X1*(X2*Z1^2 - X1)^2
539 GOTO_ERR_IF(BN_ModAddQuick(t1, t3, t3, para->p, opt), ret); // 2*X1*(X2*Z1^2 - X1)^2
540 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->x, t2, para->montP, opt), ret); // (Y2*Z1^3 - Y1)^2
541 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t1, para->p, opt), ret); // (Y2*Z1^3-Y1)^2 - 2*X1*(X2*Z1^2-X1)^2
542 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t4, para->p, opt), ret); // X3
543 GOTO_ERR_IF(BN_ModSubQuick(t3, t3, r->x, para->p, opt), ret); // X1*(X2*Z1^2-X1)^2 - X3
544 // (Y2*Z1^3-Y1)*(X1*(X2*Z1^2-X1)^2-X3)
545 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, t3, t2, para->montP, opt), ret);
546 GOTO_ERR_IF(para->method->bnModNistEccMul(t4, t4, a->y, para->montP, opt), ret); // Y1*(X2*Z1^2 - X1)^3
547 GOTO_ERR_IF(BN_ModSubQuick(r->y, t3, t4, para->p, opt), ret); // Y3
548 ERR:
549 BN_OptimizerDestroy(opt);
550 return ret;
551 }
552 #endif
553
ECP_Point2AffineMont(const ECC_Para * para,ECC_Point * r,const ECC_Point * pt)554 int32_t ECP_Point2AffineMont(const ECC_Para *para, ECC_Point *r, const ECC_Point *pt)
555 {
556 if (pt == NULL || r == NULL || para == NULL) {
557 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
558 return CRYPT_NULL_INPUT;
559 }
560 if (para->id != r->id || para->id != pt->id) {
561 BSL_ERR_PUSH_ERROR(CRYPT_ECC_POINT_ERR_CURVE_ID);
562 return CRYPT_ECC_POINT_ERR_CURVE_ID;
563 }
564 if (BN_IsZero(pt->z)) {
565 BSL_ERR_PUSH_ERROR(CRYPT_ECC_POINT_AT_INFINITY);
566 return CRYPT_ECC_POINT_AT_INFINITY;
567 }
568 if (BN_IsOne(pt->z)) {
569 return ECC_CopyPoint(r, pt);
570 }
571 uint32_t bits = BN_Bits(para->p);
572 BN_BigNum *inv = BN_Create(bits);
573 BN_BigNum *zz = BN_Create(bits);
574 BN_Optimizer *opt = BN_OptimizerCreate();
575 ECC_Point *base = ECC_DupPoint(pt);
576 int32_t ret;
577 if (inv == NULL || zz == NULL || opt == NULL || base == NULL) {
578 ret = CRYPT_MEM_ALLOC_FAIL;
579 BSL_ERR_PUSH_ERROR(ret);
580 goto ERR;
581 }
582 GOTO_ERR_IF(para->method->modInv(inv, base->z, para->p, opt), ret);
583 GOTO_ERR_IF(para->method->bnMontEnc(base->x, para->montP, opt, false), ret);
584 GOTO_ERR_IF(para->method->bnMontEnc(base->y, para->montP, opt, false), ret);
585 GOTO_ERR_IF(para->method->bnMontEnc(inv, para->montP, opt, false), ret);
586 GOTO_ERR_IF(para->method->bnModNistEccSqr(zz, inv, para->montP, opt), ret);
587 GOTO_ERR_IF(para->method->bnModNistEccMul(r->x, base->x, zz, para->montP, opt), ret);
588 GOTO_ERR_IF(para->method->bnModNistEccMul(zz, zz, inv, para->montP, opt), ret);
589 GOTO_ERR_IF(para->method->bnModNistEccMul(r->y, base->y, zz, para->montP, opt), ret);
590 GOTO_ERR_IF(BN_SetLimb(r->z, 1), ret);
591 para->method->bnMontDec(r->x, para->montP);
592 para->method->bnMontDec(r->y, para->montP);
593 ERR:
594 BN_Destroy(zz);
595 BN_Destroy(inv);
596 ECC_FreePoint(base);
597 BN_OptimizerDestroy(opt);
598 return ret;
599 }
600
601 /*
602 * XZ coordinates for short Weierstrass curves
603 * https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#ladder-mladd-2002-bj-3
604 * MontLadderDoubleAndAdd return:
605 * r2 = 2 * r2
606 * r3 = r2 + r3
607 */
MontLadderDoubleAndAdd(ECC_Para * para,ECC_Point * r2,ECC_Point * r3,ECC_Point * p,BN_Optimizer * opt)608 static int32_t MontLadderDoubleAndAdd(ECC_Para *para, ECC_Point *r2, ECC_Point *r3, ECC_Point *p, BN_Optimizer *opt)
609 {
610 int32_t ret;
611 (void)OptimizerStart(opt);
612 BN_BigNum *t0 = OptimizerGetBn(opt, p->x->room);
613 BN_BigNum *t1 = OptimizerGetBn(opt, p->x->room);
614 BN_BigNum *t2 = OptimizerGetBn(opt, p->x->room);
615 BN_BigNum *t3 = OptimizerGetBn(opt, p->x->room);
616 BN_BigNum *t4 = OptimizerGetBn(opt, p->x->room);
617 BN_BigNum *t5 = OptimizerGetBn(opt, p->x->room);
618 if (t0 == NULL || t1 == NULL || t2 == NULL || t3 == NULL || t4 == NULL || t5 == NULL) {
619 OptimizerEnd(opt);
620 return CRYPT_MEM_ALLOC_FAIL; // 不需要释放其他大数,统一交给大数优化器管理
621 }
622 GOTO_ERR_IF(para->method->bnModNistEccSqr(r2->y, r2->x, para->montP, opt), ret); // x2 ^ 2
623 GOTO_ERR_IF(para->method->bnModNistEccSqr(r3->y, r2->z, para->montP, opt), ret); // z2 ^ 2
624 GOTO_ERR_IF(para->method->bnModNistEccMul(t0, r2->x, r2->z, para->montP, opt), ret); // X2 * Z2
625 GOTO_ERR_IF(BN_ModAddQuick(t0, t0, t0, para->p, opt), ret); // 2 * X2 * Z2
626 GOTO_ERR_IF(BN_ModAddQuick(t0, t0, t0, para->p, opt), ret); // 4 * X2 * Z2
627 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, para->a, r3->y, para->montP, opt), ret); // aZZ = a * ZZ
628
629 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, r2->x, r3->x, para->montP, opt), ret); // X2 * X3
630 GOTO_ERR_IF(para->method->bnModNistEccMul(t3, r2->z, r3->z, para->montP, opt), ret); // Z2 * Z3
631 GOTO_ERR_IF(para->method->bnModNistEccMul(t4, r2->x, r3->z, para->montP, opt), ret); // X2 * Z3
632 GOTO_ERR_IF(para->method->bnModNistEccMul(t5, r2->z, r3->x, para->montP, opt), ret); // Z2 * X3
633
634 GOTO_ERR_IF(BN_ModSubQuick(r2->x, r2->y, t1, para->p, opt), ret); // XX - aZZ
635 GOTO_ERR_IF(BN_ModAddQuick(r2->z, r2->y, t1, para->p, opt), ret); // XX + aZZ
636 GOTO_ERR_IF(para->method->bnModNistEccMul(r2->z, t0, r2->z, para->montP, opt), ret); // E * (XX + aZZ)
637
638 GOTO_ERR_IF(para->method->bnModNistEccMul(t0, t0, r3->y, para->montP, opt), ret); // E * ZZ
639 GOTO_ERR_IF(para->method->bnModNistEccMul(t0, t0, para->b, para->montP, opt), ret); // b * E * ZZ
640 GOTO_ERR_IF(BN_ModAddQuick(t0, t0, t0, para->p, opt), ret); // 2b * E * ZZ
641
642 GOTO_ERR_IF(para->method->bnModNistEccSqr(r2->x, r2->x, para->montP, opt), ret); // (XX - aZZ) ^ 2
643 GOTO_ERR_IF(BN_ModSubQuick(r2->x, r2->x, t0, para->p, opt), ret); // (XX - aZZ) ^ 2 - 2b * E * ZZ
644
645 GOTO_ERR_IF(para->method->bnModNistEccSqr(r3->y, r3->y, para->montP, opt), ret); // ZZ ^ 2
646 GOTO_ERR_IF(para->method->bnModNistEccMul(r3->y, r3->y, para->b, para->montP, opt), ret); // b * ZZ^2
647 GOTO_ERR_IF(BN_ModAddQuick(r3->y, r3->y, r3->y, para->p, opt), ret); // 2 * b * ZZ^2
648 GOTO_ERR_IF(BN_ModAddQuick(r3->y, r3->y, r3->y, para->p, opt), ret); // 4 * b * ZZ^2
649 GOTO_ERR_IF(BN_ModAddQuick(r2->z, r2->z, r3->y, para->p, opt), ret); // E * (XX + aZZ) + 4 * b * ZZ^2
650
651 GOTO_ERR_IF(para->method->bnModNistEccMul(r3->x, para->a, t3, para->montP, opt), ret); // a * B
652 GOTO_ERR_IF(BN_ModSubQuick(r3->x, t2, r3->x, para->p, opt), ret); // A - a * B
653 GOTO_ERR_IF(para->method->bnModNistEccSqr(r3->x, r3->x, para->montP, opt), ret); // (A - a * B) ^ 2
654 GOTO_ERR_IF(BN_ModAddQuick(t2, t4, t5, para->p, opt), ret); // C + D
655 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t2, t3, para->montP, opt), ret); // B * (C + D)
656 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t2, para->b, para->montP, opt), ret); // b * B * (C + D)
657 GOTO_ERR_IF(BN_ModAddQuick(t2, t2, t2, para->p, opt), ret); // 2 * b * B * (C + D)
658 GOTO_ERR_IF(BN_ModAddQuick(t2, t2, t2, para->p, opt), ret); // 4 * b * B * (C + D)
659 GOTO_ERR_IF(BN_ModSubQuick(r3->x, r3->x, t2, para->p, opt), ret); // (A - a * B) ^ 2 - 4 * b * B * (C + D)
660
661 GOTO_ERR_IF(BN_ModSubQuick(t4, t4, t5, para->p, opt), ret); // C - D
662 GOTO_ERR_IF(para->method->bnModNistEccSqr(t4, t4, para->montP, opt), ret); // (C - D) ^ 2
663 GOTO_ERR_IF(para->method->bnModNistEccMul(r3->z, p->x, t4, para->montP, opt), ret); // px * (C + D) ^ 2
664
665 ERR:
666 OptimizerEnd(opt);
667 return ret;
668 }
669
670 /*
671 * ref <Weierstraß Elliptic Curves and side-Channel Attacks> formula 8.
672 * XZ coordinates [database entry] represent x y as X Z satisfying the following equations:
673 * x = X / Z
674 * MontLadderRecoverYAndToMont return:
675 * r1->x = r1->x / r1->z
676 * r1->y = (2b + (a + x*x1)*(x + x1) - x2(x - x1)^2) / (2*y)
677 * = (2b*z2*(z1^2) + z2(a*z1 + x*x1)(x*z1 + x1) - x2(x*z1 - x1) ^ 2) / (2y*z2*(z1^2))
678 */
MontLadderRecoverYAndToMont(ECC_Para * para,ECC_Point * r1,ECC_Point * r2,ECC_Point * p,BN_Optimizer * opt)679 static int32_t MontLadderRecoverYAndToMont(ECC_Para *para, ECC_Point *r1, ECC_Point *r2, ECC_Point *p,
680 BN_Optimizer *opt)
681 {
682 int32_t ret;
683 if (BN_IsZero(r1->z)) {
684 para->method->bnMontDec(r1->x, para->montP);
685 para->method->bnMontDec(r1->y, para->montP);
686 return CRYPT_SUCCESS;
687 }
688 if (BN_IsZero(r2->z)) {
689 GOTO_ERR_IF(ECC_CopyPoint(r1, p), ret); // r2 = r1 + p = 0 -> r1 = -p
690 GOTO_ERR_IF(BN_Sub(r1->y, para->p, r1->y), ret);
691 para->method->bnMontDec(r1->x, para->montP);
692 para->method->bnMontDec(r1->y, para->montP);
693 GOTO_ERR_IF(BN_SetLimb(r1->z, 1), ret);
694 return CRYPT_SUCCESS;
695 }
696 (void)OptimizerStart(opt);
697 BN_BigNum *t0 = OptimizerGetBn(opt, p->x->room);
698 BN_BigNum *t1 = OptimizerGetBn(opt, p->x->room);
699 BN_BigNum *t2 = OptimizerGetBn(opt, p->x->room);
700 BN_BigNum *t3 = OptimizerGetBn(opt, p->x->room);
701 if (t0 == NULL || t1 == NULL || t2 == NULL || t3 == NULL) {
702 OptimizerEnd(opt);
703 return CRYPT_MEM_ALLOC_FAIL; // Other bn do not need to be released. They are managed by the opt.
704 }
705 GOTO_ERR_IF(para->method->bnModNistEccSqr(t0, r1->z, para->montP, opt), ret); // t0 = z1 ^ 2
706 GOTO_ERR_IF(para->method->bnModNistEccMul(t0, t0, r2->z, para->montP, opt), ret); // t0 = z2 * z1^2
707
708 GOTO_ERR_IF(BN_ModAddQuick(t1, para->b, para->b, para->p, opt), ret); // 2b
709 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, t0, t1, para->montP, opt), ret); // t1 = 2b*z2*z1^2
710
711 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, para->a, r1->z, para->montP, opt), ret); // t2 = a*z1
712 GOTO_ERR_IF(para->method->bnModNistEccMul(r2->y, p->x, r1->x, para->montP, opt), ret); // r2->y = x*x1
713 GOTO_ERR_IF(para->method->bnModNistEccMul(r1->y, p->x, r1->z, para->montP, opt), ret); // t4 = x*z1
714 GOTO_ERR_IF(BN_ModAddQuick(t2, t2, r2->y, para->p, opt), ret); // a*z1 + x*x1
715 GOTO_ERR_IF(BN_ModAddQuick(r1->y, r1->y, r1->x, para->p, opt), ret); // x*z1 + x1
716 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t2, r2->z, para->montP, opt), ret); // (a*z1 + x*x1) * z2
717 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t2, r1->y, para->montP, opt), ret); // t2=(a*z1+x*x1)*z2*(x*z1+x1)
718
719 GOTO_ERR_IF(para->method->bnModNistEccMul(r2->y, p->x, r1->z, para->montP, opt), ret); // x * z1
720 GOTO_ERR_IF(BN_ModSubQuick(r2->y, r2->y, r1->x, para->p, opt), ret); // x * z1 - x1
721 GOTO_ERR_IF(para->method->bnModNistEccSqr(r2->y, r2->y, para->montP, opt), ret); // (x * z1 - x1) ^ 2
722 GOTO_ERR_IF(para->method->bnModNistEccMul(r2->y, r2->y, r2->x, para->montP, opt), ret); // x2 * (x * z1 - x1) ^ 2
723 GOTO_ERR_IF(BN_ModAddQuick(t1, t1, t2, para->p, opt), ret); // 2b*z2*z1^2 + t2
724 GOTO_ERR_IF(BN_ModSubQuick(t1, t1, r2->y, para->p, opt), ret); // 2b*z2*z1^2 + t2 - r2->y
725 GOTO_ERR_IF(para->method->bnModNistEccMul(t1, t1, r1->z, para->montP, opt), ret); // (2b*z2*z1^2 - t2 - r2->y) * z1
726
727 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t0, p->y, para->montP, opt), ret); // t2 = z2 * z1^2 * y
728 GOTO_ERR_IF(BN_ModAddQuick(t2, t2, t2, para->p, opt), ret); // 2 * y * z2 * z1^2
729
730 GOTO_ERR_IF(para->method->bnModNistEccMul(t0, r1->x, t2, para->montP, opt), ret); // x * (2 * y * z2 * z1^2)
731 GOTO_ERR_IF(para->method->bnModNistEccMul(t2, t2, r1->z, para->montP, opt), ret); // (2 * y * z2 * z1^2) * z1
732
733 para->method->bnMontDec(t2, para->montP);
734 GOTO_ERR_IF(para->method->modInv(t2, t2, para->p, opt), ret); // (2 * y * z2 * z1^2) * -1
735 GOTO_ERR_IF(para->method->bnMontEnc(t2, para->montP, opt, false), ret);
736
737 GOTO_ERR_IF(para->method->bnModNistEccMul(r1->x, t0, t2, para->montP, opt), ret); // x1 / z1
738 // (2b*z2*z1^2 - t2 - t3) * ((2 * y * z2 * z1^2)
739 GOTO_ERR_IF(para->method->bnModNistEccMul(r1->y, t1, t2, para->montP, opt), ret);
740 para->method->bnMontDec(r1->x, para->montP);
741 para->method->bnMontDec(r1->y, para->montP);
742 GOTO_ERR_IF(BN_SetLimb(r1->z, 1), ret); // x * (2 * y * z2 * z1^2)
743 ERR:
744 OptimizerEnd(opt);
745 return ret;
746 }
747
748 /*
749 * XZ coordinates for short Weierstrass curves
750 * 2M + 5S + 1*b2 + 1*a + 1*b4
751 * https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#doubling-dbl-2002-bj-3
752 * p->z = 1, the above formula can reduce the calculation amount.
753 * MontLadderDouble return:
754 * r = 2 * p
755 */
MontLadderDouble(const ECC_Para * para,ECC_Point * r,ECC_Point * p,BN_Optimizer * opt)756 static int32_t MontLadderDouble(const ECC_Para *para, ECC_Point *r, ECC_Point *p, BN_Optimizer *opt)
757 {
758 int32_t ret;
759 (void)OptimizerStart(opt);
760 BN_BigNum *t0 = OptimizerGetBn(opt, p->x->room);
761 if (t0 == NULL) {
762 return CRYPT_MEM_ALLOC_FAIL;
763 }
764 GOTO_ERR_IF(para->method->bnModNistEccSqr(t0, p->x, para->montP, opt), ret); // x^2
765 GOTO_ERR_IF(BN_ModAddQuick(r->y, p->x, p->x, para->p, opt), ret); // 2 * x
766 GOTO_ERR_IF(BN_ModAddQuick(r->y, r->y, r->y, para->p, opt), ret); // ry = 4 * x * z = 4 * x (z = 1)
767
768 GOTO_ERR_IF(BN_ModSubQuick(r->x, t0, para->a, para->p, opt), ret); // t0 - a
769 GOTO_ERR_IF(BN_ModAddQuick(r->z, t0, para->a, para->p, opt), ret); // t0 + a
770
771 GOTO_ERR_IF(para->method->bnModNistEccSqr(r->x, r->x, para->montP, opt), ret); // (t0 - a)^2
772 GOTO_ERR_IF(para->method->bnModNistEccMul(t0, para->b, r->y, para->montP, opt), ret); // b * ry
773 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t0, para->p, opt), ret); // (t0 - a)^2 - b * ry
774 GOTO_ERR_IF(BN_ModSubQuick(r->x, r->x, t0, para->p, opt), ret); // (t0 - a)^2 - 2 * b * ry
775
776 GOTO_ERR_IF(para->method->bnModNistEccMul(r->z, r->y, r->z, para->montP, opt), ret); // ry * (t0 + a)
777 GOTO_ERR_IF(BN_ModAddQuick(t0, para->b, para->b, para->p, opt), ret); // 2 * b
778 GOTO_ERR_IF(BN_ModAddQuick(t0, t0, t0, para->p, opt), ret); // 4 * b
779 GOTO_ERR_IF(BN_ModAddQuick(r->z, r->z, t0, para->p, opt), ret); // ry * (t0 + a) + 4 * b
780
781 ERR:
782 OptimizerEnd(opt);
783 return ret;
784 }
785
ECP_PointSwapWithMask(ECC_Point * a,ECC_Point * b,BN_UINT mask)786 static int32_t ECP_PointSwapWithMask(ECC_Point *a, ECC_Point *b, BN_UINT mask)
787 {
788 int32_t ret;
789 GOTO_ERR_IF(BN_SwapWithMask(a->x, b->x, mask), ret);
790 GOTO_ERR_IF(BN_SwapWithMask(a->y, b->y, mask), ret);
791 GOTO_ERR_IF(BN_SwapWithMask(a->z, b->z, mask), ret);
792 ERR:
793 return ret;
794 }
795
796 /*
797 * ref <Weierstraß Elliptic Curves and side-Channel Attacks>
798 * Montgomery ladder to achieve k * Pt
799 */
ECP_PointMulMont(ECC_Para * para,ECC_Point * r,const BN_BigNum * k,const ECC_Point * pt)800 int32_t ECP_PointMulMont(ECC_Para *para, ECC_Point *r, const BN_BigNum *k, const ECC_Point *pt)
801 {
802 if (para == NULL || r == NULL || k == NULL) {
803 return CRYPT_NULL_INPUT;
804 }
805 if (((pt != NULL) && (para->id != pt->id)) || (para->id != r->id)) {
806 return CRYPT_ECC_POINT_ERR_CURVE_ID;
807 }
808 if (pt != NULL && BN_IsZero(pt->z)) {
809 return CRYPT_ECC_POINT_AT_INFINITY;
810 }
811 if (BN_IsZero(k)) {
812 BN_Zeroize(r->z);
813 return CRYPT_SUCCESS;
814 }
815 if (BN_Cmp(k, para->n) == 0 && pt != NULL) {
816 return ECP_PointMulFast(para, r, para->n, pt);
817 }
818 int32_t ret;
819 BN_UINT mask1 = 0;
820 BN_UINT mask2 = 0;
821 BN_UINT tmp;
822 uint32_t bits;
823 ECC_Point *base = (pt != NULL) ? ECC_DupPoint(pt) : ECC_GetGFromPara(para);
824 ECC_Point *r1 = ECC_NewPoint(para);
825 BN_Optimizer *opt = BN_OptimizerCreate();
826 if (base == NULL || r1 == NULL || opt == NULL) {
827 ret = CRYPT_MEM_ALLOC_FAIL;
828 BSL_ERR_PUSH_ERROR(ret);
829 goto ERR;
830 }
831 // Convert base to affine.
832 GOTO_ERR_IF(ECP_Point2Affine(para, base, base), ret);
833 GOTO_ERR_IF(ECC_PointToMont(para, base, opt), ret);
834 GOTO_ERR_IF(ECC_CopyPoint(r, base), ret); // r = base
835 GOTO_ERR_IF(MontLadderDouble(para, r1, r, opt), ret);
836 bits = BN_Bits(k);
837 for (uint32_t i = bits - 1; i > 0; i--) {
838 tmp = BN_GetBit(k, i - 1);
839 mask2 = (-tmp) & BN_MASK;
840 GOTO_ERR_IF(ECP_PointSwapWithMask(r, r1, mask2 ^ mask1), ret);
841 GOTO_ERR_IF(MontLadderDoubleAndAdd(para, r, r1, base, opt), ret);
842 mask1 ^= (mask2 ^ mask1);
843 }
844 GOTO_ERR_IF(ECP_PointSwapWithMask(r, r1, mask1), ret);
845 GOTO_ERR_IF(MontLadderRecoverYAndToMont(para, r, r1, base, opt), ret);
846 ERR:
847 BN_OptimizerDestroy(opt);
848 ECC_FreePoint(r1);
849 ECC_FreePoint(base);
850 return ret;
851 }
852
853 #endif /* HITLS_CRYPTO_ECC */
854