1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/ecl/ecp_jac.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,514 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "ecp.h" 1.9 +#include "mplogic.h" 1.10 +#include <stdlib.h> 1.11 +#ifdef ECL_DEBUG 1.12 +#include <assert.h> 1.13 +#endif 1.14 + 1.15 +/* Converts a point P(px, py) from affine coordinates to Jacobian 1.16 + * projective coordinates R(rx, ry, rz). Assumes input is already 1.17 + * field-encoded using field_enc, and returns output that is still 1.18 + * field-encoded. */ 1.19 +mp_err 1.20 +ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx, 1.21 + mp_int *ry, mp_int *rz, const ECGroup *group) 1.22 +{ 1.23 + mp_err res = MP_OKAY; 1.24 + 1.25 + if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) { 1.26 + MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); 1.27 + } else { 1.28 + MP_CHECKOK(mp_copy(px, rx)); 1.29 + MP_CHECKOK(mp_copy(py, ry)); 1.30 + MP_CHECKOK(mp_set_int(rz, 1)); 1.31 + if (group->meth->field_enc) { 1.32 + MP_CHECKOK(group->meth->field_enc(rz, rz, group->meth)); 1.33 + } 1.34 + } 1.35 + CLEANUP: 1.36 + return res; 1.37 +} 1.38 + 1.39 +/* Converts a point P(px, py, pz) from Jacobian projective coordinates to 1.40 + * affine coordinates R(rx, ry). P and R can share x and y coordinates. 1.41 + * Assumes input is already field-encoded using field_enc, and returns 1.42 + * output that is still field-encoded. */ 1.43 +mp_err 1.44 +ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz, 1.45 + mp_int *rx, mp_int *ry, const ECGroup *group) 1.46 +{ 1.47 + mp_err res = MP_OKAY; 1.48 + mp_int z1, z2, z3; 1.49 + 1.50 + MP_DIGITS(&z1) = 0; 1.51 + MP_DIGITS(&z2) = 0; 1.52 + MP_DIGITS(&z3) = 0; 1.53 + MP_CHECKOK(mp_init(&z1)); 1.54 + MP_CHECKOK(mp_init(&z2)); 1.55 + MP_CHECKOK(mp_init(&z3)); 1.56 + 1.57 + /* if point at infinity, then set point at infinity and exit */ 1.58 + if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { 1.59 + MP_CHECKOK(ec_GFp_pt_set_inf_aff(rx, ry)); 1.60 + goto CLEANUP; 1.61 + } 1.62 + 1.63 + /* transform (px, py, pz) into (px / pz^2, py / pz^3) */ 1.64 + if (mp_cmp_d(pz, 1) == 0) { 1.65 + MP_CHECKOK(mp_copy(px, rx)); 1.66 + MP_CHECKOK(mp_copy(py, ry)); 1.67 + } else { 1.68 + MP_CHECKOK(group->meth->field_div(NULL, pz, &z1, group->meth)); 1.69 + MP_CHECKOK(group->meth->field_sqr(&z1, &z2, group->meth)); 1.70 + MP_CHECKOK(group->meth->field_mul(&z1, &z2, &z3, group->meth)); 1.71 + MP_CHECKOK(group->meth->field_mul(px, &z2, rx, group->meth)); 1.72 + MP_CHECKOK(group->meth->field_mul(py, &z3, ry, group->meth)); 1.73 + } 1.74 + 1.75 + CLEANUP: 1.76 + mp_clear(&z1); 1.77 + mp_clear(&z2); 1.78 + mp_clear(&z3); 1.79 + return res; 1.80 +} 1.81 + 1.82 +/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian 1.83 + * coordinates. */ 1.84 +mp_err 1.85 +ec_GFp_pt_is_inf_jac(const mp_int *px, const mp_int *py, const mp_int *pz) 1.86 +{ 1.87 + return mp_cmp_z(pz); 1.88 +} 1.89 + 1.90 +/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian 1.91 + * coordinates. */ 1.92 +mp_err 1.93 +ec_GFp_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz) 1.94 +{ 1.95 + mp_zero(pz); 1.96 + return MP_OKAY; 1.97 +} 1.98 + 1.99 +/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is 1.100 + * (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical. 1.101 + * Uses mixed Jacobian-affine coordinates. Assumes input is already 1.102 + * field-encoded using field_enc, and returns output that is still 1.103 + * field-encoded. Uses equation (2) from Brown, Hankerson, Lopez, and 1.104 + * Menezes. Software Implementation of the NIST Elliptic Curves Over Prime 1.105 + * Fields. */ 1.106 +mp_err 1.107 +ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py, const mp_int *pz, 1.108 + const mp_int *qx, const mp_int *qy, mp_int *rx, 1.109 + mp_int *ry, mp_int *rz, const ECGroup *group) 1.110 +{ 1.111 + mp_err res = MP_OKAY; 1.112 + mp_int A, B, C, D, C2, C3; 1.113 + 1.114 + MP_DIGITS(&A) = 0; 1.115 + MP_DIGITS(&B) = 0; 1.116 + MP_DIGITS(&C) = 0; 1.117 + MP_DIGITS(&D) = 0; 1.118 + MP_DIGITS(&C2) = 0; 1.119 + MP_DIGITS(&C3) = 0; 1.120 + MP_CHECKOK(mp_init(&A)); 1.121 + MP_CHECKOK(mp_init(&B)); 1.122 + MP_CHECKOK(mp_init(&C)); 1.123 + MP_CHECKOK(mp_init(&D)); 1.124 + MP_CHECKOK(mp_init(&C2)); 1.125 + MP_CHECKOK(mp_init(&C3)); 1.126 + 1.127 + /* If either P or Q is the point at infinity, then return the other 1.128 + * point */ 1.129 + if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { 1.130 + MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group)); 1.131 + goto CLEANUP; 1.132 + } 1.133 + if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) { 1.134 + MP_CHECKOK(mp_copy(px, rx)); 1.135 + MP_CHECKOK(mp_copy(py, ry)); 1.136 + MP_CHECKOK(mp_copy(pz, rz)); 1.137 + goto CLEANUP; 1.138 + } 1.139 + 1.140 + /* A = qx * pz^2, B = qy * pz^3 */ 1.141 + MP_CHECKOK(group->meth->field_sqr(pz, &A, group->meth)); 1.142 + MP_CHECKOK(group->meth->field_mul(&A, pz, &B, group->meth)); 1.143 + MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth)); 1.144 + MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth)); 1.145 + 1.146 + /* C = A - px, D = B - py */ 1.147 + MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth)); 1.148 + MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth)); 1.149 + 1.150 + /* C2 = C^2, C3 = C^3 */ 1.151 + MP_CHECKOK(group->meth->field_sqr(&C, &C2, group->meth)); 1.152 + MP_CHECKOK(group->meth->field_mul(&C, &C2, &C3, group->meth)); 1.153 + 1.154 + /* rz = pz * C */ 1.155 + MP_CHECKOK(group->meth->field_mul(pz, &C, rz, group->meth)); 1.156 + 1.157 + /* C = px * C^2 */ 1.158 + MP_CHECKOK(group->meth->field_mul(px, &C2, &C, group->meth)); 1.159 + /* A = D^2 */ 1.160 + MP_CHECKOK(group->meth->field_sqr(&D, &A, group->meth)); 1.161 + 1.162 + /* rx = D^2 - (C^3 + 2 * (px * C^2)) */ 1.163 + MP_CHECKOK(group->meth->field_add(&C, &C, rx, group->meth)); 1.164 + MP_CHECKOK(group->meth->field_add(&C3, rx, rx, group->meth)); 1.165 + MP_CHECKOK(group->meth->field_sub(&A, rx, rx, group->meth)); 1.166 + 1.167 + /* C3 = py * C^3 */ 1.168 + MP_CHECKOK(group->meth->field_mul(py, &C3, &C3, group->meth)); 1.169 + 1.170 + /* ry = D * (px * C^2 - rx) - py * C^3 */ 1.171 + MP_CHECKOK(group->meth->field_sub(&C, rx, ry, group->meth)); 1.172 + MP_CHECKOK(group->meth->field_mul(&D, ry, ry, group->meth)); 1.173 + MP_CHECKOK(group->meth->field_sub(ry, &C3, ry, group->meth)); 1.174 + 1.175 + CLEANUP: 1.176 + mp_clear(&A); 1.177 + mp_clear(&B); 1.178 + mp_clear(&C); 1.179 + mp_clear(&D); 1.180 + mp_clear(&C2); 1.181 + mp_clear(&C3); 1.182 + return res; 1.183 +} 1.184 + 1.185 +/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses 1.186 + * Jacobian coordinates. 1.187 + * 1.188 + * Assumes input is already field-encoded using field_enc, and returns 1.189 + * output that is still field-encoded. 1.190 + * 1.191 + * This routine implements Point Doubling in the Jacobian Projective 1.192 + * space as described in the paper "Efficient elliptic curve exponentiation 1.193 + * using mixed coordinates", by H. Cohen, A Miyaji, T. Ono. 1.194 + */ 1.195 +mp_err 1.196 +ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py, const mp_int *pz, 1.197 + mp_int *rx, mp_int *ry, mp_int *rz, const ECGroup *group) 1.198 +{ 1.199 + mp_err res = MP_OKAY; 1.200 + mp_int t0, t1, M, S; 1.201 + 1.202 + MP_DIGITS(&t0) = 0; 1.203 + MP_DIGITS(&t1) = 0; 1.204 + MP_DIGITS(&M) = 0; 1.205 + MP_DIGITS(&S) = 0; 1.206 + MP_CHECKOK(mp_init(&t0)); 1.207 + MP_CHECKOK(mp_init(&t1)); 1.208 + MP_CHECKOK(mp_init(&M)); 1.209 + MP_CHECKOK(mp_init(&S)); 1.210 + 1.211 + if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { 1.212 + MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); 1.213 + goto CLEANUP; 1.214 + } 1.215 + 1.216 + if (mp_cmp_d(pz, 1) == 0) { 1.217 + /* M = 3 * px^2 + a */ 1.218 + MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth)); 1.219 + MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth)); 1.220 + MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth)); 1.221 + MP_CHECKOK(group->meth-> 1.222 + field_add(&t0, &group->curvea, &M, group->meth)); 1.223 + } else if (mp_cmp_int(&group->curvea, -3) == 0) { 1.224 + /* M = 3 * (px + pz^2) * (px - pz^2) */ 1.225 + MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth)); 1.226 + MP_CHECKOK(group->meth->field_add(px, &M, &t0, group->meth)); 1.227 + MP_CHECKOK(group->meth->field_sub(px, &M, &t1, group->meth)); 1.228 + MP_CHECKOK(group->meth->field_mul(&t0, &t1, &M, group->meth)); 1.229 + MP_CHECKOK(group->meth->field_add(&M, &M, &t0, group->meth)); 1.230 + MP_CHECKOK(group->meth->field_add(&t0, &M, &M, group->meth)); 1.231 + } else { 1.232 + /* M = 3 * (px^2) + a * (pz^4) */ 1.233 + MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth)); 1.234 + MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth)); 1.235 + MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth)); 1.236 + MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth)); 1.237 + MP_CHECKOK(group->meth->field_sqr(&M, &M, group->meth)); 1.238 + MP_CHECKOK(group->meth-> 1.239 + field_mul(&M, &group->curvea, &M, group->meth)); 1.240 + MP_CHECKOK(group->meth->field_add(&M, &t0, &M, group->meth)); 1.241 + } 1.242 + 1.243 + /* rz = 2 * py * pz */ 1.244 + /* t0 = 4 * py^2 */ 1.245 + if (mp_cmp_d(pz, 1) == 0) { 1.246 + MP_CHECKOK(group->meth->field_add(py, py, rz, group->meth)); 1.247 + MP_CHECKOK(group->meth->field_sqr(rz, &t0, group->meth)); 1.248 + } else { 1.249 + MP_CHECKOK(group->meth->field_add(py, py, &t0, group->meth)); 1.250 + MP_CHECKOK(group->meth->field_mul(&t0, pz, rz, group->meth)); 1.251 + MP_CHECKOK(group->meth->field_sqr(&t0, &t0, group->meth)); 1.252 + } 1.253 + 1.254 + /* S = 4 * px * py^2 = px * (2 * py)^2 */ 1.255 + MP_CHECKOK(group->meth->field_mul(px, &t0, &S, group->meth)); 1.256 + 1.257 + /* rx = M^2 - 2 * S */ 1.258 + MP_CHECKOK(group->meth->field_add(&S, &S, &t1, group->meth)); 1.259 + MP_CHECKOK(group->meth->field_sqr(&M, rx, group->meth)); 1.260 + MP_CHECKOK(group->meth->field_sub(rx, &t1, rx, group->meth)); 1.261 + 1.262 + /* ry = M * (S - rx) - 8 * py^4 */ 1.263 + MP_CHECKOK(group->meth->field_sqr(&t0, &t1, group->meth)); 1.264 + if (mp_isodd(&t1)) { 1.265 + MP_CHECKOK(mp_add(&t1, &group->meth->irr, &t1)); 1.266 + } 1.267 + MP_CHECKOK(mp_div_2(&t1, &t1)); 1.268 + MP_CHECKOK(group->meth->field_sub(&S, rx, &S, group->meth)); 1.269 + MP_CHECKOK(group->meth->field_mul(&M, &S, &M, group->meth)); 1.270 + MP_CHECKOK(group->meth->field_sub(&M, &t1, ry, group->meth)); 1.271 + 1.272 + CLEANUP: 1.273 + mp_clear(&t0); 1.274 + mp_clear(&t1); 1.275 + mp_clear(&M); 1.276 + mp_clear(&S); 1.277 + return res; 1.278 +} 1.279 + 1.280 +/* by default, this routine is unused and thus doesn't need to be compiled */ 1.281 +#ifdef ECL_ENABLE_GFP_PT_MUL_JAC 1.282 +/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters 1.283 + * a, b and p are the elliptic curve coefficients and the prime that 1.284 + * determines the field GFp. Elliptic curve points P and R can be 1.285 + * identical. Uses mixed Jacobian-affine coordinates. Assumes input is 1.286 + * already field-encoded using field_enc, and returns output that is still 1.287 + * field-encoded. Uses 4-bit window method. */ 1.288 +mp_err 1.289 +ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px, const mp_int *py, 1.290 + mp_int *rx, mp_int *ry, const ECGroup *group) 1.291 +{ 1.292 + mp_err res = MP_OKAY; 1.293 + mp_int precomp[16][2], rz; 1.294 + int i, ni, d; 1.295 + 1.296 + MP_DIGITS(&rz) = 0; 1.297 + for (i = 0; i < 16; i++) { 1.298 + MP_DIGITS(&precomp[i][0]) = 0; 1.299 + MP_DIGITS(&precomp[i][1]) = 0; 1.300 + } 1.301 + 1.302 + ARGCHK(group != NULL, MP_BADARG); 1.303 + ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG); 1.304 + 1.305 + /* initialize precomputation table */ 1.306 + for (i = 0; i < 16; i++) { 1.307 + MP_CHECKOK(mp_init(&precomp[i][0])); 1.308 + MP_CHECKOK(mp_init(&precomp[i][1])); 1.309 + } 1.310 + 1.311 + /* fill precomputation table */ 1.312 + mp_zero(&precomp[0][0]); 1.313 + mp_zero(&precomp[0][1]); 1.314 + MP_CHECKOK(mp_copy(px, &precomp[1][0])); 1.315 + MP_CHECKOK(mp_copy(py, &precomp[1][1])); 1.316 + for (i = 2; i < 16; i++) { 1.317 + MP_CHECKOK(group-> 1.318 + point_add(&precomp[1][0], &precomp[1][1], 1.319 + &precomp[i - 1][0], &precomp[i - 1][1], 1.320 + &precomp[i][0], &precomp[i][1], group)); 1.321 + } 1.322 + 1.323 + d = (mpl_significant_bits(n) + 3) / 4; 1.324 + 1.325 + /* R = inf */ 1.326 + MP_CHECKOK(mp_init(&rz)); 1.327 + MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz)); 1.328 + 1.329 + for (i = d - 1; i >= 0; i--) { 1.330 + /* compute window ni */ 1.331 + ni = MP_GET_BIT(n, 4 * i + 3); 1.332 + ni <<= 1; 1.333 + ni |= MP_GET_BIT(n, 4 * i + 2); 1.334 + ni <<= 1; 1.335 + ni |= MP_GET_BIT(n, 4 * i + 1); 1.336 + ni <<= 1; 1.337 + ni |= MP_GET_BIT(n, 4 * i); 1.338 + /* R = 2^4 * R */ 1.339 + MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); 1.340 + MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); 1.341 + MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); 1.342 + MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); 1.343 + /* R = R + (ni * P) */ 1.344 + MP_CHECKOK(ec_GFp_pt_add_jac_aff 1.345 + (rx, ry, &rz, &precomp[ni][0], &precomp[ni][1], rx, ry, 1.346 + &rz, group)); 1.347 + } 1.348 + 1.349 + /* convert result S to affine coordinates */ 1.350 + MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group)); 1.351 + 1.352 + CLEANUP: 1.353 + mp_clear(&rz); 1.354 + for (i = 0; i < 16; i++) { 1.355 + mp_clear(&precomp[i][0]); 1.356 + mp_clear(&precomp[i][1]); 1.357 + } 1.358 + return res; 1.359 +} 1.360 +#endif 1.361 + 1.362 +/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G + 1.363 + * k2 * P(x, y), where G is the generator (base point) of the group of 1.364 + * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL. 1.365 + * Uses mixed Jacobian-affine coordinates. Input and output values are 1.366 + * assumed to be NOT field-encoded. Uses algorithm 15 (simultaneous 1.367 + * multiple point multiplication) from Brown, Hankerson, Lopez, Menezes. 1.368 + * Software Implementation of the NIST Elliptic Curves over Prime Fields. */ 1.369 +mp_err 1.370 +ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px, 1.371 + const mp_int *py, mp_int *rx, mp_int *ry, 1.372 + const ECGroup *group) 1.373 +{ 1.374 + mp_err res = MP_OKAY; 1.375 + mp_int precomp[4][4][2]; 1.376 + mp_int rz; 1.377 + const mp_int *a, *b; 1.378 + int i, j; 1.379 + int ai, bi, d; 1.380 + 1.381 + for (i = 0; i < 4; i++) { 1.382 + for (j = 0; j < 4; j++) { 1.383 + MP_DIGITS(&precomp[i][j][0]) = 0; 1.384 + MP_DIGITS(&precomp[i][j][1]) = 0; 1.385 + } 1.386 + } 1.387 + MP_DIGITS(&rz) = 0; 1.388 + 1.389 + ARGCHK(group != NULL, MP_BADARG); 1.390 + ARGCHK(!((k1 == NULL) 1.391 + && ((k2 == NULL) || (px == NULL) 1.392 + || (py == NULL))), MP_BADARG); 1.393 + 1.394 + /* if some arguments are not defined used ECPoint_mul */ 1.395 + if (k1 == NULL) { 1.396 + return ECPoint_mul(group, k2, px, py, rx, ry); 1.397 + } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) { 1.398 + return ECPoint_mul(group, k1, NULL, NULL, rx, ry); 1.399 + } 1.400 + 1.401 + /* initialize precomputation table */ 1.402 + for (i = 0; i < 4; i++) { 1.403 + for (j = 0; j < 4; j++) { 1.404 + MP_CHECKOK(mp_init(&precomp[i][j][0])); 1.405 + MP_CHECKOK(mp_init(&precomp[i][j][1])); 1.406 + } 1.407 + } 1.408 + 1.409 + /* fill precomputation table */ 1.410 + /* assign {k1, k2} = {a, b} such that len(a) >= len(b) */ 1.411 + if (mpl_significant_bits(k1) < mpl_significant_bits(k2)) { 1.412 + a = k2; 1.413 + b = k1; 1.414 + if (group->meth->field_enc) { 1.415 + MP_CHECKOK(group->meth-> 1.416 + field_enc(px, &precomp[1][0][0], group->meth)); 1.417 + MP_CHECKOK(group->meth-> 1.418 + field_enc(py, &precomp[1][0][1], group->meth)); 1.419 + } else { 1.420 + MP_CHECKOK(mp_copy(px, &precomp[1][0][0])); 1.421 + MP_CHECKOK(mp_copy(py, &precomp[1][0][1])); 1.422 + } 1.423 + MP_CHECKOK(mp_copy(&group->genx, &precomp[0][1][0])); 1.424 + MP_CHECKOK(mp_copy(&group->geny, &precomp[0][1][1])); 1.425 + } else { 1.426 + a = k1; 1.427 + b = k2; 1.428 + MP_CHECKOK(mp_copy(&group->genx, &precomp[1][0][0])); 1.429 + MP_CHECKOK(mp_copy(&group->geny, &precomp[1][0][1])); 1.430 + if (group->meth->field_enc) { 1.431 + MP_CHECKOK(group->meth-> 1.432 + field_enc(px, &precomp[0][1][0], group->meth)); 1.433 + MP_CHECKOK(group->meth-> 1.434 + field_enc(py, &precomp[0][1][1], group->meth)); 1.435 + } else { 1.436 + MP_CHECKOK(mp_copy(px, &precomp[0][1][0])); 1.437 + MP_CHECKOK(mp_copy(py, &precomp[0][1][1])); 1.438 + } 1.439 + } 1.440 + /* precompute [*][0][*] */ 1.441 + mp_zero(&precomp[0][0][0]); 1.442 + mp_zero(&precomp[0][0][1]); 1.443 + MP_CHECKOK(group-> 1.444 + point_dbl(&precomp[1][0][0], &precomp[1][0][1], 1.445 + &precomp[2][0][0], &precomp[2][0][1], group)); 1.446 + MP_CHECKOK(group-> 1.447 + point_add(&precomp[1][0][0], &precomp[1][0][1], 1.448 + &precomp[2][0][0], &precomp[2][0][1], 1.449 + &precomp[3][0][0], &precomp[3][0][1], group)); 1.450 + /* precompute [*][1][*] */ 1.451 + for (i = 1; i < 4; i++) { 1.452 + MP_CHECKOK(group-> 1.453 + point_add(&precomp[0][1][0], &precomp[0][1][1], 1.454 + &precomp[i][0][0], &precomp[i][0][1], 1.455 + &precomp[i][1][0], &precomp[i][1][1], group)); 1.456 + } 1.457 + /* precompute [*][2][*] */ 1.458 + MP_CHECKOK(group-> 1.459 + point_dbl(&precomp[0][1][0], &precomp[0][1][1], 1.460 + &precomp[0][2][0], &precomp[0][2][1], group)); 1.461 + for (i = 1; i < 4; i++) { 1.462 + MP_CHECKOK(group-> 1.463 + point_add(&precomp[0][2][0], &precomp[0][2][1], 1.464 + &precomp[i][0][0], &precomp[i][0][1], 1.465 + &precomp[i][2][0], &precomp[i][2][1], group)); 1.466 + } 1.467 + /* precompute [*][3][*] */ 1.468 + MP_CHECKOK(group-> 1.469 + point_add(&precomp[0][1][0], &precomp[0][1][1], 1.470 + &precomp[0][2][0], &precomp[0][2][1], 1.471 + &precomp[0][3][0], &precomp[0][3][1], group)); 1.472 + for (i = 1; i < 4; i++) { 1.473 + MP_CHECKOK(group-> 1.474 + point_add(&precomp[0][3][0], &precomp[0][3][1], 1.475 + &precomp[i][0][0], &precomp[i][0][1], 1.476 + &precomp[i][3][0], &precomp[i][3][1], group)); 1.477 + } 1.478 + 1.479 + d = (mpl_significant_bits(a) + 1) / 2; 1.480 + 1.481 + /* R = inf */ 1.482 + MP_CHECKOK(mp_init(&rz)); 1.483 + MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz)); 1.484 + 1.485 + for (i = d - 1; i >= 0; i--) { 1.486 + ai = MP_GET_BIT(a, 2 * i + 1); 1.487 + ai <<= 1; 1.488 + ai |= MP_GET_BIT(a, 2 * i); 1.489 + bi = MP_GET_BIT(b, 2 * i + 1); 1.490 + bi <<= 1; 1.491 + bi |= MP_GET_BIT(b, 2 * i); 1.492 + /* R = 2^2 * R */ 1.493 + MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); 1.494 + MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); 1.495 + /* R = R + (ai * A + bi * B) */ 1.496 + MP_CHECKOK(ec_GFp_pt_add_jac_aff 1.497 + (rx, ry, &rz, &precomp[ai][bi][0], &precomp[ai][bi][1], 1.498 + rx, ry, &rz, group)); 1.499 + } 1.500 + 1.501 + MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group)); 1.502 + 1.503 + if (group->meth->field_dec) { 1.504 + MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth)); 1.505 + MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth)); 1.506 + } 1.507 + 1.508 + CLEANUP: 1.509 + mp_clear(&rz); 1.510 + for (i = 0; i < 4; i++) { 1.511 + for (j = 0; j < 4; j++) { 1.512 + mp_clear(&precomp[i][j][0]); 1.513 + mp_clear(&precomp[i][j][1]); 1.514 + } 1.515 + } 1.516 + return res; 1.517 +}