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 prime 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 * Douglas Stebila <douglas@stebila.ca> 38 * 39 * Alternatively, the contents of this file may be used under the terms of 40 * either the GNU General Public License Version 2 or later (the "GPL"), or 41 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 42 * in which case the provisions of the GPL or the LGPL are applicable instead 43 * of those above. If you wish to allow use of your version of this file only 44 * under the terms of either the GPL or the LGPL, and not to allow others to 45 * use your version of this file under the terms of the MPL, indicate your 46 * decision by deleting the provisions above and replace them with the notice 47 * and other provisions required by the GPL or the LGPL. If you do not delete 48 * the provisions above, a recipient may use your version of this file under 49 * the terms of any one of the MPL, the GPL or the LGPL. 50 * 51 *********************************************************************** */ 52 /* 53 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 54 * Use is subject to license terms. 55 */ 56 57 #include "ecp.h" 58 #include "mpi.h" 59 #include "mplogic.h" 60 #include "mpi-priv.h" 61 #ifndef _KERNEL 62 #include <stdlib.h> 63 #endif 64 65 #define ECP521_DIGITS ECL_CURVE_DIGITS(521) 66 67 /* Fast modular reduction for p521 = 2^521 - 1. a can be r. Uses 68 * algorithm 2.31 from Hankerson, Menezes, Vanstone. Guide to 69 * Elliptic Curve Cryptography. */ 70 mp_err 71 ec_GFp_nistp521_mod(const mp_int *a, mp_int *r, const GFMethod *meth) 72 { 73 mp_err res = MP_OKAY; 74 int a_bits = mpl_significant_bits(a); 75 unsigned int i; 76 77 /* m1, m2 are statically-allocated mp_int of exactly the size we need */ 78 mp_int m1; 79 80 mp_digit s1[ECP521_DIGITS] = { 0 }; 81 82 MP_SIGN(&m1) = MP_ZPOS; 83 MP_ALLOC(&m1) = ECP521_DIGITS; 84 MP_USED(&m1) = ECP521_DIGITS; 85 MP_DIGITS(&m1) = s1; 86 87 if (a_bits < 521) { 88 if (a==r) return MP_OKAY; 89 return mp_copy(a, r); 90 } 91 /* for polynomials larger than twice the field size or polynomials 92 * not using all words, use regular reduction */ 93 if (a_bits > (521*2)) { 94 MP_CHECKOK(mp_mod(a, &meth->irr, r)); 95 } else { 96 #define FIRST_DIGIT (ECP521_DIGITS-1) 97 for (i = FIRST_DIGIT; i < MP_USED(a)-1; i++) { 98 s1[i-FIRST_DIGIT] = (MP_DIGIT(a, i) >> 9) 99 | (MP_DIGIT(a, 1+i) << (MP_DIGIT_BIT-9)); 100 } 101 s1[i-FIRST_DIGIT] = MP_DIGIT(a, i) >> 9; 102 103 if ( a != r ) { 104 MP_CHECKOK(s_mp_pad(r,ECP521_DIGITS)); 105 for (i = 0; i < ECP521_DIGITS; i++) { 106 MP_DIGIT(r,i) = MP_DIGIT(a, i); 107 } 108 } 109 MP_USED(r) = ECP521_DIGITS; 110 MP_DIGIT(r,FIRST_DIGIT) &= 0x1FF; 111 112 MP_CHECKOK(s_mp_add(r, &m1)); 113 if (MP_DIGIT(r, FIRST_DIGIT) & 0x200) { 114 MP_CHECKOK(s_mp_add_d(r,1)); 115 MP_DIGIT(r,FIRST_DIGIT) &= 0x1FF; 116 } 117 s_mp_clamp(r); 118 } 119 120 CLEANUP: 121 return res; 122 } 123 124 /* Compute the square of polynomial a, reduce modulo p521. Store the 125 * result in r. r could be a. Uses optimized modular reduction for p521. 126 */ 127 mp_err 128 ec_GFp_nistp521_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) 129 { 130 mp_err res = MP_OKAY; 131 132 MP_CHECKOK(mp_sqr(a, r)); 133 MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth)); 134 CLEANUP: 135 return res; 136 } 137 138 /* Compute the product of two polynomials a and b, reduce modulo p521. 139 * Store the result in r. r could be a or b; a could be b. Uses 140 * optimized modular reduction for p521. */ 141 mp_err 142 ec_GFp_nistp521_mul(const mp_int *a, const mp_int *b, mp_int *r, 143 const GFMethod *meth) 144 { 145 mp_err res = MP_OKAY; 146 147 MP_CHECKOK(mp_mul(a, b, r)); 148 MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth)); 149 CLEANUP: 150 return res; 151 } 152 153 /* Divides two field elements. If a is NULL, then returns the inverse of 154 * b. */ 155 mp_err 156 ec_GFp_nistp521_div(const mp_int *a, const mp_int *b, mp_int *r, 157 const GFMethod *meth) 158 { 159 mp_err res = MP_OKAY; 160 mp_int t; 161 162 /* If a is NULL, then return the inverse of b, otherwise return a/b. */ 163 if (a == NULL) { 164 return mp_invmod(b, &meth->irr, r); 165 } else { 166 /* MPI doesn't support divmod, so we implement it using invmod and 167 * mulmod. */ 168 MP_CHECKOK(mp_init(&t, FLAG(b))); 169 MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); 170 MP_CHECKOK(mp_mul(a, &t, r)); 171 MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth)); 172 CLEANUP: 173 mp_clear(&t); 174 return res; 175 } 176 } 177 178 /* Wire in fast field arithmetic and precomputation of base point for 179 * named curves. */ 180 mp_err 181 ec_group_set_gfp521(ECGroup *group, ECCurveName name) 182 { 183 if (name == ECCurve_NIST_P521) { 184 group->meth->field_mod = &ec_GFp_nistp521_mod; 185 group->meth->field_mul = &ec_GFp_nistp521_mul; 186 group->meth->field_sqr = &ec_GFp_nistp521_sqr; 187 group->meth->field_div = &ec_GFp_nistp521_div; 188 } 189 return MP_OKAY; 190 }