Coverage Report

Created: 2024-05-20 06:23

/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
}