security/nss/lib/freebl/ecl/ecp_aff.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial