security/nss/lib/freebl/ecl/ec2_proj.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 "ec2.h"
michael@0 6 #include "mplogic.h"
michael@0 7 #include "mp_gf2m.h"
michael@0 8 #include <stdlib.h>
michael@0 9 #ifdef ECL_DEBUG
michael@0 10 #include <assert.h>
michael@0 11 #endif
michael@0 12
michael@0 13 /* by default, these routines are unused and thus don't need to be compiled */
michael@0 14 #ifdef ECL_ENABLE_GF2M_PROJ
michael@0 15 /* Converts a point P(px, py) from affine coordinates to projective
michael@0 16 * coordinates R(rx, ry, rz). Assumes input is already field-encoded using
michael@0 17 * field_enc, and returns output that is still field-encoded. */
michael@0 18 mp_err
michael@0 19 ec_GF2m_pt_aff2proj(const mp_int *px, const mp_int *py, mp_int *rx,
michael@0 20 mp_int *ry, mp_int *rz, const ECGroup *group)
michael@0 21 {
michael@0 22 mp_err res = MP_OKAY;
michael@0 23
michael@0 24 MP_CHECKOK(mp_copy(px, rx));
michael@0 25 MP_CHECKOK(mp_copy(py, ry));
michael@0 26 MP_CHECKOK(mp_set_int(rz, 1));
michael@0 27 if (group->meth->field_enc) {
michael@0 28 MP_CHECKOK(group->meth->field_enc(rz, rz, group->meth));
michael@0 29 }
michael@0 30 CLEANUP:
michael@0 31 return res;
michael@0 32 }
michael@0 33
michael@0 34 /* Converts a point P(px, py, pz) from projective coordinates to affine
michael@0 35 * coordinates R(rx, ry). P and R can share x and y coordinates. Assumes
michael@0 36 * input is already field-encoded using field_enc, and returns output that
michael@0 37 * is still field-encoded. */
michael@0 38 mp_err
michael@0 39 ec_GF2m_pt_proj2aff(const mp_int *px, const mp_int *py, const mp_int *pz,
michael@0 40 mp_int *rx, mp_int *ry, const ECGroup *group)
michael@0 41 {
michael@0 42 mp_err res = MP_OKAY;
michael@0 43 mp_int z1, z2;
michael@0 44
michael@0 45 MP_DIGITS(&z1) = 0;
michael@0 46 MP_DIGITS(&z2) = 0;
michael@0 47 MP_CHECKOK(mp_init(&z1));
michael@0 48 MP_CHECKOK(mp_init(&z2));
michael@0 49
michael@0 50 /* if point at infinity, then set point at infinity and exit */
michael@0 51 if (ec_GF2m_pt_is_inf_proj(px, py, pz) == MP_YES) {
michael@0 52 MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry));
michael@0 53 goto CLEANUP;
michael@0 54 }
michael@0 55
michael@0 56 /* transform (px, py, pz) into (px / pz, py / pz^2) */
michael@0 57 if (mp_cmp_d(pz, 1) == 0) {
michael@0 58 MP_CHECKOK(mp_copy(px, rx));
michael@0 59 MP_CHECKOK(mp_copy(py, ry));
michael@0 60 } else {
michael@0 61 MP_CHECKOK(group->meth->field_div(NULL, pz, &z1, group->meth));
michael@0 62 MP_CHECKOK(group->meth->field_sqr(&z1, &z2, group->meth));
michael@0 63 MP_CHECKOK(group->meth->field_mul(px, &z1, rx, group->meth));
michael@0 64 MP_CHECKOK(group->meth->field_mul(py, &z2, ry, group->meth));
michael@0 65 }
michael@0 66
michael@0 67 CLEANUP:
michael@0 68 mp_clear(&z1);
michael@0 69 mp_clear(&z2);
michael@0 70 return res;
michael@0 71 }
michael@0 72
michael@0 73 /* Checks if point P(px, py, pz) is at infinity. Uses projective
michael@0 74 * coordinates. */
michael@0 75 mp_err
michael@0 76 ec_GF2m_pt_is_inf_proj(const mp_int *px, const mp_int *py,
michael@0 77 const mp_int *pz)
michael@0 78 {
michael@0 79 return mp_cmp_z(pz);
michael@0 80 }
michael@0 81
michael@0 82 /* Sets P(px, py, pz) to be the point at infinity. Uses projective
michael@0 83 * coordinates. */
michael@0 84 mp_err
michael@0 85 ec_GF2m_pt_set_inf_proj(mp_int *px, mp_int *py, mp_int *pz)
michael@0 86 {
michael@0 87 mp_zero(pz);
michael@0 88 return MP_OKAY;
michael@0 89 }
michael@0 90
michael@0 91 /* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
michael@0 92 * (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical.
michael@0 93 * Uses mixed projective-affine coordinates. Assumes input is already
michael@0 94 * field-encoded using field_enc, and returns output that is still
michael@0 95 * field-encoded. Uses equation (3) from Hankerson, Hernandez, Menezes.
michael@0 96 * Software Implementation of Elliptic Curve Cryptography Over Binary
michael@0 97 * Fields. */
michael@0 98 mp_err
michael@0 99 ec_GF2m_pt_add_proj(const mp_int *px, const mp_int *py, const mp_int *pz,
michael@0 100 const mp_int *qx, const mp_int *qy, mp_int *rx,
michael@0 101 mp_int *ry, mp_int *rz, const ECGroup *group)
michael@0 102 {
michael@0 103 mp_err res = MP_OKAY;
michael@0 104 mp_int A, B, C, D, E, F, G;
michael@0 105
michael@0 106 /* If either P or Q is the point at infinity, then return the other
michael@0 107 * point */
michael@0 108 if (ec_GF2m_pt_is_inf_proj(px, py, pz) == MP_YES) {
michael@0 109 return ec_GF2m_pt_aff2proj(qx, qy, rx, ry, rz, group);
michael@0 110 }
michael@0 111 if (ec_GF2m_pt_is_inf_aff(qx, qy) == MP_YES) {
michael@0 112 MP_CHECKOK(mp_copy(px, rx));
michael@0 113 MP_CHECKOK(mp_copy(py, ry));
michael@0 114 return mp_copy(pz, rz);
michael@0 115 }
michael@0 116
michael@0 117 MP_DIGITS(&A) = 0;
michael@0 118 MP_DIGITS(&B) = 0;
michael@0 119 MP_DIGITS(&C) = 0;
michael@0 120 MP_DIGITS(&D) = 0;
michael@0 121 MP_DIGITS(&E) = 0;
michael@0 122 MP_DIGITS(&F) = 0;
michael@0 123 MP_DIGITS(&G) = 0;
michael@0 124 MP_CHECKOK(mp_init(&A));
michael@0 125 MP_CHECKOK(mp_init(&B));
michael@0 126 MP_CHECKOK(mp_init(&C));
michael@0 127 MP_CHECKOK(mp_init(&D));
michael@0 128 MP_CHECKOK(mp_init(&E));
michael@0 129 MP_CHECKOK(mp_init(&F));
michael@0 130 MP_CHECKOK(mp_init(&G));
michael@0 131
michael@0 132 /* D = pz^2 */
michael@0 133 MP_CHECKOK(group->meth->field_sqr(pz, &D, group->meth));
michael@0 134
michael@0 135 /* A = qy * pz^2 + py */
michael@0 136 MP_CHECKOK(group->meth->field_mul(qy, &D, &A, group->meth));
michael@0 137 MP_CHECKOK(group->meth->field_add(&A, py, &A, group->meth));
michael@0 138
michael@0 139 /* B = qx * pz + px */
michael@0 140 MP_CHECKOK(group->meth->field_mul(qx, pz, &B, group->meth));
michael@0 141 MP_CHECKOK(group->meth->field_add(&B, px, &B, group->meth));
michael@0 142
michael@0 143 /* C = pz * B */
michael@0 144 MP_CHECKOK(group->meth->field_mul(pz, &B, &C, group->meth));
michael@0 145
michael@0 146 /* D = B^2 * (C + a * pz^2) (using E as a temporary variable) */
michael@0 147 MP_CHECKOK(group->meth->
michael@0 148 field_mul(&group->curvea, &D, &D, group->meth));
michael@0 149 MP_CHECKOK(group->meth->field_add(&C, &D, &D, group->meth));
michael@0 150 MP_CHECKOK(group->meth->field_sqr(&B, &E, group->meth));
michael@0 151 MP_CHECKOK(group->meth->field_mul(&E, &D, &D, group->meth));
michael@0 152
michael@0 153 /* rz = C^2 */
michael@0 154 MP_CHECKOK(group->meth->field_sqr(&C, rz, group->meth));
michael@0 155
michael@0 156 /* E = A * C */
michael@0 157 MP_CHECKOK(group->meth->field_mul(&A, &C, &E, group->meth));
michael@0 158
michael@0 159 /* rx = A^2 + D + E */
michael@0 160 MP_CHECKOK(group->meth->field_sqr(&A, rx, group->meth));
michael@0 161 MP_CHECKOK(group->meth->field_add(rx, &D, rx, group->meth));
michael@0 162 MP_CHECKOK(group->meth->field_add(rx, &E, rx, group->meth));
michael@0 163
michael@0 164 /* F = rx + qx * rz */
michael@0 165 MP_CHECKOK(group->meth->field_mul(qx, rz, &F, group->meth));
michael@0 166 MP_CHECKOK(group->meth->field_add(rx, &F, &F, group->meth));
michael@0 167
michael@0 168 /* G = rx + qy * rz */
michael@0 169 MP_CHECKOK(group->meth->field_mul(qy, rz, &G, group->meth));
michael@0 170 MP_CHECKOK(group->meth->field_add(rx, &G, &G, group->meth));
michael@0 171
michael@0 172 /* ry = E * F + rz * G (using G as a temporary variable) */
michael@0 173 MP_CHECKOK(group->meth->field_mul(rz, &G, &G, group->meth));
michael@0 174 MP_CHECKOK(group->meth->field_mul(&E, &F, ry, group->meth));
michael@0 175 MP_CHECKOK(group->meth->field_add(ry, &G, ry, group->meth));
michael@0 176
michael@0 177 CLEANUP:
michael@0 178 mp_clear(&A);
michael@0 179 mp_clear(&B);
michael@0 180 mp_clear(&C);
michael@0 181 mp_clear(&D);
michael@0 182 mp_clear(&E);
michael@0 183 mp_clear(&F);
michael@0 184 mp_clear(&G);
michael@0 185 return res;
michael@0 186 }
michael@0 187
michael@0 188 /* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
michael@0 189 * projective coordinates.
michael@0 190 *
michael@0 191 * Assumes input is already field-encoded using field_enc, and returns
michael@0 192 * output that is still field-encoded.
michael@0 193 *
michael@0 194 * Uses equation (3) from Hankerson, Hernandez, Menezes. Software
michael@0 195 * Implementation of Elliptic Curve Cryptography Over Binary Fields.
michael@0 196 */
michael@0 197 mp_err
michael@0 198 ec_GF2m_pt_dbl_proj(const mp_int *px, const mp_int *py, const mp_int *pz,
michael@0 199 mp_int *rx, mp_int *ry, mp_int *rz,
michael@0 200 const ECGroup *group)
michael@0 201 {
michael@0 202 mp_err res = MP_OKAY;
michael@0 203 mp_int t0, t1;
michael@0 204
michael@0 205 if (ec_GF2m_pt_is_inf_proj(px, py, pz) == MP_YES) {
michael@0 206 return ec_GF2m_pt_set_inf_proj(rx, ry, rz);
michael@0 207 }
michael@0 208
michael@0 209 MP_DIGITS(&t0) = 0;
michael@0 210 MP_DIGITS(&t1) = 0;
michael@0 211 MP_CHECKOK(mp_init(&t0));
michael@0 212 MP_CHECKOK(mp_init(&t1));
michael@0 213
michael@0 214 /* t0 = px^2 */
michael@0 215 /* t1 = pz^2 */
michael@0 216 MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth));
michael@0 217 MP_CHECKOK(group->meth->field_sqr(pz, &t1, group->meth));
michael@0 218
michael@0 219 /* rz = px^2 * pz^2 */
michael@0 220 MP_CHECKOK(group->meth->field_mul(&t0, &t1, rz, group->meth));
michael@0 221
michael@0 222 /* t0 = px^4 */
michael@0 223 /* t1 = b * pz^4 */
michael@0 224 MP_CHECKOK(group->meth->field_sqr(&t0, &t0, group->meth));
michael@0 225 MP_CHECKOK(group->meth->field_sqr(&t1, &t1, group->meth));
michael@0 226 MP_CHECKOK(group->meth->
michael@0 227 field_mul(&group->curveb, &t1, &t1, group->meth));
michael@0 228
michael@0 229 /* rx = px^4 + b * pz^4 */
michael@0 230 MP_CHECKOK(group->meth->field_add(&t0, &t1, rx, group->meth));
michael@0 231
michael@0 232 /* ry = b * pz^4 * rz + rx * (a * rz + py^2 + b * pz^4) */
michael@0 233 MP_CHECKOK(group->meth->field_sqr(py, ry, group->meth));
michael@0 234 MP_CHECKOK(group->meth->field_add(ry, &t1, ry, group->meth));
michael@0 235 /* t0 = a * rz */
michael@0 236 MP_CHECKOK(group->meth->
michael@0 237 field_mul(&group->curvea, rz, &t0, group->meth));
michael@0 238 MP_CHECKOK(group->meth->field_add(&t0, ry, ry, group->meth));
michael@0 239 MP_CHECKOK(group->meth->field_mul(rx, ry, ry, group->meth));
michael@0 240 /* t1 = b * pz^4 * rz */
michael@0 241 MP_CHECKOK(group->meth->field_mul(&t1, rz, &t1, group->meth));
michael@0 242 MP_CHECKOK(group->meth->field_add(&t1, ry, ry, group->meth));
michael@0 243
michael@0 244 CLEANUP:
michael@0 245 mp_clear(&t0);
michael@0 246 mp_clear(&t1);
michael@0 247 return res;
michael@0 248 }
michael@0 249
michael@0 250 /* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
michael@0 251 * a, b and p are the elliptic curve coefficients and the prime that
michael@0 252 * determines the field GF2m. Elliptic curve points P and R can be
michael@0 253 * identical. Uses mixed projective-affine coordinates. Assumes input is
michael@0 254 * already field-encoded using field_enc, and returns output that is still
michael@0 255 * field-encoded. Uses 4-bit window method. */
michael@0 256 mp_err
michael@0 257 ec_GF2m_pt_mul_proj(const mp_int *n, const mp_int *px, const mp_int *py,
michael@0 258 mp_int *rx, mp_int *ry, const ECGroup *group)
michael@0 259 {
michael@0 260 mp_err res = MP_OKAY;
michael@0 261 mp_int precomp[16][2], rz;
michael@0 262 mp_digit precomp_arr[ECL_MAX_FIELD_SIZE_DIGITS * 16 * 2], *t;
michael@0 263 int i, ni, d;
michael@0 264
michael@0 265 ARGCHK(group != NULL, MP_BADARG);
michael@0 266 ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);
michael@0 267
michael@0 268 /* initialize precomputation table */
michael@0 269 t = precomp_arr;
michael@0 270 for (i = 0; i < 16; i++) {
michael@0 271 /* x co-ord */
michael@0 272 MP_SIGN(&precomp[i][0]) = MP_ZPOS;
michael@0 273 MP_ALLOC(&precomp[i][0]) = ECL_MAX_FIELD_SIZE_DIGITS;
michael@0 274 MP_USED(&precomp[i][0]) = 1;
michael@0 275 *t = 0;
michael@0 276 MP_DIGITS(&precomp[i][0]) = t;
michael@0 277 t += ECL_MAX_FIELD_SIZE_DIGITS;
michael@0 278 /* y co-ord */
michael@0 279 MP_SIGN(&precomp[i][1]) = MP_ZPOS;
michael@0 280 MP_ALLOC(&precomp[i][1]) = ECL_MAX_FIELD_SIZE_DIGITS;
michael@0 281 MP_USED(&precomp[i][1]) = 1;
michael@0 282 *t = 0;
michael@0 283 MP_DIGITS(&precomp[i][1]) = t;
michael@0 284 t += ECL_MAX_FIELD_SIZE_DIGITS;
michael@0 285 }
michael@0 286
michael@0 287 /* fill precomputation table */
michael@0 288 mp_zero(&precomp[0][0]);
michael@0 289 mp_zero(&precomp[0][1]);
michael@0 290 MP_CHECKOK(mp_copy(px, &precomp[1][0]));
michael@0 291 MP_CHECKOK(mp_copy(py, &precomp[1][1]));
michael@0 292 for (i = 2; i < 16; i++) {
michael@0 293 MP_CHECKOK(group->
michael@0 294 point_add(&precomp[1][0], &precomp[1][1],
michael@0 295 &precomp[i - 1][0], &precomp[i - 1][1],
michael@0 296 &precomp[i][0], &precomp[i][1], group));
michael@0 297 }
michael@0 298
michael@0 299 d = (mpl_significant_bits(n) + 3) / 4;
michael@0 300
michael@0 301 /* R = inf */
michael@0 302 MP_DIGITS(&rz) = 0;
michael@0 303 MP_CHECKOK(mp_init(&rz));
michael@0 304 MP_CHECKOK(ec_GF2m_pt_set_inf_proj(rx, ry, &rz));
michael@0 305
michael@0 306 for (i = d - 1; i >= 0; i--) {
michael@0 307 /* compute window ni */
michael@0 308 ni = MP_GET_BIT(n, 4 * i + 3);
michael@0 309 ni <<= 1;
michael@0 310 ni |= MP_GET_BIT(n, 4 * i + 2);
michael@0 311 ni <<= 1;
michael@0 312 ni |= MP_GET_BIT(n, 4 * i + 1);
michael@0 313 ni <<= 1;
michael@0 314 ni |= MP_GET_BIT(n, 4 * i);
michael@0 315 /* R = 2^4 * R */
michael@0 316 MP_CHECKOK(ec_GF2m_pt_dbl_proj(rx, ry, &rz, rx, ry, &rz, group));
michael@0 317 MP_CHECKOK(ec_GF2m_pt_dbl_proj(rx, ry, &rz, rx, ry, &rz, group));
michael@0 318 MP_CHECKOK(ec_GF2m_pt_dbl_proj(rx, ry, &rz, rx, ry, &rz, group));
michael@0 319 MP_CHECKOK(ec_GF2m_pt_dbl_proj(rx, ry, &rz, rx, ry, &rz, group));
michael@0 320 /* R = R + (ni * P) */
michael@0 321 MP_CHECKOK(ec_GF2m_pt_add_proj
michael@0 322 (rx, ry, &rz, &precomp[ni][0], &precomp[ni][1], rx, ry,
michael@0 323 &rz, group));
michael@0 324 }
michael@0 325
michael@0 326 /* convert result S to affine coordinates */
michael@0 327 MP_CHECKOK(ec_GF2m_pt_proj2aff(rx, ry, &rz, rx, ry, group));
michael@0 328
michael@0 329 CLEANUP:
michael@0 330 mp_clear(&rz);
michael@0 331 return res;
michael@0 332 }
michael@0 333 #endif

mercurial