| 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 binary polynomial 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 | * |
| 38 | * Last Modified Date from the Original Code: May 2017 |
| 39 | *********************************************************************** */ |
| 40 | |
| 41 | #include "ec2.h" |
| 42 | #include "mplogic.h" |
| 43 | #include "mp_gf2m.h" |
| 44 | #ifndef _KERNEL |
| 45 | #include <stdlib.h> |
| 46 | #endif |
| 47 | |
| 48 | /* Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery |
| 49 | * projective coordinates. Uses algorithm Mdouble in appendix of Lopez, J. |
| 50 | * and Dahab, R. "Fast multiplication on elliptic curves over GF(2^m) |
| 51 | * without precomputation". modified to not require precomputation of |
| 52 | * c=b^{2^{m-1}}. */ |
| 53 | static mp_err |
| 54 | gf2m_Mdouble(mp_int *x, mp_int *z, const ECGroup *group, int kmflag) |
| 55 | { |
| 56 | mp_err res = MP_OKAY; |
| 57 | mp_int t1; |
| 58 | |
| 59 | MP_DIGITS(&t1) = 0; |
| 60 | MP_CHECKOK(mp_init(&t1, kmflag)); |
| 61 | |
| 62 | MP_CHECKOK(group->meth->field_sqr(x, x, group->meth)); |
| 63 | MP_CHECKOK(group->meth->field_sqr(z, &t1, group->meth)); |
| 64 | MP_CHECKOK(group->meth->field_mul(x, &t1, z, group->meth)); |
| 65 | MP_CHECKOK(group->meth->field_sqr(x, x, group->meth)); |
| 66 | MP_CHECKOK(group->meth->field_sqr(&t1, &t1, group->meth)); |
| 67 | MP_CHECKOK(group->meth-> |
| 68 | field_mul(&group->curveb, &t1, &t1, group->meth)); |
| 69 | MP_CHECKOK(group->meth->field_add(x, &t1, x, group->meth)); |
| 70 | |
| 71 | CLEANUP: |
| 72 | mp_clear(&t1); |
| 73 | return res; |
| 74 | } |
| 75 | |
| 76 | /* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in |
| 77 | * Montgomery projective coordinates. Uses algorithm Madd in appendix of |
| 78 | * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over |
| 79 | * GF(2^m) without precomputation". */ |
| 80 | static mp_err |
| 81 | gf2m_Madd(const mp_int *x, mp_int *x1, mp_int *z1, mp_int *x2, mp_int *z2, |
| 82 | const ECGroup *group, int kmflag) |
| 83 | { |
| 84 | mp_err res = MP_OKAY; |
| 85 | mp_int t1, t2; |
| 86 | |
| 87 | MP_DIGITS(&t1) = 0; |
| 88 | MP_DIGITS(&t2) = 0; |
| 89 | MP_CHECKOK(mp_init(&t1, kmflag)); |
| 90 | MP_CHECKOK(mp_init(&t2, kmflag)); |
| 91 | |
| 92 | MP_CHECKOK(mp_copy(x, &t1)); |
| 93 | MP_CHECKOK(group->meth->field_mul(x1, z2, x1, group->meth)); |
| 94 | MP_CHECKOK(group->meth->field_mul(z1, x2, z1, group->meth)); |
| 95 | MP_CHECKOK(group->meth->field_mul(x1, z1, &t2, group->meth)); |
| 96 | MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth)); |
| 97 | MP_CHECKOK(group->meth->field_sqr(z1, z1, group->meth)); |
| 98 | MP_CHECKOK(group->meth->field_mul(z1, &t1, x1, group->meth)); |
| 99 | MP_CHECKOK(group->meth->field_add(x1, &t2, x1, group->meth)); |
| 100 | |
| 101 | CLEANUP: |
| 102 | mp_clear(&t1); |
| 103 | mp_clear(&t2); |
| 104 | return res; |
| 105 | } |
| 106 | |
| 107 | /* Compute the x, y affine coordinates from the point (x1, z1) (x2, z2) |
| 108 | * using Montgomery point multiplication algorithm Mxy() in appendix of |
| 109 | * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over |
| 110 | * GF(2^m) without precomputation". Returns: 0 on error 1 if return value |
| 111 | * should be the point at infinity 2 otherwise */ |
| 112 | static int |
| 113 | gf2m_Mxy(const mp_int *x, const mp_int *y, mp_int *x1, mp_int *z1, |
| 114 | mp_int *x2, mp_int *z2, const ECGroup *group) |
| 115 | { |
| 116 | mp_err res = MP_OKAY; |
| 117 | int ret = 0; |
| 118 | mp_int t3, t4, t5; |
| 119 | |
| 120 | MP_DIGITS(&t3) = 0; |
| 121 | MP_DIGITS(&t4) = 0; |
| 122 | MP_DIGITS(&t5) = 0; |
| 123 | MP_CHECKOK(mp_init(&t3, FLAG(x2))); |
| 124 | MP_CHECKOK(mp_init(&t4, FLAG(x2))); |
| 125 | MP_CHECKOK(mp_init(&t5, FLAG(x2))); |
| 126 | |
| 127 | if (mp_cmp_z(z1) == 0) { |
| 128 | mp_zero(x2); |
| 129 | mp_zero(z2); |
| 130 | ret = 1; |
| 131 | goto CLEANUP; |
| 132 | } |
| 133 | |
| 134 | if (mp_cmp_z(z2) == 0) { |
| 135 | MP_CHECKOK(mp_copy(x, x2)); |
| 136 | MP_CHECKOK(group->meth->field_add(x, y, z2, group->meth)); |
| 137 | ret = 2; |
| 138 | goto CLEANUP; |
| 139 | } |
| 140 | |
| 141 | MP_CHECKOK(mp_set_int(&t5, 1)); |
| 142 | if (group->meth->field_enc) { |
| 143 | MP_CHECKOK(group->meth->field_enc(&t5, &t5, group->meth)); |
| 144 | } |
| 145 | |
| 146 | MP_CHECKOK(group->meth->field_mul(z1, z2, &t3, group->meth)); |
| 147 | |
| 148 | MP_CHECKOK(group->meth->field_mul(z1, x, z1, group->meth)); |
| 149 | MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth)); |
| 150 | MP_CHECKOK(group->meth->field_mul(z2, x, z2, group->meth)); |
| 151 | MP_CHECKOK(group->meth->field_mul(z2, x1, x1, group->meth)); |
| 152 | MP_CHECKOK(group->meth->field_add(z2, x2, z2, group->meth)); |
| 153 | |
| 154 | MP_CHECKOK(group->meth->field_mul(z2, z1, z2, group->meth)); |
| 155 | MP_CHECKOK(group->meth->field_sqr(x, &t4, group->meth)); |
| 156 | MP_CHECKOK(group->meth->field_add(&t4, y, &t4, group->meth)); |
| 157 | MP_CHECKOK(group->meth->field_mul(&t4, &t3, &t4, group->meth)); |
| 158 | MP_CHECKOK(group->meth->field_add(&t4, z2, &t4, group->meth)); |
| 159 | |
| 160 | MP_CHECKOK(group->meth->field_mul(&t3, x, &t3, group->meth)); |
| 161 | MP_CHECKOK(group->meth->field_div(&t5, &t3, &t3, group->meth)); |
| 162 | MP_CHECKOK(group->meth->field_mul(&t3, &t4, &t4, group->meth)); |
| 163 | MP_CHECKOK(group->meth->field_mul(x1, &t3, x2, group->meth)); |
| 164 | MP_CHECKOK(group->meth->field_add(x2, x, z2, group->meth)); |
| 165 | |
| 166 | MP_CHECKOK(group->meth->field_mul(z2, &t4, z2, group->meth)); |
| 167 | MP_CHECKOK(group->meth->field_add(z2, y, z2, group->meth)); |
| 168 | |
| 169 | ret = 2; |
| 170 | |
| 171 | CLEANUP: |
| 172 | mp_clear(&t3); |
| 173 | mp_clear(&t4); |
| 174 | mp_clear(&t5); |
| 175 | if (res == MP_OKAY) { |
| 176 | return ret; |
| 177 | } else { |
| 178 | return 0; |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | /* Computes R = nP based on algorithm 2P of Lopex, J. and Dahab, R. "Fast |
| 183 | * multiplication on elliptic curves over GF(2^m) without |
| 184 | * precomputation". Elliptic curve points P and R can be identical. Uses |
| 185 | * Montgomery projective coordinates. The timing parameter is ignored |
| 186 | * because this algorithm resists timing attacks by default. */ |
| 187 | mp_err |
| 188 | ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px, const mp_int *py, |
| 189 | mp_int *rx, mp_int *ry, const ECGroup *group, |
| 190 | int timing) |
| 191 | { |
| 192 | mp_err res = MP_OKAY; |
| 193 | mp_int x1, x2, z1, z2; |
| 194 | int i, j; |
| 195 | mp_digit top_bit, mask; |
| 196 | |
| 197 | MP_DIGITS(&x1) = 0; |
| 198 | MP_DIGITS(&x2) = 0; |
| 199 | MP_DIGITS(&z1) = 0; |
| 200 | MP_DIGITS(&z2) = 0; |
| 201 | MP_CHECKOK(mp_init(&x1, FLAG(n))); |
| 202 | MP_CHECKOK(mp_init(&x2, FLAG(n))); |
| 203 | MP_CHECKOK(mp_init(&z1, FLAG(n))); |
| 204 | MP_CHECKOK(mp_init(&z2, FLAG(n))); |
| 205 | |
| 206 | /* if result should be point at infinity */ |
| 207 | if ((mp_cmp_z(n) == 0) || (ec_GF2m_pt_is_inf_aff(px, py) == MP_YES)) { |
| 208 | MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry)); |
| 209 | goto CLEANUP; |
| 210 | } |
| 211 | |
| 212 | MP_CHECKOK(mp_copy(px, &x1)); /* x1 = px */ |
| 213 | MP_CHECKOK(mp_set_int(&z1, 1)); /* z1 = 1 */ |
| 214 | MP_CHECKOK(group->meth->field_sqr(&x1, &z2, group->meth)); /* z2 = |
| 215 | * x1^2 = |
| 216 | * px^2 */ |
| 217 | MP_CHECKOK(group->meth->field_sqr(&z2, &x2, group->meth)); |
| 218 | MP_CHECKOK(group->meth->field_add(&x2, &group->curveb, &x2, group->meth)); /* x2 |
| 219 | * = |
| 220 | * px^4 |
| 221 | * + |
| 222 | * b |
| 223 | */ |
| 224 | |
| 225 | /* find top-most bit and go one past it */ |
| 226 | i = MP_USED(n) - 1; |
| 227 | j = MP_DIGIT_BIT - 1; |
| 228 | top_bit = 1; |
| 229 | top_bit <<= MP_DIGIT_BIT - 1; |
| 230 | mask = top_bit; |
| 231 | while (!(MP_DIGITS(n)[i] & mask)) { |
| 232 | mask >>= 1; |
| 233 | j--; |
| 234 | } |
| 235 | mask >>= 1; |
| 236 | j--; |
| 237 | |
| 238 | /* if top most bit was at word break, go to next word */ |
| 239 | if (!mask) { |
| 240 | i--; |
| 241 | j = MP_DIGIT_BIT - 1; |
| 242 | mask = top_bit; |
| 243 | } |
| 244 | |
| 245 | for (; i >= 0; i--) { |
| 246 | for (; j >= 0; j--) { |
| 247 | if (MP_DIGITS(n)[i] & mask) { |
| 248 | MP_CHECKOK(gf2m_Madd(px, &x1, &z1, &x2, &z2, group, FLAG(n))); |
| 249 | MP_CHECKOK(gf2m_Mdouble(&x2, &z2, group, FLAG(n))); |
| 250 | } else { |
| 251 | MP_CHECKOK(gf2m_Madd(px, &x2, &z2, &x1, &z1, group, FLAG(n))); |
| 252 | MP_CHECKOK(gf2m_Mdouble(&x1, &z1, group, FLAG(n))); |
| 253 | } |
| 254 | mask >>= 1; |
| 255 | } |
| 256 | j = MP_DIGIT_BIT - 1; |
| 257 | mask = top_bit; |
| 258 | } |
| 259 | |
| 260 | /* convert out of "projective" coordinates */ |
| 261 | i = gf2m_Mxy(px, py, &x1, &z1, &x2, &z2, group); |
| 262 | if (i == 0) { |
| 263 | res = MP_BADARG; |
| 264 | goto CLEANUP; |
| 265 | } else if (i == 1) { |
| 266 | MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry)); |
| 267 | } else { |
| 268 | MP_CHECKOK(mp_copy(&x2, rx)); |
| 269 | MP_CHECKOK(mp_copy(&z2, ry)); |
| 270 | } |
| 271 | |
| 272 | CLEANUP: |
| 273 | mp_clear(&x1); |
| 274 | mp_clear(&x2); |
| 275 | mp_clear(&z1); |
| 276 | mp_clear(&z2); |
| 277 | return res; |
| 278 | } |
| 279 | |