| 1 | /* |
| 2 | * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. |
| 3 | * Use is subject to license terms. |
| 4 | * |
| 5 | * This library is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU Lesser General Public |
| 7 | * License as published by the Free Software Foundation; either |
| 8 | * version 2.1 of the License, or (at your option) any later version. |
| 9 | * |
| 10 | * This library is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | * Lesser General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU Lesser General Public License |
| 16 | * along with this library; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | */ |
| 23 | |
| 24 | /* ********************************************************************* |
| 25 | * |
| 26 | * The Original Code is the elliptic curve math library for prime field curves. |
| 27 | * |
| 28 | * The Initial Developer of the Original Code is |
| 29 | * Sun Microsystems, Inc. |
| 30 | * Portions created by the Initial Developer are Copyright (C) 2003 |
| 31 | * the Initial Developer. All Rights Reserved. |
| 32 | * |
| 33 | * Contributor(s): |
| 34 | * Sheueling Chang-Shantz <sheueling.chang@sun.com>, |
| 35 | * Stephen Fung <fungstep@hotmail.com>, and |
| 36 | * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories. |
| 37 | * Bodo Moeller <moeller@cdc.informatik.tu-darmstadt.de>, |
| 38 | * Nils Larsch <nla@trustcenter.de>, and |
| 39 | * Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project |
| 40 | * |
| 41 | * Last Modified Date from the Original Code: May 2017 |
| 42 | *********************************************************************** */ |
| 43 | |
| 44 | #include "ecp.h" |
| 45 | #include "mplogic.h" |
| 46 | #ifndef _KERNEL |
| 47 | #include <stdlib.h> |
| 48 | #endif |
| 49 | |
| 50 | /* Checks if point P(px, py) is at infinity. Uses affine coordinates. */ |
| 51 | mp_err |
| 52 | ec_GFp_pt_is_inf_aff(const mp_int *px, const mp_int *py) |
| 53 | { |
| 54 | |
| 55 | if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) { |
| 56 | return MP_YES; |
| 57 | } else { |
| 58 | return MP_NO; |
| 59 | } |
| 60 | |
| 61 | } |
| 62 | |
| 63 | /* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */ |
| 64 | mp_err |
| 65 | ec_GFp_pt_set_inf_aff(mp_int *px, mp_int *py) |
| 66 | { |
| 67 | mp_zero(px); |
| 68 | mp_zero(py); |
| 69 | return MP_OKAY; |
| 70 | } |
| 71 | |
| 72 | /* Computes R = P + Q based on IEEE P1363 A.10.1. Elliptic curve points P, |
| 73 | * Q, and R can all be identical. Uses affine coordinates. Assumes input |
| 74 | * is already field-encoded using field_enc, and returns output that is |
| 75 | * still field-encoded. */ |
| 76 | mp_err |
| 77 | ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py, const mp_int *qx, |
| 78 | const mp_int *qy, mp_int *rx, mp_int *ry, |
| 79 | const ECGroup *group) |
| 80 | { |
| 81 | mp_err res = MP_OKAY; |
| 82 | mp_int lambda, temp, tempx, tempy; |
| 83 | |
| 84 | MP_DIGITS(&lambda) = 0; |
| 85 | MP_DIGITS(&temp) = 0; |
| 86 | MP_DIGITS(&tempx) = 0; |
| 87 | MP_DIGITS(&tempy) = 0; |
| 88 | MP_CHECKOK(mp_init(&lambda, FLAG(px))); |
| 89 | MP_CHECKOK(mp_init(&temp, FLAG(px))); |
| 90 | MP_CHECKOK(mp_init(&tempx, FLAG(px))); |
| 91 | MP_CHECKOK(mp_init(&tempy, FLAG(px))); |
| 92 | /* if P = inf, then R = Q */ |
| 93 | if (ec_GFp_pt_is_inf_aff(px, py) == 0) { |
| 94 | MP_CHECKOK(mp_copy(qx, rx)); |
| 95 | MP_CHECKOK(mp_copy(qy, ry)); |
| 96 | res = MP_OKAY; |
| 97 | goto CLEANUP; |
| 98 | } |
| 99 | /* if Q = inf, then R = P */ |
| 100 | if (ec_GFp_pt_is_inf_aff(qx, qy) == 0) { |
| 101 | MP_CHECKOK(mp_copy(px, rx)); |
| 102 | MP_CHECKOK(mp_copy(py, ry)); |
| 103 | res = MP_OKAY; |
| 104 | goto CLEANUP; |
| 105 | } |
| 106 | /* if px != qx, then lambda = (py-qy) / (px-qx) */ |
| 107 | if (mp_cmp(px, qx) != 0) { |
| 108 | MP_CHECKOK(group->meth->field_sub(py, qy, &tempy, group->meth)); |
| 109 | MP_CHECKOK(group->meth->field_sub(px, qx, &tempx, group->meth)); |
| 110 | MP_CHECKOK(group->meth-> |
| 111 | field_div(&tempy, &tempx, &lambda, group->meth)); |
| 112 | } else { |
| 113 | /* if py != qy or qy = 0, then R = inf */ |
| 114 | if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qy) == 0)) { |
| 115 | mp_zero(rx); |
| 116 | mp_zero(ry); |
| 117 | res = MP_OKAY; |
| 118 | goto CLEANUP; |
| 119 | } |
| 120 | /* lambda = (3qx^2+a) / (2qy) */ |
| 121 | MP_CHECKOK(group->meth->field_sqr(qx, &tempx, group->meth)); |
| 122 | MP_CHECKOK(mp_set_int(&temp, 3)); |
| 123 | if (group->meth->field_enc) { |
| 124 | MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth)); |
| 125 | } |
| 126 | MP_CHECKOK(group->meth-> |
| 127 | field_mul(&tempx, &temp, &tempx, group->meth)); |
| 128 | MP_CHECKOK(group->meth-> |
| 129 | field_add(&tempx, &group->curvea, &tempx, group->meth)); |
| 130 | MP_CHECKOK(mp_set_int(&temp, 2)); |
| 131 | if (group->meth->field_enc) { |
| 132 | MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth)); |
| 133 | } |
| 134 | MP_CHECKOK(group->meth->field_mul(qy, &temp, &tempy, group->meth)); |
| 135 | MP_CHECKOK(group->meth-> |
| 136 | field_div(&tempx, &tempy, &lambda, group->meth)); |
| 137 | } |
| 138 | /* rx = lambda^2 - px - qx */ |
| 139 | MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth)); |
| 140 | MP_CHECKOK(group->meth->field_sub(&tempx, px, &tempx, group->meth)); |
| 141 | MP_CHECKOK(group->meth->field_sub(&tempx, qx, &tempx, group->meth)); |
| 142 | /* ry = (x1-x2) * lambda - y1 */ |
| 143 | MP_CHECKOK(group->meth->field_sub(qx, &tempx, &tempy, group->meth)); |
| 144 | MP_CHECKOK(group->meth-> |
| 145 | field_mul(&tempy, &lambda, &tempy, group->meth)); |
| 146 | MP_CHECKOK(group->meth->field_sub(&tempy, qy, &tempy, group->meth)); |
| 147 | MP_CHECKOK(mp_copy(&tempx, rx)); |
| 148 | MP_CHECKOK(mp_copy(&tempy, ry)); |
| 149 | |
| 150 | CLEANUP: |
| 151 | mp_clear(&lambda); |
| 152 | mp_clear(&temp); |
| 153 | mp_clear(&tempx); |
| 154 | mp_clear(&tempy); |
| 155 | return res; |
| 156 | } |
| 157 | |
| 158 | /* Computes R = P - Q. Elliptic curve points P, Q, and R can all be |
| 159 | * identical. Uses affine coordinates. Assumes input is already |
| 160 | * field-encoded using field_enc, and returns output that is still |
| 161 | * field-encoded. */ |
| 162 | mp_err |
| 163 | ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx, |
| 164 | const mp_int *qy, mp_int *rx, mp_int *ry, |
| 165 | const ECGroup *group) |
| 166 | { |
| 167 | mp_err res = MP_OKAY; |
| 168 | mp_int nqy; |
| 169 | |
| 170 | MP_DIGITS(&nqy) = 0; |
| 171 | MP_CHECKOK(mp_init(&nqy, FLAG(px))); |
| 172 | /* nqy = -qy */ |
| 173 | MP_CHECKOK(group->meth->field_neg(qy, &nqy, group->meth)); |
| 174 | res = group->point_add(px, py, qx, &nqy, rx, ry, group); |
| 175 | CLEANUP: |
| 176 | mp_clear(&nqy); |
| 177 | return res; |
| 178 | } |
| 179 | |
| 180 | /* Computes R = 2P. Elliptic curve points P and R can be identical. Uses |
| 181 | * affine coordinates. Assumes input is already field-encoded using |
| 182 | * field_enc, and returns output that is still field-encoded. */ |
| 183 | mp_err |
| 184 | ec_GFp_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx, |
| 185 | mp_int *ry, const ECGroup *group) |
| 186 | { |
| 187 | return ec_GFp_pt_add_aff(px, py, px, py, rx, ry, group); |
| 188 | } |
| 189 | |
| 190 | /* by default, this routine is unused and thus doesn't need to be compiled */ |
| 191 | #ifdef ECL_ENABLE_GFP_PT_MUL_AFF |
| 192 | /* Computes R = nP based on IEEE P1363 A.10.3. Elliptic curve points P and |
| 193 | * R can be identical. Uses affine coordinates. Assumes input is already |
| 194 | * field-encoded using field_enc, and returns output that is still |
| 195 | * field-encoded. */ |
| 196 | mp_err |
| 197 | ec_GFp_pt_mul_aff(const mp_int *n, const mp_int *px, const mp_int *py, |
| 198 | mp_int *rx, mp_int *ry, const ECGroup *group) |
| 199 | { |
| 200 | mp_err res = MP_OKAY; |
| 201 | mp_int k, k3, qx, qy, sx, sy; |
| 202 | int b1, b3, i, l; |
| 203 | |
| 204 | MP_DIGITS(&k) = 0; |
| 205 | MP_DIGITS(&k3) = 0; |
| 206 | MP_DIGITS(&qx) = 0; |
| 207 | MP_DIGITS(&qy) = 0; |
| 208 | MP_DIGITS(&sx) = 0; |
| 209 | MP_DIGITS(&sy) = 0; |
| 210 | MP_CHECKOK(mp_init(&k)); |
| 211 | MP_CHECKOK(mp_init(&k3)); |
| 212 | MP_CHECKOK(mp_init(&qx)); |
| 213 | MP_CHECKOK(mp_init(&qy)); |
| 214 | MP_CHECKOK(mp_init(&sx)); |
| 215 | MP_CHECKOK(mp_init(&sy)); |
| 216 | |
| 217 | /* if n = 0 then r = inf */ |
| 218 | if (mp_cmp_z(n) == 0) { |
| 219 | mp_zero(rx); |
| 220 | mp_zero(ry); |
| 221 | res = MP_OKAY; |
| 222 | goto CLEANUP; |
| 223 | } |
| 224 | /* Q = P, k = n */ |
| 225 | MP_CHECKOK(mp_copy(px, &qx)); |
| 226 | MP_CHECKOK(mp_copy(py, &qy)); |
| 227 | MP_CHECKOK(mp_copy(n, &k)); |
| 228 | /* if n < 0 then Q = -Q, k = -k */ |
| 229 | if (mp_cmp_z(n) < 0) { |
| 230 | MP_CHECKOK(group->meth->field_neg(&qy, &qy, group->meth)); |
| 231 | MP_CHECKOK(mp_neg(&k, &k)); |
| 232 | } |
| 233 | #ifdef ECL_DEBUG /* basic double and add method */ |
| 234 | l = mpl_significant_bits(&k) - 1; |
| 235 | MP_CHECKOK(mp_copy(&qx, &sx)); |
| 236 | MP_CHECKOK(mp_copy(&qy, &sy)); |
| 237 | for (i = l - 1; i >= 0; i--) { |
| 238 | /* S = 2S */ |
| 239 | MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group)); |
| 240 | /* if k_i = 1, then S = S + Q */ |
| 241 | if (mpl_get_bit(&k, i) != 0) { |
| 242 | MP_CHECKOK(group-> |
| 243 | point_add(&sx, &sy, &qx, &qy, &sx, &sy, group)); |
| 244 | } |
| 245 | } |
| 246 | #else /* double and add/subtract method from |
| 247 | * standard */ |
| 248 | /* k3 = 3 * k */ |
| 249 | MP_CHECKOK(mp_set_int(&k3, 3)); |
| 250 | MP_CHECKOK(mp_mul(&k, &k3, &k3)); |
| 251 | /* S = Q */ |
| 252 | MP_CHECKOK(mp_copy(&qx, &sx)); |
| 253 | MP_CHECKOK(mp_copy(&qy, &sy)); |
| 254 | /* l = index of high order bit in binary representation of 3*k */ |
| 255 | l = mpl_significant_bits(&k3) - 1; |
| 256 | /* for i = l-1 downto 1 */ |
| 257 | for (i = l - 1; i >= 1; i--) { |
| 258 | /* S = 2S */ |
| 259 | MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group)); |
| 260 | b3 = MP_GET_BIT(&k3, i); |
| 261 | b1 = MP_GET_BIT(&k, i); |
| 262 | /* if k3_i = 1 and k_i = 0, then S = S + Q */ |
| 263 | if ((b3 == 1) && (b1 == 0)) { |
| 264 | MP_CHECKOK(group-> |
| 265 | point_add(&sx, &sy, &qx, &qy, &sx, &sy, group)); |
| 266 | /* if k3_i = 0 and k_i = 1, then S = S - Q */ |
| 267 | } else if ((b3 == 0) && (b1 == 1)) { |
| 268 | MP_CHECKOK(group-> |
| 269 | point_sub(&sx, &sy, &qx, &qy, &sx, &sy, group)); |
| 270 | } |
| 271 | } |
| 272 | #endif |
| 273 | /* output S */ |
| 274 | MP_CHECKOK(mp_copy(&sx, rx)); |
| 275 | MP_CHECKOK(mp_copy(&sy, ry)); |
| 276 | |
| 277 | CLEANUP: |
| 278 | mp_clear(&k); |
| 279 | mp_clear(&k3); |
| 280 | mp_clear(&qx); |
| 281 | mp_clear(&qy); |
| 282 | mp_clear(&sx); |
| 283 | mp_clear(&sy); |
| 284 | return res; |
| 285 | } |
| 286 | #endif |
| 287 | |
| 288 | /* Validates a point on a GFp curve. */ |
| 289 | mp_err |
| 290 | ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group) |
| 291 | { |
| 292 | mp_err res = MP_NO; |
| 293 | mp_int accl, accr, tmp, pxt, pyt; |
| 294 | |
| 295 | MP_DIGITS(&accl) = 0; |
| 296 | MP_DIGITS(&accr) = 0; |
| 297 | MP_DIGITS(&tmp) = 0; |
| 298 | MP_DIGITS(&pxt) = 0; |
| 299 | MP_DIGITS(&pyt) = 0; |
| 300 | MP_CHECKOK(mp_init(&accl, FLAG(px))); |
| 301 | MP_CHECKOK(mp_init(&accr, FLAG(px))); |
| 302 | MP_CHECKOK(mp_init(&tmp, FLAG(px))); |
| 303 | MP_CHECKOK(mp_init(&pxt, FLAG(px))); |
| 304 | MP_CHECKOK(mp_init(&pyt, FLAG(px))); |
| 305 | |
| 306 | /* 1: Verify that publicValue is not the point at infinity */ |
| 307 | if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) { |
| 308 | res = MP_NO; |
| 309 | goto CLEANUP; |
| 310 | } |
| 311 | /* 2: Verify that the coordinates of publicValue are elements |
| 312 | * of the field. |
| 313 | */ |
| 314 | if ((MP_SIGN(px) == MP_NEG) || (mp_cmp(px, &group->meth->irr) >= 0) || |
| 315 | (MP_SIGN(py) == MP_NEG) || (mp_cmp(py, &group->meth->irr) >= 0)) { |
| 316 | res = MP_NO; |
| 317 | goto CLEANUP; |
| 318 | } |
| 319 | /* 3: Verify that publicValue is on the curve. */ |
| 320 | if (group->meth->field_enc) { |
| 321 | group->meth->field_enc(px, &pxt, group->meth); |
| 322 | group->meth->field_enc(py, &pyt, group->meth); |
| 323 | } else { |
| 324 | mp_copy(px, &pxt); |
| 325 | mp_copy(py, &pyt); |
| 326 | } |
| 327 | /* left-hand side: y^2 */ |
| 328 | MP_CHECKOK( group->meth->field_sqr(&pyt, &accl, group->meth) ); |
| 329 | /* right-hand side: x^3 + a*x + b */ |
| 330 | MP_CHECKOK( group->meth->field_sqr(&pxt, &tmp, group->meth) ); |
| 331 | MP_CHECKOK( group->meth->field_mul(&pxt, &tmp, &accr, group->meth) ); |
| 332 | MP_CHECKOK( group->meth->field_mul(&group->curvea, &pxt, &tmp, group->meth) ); |
| 333 | MP_CHECKOK( group->meth->field_add(&tmp, &accr, &accr, group->meth) ); |
| 334 | MP_CHECKOK( group->meth->field_add(&accr, &group->curveb, &accr, group->meth) ); |
| 335 | /* check LHS - RHS == 0 */ |
| 336 | MP_CHECKOK( group->meth->field_sub(&accl, &accr, &accr, group->meth) ); |
| 337 | if (mp_cmp_z(&accr) != 0) { |
| 338 | res = MP_NO; |
| 339 | goto CLEANUP; |
| 340 | } |
| 341 | /* 4: Verify that the order of the curve times the publicValue |
| 342 | * is the point at infinity. |
| 343 | */ |
| 344 | /* timing mitigation is not supported */ |
| 345 | MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) ); |
| 346 | if (ec_GFp_pt_is_inf_aff(&pxt, &pyt) != MP_YES) { |
| 347 | res = MP_NO; |
| 348 | goto CLEANUP; |
| 349 | } |
| 350 | |
| 351 | res = MP_YES; |
| 352 | |
| 353 | CLEANUP: |
| 354 | mp_clear(&accl); |
| 355 | mp_clear(&accr); |
| 356 | mp_clear(&tmp); |
| 357 | mp_clear(&pxt); |
| 358 | mp_clear(&pyt); |
| 359 | return res; |
| 360 | } |
| 361 | |