| OLD | NEW |
| (Empty) |
| 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 | |
| 9 /* Checks if point P(px, py) is at infinity. Uses affine coordinates. */ | |
| 10 mp_err | |
| 11 ec_GFp_pt_is_inf_aff(const mp_int *px, const mp_int *py) | |
| 12 { | |
| 13 | |
| 14 if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) { | |
| 15 return MP_YES; | |
| 16 } else { | |
| 17 return MP_NO; | |
| 18 } | |
| 19 | |
| 20 } | |
| 21 | |
| 22 /* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */ | |
| 23 mp_err | |
| 24 ec_GFp_pt_set_inf_aff(mp_int *px, mp_int *py) | |
| 25 { | |
| 26 mp_zero(px); | |
| 27 mp_zero(py); | |
| 28 return MP_OKAY; | |
| 29 } | |
| 30 | |
| 31 /* Computes R = P + Q based on IEEE P1363 A.10.1. Elliptic curve points P, | |
| 32 * Q, and R can all be identical. Uses affine coordinates. Assumes input | |
| 33 * is already field-encoded using field_enc, and returns output that is | |
| 34 * still field-encoded. */ | |
| 35 mp_err | |
| 36 ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py, const mp_int *qx, | |
| 37 const mp_int *qy, mp_int *rx, mp_int *ry, | |
| 38 const ECGroup *group) | |
| 39 { | |
| 40 mp_err res = MP_OKAY; | |
| 41 mp_int lambda, temp, tempx, tempy; | |
| 42 | |
| 43 MP_DIGITS(&lambda) = 0; | |
| 44 MP_DIGITS(&temp) = 0; | |
| 45 MP_DIGITS(&tempx) = 0; | |
| 46 MP_DIGITS(&tempy) = 0; | |
| 47 MP_CHECKOK(mp_init(&lambda)); | |
| 48 MP_CHECKOK(mp_init(&temp)); | |
| 49 MP_CHECKOK(mp_init(&tempx)); | |
| 50 MP_CHECKOK(mp_init(&tempy)); | |
| 51 /* if P = inf, then R = Q */ | |
| 52 if (ec_GFp_pt_is_inf_aff(px, py) == 0) { | |
| 53 MP_CHECKOK(mp_copy(qx, rx)); | |
| 54 MP_CHECKOK(mp_copy(qy, ry)); | |
| 55 res = MP_OKAY; | |
| 56 goto CLEANUP; | |
| 57 } | |
| 58 /* if Q = inf, then R = P */ | |
| 59 if (ec_GFp_pt_is_inf_aff(qx, qy) == 0) { | |
| 60 MP_CHECKOK(mp_copy(px, rx)); | |
| 61 MP_CHECKOK(mp_copy(py, ry)); | |
| 62 res = MP_OKAY; | |
| 63 goto CLEANUP; | |
| 64 } | |
| 65 /* if px != qx, then lambda = (py-qy) / (px-qx) */ | |
| 66 if (mp_cmp(px, qx) != 0) { | |
| 67 MP_CHECKOK(group->meth->field_sub(py, qy, &tempy, group->meth)); | |
| 68 MP_CHECKOK(group->meth->field_sub(px, qx, &tempx, group->meth)); | |
| 69 MP_CHECKOK(group->meth-> | |
| 70 field_div(&tempy, &tempx, &lambda, group->met
h)); | |
| 71 } else { | |
| 72 /* if py != qy or qy = 0, then R = inf */ | |
| 73 if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qy) == 0)) { | |
| 74 mp_zero(rx); | |
| 75 mp_zero(ry); | |
| 76 res = MP_OKAY; | |
| 77 goto CLEANUP; | |
| 78 } | |
| 79 /* lambda = (3qx^2+a) / (2qy) */ | |
| 80 MP_CHECKOK(group->meth->field_sqr(qx, &tempx, group->meth)); | |
| 81 MP_CHECKOK(mp_set_int(&temp, 3)); | |
| 82 if (group->meth->field_enc) { | |
| 83 MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->m
eth)); | |
| 84 } | |
| 85 MP_CHECKOK(group->meth-> | |
| 86 field_mul(&tempx, &temp, &tempx, group->meth)
); | |
| 87 MP_CHECKOK(group->meth-> | |
| 88 field_add(&tempx, &group->curvea, &tempx, gro
up->meth)); | |
| 89 MP_CHECKOK(mp_set_int(&temp, 2)); | |
| 90 if (group->meth->field_enc) { | |
| 91 MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->m
eth)); | |
| 92 } | |
| 93 MP_CHECKOK(group->meth->field_mul(qy, &temp, &tempy, group->meth
)); | |
| 94 MP_CHECKOK(group->meth-> | |
| 95 field_div(&tempx, &tempy, &lambda, group->met
h)); | |
| 96 } | |
| 97 /* rx = lambda^2 - px - qx */ | |
| 98 MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth)); | |
| 99 MP_CHECKOK(group->meth->field_sub(&tempx, px, &tempx, group->meth)); | |
| 100 MP_CHECKOK(group->meth->field_sub(&tempx, qx, &tempx, group->meth)); | |
| 101 /* ry = (x1-x2) * lambda - y1 */ | |
| 102 MP_CHECKOK(group->meth->field_sub(qx, &tempx, &tempy, group->meth)); | |
| 103 MP_CHECKOK(group->meth-> | |
| 104 field_mul(&tempy, &lambda, &tempy, group->meth)); | |
| 105 MP_CHECKOK(group->meth->field_sub(&tempy, qy, &tempy, group->meth)); | |
| 106 MP_CHECKOK(mp_copy(&tempx, rx)); | |
| 107 MP_CHECKOK(mp_copy(&tempy, ry)); | |
| 108 | |
| 109 CLEANUP: | |
| 110 mp_clear(&lambda); | |
| 111 mp_clear(&temp); | |
| 112 mp_clear(&tempx); | |
| 113 mp_clear(&tempy); | |
| 114 return res; | |
| 115 } | |
| 116 | |
| 117 /* Computes R = P - Q. Elliptic curve points P, Q, and R can all be | |
| 118 * identical. Uses affine coordinates. Assumes input is already | |
| 119 * field-encoded using field_enc, and returns output that is still | |
| 120 * field-encoded. */ | |
| 121 mp_err | |
| 122 ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx, | |
| 123 const mp_int *qy, mp_int *rx, mp_int *ry, | |
| 124 const ECGroup *group) | |
| 125 { | |
| 126 mp_err res = MP_OKAY; | |
| 127 mp_int nqy; | |
| 128 | |
| 129 MP_DIGITS(&nqy) = 0; | |
| 130 MP_CHECKOK(mp_init(&nqy)); | |
| 131 /* nqy = -qy */ | |
| 132 MP_CHECKOK(group->meth->field_neg(qy, &nqy, group->meth)); | |
| 133 res = group->point_add(px, py, qx, &nqy, rx, ry, group); | |
| 134 CLEANUP: | |
| 135 mp_clear(&nqy); | |
| 136 return res; | |
| 137 } | |
| 138 | |
| 139 /* Computes R = 2P. Elliptic curve points P and R can be identical. Uses | |
| 140 * affine coordinates. Assumes input is already field-encoded using | |
| 141 * field_enc, and returns output that is still field-encoded. */ | |
| 142 mp_err | |
| 143 ec_GFp_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx, | |
| 144 mp_int *ry, const ECGroup *group) | |
| 145 { | |
| 146 return ec_GFp_pt_add_aff(px, py, px, py, rx, ry, group); | |
| 147 } | |
| 148 | |
| 149 /* by default, this routine is unused and thus doesn't need to be compiled */ | |
| 150 #ifdef ECL_ENABLE_GFP_PT_MUL_AFF | |
| 151 /* Computes R = nP based on IEEE P1363 A.10.3. Elliptic curve points P and | |
| 152 * R can be identical. Uses affine coordinates. Assumes input is already | |
| 153 * field-encoded using field_enc, and returns output that is still | |
| 154 * field-encoded. */ | |
| 155 mp_err | |
| 156 ec_GFp_pt_mul_aff(const mp_int *n, const mp_int *px, const mp_int *py, | |
| 157 mp_int *rx, mp_int *ry, const ECGroup *group) | |
| 158 { | |
| 159 mp_err res = MP_OKAY; | |
| 160 mp_int k, k3, qx, qy, sx, sy; | |
| 161 int b1, b3, i, l; | |
| 162 | |
| 163 MP_DIGITS(&k) = 0; | |
| 164 MP_DIGITS(&k3) = 0; | |
| 165 MP_DIGITS(&qx) = 0; | |
| 166 MP_DIGITS(&qy) = 0; | |
| 167 MP_DIGITS(&sx) = 0; | |
| 168 MP_DIGITS(&sy) = 0; | |
| 169 MP_CHECKOK(mp_init(&k)); | |
| 170 MP_CHECKOK(mp_init(&k3)); | |
| 171 MP_CHECKOK(mp_init(&qx)); | |
| 172 MP_CHECKOK(mp_init(&qy)); | |
| 173 MP_CHECKOK(mp_init(&sx)); | |
| 174 MP_CHECKOK(mp_init(&sy)); | |
| 175 | |
| 176 /* if n = 0 then r = inf */ | |
| 177 if (mp_cmp_z(n) == 0) { | |
| 178 mp_zero(rx); | |
| 179 mp_zero(ry); | |
| 180 res = MP_OKAY; | |
| 181 goto CLEANUP; | |
| 182 } | |
| 183 /* Q = P, k = n */ | |
| 184 MP_CHECKOK(mp_copy(px, &qx)); | |
| 185 MP_CHECKOK(mp_copy(py, &qy)); | |
| 186 MP_CHECKOK(mp_copy(n, &k)); | |
| 187 /* if n < 0 then Q = -Q, k = -k */ | |
| 188 if (mp_cmp_z(n) < 0) { | |
| 189 MP_CHECKOK(group->meth->field_neg(&qy, &qy, group->meth)); | |
| 190 MP_CHECKOK(mp_neg(&k, &k)); | |
| 191 } | |
| 192 #ifdef ECL_DEBUG /* basic double and add method *
/ | |
| 193 l = mpl_significant_bits(&k) - 1; | |
| 194 MP_CHECKOK(mp_copy(&qx, &sx)); | |
| 195 MP_CHECKOK(mp_copy(&qy, &sy)); | |
| 196 for (i = l - 1; i >= 0; i--) { | |
| 197 /* S = 2S */ | |
| 198 MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group)); | |
| 199 /* if k_i = 1, then S = S + Q */ | |
| 200 if (mpl_get_bit(&k, i) != 0) { | |
| 201 MP_CHECKOK(group-> | |
| 202 point_add(&sx, &sy, &qx, &qy, &sx, &s
y, group)); | |
| 203 } | |
| 204 } | |
| 205 #else /* double and add/subtra
ct method from | |
| 206 * standard */ | |
| 207 /* k3 = 3 * k */ | |
| 208 MP_CHECKOK(mp_set_int(&k3, 3)); | |
| 209 MP_CHECKOK(mp_mul(&k, &k3, &k3)); | |
| 210 /* S = Q */ | |
| 211 MP_CHECKOK(mp_copy(&qx, &sx)); | |
| 212 MP_CHECKOK(mp_copy(&qy, &sy)); | |
| 213 /* l = index of high order bit in binary representation of 3*k */ | |
| 214 l = mpl_significant_bits(&k3) - 1; | |
| 215 /* for i = l-1 downto 1 */ | |
| 216 for (i = l - 1; i >= 1; i--) { | |
| 217 /* S = 2S */ | |
| 218 MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group)); | |
| 219 b3 = MP_GET_BIT(&k3, i); | |
| 220 b1 = MP_GET_BIT(&k, i); | |
| 221 /* if k3_i = 1 and k_i = 0, then S = S + Q */ | |
| 222 if ((b3 == 1) && (b1 == 0)) { | |
| 223 MP_CHECKOK(group-> | |
| 224 point_add(&sx, &sy, &qx, &qy, &sx, &s
y, group)); | |
| 225 /* if k3_i = 0 and k_i = 1, then S = S - Q */ | |
| 226 } else if ((b3 == 0) && (b1 == 1)) { | |
| 227 MP_CHECKOK(group-> | |
| 228 point_sub(&sx, &sy, &qx, &qy, &sx, &s
y, group)); | |
| 229 } | |
| 230 } | |
| 231 #endif | |
| 232 /* output S */ | |
| 233 MP_CHECKOK(mp_copy(&sx, rx)); | |
| 234 MP_CHECKOK(mp_copy(&sy, ry)); | |
| 235 | |
| 236 CLEANUP: | |
| 237 mp_clear(&k); | |
| 238 mp_clear(&k3); | |
| 239 mp_clear(&qx); | |
| 240 mp_clear(&qy); | |
| 241 mp_clear(&sx); | |
| 242 mp_clear(&sy); | |
| 243 return res; | |
| 244 } | |
| 245 #endif | |
| 246 | |
| 247 /* Validates a point on a GFp curve. */ | |
| 248 mp_err | |
| 249 ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group) | |
| 250 { | |
| 251 mp_err res = MP_NO; | |
| 252 mp_int accl, accr, tmp, pxt, pyt; | |
| 253 | |
| 254 MP_DIGITS(&accl) = 0; | |
| 255 MP_DIGITS(&accr) = 0; | |
| 256 MP_DIGITS(&tmp) = 0; | |
| 257 MP_DIGITS(&pxt) = 0; | |
| 258 MP_DIGITS(&pyt) = 0; | |
| 259 MP_CHECKOK(mp_init(&accl)); | |
| 260 MP_CHECKOK(mp_init(&accr)); | |
| 261 MP_CHECKOK(mp_init(&tmp)); | |
| 262 MP_CHECKOK(mp_init(&pxt)); | |
| 263 MP_CHECKOK(mp_init(&pyt)); | |
| 264 | |
| 265 /* 1: Verify that publicValue is not the point at infinity */ | |
| 266 if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) { | |
| 267 res = MP_NO; | |
| 268 goto CLEANUP; | |
| 269 } | |
| 270 /* 2: Verify that the coordinates of publicValue are elements | |
| 271 * of the field. | |
| 272 */ | |
| 273 if ((MP_SIGN(px) == MP_NEG) || (mp_cmp(px, &group->meth->irr) >= 0) || | |
| 274 (MP_SIGN(py) == MP_NEG) || (mp_cmp(py, &group->meth->irr) >= 0))
{ | |
| 275 res = MP_NO; | |
| 276 goto CLEANUP; | |
| 277 } | |
| 278 /* 3: Verify that publicValue is on the curve. */ | |
| 279 if (group->meth->field_enc) { | |
| 280 group->meth->field_enc(px, &pxt, group->meth); | |
| 281 group->meth->field_enc(py, &pyt, group->meth); | |
| 282 } else { | |
| 283 MP_CHECKOK( mp_copy(px, &pxt) ); | |
| 284 MP_CHECKOK( mp_copy(py, &pyt) ); | |
| 285 } | |
| 286 /* left-hand side: y^2 */ | |
| 287 MP_CHECKOK( group->meth->field_sqr(&pyt, &accl, group->meth) ); | |
| 288 /* right-hand side: x^3 + a*x + b = (x^2 + a)*x + b by Horner's rule */ | |
| 289 MP_CHECKOK( group->meth->field_sqr(&pxt, &tmp, group->meth) ); | |
| 290 MP_CHECKOK( group->meth->field_add(&tmp, &group->curvea, &tmp, group->me
th) ); | |
| 291 MP_CHECKOK( group->meth->field_mul(&tmp, &pxt, &accr, group->meth) ); | |
| 292 MP_CHECKOK( group->meth->field_add(&accr, &group->curveb, &accr, group->
meth) ); | |
| 293 /* check LHS - RHS == 0 */ | |
| 294 MP_CHECKOK( group->meth->field_sub(&accl, &accr, &accr, group->meth) ); | |
| 295 if (mp_cmp_z(&accr) != 0) { | |
| 296 res = MP_NO; | |
| 297 goto CLEANUP; | |
| 298 } | |
| 299 /* 4: Verify that the order of the curve times the publicValue | |
| 300 * is the point at infinity. | |
| 301 */ | |
| 302 MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt) ); | |
| 303 if (ec_GFp_pt_is_inf_aff(&pxt, &pyt) != MP_YES) { | |
| 304 res = MP_NO; | |
| 305 goto CLEANUP; | |
| 306 } | |
| 307 | |
| 308 res = MP_YES; | |
| 309 | |
| 310 CLEANUP: | |
| 311 mp_clear(&accl); | |
| 312 mp_clear(&accr); | |
| 313 mp_clear(&tmp); | |
| 314 mp_clear(&pxt); | |
| 315 mp_clear(&pyt); | |
| 316 return res; | |
| 317 } | |
| OLD | NEW |