1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/ecl/ecp_224.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,340 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "ecp.h" 1.9 +#include "mpi.h" 1.10 +#include "mplogic.h" 1.11 +#include "mpi-priv.h" 1.12 + 1.13 +#define ECP224_DIGITS ECL_CURVE_DIGITS(224) 1.14 + 1.15 +/* Fast modular reduction for p224 = 2^224 - 2^96 + 1. a can be r. Uses 1.16 + * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software 1.17 + * Implementation of the NIST Elliptic Curves over Prime Fields. */ 1.18 +static mp_err 1.19 +ec_GFp_nistp224_mod(const mp_int *a, mp_int *r, const GFMethod *meth) 1.20 +{ 1.21 + mp_err res = MP_OKAY; 1.22 + mp_size a_used = MP_USED(a); 1.23 + 1.24 + int r3b; 1.25 + mp_digit carry; 1.26 +#ifdef ECL_THIRTY_TWO_BIT 1.27 + mp_digit a6a = 0, a6b = 0, 1.28 + a5a = 0, a5b = 0, a4a = 0, a4b = 0, a3a = 0, a3b = 0; 1.29 + mp_digit r0a, r0b, r1a, r1b, r2a, r2b, r3a; 1.30 +#else 1.31 + mp_digit a6 = 0, a5 = 0, a4 = 0, a3b = 0, a5a = 0; 1.32 + mp_digit a6b = 0, a6a_a5b = 0, a5b = 0, a5a_a4b = 0, a4a_a3b = 0; 1.33 + mp_digit r0, r1, r2, r3; 1.34 +#endif 1.35 + 1.36 + /* reduction not needed if a is not larger than field size */ 1.37 + if (a_used < ECP224_DIGITS) { 1.38 + if (a == r) return MP_OKAY; 1.39 + return mp_copy(a, r); 1.40 + } 1.41 + /* for polynomials larger than twice the field size, use regular 1.42 + * reduction */ 1.43 + if (a_used > ECL_CURVE_DIGITS(224*2)) { 1.44 + MP_CHECKOK(mp_mod(a, &meth->irr, r)); 1.45 + } else { 1.46 +#ifdef ECL_THIRTY_TWO_BIT 1.47 + /* copy out upper words of a */ 1.48 + switch (a_used) { 1.49 + case 14: 1.50 + a6b = MP_DIGIT(a, 13); 1.51 + case 13: 1.52 + a6a = MP_DIGIT(a, 12); 1.53 + case 12: 1.54 + a5b = MP_DIGIT(a, 11); 1.55 + case 11: 1.56 + a5a = MP_DIGIT(a, 10); 1.57 + case 10: 1.58 + a4b = MP_DIGIT(a, 9); 1.59 + case 9: 1.60 + a4a = MP_DIGIT(a, 8); 1.61 + case 8: 1.62 + a3b = MP_DIGIT(a, 7); 1.63 + } 1.64 + r3a = MP_DIGIT(a, 6); 1.65 + r2b= MP_DIGIT(a, 5); 1.66 + r2a= MP_DIGIT(a, 4); 1.67 + r1b = MP_DIGIT(a, 3); 1.68 + r1a = MP_DIGIT(a, 2); 1.69 + r0b = MP_DIGIT(a, 1); 1.70 + r0a = MP_DIGIT(a, 0); 1.71 + 1.72 + 1.73 + /* implement r = (a3a,a2,a1,a0) 1.74 + +(a5a, a4,a3b, 0) 1.75 + +( 0, a6,a5b, 0) 1.76 + -( 0 0, 0|a6b, a6a|a5b ) 1.77 + -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */ 1.78 + MP_ADD_CARRY (r1b, a3b, r1b, 0, carry); 1.79 + MP_ADD_CARRY (r2a, a4a, r2a, carry, carry); 1.80 + MP_ADD_CARRY (r2b, a4b, r2b, carry, carry); 1.81 + MP_ADD_CARRY (r3a, a5a, r3a, carry, carry); 1.82 + r3b = carry; 1.83 + MP_ADD_CARRY (r1b, a5b, r1b, 0, carry); 1.84 + MP_ADD_CARRY (r2a, a6a, r2a, carry, carry); 1.85 + MP_ADD_CARRY (r2b, a6b, r2b, carry, carry); 1.86 + MP_ADD_CARRY (r3a, 0, r3a, carry, carry); 1.87 + r3b += carry; 1.88 + MP_SUB_BORROW(r0a, a3b, r0a, 0, carry); 1.89 + MP_SUB_BORROW(r0b, a4a, r0b, carry, carry); 1.90 + MP_SUB_BORROW(r1a, a4b, r1a, carry, carry); 1.91 + MP_SUB_BORROW(r1b, a5a, r1b, carry, carry); 1.92 + MP_SUB_BORROW(r2a, a5b, r2a, carry, carry); 1.93 + MP_SUB_BORROW(r2b, a6a, r2b, carry, carry); 1.94 + MP_SUB_BORROW(r3a, a6b, r3a, carry, carry); 1.95 + r3b -= carry; 1.96 + MP_SUB_BORROW(r0a, a5b, r0a, 0, carry); 1.97 + MP_SUB_BORROW(r0b, a6a, r0b, carry, carry); 1.98 + MP_SUB_BORROW(r1a, a6b, r1a, carry, carry); 1.99 + if (carry) { 1.100 + MP_SUB_BORROW(r1b, 0, r1b, carry, carry); 1.101 + MP_SUB_BORROW(r2a, 0, r2a, carry, carry); 1.102 + MP_SUB_BORROW(r2b, 0, r2b, carry, carry); 1.103 + MP_SUB_BORROW(r3a, 0, r3a, carry, carry); 1.104 + r3b -= carry; 1.105 + } 1.106 + 1.107 + while (r3b > 0) { 1.108 + int tmp; 1.109 + MP_ADD_CARRY(r1b, r3b, r1b, 0, carry); 1.110 + if (carry) { 1.111 + MP_ADD_CARRY(r2a, 0, r2a, carry, carry); 1.112 + MP_ADD_CARRY(r2b, 0, r2b, carry, carry); 1.113 + MP_ADD_CARRY(r3a, 0, r3a, carry, carry); 1.114 + } 1.115 + tmp = carry; 1.116 + MP_SUB_BORROW(r0a, r3b, r0a, 0, carry); 1.117 + if (carry) { 1.118 + MP_SUB_BORROW(r0b, 0, r0b, carry, carry); 1.119 + MP_SUB_BORROW(r1a, 0, r1a, carry, carry); 1.120 + MP_SUB_BORROW(r1b, 0, r1b, carry, carry); 1.121 + MP_SUB_BORROW(r2a, 0, r2a, carry, carry); 1.122 + MP_SUB_BORROW(r2b, 0, r2b, carry, carry); 1.123 + MP_SUB_BORROW(r3a, 0, r3a, carry, carry); 1.124 + tmp -= carry; 1.125 + } 1.126 + r3b = tmp; 1.127 + } 1.128 + 1.129 + while (r3b < 0) { 1.130 + mp_digit maxInt = MP_DIGIT_MAX; 1.131 + MP_ADD_CARRY (r0a, 1, r0a, 0, carry); 1.132 + MP_ADD_CARRY (r0b, 0, r0b, carry, carry); 1.133 + MP_ADD_CARRY (r1a, 0, r1a, carry, carry); 1.134 + MP_ADD_CARRY (r1b, maxInt, r1b, carry, carry); 1.135 + MP_ADD_CARRY (r2a, maxInt, r2a, carry, carry); 1.136 + MP_ADD_CARRY (r2b, maxInt, r2b, carry, carry); 1.137 + MP_ADD_CARRY (r3a, maxInt, r3a, carry, carry); 1.138 + r3b += carry; 1.139 + } 1.140 + /* check for final reduction */ 1.141 + /* now the only way we are over is if the top 4 words are all ones */ 1.142 + if ((r3a == MP_DIGIT_MAX) && (r2b == MP_DIGIT_MAX) 1.143 + && (r2a == MP_DIGIT_MAX) && (r1b == MP_DIGIT_MAX) && 1.144 + ((r1a != 0) || (r0b != 0) || (r0a != 0)) ) { 1.145 + /* one last subraction */ 1.146 + MP_SUB_BORROW(r0a, 1, r0a, 0, carry); 1.147 + MP_SUB_BORROW(r0b, 0, r0b, carry, carry); 1.148 + MP_SUB_BORROW(r1a, 0, r1a, carry, carry); 1.149 + r1b = r2a = r2b = r3a = 0; 1.150 + } 1.151 + 1.152 + 1.153 + if (a != r) { 1.154 + MP_CHECKOK(s_mp_pad(r, 7)); 1.155 + } 1.156 + /* set the lower words of r */ 1.157 + MP_SIGN(r) = MP_ZPOS; 1.158 + MP_USED(r) = 7; 1.159 + MP_DIGIT(r, 6) = r3a; 1.160 + MP_DIGIT(r, 5) = r2b; 1.161 + MP_DIGIT(r, 4) = r2a; 1.162 + MP_DIGIT(r, 3) = r1b; 1.163 + MP_DIGIT(r, 2) = r1a; 1.164 + MP_DIGIT(r, 1) = r0b; 1.165 + MP_DIGIT(r, 0) = r0a; 1.166 +#else 1.167 + /* copy out upper words of a */ 1.168 + switch (a_used) { 1.169 + case 7: 1.170 + a6 = MP_DIGIT(a, 6); 1.171 + a6b = a6 >> 32; 1.172 + a6a_a5b = a6 << 32; 1.173 + case 6: 1.174 + a5 = MP_DIGIT(a, 5); 1.175 + a5b = a5 >> 32; 1.176 + a6a_a5b |= a5b; 1.177 + a5b = a5b << 32; 1.178 + a5a_a4b = a5 << 32; 1.179 + a5a = a5 & 0xffffffff; 1.180 + case 5: 1.181 + a4 = MP_DIGIT(a, 4); 1.182 + a5a_a4b |= a4 >> 32; 1.183 + a4a_a3b = a4 << 32; 1.184 + case 4: 1.185 + a3b = MP_DIGIT(a, 3) >> 32; 1.186 + a4a_a3b |= a3b; 1.187 + a3b = a3b << 32; 1.188 + } 1.189 + 1.190 + r3 = MP_DIGIT(a, 3) & 0xffffffff; 1.191 + r2 = MP_DIGIT(a, 2); 1.192 + r1 = MP_DIGIT(a, 1); 1.193 + r0 = MP_DIGIT(a, 0); 1.194 + 1.195 + /* implement r = (a3a,a2,a1,a0) 1.196 + +(a5a, a4,a3b, 0) 1.197 + +( 0, a6,a5b, 0) 1.198 + -( 0 0, 0|a6b, a6a|a5b ) 1.199 + -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */ 1.200 + MP_ADD_CARRY (r1, a3b, r1, 0, carry); 1.201 + MP_ADD_CARRY (r2, a4 , r2, carry, carry); 1.202 + MP_ADD_CARRY (r3, a5a, r3, carry, carry); 1.203 + MP_ADD_CARRY (r1, a5b, r1, 0, carry); 1.204 + MP_ADD_CARRY (r2, a6 , r2, carry, carry); 1.205 + MP_ADD_CARRY (r3, 0, r3, carry, carry); 1.206 + 1.207 + MP_SUB_BORROW(r0, a4a_a3b, r0, 0, carry); 1.208 + MP_SUB_BORROW(r1, a5a_a4b, r1, carry, carry); 1.209 + MP_SUB_BORROW(r2, a6a_a5b, r2, carry, carry); 1.210 + MP_SUB_BORROW(r3, a6b , r3, carry, carry); 1.211 + MP_SUB_BORROW(r0, a6a_a5b, r0, 0, carry); 1.212 + MP_SUB_BORROW(r1, a6b , r1, carry, carry); 1.213 + if (carry) { 1.214 + MP_SUB_BORROW(r2, 0, r2, carry, carry); 1.215 + MP_SUB_BORROW(r3, 0, r3, carry, carry); 1.216 + } 1.217 + 1.218 + 1.219 + /* if the value is negative, r3 has a 2's complement 1.220 + * high value */ 1.221 + r3b = (int)(r3 >>32); 1.222 + while (r3b > 0) { 1.223 + r3 &= 0xffffffff; 1.224 + MP_ADD_CARRY(r1,((mp_digit)r3b) << 32, r1, 0, carry); 1.225 + if (carry) { 1.226 + MP_ADD_CARRY(r2, 0, r2, carry, carry); 1.227 + MP_ADD_CARRY(r3, 0, r3, carry, carry); 1.228 + } 1.229 + MP_SUB_BORROW(r0, r3b, r0, 0, carry); 1.230 + if (carry) { 1.231 + MP_SUB_BORROW(r1, 0, r1, carry, carry); 1.232 + MP_SUB_BORROW(r2, 0, r2, carry, carry); 1.233 + MP_SUB_BORROW(r3, 0, r3, carry, carry); 1.234 + } 1.235 + r3b = (int)(r3 >>32); 1.236 + } 1.237 + 1.238 + while (r3b < 0) { 1.239 + MP_ADD_CARRY (r0, 1, r0, 0, carry); 1.240 + MP_ADD_CARRY (r1, MP_DIGIT_MAX <<32, r1, carry, carry); 1.241 + MP_ADD_CARRY (r2, MP_DIGIT_MAX, r2, carry, carry); 1.242 + MP_ADD_CARRY (r3, MP_DIGIT_MAX >> 32, r3, carry, carry); 1.243 + r3b = (int)(r3 >>32); 1.244 + } 1.245 + /* check for final reduction */ 1.246 + /* now the only way we are over is if the top 4 words are 1.247 + * all ones. Subtract the curve. (curve is 2^224 - 2^96 +1) 1.248 + */ 1.249 + if ((r3 == (MP_DIGIT_MAX >> 32)) && (r2 == MP_DIGIT_MAX) 1.250 + && ((r1 & MP_DIGIT_MAX << 32)== MP_DIGIT_MAX << 32) && 1.251 + ((r1 != MP_DIGIT_MAX << 32 ) || (r0 != 0)) ) { 1.252 + /* one last subraction */ 1.253 + MP_SUB_BORROW(r0, 1, r0, 0, carry); 1.254 + MP_SUB_BORROW(r1, MP_DIGIT_MAX << 32, r1, carry, carry); 1.255 + r2 = r3 = 0; 1.256 + } 1.257 + 1.258 + 1.259 + if (a != r) { 1.260 + MP_CHECKOK(s_mp_pad(r, 4)); 1.261 + } 1.262 + /* set the lower words of r */ 1.263 + MP_SIGN(r) = MP_ZPOS; 1.264 + MP_USED(r) = 4; 1.265 + MP_DIGIT(r, 3) = r3; 1.266 + MP_DIGIT(r, 2) = r2; 1.267 + MP_DIGIT(r, 1) = r1; 1.268 + MP_DIGIT(r, 0) = r0; 1.269 +#endif 1.270 + } 1.271 + s_mp_clamp(r); 1.272 + 1.273 + CLEANUP: 1.274 + return res; 1.275 +} 1.276 + 1.277 +/* Compute the square of polynomial a, reduce modulo p224. Store the 1.278 + * result in r. r could be a. Uses optimized modular reduction for p224. 1.279 + */ 1.280 +static mp_err 1.281 +ec_GFp_nistp224_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) 1.282 +{ 1.283 + mp_err res = MP_OKAY; 1.284 + 1.285 + MP_CHECKOK(mp_sqr(a, r)); 1.286 + MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); 1.287 + CLEANUP: 1.288 + return res; 1.289 +} 1.290 + 1.291 +/* Compute the product of two polynomials a and b, reduce modulo p224. 1.292 + * Store the result in r. r could be a or b; a could be b. Uses 1.293 + * optimized modular reduction for p224. */ 1.294 +static mp_err 1.295 +ec_GFp_nistp224_mul(const mp_int *a, const mp_int *b, mp_int *r, 1.296 + const GFMethod *meth) 1.297 +{ 1.298 + mp_err res = MP_OKAY; 1.299 + 1.300 + MP_CHECKOK(mp_mul(a, b, r)); 1.301 + MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); 1.302 + CLEANUP: 1.303 + return res; 1.304 +} 1.305 + 1.306 +/* Divides two field elements. If a is NULL, then returns the inverse of 1.307 + * b. */ 1.308 +static mp_err 1.309 +ec_GFp_nistp224_div(const mp_int *a, const mp_int *b, mp_int *r, 1.310 + const GFMethod *meth) 1.311 +{ 1.312 + mp_err res = MP_OKAY; 1.313 + mp_int t; 1.314 + 1.315 + /* If a is NULL, then return the inverse of b, otherwise return a/b. */ 1.316 + if (a == NULL) { 1.317 + return mp_invmod(b, &meth->irr, r); 1.318 + } else { 1.319 + /* MPI doesn't support divmod, so we implement it using invmod and 1.320 + * mulmod. */ 1.321 + MP_CHECKOK(mp_init(&t)); 1.322 + MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); 1.323 + MP_CHECKOK(mp_mul(a, &t, r)); 1.324 + MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); 1.325 + CLEANUP: 1.326 + mp_clear(&t); 1.327 + return res; 1.328 + } 1.329 +} 1.330 + 1.331 +/* Wire in fast field arithmetic and precomputation of base point for 1.332 + * named curves. */ 1.333 +mp_err 1.334 +ec_group_set_gfp224(ECGroup *group, ECCurveName name) 1.335 +{ 1.336 + if (name == ECCurve_NIST_P224) { 1.337 + group->meth->field_mod = &ec_GFp_nistp224_mod; 1.338 + group->meth->field_mul = &ec_GFp_nistp224_mul; 1.339 + group->meth->field_sqr = &ec_GFp_nistp224_sqr; 1.340 + group->meth->field_div = &ec_GFp_nistp224_div; 1.341 + } 1.342 + return MP_OKAY; 1.343 +}