1 /* ********************************************************************* 2 * 3 * Sun elects to have this file available under and governed by the 4 * Mozilla Public License Version 1.1 ("MPL") (see 5 * http://www.mozilla.org/MPL/ for full license text). For the avoidance 6 * of doubt and subject to the following, Sun also elects to allow 7 * licensees to use this file under the MPL, the GNU General Public 8 * License version 2 only or the Lesser General Public License version 9 * 2.1 only. Any references to the "GNU General Public License version 2 10 * or later" or "GPL" in the following shall be construed to mean the 11 * GNU General Public License version 2 only. Any references to the "GNU 12 * Lesser General Public License version 2.1 or later" or "LGPL" in the 13 * following shall be construed to mean the GNU Lesser General Public 14 * License version 2.1 only. However, the following notice accompanied 15 * the original version of this file: 16 * 17 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 18 * 19 * The contents of this file are subject to the Mozilla Public License Version 20 * 1.1 (the "License"); you may not use this file except in compliance with 21 * the License. You may obtain a copy of the License at 22 * http://www.mozilla.org/MPL/ 23 * 24 * Software distributed under the License is distributed on an "AS IS" basis, 25 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 26 * for the specific language governing rights and limitations under the 27 * License. 28 * 29 * The Original Code is the elliptic curve math library for binary polynomial field curves. 30 * 31 * The Initial Developer of the Original Code is 32 * Sun Microsystems, Inc. 33 * Portions created by the Initial Developer are Copyright (C) 2003 34 * the Initial Developer. All Rights Reserved. 35 * 36 * Contributor(s): 37 * Sheueling Chang-Shantz <sheueling.chang@sun.com>, 38 * Stephen Fung <fungstep@hotmail.com>, and 39 * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories. 40 * 41 * Alternatively, the contents of this file may be used under the terms of 42 * either the GNU General Public License Version 2 or later (the "GPL"), or 43 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 44 * in which case the provisions of the GPL or the LGPL are applicable instead 45 * of those above. If you wish to allow use of your version of this file only 46 * under the terms of either the GPL or the LGPL, and not to allow others to 47 * use your version of this file under the terms of the MPL, indicate your 48 * decision by deleting the provisions above and replace them with the notice 49 * and other provisions required by the GPL or the LGPL. If you do not delete 50 * the provisions above, a recipient may use your version of this file under 51 * the terms of any one of the MPL, the GPL or the LGPL. 52 * 53 *********************************************************************** */ 54 /* 55 * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. 56 * Use is subject to license terms. 57 */ 58 59 #include "ec2.h" 60 #include "mplogic.h" 61 #include "mp_gf2m.h" 62 #ifndef _KERNEL 63 #include <stdlib.h> 64 #endif 65 66 /* Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery 67 * projective coordinates. Uses algorithm Mdouble in appendix of Lopez, J. 68 * and Dahab, R. "Fast multiplication on elliptic curves over GF(2^m) 69 * without precomputation". modified to not require precomputation of 70 * c=b^{2^{m-1}}. */ 71 static mp_err 72 gf2m_Mdouble(mp_int *x, mp_int *z, const ECGroup *group, int kmflag) 73 { 74 mp_err res = MP_OKAY; 75 mp_int t1; 76 77 MP_DIGITS(&t1) = 0; 78 MP_CHECKOK(mp_init(&t1, kmflag)); 79 80 MP_CHECKOK(group->meth->field_sqr(x, x, group->meth)); 81 MP_CHECKOK(group->meth->field_sqr(z, &t1, group->meth)); 82 MP_CHECKOK(group->meth->field_mul(x, &t1, z, group->meth)); 83 MP_CHECKOK(group->meth->field_sqr(x, x, group->meth)); 84 MP_CHECKOK(group->meth->field_sqr(&t1, &t1, group->meth)); 85 MP_CHECKOK(group->meth-> 86 field_mul(&group->curveb, &t1, &t1, group->meth)); 87 MP_CHECKOK(group->meth->field_add(x, &t1, x, group->meth)); 88 89 CLEANUP: 90 mp_clear(&t1); 91 return res; 92 } 93 94 /* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in 95 * Montgomery projective coordinates. Uses algorithm Madd in appendix of 96 * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over 97 * GF(2^m) without precomputation". */ 98 static mp_err 99 gf2m_Madd(const mp_int *x, mp_int *x1, mp_int *z1, mp_int *x2, mp_int *z2, 100 const ECGroup *group, int kmflag) 101 { 102 mp_err res = MP_OKAY; 103 mp_int t1, t2; 104 105 MP_DIGITS(&t1) = 0; 106 MP_DIGITS(&t2) = 0; 107 MP_CHECKOK(mp_init(&t1, kmflag)); 108 MP_CHECKOK(mp_init(&t2, kmflag)); 109 110 MP_CHECKOK(mp_copy(x, &t1)); 111 MP_CHECKOK(group->meth->field_mul(x1, z2, x1, group->meth)); 112 MP_CHECKOK(group->meth->field_mul(z1, x2, z1, group->meth)); 113 MP_CHECKOK(group->meth->field_mul(x1, z1, &t2, group->meth)); 114 MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth)); 115 MP_CHECKOK(group->meth->field_sqr(z1, z1, group->meth)); 116 MP_CHECKOK(group->meth->field_mul(z1, &t1, x1, group->meth)); 117 MP_CHECKOK(group->meth->field_add(x1, &t2, x1, group->meth)); 118 119 CLEANUP: 120 mp_clear(&t1); 121 mp_clear(&t2); 122 return res; 123 } 124 125 /* Compute the x, y affine coordinates from the point (x1, z1) (x2, z2) 126 * using Montgomery point multiplication algorithm Mxy() in appendix of 127 * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over 128 * GF(2^m) without precomputation". Returns: 0 on error 1 if return value 129 * should be the point at infinity 2 otherwise */ 130 static int 131 gf2m_Mxy(const mp_int *x, const mp_int *y, mp_int *x1, mp_int *z1, 132 mp_int *x2, mp_int *z2, const ECGroup *group) 133 { 134 mp_err res = MP_OKAY; 135 int ret = 0; 136 mp_int t3, t4, t5; 137 138 MP_DIGITS(&t3) = 0; 139 MP_DIGITS(&t4) = 0; 140 MP_DIGITS(&t5) = 0; 141 MP_CHECKOK(mp_init(&t3, FLAG(x2))); 142 MP_CHECKOK(mp_init(&t4, FLAG(x2))); 143 MP_CHECKOK(mp_init(&t5, FLAG(x2))); 144 145 if (mp_cmp_z(z1) == 0) { 146 mp_zero(x2); 147 mp_zero(z2); 148 ret = 1; 149 goto CLEANUP; 150 } 151 152 if (mp_cmp_z(z2) == 0) { 153 MP_CHECKOK(mp_copy(x, x2)); 154 MP_CHECKOK(group->meth->field_add(x, y, z2, group->meth)); 155 ret = 2; 156 goto CLEANUP; 157 } 158 159 MP_CHECKOK(mp_set_int(&t5, 1)); 160 if (group->meth->field_enc) { 161 MP_CHECKOK(group->meth->field_enc(&t5, &t5, group->meth)); 162 } 163 164 MP_CHECKOK(group->meth->field_mul(z1, z2, &t3, group->meth)); 165 166 MP_CHECKOK(group->meth->field_mul(z1, x, z1, group->meth)); 167 MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth)); 168 MP_CHECKOK(group->meth->field_mul(z2, x, z2, group->meth)); 169 MP_CHECKOK(group->meth->field_mul(z2, x1, x1, group->meth)); 170 MP_CHECKOK(group->meth->field_add(z2, x2, z2, group->meth)); 171 172 MP_CHECKOK(group->meth->field_mul(z2, z1, z2, group->meth)); 173 MP_CHECKOK(group->meth->field_sqr(x, &t4, group->meth)); 174 MP_CHECKOK(group->meth->field_add(&t4, y, &t4, group->meth)); 175 MP_CHECKOK(group->meth->field_mul(&t4, &t3, &t4, group->meth)); 176 MP_CHECKOK(group->meth->field_add(&t4, z2, &t4, group->meth)); 177 178 MP_CHECKOK(group->meth->field_mul(&t3, x, &t3, group->meth)); 179 MP_CHECKOK(group->meth->field_div(&t5, &t3, &t3, group->meth)); 180 MP_CHECKOK(group->meth->field_mul(&t3, &t4, &t4, group->meth)); 181 MP_CHECKOK(group->meth->field_mul(x1, &t3, x2, group->meth)); 182 MP_CHECKOK(group->meth->field_add(x2, x, z2, group->meth)); 183 184 MP_CHECKOK(group->meth->field_mul(z2, &t4, z2, group->meth)); 185 MP_CHECKOK(group->meth->field_add(z2, y, z2, group->meth)); 186 187 ret = 2; 188 189 CLEANUP: 190 mp_clear(&t3); 191 mp_clear(&t4); 192 mp_clear(&t5); 193 if (res == MP_OKAY) { 194 return ret; 195 } else { 196 return 0; 197 } 198 } 199 200 /* Computes R = nP based on algorithm 2P of Lopex, J. and Dahab, R. "Fast 201 * multiplication on elliptic curves over GF(2^m) without 202 * precomputation". Elliptic curve points P and R can be identical. Uses 203 * Montgomery projective coordinates. */ 204 mp_err 205 ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px, const mp_int *py, 206 mp_int *rx, mp_int *ry, const ECGroup *group) 207 { 208 mp_err res = MP_OKAY; 209 mp_int x1, x2, z1, z2; 210 int i, j; 211 mp_digit top_bit, mask; 212 213 MP_DIGITS(&x1) = 0; 214 MP_DIGITS(&x2) = 0; 215 MP_DIGITS(&z1) = 0; 216 MP_DIGITS(&z2) = 0; 217 MP_CHECKOK(mp_init(&x1, FLAG(n))); 218 MP_CHECKOK(mp_init(&x2, FLAG(n))); 219 MP_CHECKOK(mp_init(&z1, FLAG(n))); 220 MP_CHECKOK(mp_init(&z2, FLAG(n))); 221 222 /* if result should be point at infinity */ 223 if ((mp_cmp_z(n) == 0) || (ec_GF2m_pt_is_inf_aff(px, py) == MP_YES)) { 224 MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry)); 225 goto CLEANUP; 226 } 227 228 MP_CHECKOK(mp_copy(px, &x1)); /* x1 = px */ 229 MP_CHECKOK(mp_set_int(&z1, 1)); /* z1 = 1 */ 230 MP_CHECKOK(group->meth->field_sqr(&x1, &z2, group->meth)); /* z2 = 231 * x1^2 = 232 * px^2 */ 233 MP_CHECKOK(group->meth->field_sqr(&z2, &x2, group->meth)); 234 MP_CHECKOK(group->meth->field_add(&x2, &group->curveb, &x2, group->meth)); /* x2 235 * = 236 * px^4 237 * + 238 * b 239 */ 240 241 /* find top-most bit and go one past it */ 242 i = MP_USED(n) - 1; 243 j = MP_DIGIT_BIT - 1; 244 top_bit = 1; 245 top_bit <<= MP_DIGIT_BIT - 1; 246 mask = top_bit; 247 while (!(MP_DIGITS(n)[i] & mask)) { 248 mask >>= 1; 249 j--; 250 } 251 mask >>= 1; 252 j--; 253 254 /* if top most bit was at word break, go to next word */ 255 if (!mask) { 256 i--; 257 j = MP_DIGIT_BIT - 1; 258 mask = top_bit; 259 } 260 261 for (; i >= 0; i--) { 262 for (; j >= 0; j--) { 263 if (MP_DIGITS(n)[i] & mask) { 264 MP_CHECKOK(gf2m_Madd(px, &x1, &z1, &x2, &z2, group, FLAG(n))); 265 MP_CHECKOK(gf2m_Mdouble(&x2, &z2, group, FLAG(n))); 266 } else { 267 MP_CHECKOK(gf2m_Madd(px, &x2, &z2, &x1, &z1, group, FLAG(n))); 268 MP_CHECKOK(gf2m_Mdouble(&x1, &z1, group, FLAG(n))); 269 } 270 mask >>= 1; 271 } 272 j = MP_DIGIT_BIT - 1; 273 mask = top_bit; 274 } 275 276 /* convert out of "projective" coordinates */ 277 i = gf2m_Mxy(px, py, &x1, &z1, &x2, &z2, group); 278 if (i == 0) { 279 res = MP_BADARG; 280 goto CLEANUP; 281 } else if (i == 1) { 282 MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry)); 283 } else { 284 MP_CHECKOK(mp_copy(&x2, rx)); 285 MP_CHECKOK(mp_copy(&z2, ry)); 286 } 287 288 CLEANUP: 289 mp_clear(&x1); 290 mp_clear(&x2); 291 mp_clear(&z1); 292 mp_clear(&z2); 293 return res; 294 }