Wed, 31 Dec 2014 06:09:35 +0100
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 "ecp.h" |
michael@0 | 6 | #include "mpi.h" |
michael@0 | 7 | #include "mplogic.h" |
michael@0 | 8 | #include "mpi-priv.h" |
michael@0 | 9 | |
michael@0 | 10 | #define ECP224_DIGITS ECL_CURVE_DIGITS(224) |
michael@0 | 11 | |
michael@0 | 12 | /* Fast modular reduction for p224 = 2^224 - 2^96 + 1. a can be r. Uses |
michael@0 | 13 | * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software |
michael@0 | 14 | * Implementation of the NIST Elliptic Curves over Prime Fields. */ |
michael@0 | 15 | static mp_err |
michael@0 | 16 | ec_GFp_nistp224_mod(const mp_int *a, mp_int *r, const GFMethod *meth) |
michael@0 | 17 | { |
michael@0 | 18 | mp_err res = MP_OKAY; |
michael@0 | 19 | mp_size a_used = MP_USED(a); |
michael@0 | 20 | |
michael@0 | 21 | int r3b; |
michael@0 | 22 | mp_digit carry; |
michael@0 | 23 | #ifdef ECL_THIRTY_TWO_BIT |
michael@0 | 24 | mp_digit a6a = 0, a6b = 0, |
michael@0 | 25 | a5a = 0, a5b = 0, a4a = 0, a4b = 0, a3a = 0, a3b = 0; |
michael@0 | 26 | mp_digit r0a, r0b, r1a, r1b, r2a, r2b, r3a; |
michael@0 | 27 | #else |
michael@0 | 28 | mp_digit a6 = 0, a5 = 0, a4 = 0, a3b = 0, a5a = 0; |
michael@0 | 29 | mp_digit a6b = 0, a6a_a5b = 0, a5b = 0, a5a_a4b = 0, a4a_a3b = 0; |
michael@0 | 30 | mp_digit r0, r1, r2, r3; |
michael@0 | 31 | #endif |
michael@0 | 32 | |
michael@0 | 33 | /* reduction not needed if a is not larger than field size */ |
michael@0 | 34 | if (a_used < ECP224_DIGITS) { |
michael@0 | 35 | if (a == r) return MP_OKAY; |
michael@0 | 36 | return mp_copy(a, r); |
michael@0 | 37 | } |
michael@0 | 38 | /* for polynomials larger than twice the field size, use regular |
michael@0 | 39 | * reduction */ |
michael@0 | 40 | if (a_used > ECL_CURVE_DIGITS(224*2)) { |
michael@0 | 41 | MP_CHECKOK(mp_mod(a, &meth->irr, r)); |
michael@0 | 42 | } else { |
michael@0 | 43 | #ifdef ECL_THIRTY_TWO_BIT |
michael@0 | 44 | /* copy out upper words of a */ |
michael@0 | 45 | switch (a_used) { |
michael@0 | 46 | case 14: |
michael@0 | 47 | a6b = MP_DIGIT(a, 13); |
michael@0 | 48 | case 13: |
michael@0 | 49 | a6a = MP_DIGIT(a, 12); |
michael@0 | 50 | case 12: |
michael@0 | 51 | a5b = MP_DIGIT(a, 11); |
michael@0 | 52 | case 11: |
michael@0 | 53 | a5a = MP_DIGIT(a, 10); |
michael@0 | 54 | case 10: |
michael@0 | 55 | a4b = MP_DIGIT(a, 9); |
michael@0 | 56 | case 9: |
michael@0 | 57 | a4a = MP_DIGIT(a, 8); |
michael@0 | 58 | case 8: |
michael@0 | 59 | a3b = MP_DIGIT(a, 7); |
michael@0 | 60 | } |
michael@0 | 61 | r3a = MP_DIGIT(a, 6); |
michael@0 | 62 | r2b= MP_DIGIT(a, 5); |
michael@0 | 63 | r2a= MP_DIGIT(a, 4); |
michael@0 | 64 | r1b = MP_DIGIT(a, 3); |
michael@0 | 65 | r1a = MP_DIGIT(a, 2); |
michael@0 | 66 | r0b = MP_DIGIT(a, 1); |
michael@0 | 67 | r0a = MP_DIGIT(a, 0); |
michael@0 | 68 | |
michael@0 | 69 | |
michael@0 | 70 | /* implement r = (a3a,a2,a1,a0) |
michael@0 | 71 | +(a5a, a4,a3b, 0) |
michael@0 | 72 | +( 0, a6,a5b, 0) |
michael@0 | 73 | -( 0 0, 0|a6b, a6a|a5b ) |
michael@0 | 74 | -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */ |
michael@0 | 75 | MP_ADD_CARRY (r1b, a3b, r1b, 0, carry); |
michael@0 | 76 | MP_ADD_CARRY (r2a, a4a, r2a, carry, carry); |
michael@0 | 77 | MP_ADD_CARRY (r2b, a4b, r2b, carry, carry); |
michael@0 | 78 | MP_ADD_CARRY (r3a, a5a, r3a, carry, carry); |
michael@0 | 79 | r3b = carry; |
michael@0 | 80 | MP_ADD_CARRY (r1b, a5b, r1b, 0, carry); |
michael@0 | 81 | MP_ADD_CARRY (r2a, a6a, r2a, carry, carry); |
michael@0 | 82 | MP_ADD_CARRY (r2b, a6b, r2b, carry, carry); |
michael@0 | 83 | MP_ADD_CARRY (r3a, 0, r3a, carry, carry); |
michael@0 | 84 | r3b += carry; |
michael@0 | 85 | MP_SUB_BORROW(r0a, a3b, r0a, 0, carry); |
michael@0 | 86 | MP_SUB_BORROW(r0b, a4a, r0b, carry, carry); |
michael@0 | 87 | MP_SUB_BORROW(r1a, a4b, r1a, carry, carry); |
michael@0 | 88 | MP_SUB_BORROW(r1b, a5a, r1b, carry, carry); |
michael@0 | 89 | MP_SUB_BORROW(r2a, a5b, r2a, carry, carry); |
michael@0 | 90 | MP_SUB_BORROW(r2b, a6a, r2b, carry, carry); |
michael@0 | 91 | MP_SUB_BORROW(r3a, a6b, r3a, carry, carry); |
michael@0 | 92 | r3b -= carry; |
michael@0 | 93 | MP_SUB_BORROW(r0a, a5b, r0a, 0, carry); |
michael@0 | 94 | MP_SUB_BORROW(r0b, a6a, r0b, carry, carry); |
michael@0 | 95 | MP_SUB_BORROW(r1a, a6b, r1a, carry, carry); |
michael@0 | 96 | if (carry) { |
michael@0 | 97 | MP_SUB_BORROW(r1b, 0, r1b, carry, carry); |
michael@0 | 98 | MP_SUB_BORROW(r2a, 0, r2a, carry, carry); |
michael@0 | 99 | MP_SUB_BORROW(r2b, 0, r2b, carry, carry); |
michael@0 | 100 | MP_SUB_BORROW(r3a, 0, r3a, carry, carry); |
michael@0 | 101 | r3b -= carry; |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | while (r3b > 0) { |
michael@0 | 105 | int tmp; |
michael@0 | 106 | MP_ADD_CARRY(r1b, r3b, r1b, 0, carry); |
michael@0 | 107 | if (carry) { |
michael@0 | 108 | MP_ADD_CARRY(r2a, 0, r2a, carry, carry); |
michael@0 | 109 | MP_ADD_CARRY(r2b, 0, r2b, carry, carry); |
michael@0 | 110 | MP_ADD_CARRY(r3a, 0, r3a, carry, carry); |
michael@0 | 111 | } |
michael@0 | 112 | tmp = carry; |
michael@0 | 113 | MP_SUB_BORROW(r0a, r3b, r0a, 0, carry); |
michael@0 | 114 | if (carry) { |
michael@0 | 115 | MP_SUB_BORROW(r0b, 0, r0b, carry, carry); |
michael@0 | 116 | MP_SUB_BORROW(r1a, 0, r1a, carry, carry); |
michael@0 | 117 | MP_SUB_BORROW(r1b, 0, r1b, carry, carry); |
michael@0 | 118 | MP_SUB_BORROW(r2a, 0, r2a, carry, carry); |
michael@0 | 119 | MP_SUB_BORROW(r2b, 0, r2b, carry, carry); |
michael@0 | 120 | MP_SUB_BORROW(r3a, 0, r3a, carry, carry); |
michael@0 | 121 | tmp -= carry; |
michael@0 | 122 | } |
michael@0 | 123 | r3b = tmp; |
michael@0 | 124 | } |
michael@0 | 125 | |
michael@0 | 126 | while (r3b < 0) { |
michael@0 | 127 | mp_digit maxInt = MP_DIGIT_MAX; |
michael@0 | 128 | MP_ADD_CARRY (r0a, 1, r0a, 0, carry); |
michael@0 | 129 | MP_ADD_CARRY (r0b, 0, r0b, carry, carry); |
michael@0 | 130 | MP_ADD_CARRY (r1a, 0, r1a, carry, carry); |
michael@0 | 131 | MP_ADD_CARRY (r1b, maxInt, r1b, carry, carry); |
michael@0 | 132 | MP_ADD_CARRY (r2a, maxInt, r2a, carry, carry); |
michael@0 | 133 | MP_ADD_CARRY (r2b, maxInt, r2b, carry, carry); |
michael@0 | 134 | MP_ADD_CARRY (r3a, maxInt, r3a, carry, carry); |
michael@0 | 135 | r3b += carry; |
michael@0 | 136 | } |
michael@0 | 137 | /* check for final reduction */ |
michael@0 | 138 | /* now the only way we are over is if the top 4 words are all ones */ |
michael@0 | 139 | if ((r3a == MP_DIGIT_MAX) && (r2b == MP_DIGIT_MAX) |
michael@0 | 140 | && (r2a == MP_DIGIT_MAX) && (r1b == MP_DIGIT_MAX) && |
michael@0 | 141 | ((r1a != 0) || (r0b != 0) || (r0a != 0)) ) { |
michael@0 | 142 | /* one last subraction */ |
michael@0 | 143 | MP_SUB_BORROW(r0a, 1, r0a, 0, carry); |
michael@0 | 144 | MP_SUB_BORROW(r0b, 0, r0b, carry, carry); |
michael@0 | 145 | MP_SUB_BORROW(r1a, 0, r1a, carry, carry); |
michael@0 | 146 | r1b = r2a = r2b = r3a = 0; |
michael@0 | 147 | } |
michael@0 | 148 | |
michael@0 | 149 | |
michael@0 | 150 | if (a != r) { |
michael@0 | 151 | MP_CHECKOK(s_mp_pad(r, 7)); |
michael@0 | 152 | } |
michael@0 | 153 | /* set the lower words of r */ |
michael@0 | 154 | MP_SIGN(r) = MP_ZPOS; |
michael@0 | 155 | MP_USED(r) = 7; |
michael@0 | 156 | MP_DIGIT(r, 6) = r3a; |
michael@0 | 157 | MP_DIGIT(r, 5) = r2b; |
michael@0 | 158 | MP_DIGIT(r, 4) = r2a; |
michael@0 | 159 | MP_DIGIT(r, 3) = r1b; |
michael@0 | 160 | MP_DIGIT(r, 2) = r1a; |
michael@0 | 161 | MP_DIGIT(r, 1) = r0b; |
michael@0 | 162 | MP_DIGIT(r, 0) = r0a; |
michael@0 | 163 | #else |
michael@0 | 164 | /* copy out upper words of a */ |
michael@0 | 165 | switch (a_used) { |
michael@0 | 166 | case 7: |
michael@0 | 167 | a6 = MP_DIGIT(a, 6); |
michael@0 | 168 | a6b = a6 >> 32; |
michael@0 | 169 | a6a_a5b = a6 << 32; |
michael@0 | 170 | case 6: |
michael@0 | 171 | a5 = MP_DIGIT(a, 5); |
michael@0 | 172 | a5b = a5 >> 32; |
michael@0 | 173 | a6a_a5b |= a5b; |
michael@0 | 174 | a5b = a5b << 32; |
michael@0 | 175 | a5a_a4b = a5 << 32; |
michael@0 | 176 | a5a = a5 & 0xffffffff; |
michael@0 | 177 | case 5: |
michael@0 | 178 | a4 = MP_DIGIT(a, 4); |
michael@0 | 179 | a5a_a4b |= a4 >> 32; |
michael@0 | 180 | a4a_a3b = a4 << 32; |
michael@0 | 181 | case 4: |
michael@0 | 182 | a3b = MP_DIGIT(a, 3) >> 32; |
michael@0 | 183 | a4a_a3b |= a3b; |
michael@0 | 184 | a3b = a3b << 32; |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | r3 = MP_DIGIT(a, 3) & 0xffffffff; |
michael@0 | 188 | r2 = MP_DIGIT(a, 2); |
michael@0 | 189 | r1 = MP_DIGIT(a, 1); |
michael@0 | 190 | r0 = MP_DIGIT(a, 0); |
michael@0 | 191 | |
michael@0 | 192 | /* implement r = (a3a,a2,a1,a0) |
michael@0 | 193 | +(a5a, a4,a3b, 0) |
michael@0 | 194 | +( 0, a6,a5b, 0) |
michael@0 | 195 | -( 0 0, 0|a6b, a6a|a5b ) |
michael@0 | 196 | -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */ |
michael@0 | 197 | MP_ADD_CARRY (r1, a3b, r1, 0, carry); |
michael@0 | 198 | MP_ADD_CARRY (r2, a4 , r2, carry, carry); |
michael@0 | 199 | MP_ADD_CARRY (r3, a5a, r3, carry, carry); |
michael@0 | 200 | MP_ADD_CARRY (r1, a5b, r1, 0, carry); |
michael@0 | 201 | MP_ADD_CARRY (r2, a6 , r2, carry, carry); |
michael@0 | 202 | MP_ADD_CARRY (r3, 0, r3, carry, carry); |
michael@0 | 203 | |
michael@0 | 204 | MP_SUB_BORROW(r0, a4a_a3b, r0, 0, carry); |
michael@0 | 205 | MP_SUB_BORROW(r1, a5a_a4b, r1, carry, carry); |
michael@0 | 206 | MP_SUB_BORROW(r2, a6a_a5b, r2, carry, carry); |
michael@0 | 207 | MP_SUB_BORROW(r3, a6b , r3, carry, carry); |
michael@0 | 208 | MP_SUB_BORROW(r0, a6a_a5b, r0, 0, carry); |
michael@0 | 209 | MP_SUB_BORROW(r1, a6b , r1, carry, carry); |
michael@0 | 210 | if (carry) { |
michael@0 | 211 | MP_SUB_BORROW(r2, 0, r2, carry, carry); |
michael@0 | 212 | MP_SUB_BORROW(r3, 0, r3, carry, carry); |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | |
michael@0 | 216 | /* if the value is negative, r3 has a 2's complement |
michael@0 | 217 | * high value */ |
michael@0 | 218 | r3b = (int)(r3 >>32); |
michael@0 | 219 | while (r3b > 0) { |
michael@0 | 220 | r3 &= 0xffffffff; |
michael@0 | 221 | MP_ADD_CARRY(r1,((mp_digit)r3b) << 32, r1, 0, carry); |
michael@0 | 222 | if (carry) { |
michael@0 | 223 | MP_ADD_CARRY(r2, 0, r2, carry, carry); |
michael@0 | 224 | MP_ADD_CARRY(r3, 0, r3, carry, carry); |
michael@0 | 225 | } |
michael@0 | 226 | MP_SUB_BORROW(r0, r3b, r0, 0, carry); |
michael@0 | 227 | if (carry) { |
michael@0 | 228 | MP_SUB_BORROW(r1, 0, r1, carry, carry); |
michael@0 | 229 | MP_SUB_BORROW(r2, 0, r2, carry, carry); |
michael@0 | 230 | MP_SUB_BORROW(r3, 0, r3, carry, carry); |
michael@0 | 231 | } |
michael@0 | 232 | r3b = (int)(r3 >>32); |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | while (r3b < 0) { |
michael@0 | 236 | MP_ADD_CARRY (r0, 1, r0, 0, carry); |
michael@0 | 237 | MP_ADD_CARRY (r1, MP_DIGIT_MAX <<32, r1, carry, carry); |
michael@0 | 238 | MP_ADD_CARRY (r2, MP_DIGIT_MAX, r2, carry, carry); |
michael@0 | 239 | MP_ADD_CARRY (r3, MP_DIGIT_MAX >> 32, r3, carry, carry); |
michael@0 | 240 | r3b = (int)(r3 >>32); |
michael@0 | 241 | } |
michael@0 | 242 | /* check for final reduction */ |
michael@0 | 243 | /* now the only way we are over is if the top 4 words are |
michael@0 | 244 | * all ones. Subtract the curve. (curve is 2^224 - 2^96 +1) |
michael@0 | 245 | */ |
michael@0 | 246 | if ((r3 == (MP_DIGIT_MAX >> 32)) && (r2 == MP_DIGIT_MAX) |
michael@0 | 247 | && ((r1 & MP_DIGIT_MAX << 32)== MP_DIGIT_MAX << 32) && |
michael@0 | 248 | ((r1 != MP_DIGIT_MAX << 32 ) || (r0 != 0)) ) { |
michael@0 | 249 | /* one last subraction */ |
michael@0 | 250 | MP_SUB_BORROW(r0, 1, r0, 0, carry); |
michael@0 | 251 | MP_SUB_BORROW(r1, MP_DIGIT_MAX << 32, r1, carry, carry); |
michael@0 | 252 | r2 = r3 = 0; |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | |
michael@0 | 256 | if (a != r) { |
michael@0 | 257 | MP_CHECKOK(s_mp_pad(r, 4)); |
michael@0 | 258 | } |
michael@0 | 259 | /* set the lower words of r */ |
michael@0 | 260 | MP_SIGN(r) = MP_ZPOS; |
michael@0 | 261 | MP_USED(r) = 4; |
michael@0 | 262 | MP_DIGIT(r, 3) = r3; |
michael@0 | 263 | MP_DIGIT(r, 2) = r2; |
michael@0 | 264 | MP_DIGIT(r, 1) = r1; |
michael@0 | 265 | MP_DIGIT(r, 0) = r0; |
michael@0 | 266 | #endif |
michael@0 | 267 | } |
michael@0 | 268 | s_mp_clamp(r); |
michael@0 | 269 | |
michael@0 | 270 | CLEANUP: |
michael@0 | 271 | return res; |
michael@0 | 272 | } |
michael@0 | 273 | |
michael@0 | 274 | /* Compute the square of polynomial a, reduce modulo p224. Store the |
michael@0 | 275 | * result in r. r could be a. Uses optimized modular reduction for p224. |
michael@0 | 276 | */ |
michael@0 | 277 | static mp_err |
michael@0 | 278 | ec_GFp_nistp224_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) |
michael@0 | 279 | { |
michael@0 | 280 | mp_err res = MP_OKAY; |
michael@0 | 281 | |
michael@0 | 282 | MP_CHECKOK(mp_sqr(a, r)); |
michael@0 | 283 | MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); |
michael@0 | 284 | CLEANUP: |
michael@0 | 285 | return res; |
michael@0 | 286 | } |
michael@0 | 287 | |
michael@0 | 288 | /* Compute the product of two polynomials a and b, reduce modulo p224. |
michael@0 | 289 | * Store the result in r. r could be a or b; a could be b. Uses |
michael@0 | 290 | * optimized modular reduction for p224. */ |
michael@0 | 291 | static mp_err |
michael@0 | 292 | ec_GFp_nistp224_mul(const mp_int *a, const mp_int *b, mp_int *r, |
michael@0 | 293 | const GFMethod *meth) |
michael@0 | 294 | { |
michael@0 | 295 | mp_err res = MP_OKAY; |
michael@0 | 296 | |
michael@0 | 297 | MP_CHECKOK(mp_mul(a, b, r)); |
michael@0 | 298 | MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); |
michael@0 | 299 | CLEANUP: |
michael@0 | 300 | return res; |
michael@0 | 301 | } |
michael@0 | 302 | |
michael@0 | 303 | /* Divides two field elements. If a is NULL, then returns the inverse of |
michael@0 | 304 | * b. */ |
michael@0 | 305 | static mp_err |
michael@0 | 306 | ec_GFp_nistp224_div(const mp_int *a, const mp_int *b, mp_int *r, |
michael@0 | 307 | const GFMethod *meth) |
michael@0 | 308 | { |
michael@0 | 309 | mp_err res = MP_OKAY; |
michael@0 | 310 | mp_int t; |
michael@0 | 311 | |
michael@0 | 312 | /* If a is NULL, then return the inverse of b, otherwise return a/b. */ |
michael@0 | 313 | if (a == NULL) { |
michael@0 | 314 | return mp_invmod(b, &meth->irr, r); |
michael@0 | 315 | } else { |
michael@0 | 316 | /* MPI doesn't support divmod, so we implement it using invmod and |
michael@0 | 317 | * mulmod. */ |
michael@0 | 318 | MP_CHECKOK(mp_init(&t)); |
michael@0 | 319 | MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); |
michael@0 | 320 | MP_CHECKOK(mp_mul(a, &t, r)); |
michael@0 | 321 | MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); |
michael@0 | 322 | CLEANUP: |
michael@0 | 323 | mp_clear(&t); |
michael@0 | 324 | return res; |
michael@0 | 325 | } |
michael@0 | 326 | } |
michael@0 | 327 | |
michael@0 | 328 | /* Wire in fast field arithmetic and precomputation of base point for |
michael@0 | 329 | * named curves. */ |
michael@0 | 330 | mp_err |
michael@0 | 331 | ec_group_set_gfp224(ECGroup *group, ECCurveName name) |
michael@0 | 332 | { |
michael@0 | 333 | if (name == ECCurve_NIST_P224) { |
michael@0 | 334 | group->meth->field_mod = &ec_GFp_nistp224_mod; |
michael@0 | 335 | group->meth->field_mul = &ec_GFp_nistp224_mul; |
michael@0 | 336 | group->meth->field_sqr = &ec_GFp_nistp224_sqr; |
michael@0 | 337 | group->meth->field_div = &ec_GFp_nistp224_div; |
michael@0 | 338 | } |
michael@0 | 339 | return MP_OKAY; |
michael@0 | 340 | } |