/src/nss/lib/freebl/ecl/ecp_jac.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | #include "ecp.h" |
6 | | #include "mplogic.h" |
7 | | #include <stdlib.h> |
8 | | #ifdef ECL_DEBUG |
9 | | #include <assert.h> |
10 | | #endif |
11 | | |
12 | | /* Converts a point P(px, py) from affine coordinates to Jacobian |
13 | | * projective coordinates R(rx, ry, rz). Assumes input is already |
14 | | * field-encoded using field_enc, and returns output that is still |
15 | | * field-encoded. */ |
16 | | mp_err |
17 | | ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx, |
18 | | mp_int *ry, mp_int *rz, const ECGroup *group) |
19 | 0 | { |
20 | 0 | mp_err res = MP_OKAY; |
21 | |
|
22 | 0 | if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) { |
23 | 0 | MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); |
24 | 0 | } else { |
25 | 0 | MP_CHECKOK(mp_copy(px, rx)); |
26 | 0 | MP_CHECKOK(mp_copy(py, ry)); |
27 | 0 | MP_CHECKOK(mp_set_int(rz, 1)); |
28 | 0 | if (group->meth->field_enc) { |
29 | 0 | MP_CHECKOK(group->meth->field_enc(rz, rz, group->meth)); |
30 | 0 | } |
31 | 0 | } |
32 | 0 | CLEANUP: |
33 | 0 | return res; |
34 | 0 | } |
35 | | |
36 | | /* Converts a point P(px, py, pz) from Jacobian projective coordinates to |
37 | | * affine coordinates R(rx, ry). P and R can share x and y coordinates. |
38 | | * Assumes input is already field-encoded using field_enc, and returns |
39 | | * output that is still field-encoded. */ |
40 | | mp_err |
41 | | ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz, |
42 | | mp_int *rx, mp_int *ry, const ECGroup *group) |
43 | 0 | { |
44 | 0 | mp_err res = MP_OKAY; |
45 | 0 | mp_int z1, z2, z3; |
46 | |
|
47 | 0 | MP_DIGITS(&z1) = 0; |
48 | 0 | MP_DIGITS(&z2) = 0; |
49 | 0 | MP_DIGITS(&z3) = 0; |
50 | 0 | MP_CHECKOK(mp_init(&z1)); |
51 | 0 | MP_CHECKOK(mp_init(&z2)); |
52 | 0 | MP_CHECKOK(mp_init(&z3)); |
53 | | |
54 | | /* if point at infinity, then set point at infinity and exit */ |
55 | 0 | if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { |
56 | 0 | MP_CHECKOK(ec_GFp_pt_set_inf_aff(rx, ry)); |
57 | 0 | goto CLEANUP; |
58 | 0 | } |
59 | | |
60 | | /* transform (px, py, pz) into (px / pz^2, py / pz^3) */ |
61 | 0 | if (mp_cmp_d(pz, 1) == 0) { |
62 | 0 | MP_CHECKOK(mp_copy(px, rx)); |
63 | 0 | MP_CHECKOK(mp_copy(py, ry)); |
64 | 0 | } else { |
65 | 0 | MP_CHECKOK(group->meth->field_div(NULL, pz, &z1, group->meth)); |
66 | 0 | MP_CHECKOK(group->meth->field_sqr(&z1, &z2, group->meth)); |
67 | 0 | MP_CHECKOK(group->meth->field_mul(&z1, &z2, &z3, group->meth)); |
68 | 0 | MP_CHECKOK(group->meth->field_mul(px, &z2, rx, group->meth)); |
69 | 0 | MP_CHECKOK(group->meth->field_mul(py, &z3, ry, group->meth)); |
70 | 0 | } |
71 | | |
72 | 0 | CLEANUP: |
73 | 0 | mp_clear(&z1); |
74 | 0 | mp_clear(&z2); |
75 | 0 | mp_clear(&z3); |
76 | 0 | return res; |
77 | 0 | } |
78 | | |
79 | | /* Checks if point P(px, py, pz) is at infinity. Uses Jacobian |
80 | | * coordinates. */ |
81 | | mp_err |
82 | | ec_GFp_pt_is_inf_jac(const mp_int *px, const mp_int *py, const mp_int *pz) |
83 | 0 | { |
84 | 0 | return mp_cmp_z(pz); |
85 | 0 | } |
86 | | |
87 | | /* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian |
88 | | * coordinates. */ |
89 | | mp_err |
90 | | ec_GFp_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz) |
91 | 0 | { |
92 | 0 | mp_zero(pz); |
93 | 0 | return MP_OKAY; |
94 | 0 | } |
95 | | |
96 | | /* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is |
97 | | * (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical. |
98 | | * Uses mixed Jacobian-affine coordinates. Assumes input is already |
99 | | * field-encoded using field_enc, and returns output that is still |
100 | | * field-encoded. Uses equation (2) from Brown, Hankerson, Lopez, and |
101 | | * Menezes. Software Implementation of the NIST Elliptic Curves Over Prime |
102 | | * Fields. */ |
103 | | mp_err |
104 | | ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py, const mp_int *pz, |
105 | | const mp_int *qx, const mp_int *qy, mp_int *rx, |
106 | | mp_int *ry, mp_int *rz, const ECGroup *group) |
107 | 0 | { |
108 | 0 | mp_err res = MP_OKAY; |
109 | 0 | mp_int A, B, C, D, C2, C3; |
110 | |
|
111 | 0 | MP_DIGITS(&A) = 0; |
112 | 0 | MP_DIGITS(&B) = 0; |
113 | 0 | MP_DIGITS(&C) = 0; |
114 | 0 | MP_DIGITS(&D) = 0; |
115 | 0 | MP_DIGITS(&C2) = 0; |
116 | 0 | MP_DIGITS(&C3) = 0; |
117 | 0 | MP_CHECKOK(mp_init(&A)); |
118 | 0 | MP_CHECKOK(mp_init(&B)); |
119 | 0 | MP_CHECKOK(mp_init(&C)); |
120 | 0 | MP_CHECKOK(mp_init(&D)); |
121 | 0 | MP_CHECKOK(mp_init(&C2)); |
122 | 0 | MP_CHECKOK(mp_init(&C3)); |
123 | | |
124 | | /* If either P or Q is the point at infinity, then return the other |
125 | | * point */ |
126 | 0 | if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { |
127 | 0 | MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group)); |
128 | 0 | goto CLEANUP; |
129 | 0 | } |
130 | 0 | if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) { |
131 | 0 | MP_CHECKOK(mp_copy(px, rx)); |
132 | 0 | MP_CHECKOK(mp_copy(py, ry)); |
133 | 0 | MP_CHECKOK(mp_copy(pz, rz)); |
134 | 0 | goto CLEANUP; |
135 | 0 | } |
136 | | |
137 | | /* A = qx * pz^2, B = qy * pz^3 */ |
138 | 0 | MP_CHECKOK(group->meth->field_sqr(pz, &A, group->meth)); |
139 | 0 | MP_CHECKOK(group->meth->field_mul(&A, pz, &B, group->meth)); |
140 | 0 | MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth)); |
141 | 0 | MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth)); |
142 | | |
143 | | /* C = A - px, D = B - py */ |
144 | 0 | MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth)); |
145 | 0 | MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth)); |
146 | | |
147 | 0 | if (mp_cmp_z(&C) == 0) { |
148 | | /* P == Q or P == -Q */ |
149 | 0 | if (mp_cmp_z(&D) == 0) { |
150 | | /* P == Q */ |
151 | | /* It is cheaper to double (qx, qy, 1) than (px, py, pz). */ |
152 | 0 | MP_DIGIT(&D, 0) = 1; /* Set D to 1. */ |
153 | 0 | MP_CHECKOK(ec_GFp_pt_dbl_jac(qx, qy, &D, rx, ry, rz, group)); |
154 | 0 | } else { |
155 | | /* P == -Q */ |
156 | 0 | MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); |
157 | 0 | } |
158 | 0 | goto CLEANUP; |
159 | 0 | } |
160 | | |
161 | | /* C2 = C^2, C3 = C^3 */ |
162 | 0 | MP_CHECKOK(group->meth->field_sqr(&C, &C2, group->meth)); |
163 | 0 | MP_CHECKOK(group->meth->field_mul(&C, &C2, &C3, group->meth)); |
164 | | |
165 | | /* rz = pz * C */ |
166 | 0 | MP_CHECKOK(group->meth->field_mul(pz, &C, rz, group->meth)); |
167 | | |
168 | | /* C = px * C^2 */ |
169 | 0 | MP_CHECKOK(group->meth->field_mul(px, &C2, &C, group->meth)); |
170 | | /* A = D^2 */ |
171 | 0 | MP_CHECKOK(group->meth->field_sqr(&D, &A, group->meth)); |
172 | | |
173 | | /* rx = D^2 - (C^3 + 2 * (px * C^2)) */ |
174 | 0 | MP_CHECKOK(group->meth->field_add(&C, &C, rx, group->meth)); |
175 | 0 | MP_CHECKOK(group->meth->field_add(&C3, rx, rx, group->meth)); |
176 | 0 | MP_CHECKOK(group->meth->field_sub(&A, rx, rx, group->meth)); |
177 | | |
178 | | /* C3 = py * C^3 */ |
179 | 0 | MP_CHECKOK(group->meth->field_mul(py, &C3, &C3, group->meth)); |
180 | | |
181 | | /* ry = D * (px * C^2 - rx) - py * C^3 */ |
182 | 0 | MP_CHECKOK(group->meth->field_sub(&C, rx, ry, group->meth)); |
183 | 0 | MP_CHECKOK(group->meth->field_mul(&D, ry, ry, group->meth)); |
184 | 0 | MP_CHECKOK(group->meth->field_sub(ry, &C3, ry, group->meth)); |
185 | | |
186 | 0 | CLEANUP: |
187 | 0 | mp_clear(&A); |
188 | 0 | mp_clear(&B); |
189 | 0 | mp_clear(&C); |
190 | 0 | mp_clear(&D); |
191 | 0 | mp_clear(&C2); |
192 | 0 | mp_clear(&C3); |
193 | 0 | return res; |
194 | 0 | } |
195 | | |
196 | | /* Computes R = 2P. Elliptic curve points P and R can be identical. Uses |
197 | | * Jacobian coordinates. |
198 | | * |
199 | | * Assumes input is already field-encoded using field_enc, and returns |
200 | | * output that is still field-encoded. |
201 | | * |
202 | | * This routine implements Point Doubling in the Jacobian Projective |
203 | | * space as described in the paper "Efficient elliptic curve exponentiation |
204 | | * using mixed coordinates", by H. Cohen, A Miyaji, T. Ono. |
205 | | */ |
206 | | mp_err |
207 | | ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py, const mp_int *pz, |
208 | | mp_int *rx, mp_int *ry, mp_int *rz, const ECGroup *group) |
209 | 0 | { |
210 | 0 | mp_err res = MP_OKAY; |
211 | 0 | mp_int t0, t1, M, S; |
212 | |
|
213 | 0 | MP_DIGITS(&t0) = 0; |
214 | 0 | MP_DIGITS(&t1) = 0; |
215 | 0 | MP_DIGITS(&M) = 0; |
216 | 0 | MP_DIGITS(&S) = 0; |
217 | 0 | MP_CHECKOK(mp_init(&t0)); |
218 | 0 | MP_CHECKOK(mp_init(&t1)); |
219 | 0 | MP_CHECKOK(mp_init(&M)); |
220 | 0 | MP_CHECKOK(mp_init(&S)); |
221 | | |
222 | | /* P == inf or P == -P */ |
223 | 0 | if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES || mp_cmp_z(py) == 0) { |
224 | 0 | MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); |
225 | 0 | goto CLEANUP; |
226 | 0 | } |
227 | | |
228 | 0 | if (mp_cmp_d(pz, 1) == 0) { |
229 | | /* M = 3 * px^2 + a */ |
230 | 0 | MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth)); |
231 | 0 | MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth)); |
232 | 0 | MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth)); |
233 | 0 | MP_CHECKOK(group->meth->field_add(&t0, &group->curvea, &M, group->meth)); |
234 | 0 | } else if (MP_SIGN(&group->curvea) == MP_NEG && |
235 | 0 | MP_USED(&group->curvea) == 1 && |
236 | 0 | MP_DIGIT(&group->curvea, 0) == 3) { |
237 | | /* M = 3 * (px + pz^2) * (px - pz^2) */ |
238 | 0 | MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth)); |
239 | 0 | MP_CHECKOK(group->meth->field_add(px, &M, &t0, group->meth)); |
240 | 0 | MP_CHECKOK(group->meth->field_sub(px, &M, &t1, group->meth)); |
241 | 0 | MP_CHECKOK(group->meth->field_mul(&t0, &t1, &M, group->meth)); |
242 | 0 | MP_CHECKOK(group->meth->field_add(&M, &M, &t0, group->meth)); |
243 | 0 | MP_CHECKOK(group->meth->field_add(&t0, &M, &M, group->meth)); |
244 | 0 | } else { |
245 | | /* M = 3 * (px^2) + a * (pz^4) */ |
246 | 0 | MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth)); |
247 | 0 | MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth)); |
248 | 0 | MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth)); |
249 | 0 | MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth)); |
250 | 0 | MP_CHECKOK(group->meth->field_sqr(&M, &M, group->meth)); |
251 | 0 | MP_CHECKOK(group->meth->field_mul(&M, &group->curvea, &M, group->meth)); |
252 | 0 | MP_CHECKOK(group->meth->field_add(&M, &t0, &M, group->meth)); |
253 | 0 | } |
254 | | |
255 | | /* rz = 2 * py * pz */ |
256 | | /* t0 = 4 * py^2 */ |
257 | 0 | if (mp_cmp_d(pz, 1) == 0) { |
258 | 0 | MP_CHECKOK(group->meth->field_add(py, py, rz, group->meth)); |
259 | 0 | MP_CHECKOK(group->meth->field_sqr(rz, &t0, group->meth)); |
260 | 0 | } else { |
261 | 0 | MP_CHECKOK(group->meth->field_add(py, py, &t0, group->meth)); |
262 | 0 | MP_CHECKOK(group->meth->field_mul(&t0, pz, rz, group->meth)); |
263 | 0 | MP_CHECKOK(group->meth->field_sqr(&t0, &t0, group->meth)); |
264 | 0 | } |
265 | | |
266 | | /* S = 4 * px * py^2 = px * (2 * py)^2 */ |
267 | 0 | MP_CHECKOK(group->meth->field_mul(px, &t0, &S, group->meth)); |
268 | | |
269 | | /* rx = M^2 - 2 * S */ |
270 | 0 | MP_CHECKOK(group->meth->field_add(&S, &S, &t1, group->meth)); |
271 | 0 | MP_CHECKOK(group->meth->field_sqr(&M, rx, group->meth)); |
272 | 0 | MP_CHECKOK(group->meth->field_sub(rx, &t1, rx, group->meth)); |
273 | | |
274 | | /* ry = M * (S - rx) - 8 * py^4 */ |
275 | 0 | MP_CHECKOK(group->meth->field_sqr(&t0, &t1, group->meth)); |
276 | 0 | if (mp_isodd(&t1)) { |
277 | 0 | MP_CHECKOK(mp_add(&t1, &group->meth->irr, &t1)); |
278 | 0 | } |
279 | 0 | MP_CHECKOK(mp_div_2(&t1, &t1)); |
280 | 0 | MP_CHECKOK(group->meth->field_sub(&S, rx, &S, group->meth)); |
281 | 0 | MP_CHECKOK(group->meth->field_mul(&M, &S, &M, group->meth)); |
282 | 0 | MP_CHECKOK(group->meth->field_sub(&M, &t1, ry, group->meth)); |
283 | | |
284 | 0 | CLEANUP: |
285 | 0 | mp_clear(&t0); |
286 | 0 | mp_clear(&t1); |
287 | 0 | mp_clear(&M); |
288 | 0 | mp_clear(&S); |
289 | 0 | return res; |
290 | 0 | } |
291 | | |
292 | | /* by default, this routine is unused and thus doesn't need to be compiled */ |
293 | | #ifdef ECL_ENABLE_GFP_PT_MUL_JAC |
294 | | /* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters |
295 | | * a, b and p are the elliptic curve coefficients and the prime that |
296 | | * determines the field GFp. Elliptic curve points P and R can be |
297 | | * identical. Uses mixed Jacobian-affine coordinates. Assumes input is |
298 | | * already field-encoded using field_enc, and returns output that is still |
299 | | * field-encoded. Uses 4-bit window method. */ |
300 | | mp_err |
301 | | ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px, const mp_int *py, |
302 | | mp_int *rx, mp_int *ry, const ECGroup *group) |
303 | | { |
304 | | mp_err res = MP_OKAY; |
305 | | mp_int precomp[16][2], rz; |
306 | | int i, ni, d; |
307 | | |
308 | | MP_DIGITS(&rz) = 0; |
309 | | for (i = 0; i < 16; i++) { |
310 | | MP_DIGITS(&precomp[i][0]) = 0; |
311 | | MP_DIGITS(&precomp[i][1]) = 0; |
312 | | } |
313 | | |
314 | | ARGCHK(group != NULL, MP_BADARG); |
315 | | ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG); |
316 | | |
317 | | /* initialize precomputation table */ |
318 | | for (i = 0; i < 16; i++) { |
319 | | MP_CHECKOK(mp_init(&precomp[i][0])); |
320 | | MP_CHECKOK(mp_init(&precomp[i][1])); |
321 | | } |
322 | | |
323 | | /* fill precomputation table */ |
324 | | mp_zero(&precomp[0][0]); |
325 | | mp_zero(&precomp[0][1]); |
326 | | MP_CHECKOK(mp_copy(px, &precomp[1][0])); |
327 | | MP_CHECKOK(mp_copy(py, &precomp[1][1])); |
328 | | for (i = 2; i < 16; i++) { |
329 | | MP_CHECKOK(group->point_add(&precomp[1][0], &precomp[1][1], |
330 | | &precomp[i - 1][0], &precomp[i - 1][1], |
331 | | &precomp[i][0], &precomp[i][1], group)); |
332 | | } |
333 | | |
334 | | d = (mpl_significant_bits(n) + 3) / 4; |
335 | | |
336 | | /* R = inf */ |
337 | | MP_CHECKOK(mp_init(&rz)); |
338 | | MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz)); |
339 | | |
340 | | for (i = d - 1; i >= 0; i--) { |
341 | | /* compute window ni */ |
342 | | ni = MP_GET_BIT(n, 4 * i + 3); |
343 | | ni <<= 1; |
344 | | ni |= MP_GET_BIT(n, 4 * i + 2); |
345 | | ni <<= 1; |
346 | | ni |= MP_GET_BIT(n, 4 * i + 1); |
347 | | ni <<= 1; |
348 | | ni |= MP_GET_BIT(n, 4 * i); |
349 | | /* R = 2^4 * R */ |
350 | | MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); |
351 | | MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); |
352 | | MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); |
353 | | MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); |
354 | | /* R = R + (ni * P) */ |
355 | | MP_CHECKOK(ec_GFp_pt_add_jac_aff(rx, ry, &rz, &precomp[ni][0], &precomp[ni][1], rx, ry, |
356 | | &rz, group)); |
357 | | } |
358 | | |
359 | | /* convert result S to affine coordinates */ |
360 | | MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group)); |
361 | | |
362 | | CLEANUP: |
363 | | mp_clear(&rz); |
364 | | for (i = 0; i < 16; i++) { |
365 | | mp_clear(&precomp[i][0]); |
366 | | mp_clear(&precomp[i][1]); |
367 | | } |
368 | | return res; |
369 | | } |
370 | | #endif |
371 | | |
372 | | /* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G + |
373 | | * k2 * P(x, y), where G is the generator (base point) of the group of |
374 | | * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL. |
375 | | * Uses mixed Jacobian-affine coordinates. Input and output values are |
376 | | * assumed to be NOT field-encoded. Uses algorithm 15 (simultaneous |
377 | | * multiple point multiplication) from Brown, Hankerson, Lopez, Menezes. |
378 | | * Software Implementation of the NIST Elliptic Curves over Prime Fields. */ |
379 | | mp_err |
380 | | ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px, |
381 | | const mp_int *py, mp_int *rx, mp_int *ry, |
382 | | const ECGroup *group) |
383 | 0 | { |
384 | 0 | mp_err res = MP_OKAY; |
385 | 0 | mp_int precomp[4][4][2]; |
386 | 0 | mp_int rz; |
387 | 0 | const mp_int *a, *b; |
388 | 0 | unsigned int i, j; |
389 | 0 | int ai, bi, d; |
390 | |
|
391 | 0 | for (i = 0; i < 4; i++) { |
392 | 0 | for (j = 0; j < 4; j++) { |
393 | 0 | MP_DIGITS(&precomp[i][j][0]) = 0; |
394 | 0 | MP_DIGITS(&precomp[i][j][1]) = 0; |
395 | 0 | } |
396 | 0 | } |
397 | 0 | MP_DIGITS(&rz) = 0; |
398 | |
|
399 | 0 | ARGCHK(group != NULL, MP_BADARG); |
400 | 0 | ARGCHK(!((k1 == NULL) && ((k2 == NULL) || (px == NULL) || (py == NULL))), MP_BADARG); |
401 | | |
402 | | /* if some arguments are not defined used ECPoint_mul */ |
403 | 0 | if (k1 == NULL) { |
404 | 0 | return ECPoint_mul(group, k2, px, py, rx, ry); |
405 | 0 | } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) { |
406 | 0 | return ECPoint_mul(group, k1, NULL, NULL, rx, ry); |
407 | 0 | } |
408 | | |
409 | | /* initialize precomputation table */ |
410 | 0 | for (i = 0; i < 4; i++) { |
411 | 0 | for (j = 0; j < 4; j++) { |
412 | 0 | MP_CHECKOK(mp_init(&precomp[i][j][0])); |
413 | 0 | MP_CHECKOK(mp_init(&precomp[i][j][1])); |
414 | 0 | } |
415 | 0 | } |
416 | | |
417 | | /* fill precomputation table */ |
418 | | /* assign {k1, k2} = {a, b} such that len(a) >= len(b) */ |
419 | 0 | if (mpl_significant_bits(k1) < mpl_significant_bits(k2)) { |
420 | 0 | a = k2; |
421 | 0 | b = k1; |
422 | 0 | if (group->meth->field_enc) { |
423 | 0 | MP_CHECKOK(group->meth->field_enc(px, &precomp[1][0][0], group->meth)); |
424 | 0 | MP_CHECKOK(group->meth->field_enc(py, &precomp[1][0][1], group->meth)); |
425 | 0 | } else { |
426 | 0 | MP_CHECKOK(mp_copy(px, &precomp[1][0][0])); |
427 | 0 | MP_CHECKOK(mp_copy(py, &precomp[1][0][1])); |
428 | 0 | } |
429 | 0 | MP_CHECKOK(mp_copy(&group->genx, &precomp[0][1][0])); |
430 | 0 | MP_CHECKOK(mp_copy(&group->geny, &precomp[0][1][1])); |
431 | 0 | } else { |
432 | 0 | a = k1; |
433 | 0 | b = k2; |
434 | 0 | MP_CHECKOK(mp_copy(&group->genx, &precomp[1][0][0])); |
435 | 0 | MP_CHECKOK(mp_copy(&group->geny, &precomp[1][0][1])); |
436 | 0 | if (group->meth->field_enc) { |
437 | 0 | MP_CHECKOK(group->meth->field_enc(px, &precomp[0][1][0], group->meth)); |
438 | 0 | MP_CHECKOK(group->meth->field_enc(py, &precomp[0][1][1], group->meth)); |
439 | 0 | } else { |
440 | 0 | MP_CHECKOK(mp_copy(px, &precomp[0][1][0])); |
441 | 0 | MP_CHECKOK(mp_copy(py, &precomp[0][1][1])); |
442 | 0 | } |
443 | 0 | } |
444 | | /* precompute [*][0][*] */ |
445 | 0 | mp_zero(&precomp[0][0][0]); |
446 | 0 | mp_zero(&precomp[0][0][1]); |
447 | 0 | MP_CHECKOK(group->point_dbl(&precomp[1][0][0], &precomp[1][0][1], |
448 | 0 | &precomp[2][0][0], &precomp[2][0][1], group)); |
449 | 0 | MP_CHECKOK(group->point_add(&precomp[1][0][0], &precomp[1][0][1], |
450 | 0 | &precomp[2][0][0], &precomp[2][0][1], |
451 | 0 | &precomp[3][0][0], &precomp[3][0][1], group)); |
452 | | /* precompute [*][1][*] */ |
453 | 0 | for (i = 1; i < 4; i++) { |
454 | 0 | MP_CHECKOK(group->point_add(&precomp[0][1][0], &precomp[0][1][1], |
455 | 0 | &precomp[i][0][0], &precomp[i][0][1], |
456 | 0 | &precomp[i][1][0], &precomp[i][1][1], group)); |
457 | 0 | } |
458 | | /* precompute [*][2][*] */ |
459 | 0 | MP_CHECKOK(group->point_dbl(&precomp[0][1][0], &precomp[0][1][1], |
460 | 0 | &precomp[0][2][0], &precomp[0][2][1], group)); |
461 | 0 | for (i = 1; i < 4; i++) { |
462 | 0 | MP_CHECKOK(group->point_add(&precomp[0][2][0], &precomp[0][2][1], |
463 | 0 | &precomp[i][0][0], &precomp[i][0][1], |
464 | 0 | &precomp[i][2][0], &precomp[i][2][1], group)); |
465 | 0 | } |
466 | | /* precompute [*][3][*] */ |
467 | 0 | MP_CHECKOK(group->point_add(&precomp[0][1][0], &precomp[0][1][1], |
468 | 0 | &precomp[0][2][0], &precomp[0][2][1], |
469 | 0 | &precomp[0][3][0], &precomp[0][3][1], group)); |
470 | 0 | for (i = 1; i < 4; i++) { |
471 | 0 | MP_CHECKOK(group->point_add(&precomp[0][3][0], &precomp[0][3][1], |
472 | 0 | &precomp[i][0][0], &precomp[i][0][1], |
473 | 0 | &precomp[i][3][0], &precomp[i][3][1], group)); |
474 | 0 | } |
475 | | |
476 | 0 | d = (mpl_significant_bits(a) + 1) / 2; |
477 | | |
478 | | /* R = inf */ |
479 | 0 | MP_CHECKOK(mp_init(&rz)); |
480 | 0 | MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz)); |
481 | | |
482 | 0 | for (i = d; i-- > 0;) { |
483 | 0 | ai = MP_GET_BIT(a, 2 * i + 1); |
484 | 0 | ai <<= 1; |
485 | 0 | ai |= MP_GET_BIT(a, 2 * i); |
486 | 0 | bi = MP_GET_BIT(b, 2 * i + 1); |
487 | 0 | bi <<= 1; |
488 | 0 | bi |= MP_GET_BIT(b, 2 * i); |
489 | | /* R = 2^2 * R */ |
490 | 0 | MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); |
491 | 0 | MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); |
492 | | /* R = R + (ai * A + bi * B) */ |
493 | 0 | MP_CHECKOK(ec_GFp_pt_add_jac_aff(rx, ry, &rz, &precomp[ai][bi][0], &precomp[ai][bi][1], |
494 | 0 | rx, ry, &rz, group)); |
495 | 0 | } |
496 | | |
497 | 0 | MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group)); |
498 | | |
499 | 0 | if (group->meth->field_dec) { |
500 | 0 | MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth)); |
501 | 0 | MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth)); |
502 | 0 | } |
503 | | |
504 | 0 | CLEANUP: |
505 | 0 | mp_clear(&rz); |
506 | 0 | for (i = 0; i < 4; i++) { |
507 | 0 | for (j = 0; j < 4; j++) { |
508 | 0 | mp_clear(&precomp[i][j][0]); |
509 | 0 | mp_clear(&precomp[i][j][1]); |
510 | 0 | } |
511 | 0 | } |
512 | 0 | return res; |
513 | 0 | } |