1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/ecl/ecp_jm.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,289 @@ 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 "ecl-priv.h" 1.10 +#include "mplogic.h" 1.11 +#include <stdlib.h> 1.12 + 1.13 +#define MAX_SCRATCH 6 1.14 + 1.15 +/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses 1.16 + * Modified Jacobian coordinates. 1.17 + * 1.18 + * Assumes input is already field-encoded using field_enc, and returns 1.19 + * output that is still field-encoded. 1.20 + * 1.21 + */ 1.22 +mp_err 1.23 +ec_GFp_pt_dbl_jm(const mp_int *px, const mp_int *py, const mp_int *pz, 1.24 + const mp_int *paz4, mp_int *rx, mp_int *ry, mp_int *rz, 1.25 + mp_int *raz4, mp_int scratch[], const ECGroup *group) 1.26 +{ 1.27 + mp_err res = MP_OKAY; 1.28 + mp_int *t0, *t1, *M, *S; 1.29 + 1.30 + t0 = &scratch[0]; 1.31 + t1 = &scratch[1]; 1.32 + M = &scratch[2]; 1.33 + S = &scratch[3]; 1.34 + 1.35 +#if MAX_SCRATCH < 4 1.36 +#error "Scratch array defined too small " 1.37 +#endif 1.38 + 1.39 + /* Check for point at infinity */ 1.40 + if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { 1.41 + /* Set r = pt at infinity by setting rz = 0 */ 1.42 + 1.43 + MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); 1.44 + goto CLEANUP; 1.45 + } 1.46 + 1.47 + /* M = 3 (px^2) + a*(pz^4) */ 1.48 + MP_CHECKOK(group->meth->field_sqr(px, t0, group->meth)); 1.49 + MP_CHECKOK(group->meth->field_add(t0, t0, M, group->meth)); 1.50 + MP_CHECKOK(group->meth->field_add(t0, M, t0, group->meth)); 1.51 + MP_CHECKOK(group->meth->field_add(t0, paz4, M, group->meth)); 1.52 + 1.53 + /* rz = 2 * py * pz */ 1.54 + MP_CHECKOK(group->meth->field_mul(py, pz, S, group->meth)); 1.55 + MP_CHECKOK(group->meth->field_add(S, S, rz, group->meth)); 1.56 + 1.57 + /* t0 = 2y^2 , t1 = 8y^4 */ 1.58 + MP_CHECKOK(group->meth->field_sqr(py, t0, group->meth)); 1.59 + MP_CHECKOK(group->meth->field_add(t0, t0, t0, group->meth)); 1.60 + MP_CHECKOK(group->meth->field_sqr(t0, t1, group->meth)); 1.61 + MP_CHECKOK(group->meth->field_add(t1, t1, t1, group->meth)); 1.62 + 1.63 + /* S = 4 * px * py^2 = 2 * px * t0 */ 1.64 + MP_CHECKOK(group->meth->field_mul(px, t0, S, group->meth)); 1.65 + MP_CHECKOK(group->meth->field_add(S, S, S, group->meth)); 1.66 + 1.67 + 1.68 + /* rx = M^2 - 2S */ 1.69 + MP_CHECKOK(group->meth->field_sqr(M, rx, group->meth)); 1.70 + MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth)); 1.71 + MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth)); 1.72 + 1.73 + /* ry = M * (S - rx) - t1 */ 1.74 + MP_CHECKOK(group->meth->field_sub(S, rx, S, group->meth)); 1.75 + MP_CHECKOK(group->meth->field_mul(S, M, ry, group->meth)); 1.76 + MP_CHECKOK(group->meth->field_sub(ry, t1, ry, group->meth)); 1.77 + 1.78 + /* ra*z^4 = 2*t1*(apz4) */ 1.79 + MP_CHECKOK(group->meth->field_mul(paz4, t1, raz4, group->meth)); 1.80 + MP_CHECKOK(group->meth->field_add(raz4, raz4, raz4, group->meth)); 1.81 + 1.82 + 1.83 + CLEANUP: 1.84 + return res; 1.85 +} 1.86 + 1.87 +/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is 1.88 + * (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical. 1.89 + * Uses mixed Modified_Jacobian-affine coordinates. Assumes input is 1.90 + * already field-encoded using field_enc, and returns output that is still 1.91 + * field-encoded. */ 1.92 +mp_err 1.93 +ec_GFp_pt_add_jm_aff(const mp_int *px, const mp_int *py, const mp_int *pz, 1.94 + const mp_int *paz4, const mp_int *qx, 1.95 + const mp_int *qy, mp_int *rx, mp_int *ry, mp_int *rz, 1.96 + mp_int *raz4, mp_int scratch[], const ECGroup *group) 1.97 +{ 1.98 + mp_err res = MP_OKAY; 1.99 + mp_int *A, *B, *C, *D, *C2, *C3; 1.100 + 1.101 + A = &scratch[0]; 1.102 + B = &scratch[1]; 1.103 + C = &scratch[2]; 1.104 + D = &scratch[3]; 1.105 + C2 = &scratch[4]; 1.106 + C3 = &scratch[5]; 1.107 + 1.108 +#if MAX_SCRATCH < 6 1.109 +#error "Scratch array defined too small " 1.110 +#endif 1.111 + 1.112 + /* If either P or Q is the point at infinity, then return the other 1.113 + * point */ 1.114 + if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { 1.115 + MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group)); 1.116 + MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth)); 1.117 + MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth)); 1.118 + MP_CHECKOK(group->meth-> 1.119 + field_mul(raz4, &group->curvea, raz4, group->meth)); 1.120 + goto CLEANUP; 1.121 + } 1.122 + if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) { 1.123 + MP_CHECKOK(mp_copy(px, rx)); 1.124 + MP_CHECKOK(mp_copy(py, ry)); 1.125 + MP_CHECKOK(mp_copy(pz, rz)); 1.126 + MP_CHECKOK(mp_copy(paz4, raz4)); 1.127 + goto CLEANUP; 1.128 + } 1.129 + 1.130 + /* A = qx * pz^2, B = qy * pz^3 */ 1.131 + MP_CHECKOK(group->meth->field_sqr(pz, A, group->meth)); 1.132 + MP_CHECKOK(group->meth->field_mul(A, pz, B, group->meth)); 1.133 + MP_CHECKOK(group->meth->field_mul(A, qx, A, group->meth)); 1.134 + MP_CHECKOK(group->meth->field_mul(B, qy, B, group->meth)); 1.135 + 1.136 + /* C = A - px, D = B - py */ 1.137 + MP_CHECKOK(group->meth->field_sub(A, px, C, group->meth)); 1.138 + MP_CHECKOK(group->meth->field_sub(B, py, D, group->meth)); 1.139 + 1.140 + /* C2 = C^2, C3 = C^3 */ 1.141 + MP_CHECKOK(group->meth->field_sqr(C, C2, group->meth)); 1.142 + MP_CHECKOK(group->meth->field_mul(C, C2, C3, group->meth)); 1.143 + 1.144 + /* rz = pz * C */ 1.145 + MP_CHECKOK(group->meth->field_mul(pz, C, rz, group->meth)); 1.146 + 1.147 + /* C = px * C^2 */ 1.148 + MP_CHECKOK(group->meth->field_mul(px, C2, C, group->meth)); 1.149 + /* A = D^2 */ 1.150 + MP_CHECKOK(group->meth->field_sqr(D, A, group->meth)); 1.151 + 1.152 + /* rx = D^2 - (C^3 + 2 * (px * C^2)) */ 1.153 + MP_CHECKOK(group->meth->field_add(C, C, rx, group->meth)); 1.154 + MP_CHECKOK(group->meth->field_add(C3, rx, rx, group->meth)); 1.155 + MP_CHECKOK(group->meth->field_sub(A, rx, rx, group->meth)); 1.156 + 1.157 + /* C3 = py * C^3 */ 1.158 + MP_CHECKOK(group->meth->field_mul(py, C3, C3, group->meth)); 1.159 + 1.160 + /* ry = D * (px * C^2 - rx) - py * C^3 */ 1.161 + MP_CHECKOK(group->meth->field_sub(C, rx, ry, group->meth)); 1.162 + MP_CHECKOK(group->meth->field_mul(D, ry, ry, group->meth)); 1.163 + MP_CHECKOK(group->meth->field_sub(ry, C3, ry, group->meth)); 1.164 + 1.165 + /* raz4 = a * rz^4 */ 1.166 + MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth)); 1.167 + MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth)); 1.168 + MP_CHECKOK(group->meth-> 1.169 + field_mul(raz4, &group->curvea, raz4, group->meth)); 1.170 +CLEANUP: 1.171 + return res; 1.172 +} 1.173 + 1.174 +/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic 1.175 + * curve points P and R can be identical. Uses mixed Modified-Jacobian 1.176 + * co-ordinates for doubling and Chudnovsky Jacobian coordinates for 1.177 + * additions. Assumes input is already field-encoded using field_enc, and 1.178 + * returns output that is still field-encoded. Uses 5-bit window NAF 1.179 + * method (algorithm 11) for scalar-point multiplication from Brown, 1.180 + * Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic 1.181 + * Curves Over Prime Fields. */ 1.182 +mp_err 1.183 +ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py, 1.184 + mp_int *rx, mp_int *ry, const ECGroup *group) 1.185 +{ 1.186 + mp_err res = MP_OKAY; 1.187 + mp_int precomp[16][2], rz, tpx, tpy; 1.188 + mp_int raz4; 1.189 + mp_int scratch[MAX_SCRATCH]; 1.190 + signed char *naf = NULL; 1.191 + int i, orderBitSize; 1.192 + 1.193 + MP_DIGITS(&rz) = 0; 1.194 + MP_DIGITS(&raz4) = 0; 1.195 + MP_DIGITS(&tpx) = 0; 1.196 + MP_DIGITS(&tpy) = 0; 1.197 + for (i = 0; i < 16; i++) { 1.198 + MP_DIGITS(&precomp[i][0]) = 0; 1.199 + MP_DIGITS(&precomp[i][1]) = 0; 1.200 + } 1.201 + for (i = 0; i < MAX_SCRATCH; i++) { 1.202 + MP_DIGITS(&scratch[i]) = 0; 1.203 + } 1.204 + 1.205 + ARGCHK(group != NULL, MP_BADARG); 1.206 + ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG); 1.207 + 1.208 + /* initialize precomputation table */ 1.209 + MP_CHECKOK(mp_init(&tpx)); 1.210 + MP_CHECKOK(mp_init(&tpy));; 1.211 + MP_CHECKOK(mp_init(&rz)); 1.212 + MP_CHECKOK(mp_init(&raz4)); 1.213 + 1.214 + for (i = 0; i < 16; i++) { 1.215 + MP_CHECKOK(mp_init(&precomp[i][0])); 1.216 + MP_CHECKOK(mp_init(&precomp[i][1])); 1.217 + } 1.218 + for (i = 0; i < MAX_SCRATCH; i++) { 1.219 + MP_CHECKOK(mp_init(&scratch[i])); 1.220 + } 1.221 + 1.222 + /* Set out[8] = P */ 1.223 + MP_CHECKOK(mp_copy(px, &precomp[8][0])); 1.224 + MP_CHECKOK(mp_copy(py, &precomp[8][1])); 1.225 + 1.226 + /* Set (tpx, tpy) = 2P */ 1.227 + MP_CHECKOK(group-> 1.228 + point_dbl(&precomp[8][0], &precomp[8][1], &tpx, &tpy, 1.229 + group)); 1.230 + 1.231 + /* Set 3P, 5P, ..., 15P */ 1.232 + for (i = 8; i < 15; i++) { 1.233 + MP_CHECKOK(group-> 1.234 + point_add(&precomp[i][0], &precomp[i][1], &tpx, &tpy, 1.235 + &precomp[i + 1][0], &precomp[i + 1][1], 1.236 + group)); 1.237 + } 1.238 + 1.239 + /* Set -15P, -13P, ..., -P */ 1.240 + for (i = 0; i < 8; i++) { 1.241 + MP_CHECKOK(mp_copy(&precomp[15 - i][0], &precomp[i][0])); 1.242 + MP_CHECKOK(group->meth-> 1.243 + field_neg(&precomp[15 - i][1], &precomp[i][1], 1.244 + group->meth)); 1.245 + } 1.246 + 1.247 + /* R = inf */ 1.248 + MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz)); 1.249 + 1.250 + orderBitSize = mpl_significant_bits(&group->order); 1.251 + 1.252 + /* Allocate memory for NAF */ 1.253 + naf = (signed char *) malloc(sizeof(signed char) * (orderBitSize + 1)); 1.254 + if (naf == NULL) { 1.255 + res = MP_MEM; 1.256 + goto CLEANUP; 1.257 + } 1.258 + 1.259 + /* Compute 5NAF */ 1.260 + ec_compute_wNAF(naf, orderBitSize, n, 5); 1.261 + 1.262 + /* wNAF method */ 1.263 + for (i = orderBitSize; i >= 0; i--) { 1.264 + /* R = 2R */ 1.265 + ec_GFp_pt_dbl_jm(rx, ry, &rz, &raz4, rx, ry, &rz, 1.266 + &raz4, scratch, group); 1.267 + if (naf[i] != 0) { 1.268 + ec_GFp_pt_add_jm_aff(rx, ry, &rz, &raz4, 1.269 + &precomp[(naf[i] + 15) / 2][0], 1.270 + &precomp[(naf[i] + 15) / 2][1], rx, ry, 1.271 + &rz, &raz4, scratch, group); 1.272 + } 1.273 + } 1.274 + 1.275 + /* convert result S to affine coordinates */ 1.276 + MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group)); 1.277 + 1.278 + CLEANUP: 1.279 + for (i = 0; i < MAX_SCRATCH; i++) { 1.280 + mp_clear(&scratch[i]); 1.281 + } 1.282 + for (i = 0; i < 16; i++) { 1.283 + mp_clear(&precomp[i][0]); 1.284 + mp_clear(&precomp[i][1]); 1.285 + } 1.286 + mp_clear(&tpx); 1.287 + mp_clear(&tpy); 1.288 + mp_clear(&rz); 1.289 + mp_clear(&raz4); 1.290 + free(naf); 1.291 + return res; 1.292 +}