Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 ECP192_DIGITS ECL_CURVE_DIGITS(192) |
michael@0 | 11 | |
michael@0 | 12 | /* Fast modular reduction for p192 = 2^192 - 2^64 - 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_nistp192_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 | mp_digit r3; |
michael@0 | 21 | #ifndef MPI_AMD64_ADD |
michael@0 | 22 | mp_digit carry; |
michael@0 | 23 | #endif |
michael@0 | 24 | #ifdef ECL_THIRTY_TWO_BIT |
michael@0 | 25 | mp_digit a5a = 0, a5b = 0, a4a = 0, a4b = 0, a3a = 0, a3b = 0; |
michael@0 | 26 | mp_digit r0a, r0b, r1a, r1b, r2a, r2b; |
michael@0 | 27 | #else |
michael@0 | 28 | mp_digit a5 = 0, a4 = 0, a3 = 0; |
michael@0 | 29 | mp_digit r0, r1, r2; |
michael@0 | 30 | #endif |
michael@0 | 31 | |
michael@0 | 32 | /* reduction not needed if a is not larger than field size */ |
michael@0 | 33 | if (a_used < ECP192_DIGITS) { |
michael@0 | 34 | if (a == r) { |
michael@0 | 35 | return MP_OKAY; |
michael@0 | 36 | } |
michael@0 | 37 | return mp_copy(a, r); |
michael@0 | 38 | } |
michael@0 | 39 | |
michael@0 | 40 | /* for polynomials larger than twice the field size, use regular |
michael@0 | 41 | * reduction */ |
michael@0 | 42 | if (a_used > ECP192_DIGITS*2) { |
michael@0 | 43 | MP_CHECKOK(mp_mod(a, &meth->irr, r)); |
michael@0 | 44 | } else { |
michael@0 | 45 | /* copy out upper words of a */ |
michael@0 | 46 | |
michael@0 | 47 | #ifdef ECL_THIRTY_TWO_BIT |
michael@0 | 48 | |
michael@0 | 49 | /* in all the math below, |
michael@0 | 50 | * nXb is most signifiant, nXa is least significant */ |
michael@0 | 51 | switch (a_used) { |
michael@0 | 52 | case 12: |
michael@0 | 53 | a5b = MP_DIGIT(a, 11); |
michael@0 | 54 | case 11: |
michael@0 | 55 | a5a = MP_DIGIT(a, 10); |
michael@0 | 56 | case 10: |
michael@0 | 57 | a4b = MP_DIGIT(a, 9); |
michael@0 | 58 | case 9: |
michael@0 | 59 | a4a = MP_DIGIT(a, 8); |
michael@0 | 60 | case 8: |
michael@0 | 61 | a3b = MP_DIGIT(a, 7); |
michael@0 | 62 | case 7: |
michael@0 | 63 | a3a = MP_DIGIT(a, 6); |
michael@0 | 64 | } |
michael@0 | 65 | |
michael@0 | 66 | |
michael@0 | 67 | r2b= MP_DIGIT(a, 5); |
michael@0 | 68 | r2a= MP_DIGIT(a, 4); |
michael@0 | 69 | r1b = MP_DIGIT(a, 3); |
michael@0 | 70 | r1a = MP_DIGIT(a, 2); |
michael@0 | 71 | r0b = MP_DIGIT(a, 1); |
michael@0 | 72 | r0a = MP_DIGIT(a, 0); |
michael@0 | 73 | |
michael@0 | 74 | /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */ |
michael@0 | 75 | MP_ADD_CARRY(r0a, a3a, r0a, 0, carry); |
michael@0 | 76 | MP_ADD_CARRY(r0b, a3b, r0b, carry, carry); |
michael@0 | 77 | MP_ADD_CARRY(r1a, a3a, r1a, carry, carry); |
michael@0 | 78 | MP_ADD_CARRY(r1b, a3b, r1b, carry, carry); |
michael@0 | 79 | MP_ADD_CARRY(r2a, a4a, r2a, carry, carry); |
michael@0 | 80 | MP_ADD_CARRY(r2b, a4b, r2b, carry, carry); |
michael@0 | 81 | r3 = carry; carry = 0; |
michael@0 | 82 | MP_ADD_CARRY(r0a, a5a, r0a, 0, carry); |
michael@0 | 83 | MP_ADD_CARRY(r0b, a5b, r0b, carry, carry); |
michael@0 | 84 | MP_ADD_CARRY(r1a, a5a, r1a, carry, carry); |
michael@0 | 85 | MP_ADD_CARRY(r1b, a5b, r1b, carry, carry); |
michael@0 | 86 | MP_ADD_CARRY(r2a, a5a, r2a, carry, carry); |
michael@0 | 87 | MP_ADD_CARRY(r2b, a5b, r2b, carry, carry); |
michael@0 | 88 | r3 += carry; |
michael@0 | 89 | MP_ADD_CARRY(r1a, a4a, r1a, 0, carry); |
michael@0 | 90 | MP_ADD_CARRY(r1b, a4b, r1b, carry, carry); |
michael@0 | 91 | MP_ADD_CARRY(r2a, 0, r2a, carry, carry); |
michael@0 | 92 | MP_ADD_CARRY(r2b, 0, r2b, carry, carry); |
michael@0 | 93 | r3 += carry; |
michael@0 | 94 | |
michael@0 | 95 | /* reduce out the carry */ |
michael@0 | 96 | while (r3) { |
michael@0 | 97 | MP_ADD_CARRY(r0a, r3, r0a, 0, carry); |
michael@0 | 98 | MP_ADD_CARRY(r0b, 0, r0b, carry, carry); |
michael@0 | 99 | MP_ADD_CARRY(r1a, r3, r1a, carry, carry); |
michael@0 | 100 | MP_ADD_CARRY(r1b, 0, r1b, carry, carry); |
michael@0 | 101 | MP_ADD_CARRY(r2a, 0, r2a, carry, carry); |
michael@0 | 102 | MP_ADD_CARRY(r2b, 0, r2b, carry, carry); |
michael@0 | 103 | r3 = carry; |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | /* check for final reduction */ |
michael@0 | 107 | /* |
michael@0 | 108 | * our field is 0xffffffffffffffff, 0xfffffffffffffffe, |
michael@0 | 109 | * 0xffffffffffffffff. That means we can only be over and need |
michael@0 | 110 | * one more reduction |
michael@0 | 111 | * if r2 == 0xffffffffffffffffff (same as r2+1 == 0) |
michael@0 | 112 | * and |
michael@0 | 113 | * r1 == 0xffffffffffffffffff or |
michael@0 | 114 | * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff |
michael@0 | 115 | * In all cases, we subtract the field (or add the 2's |
michael@0 | 116 | * complement value (1,1,0)). (r0, r1, r2) |
michael@0 | 117 | */ |
michael@0 | 118 | if (((r2b == 0xffffffff) && (r2a == 0xffffffff) |
michael@0 | 119 | && (r1b == 0xffffffff) ) && |
michael@0 | 120 | ((r1a == 0xffffffff) || |
michael@0 | 121 | (r1a == 0xfffffffe) && (r0a == 0xffffffff) && |
michael@0 | 122 | (r0b == 0xffffffff)) ) { |
michael@0 | 123 | /* do a quick subtract */ |
michael@0 | 124 | MP_ADD_CARRY(r0a, 1, r0a, 0, carry); |
michael@0 | 125 | MP_ADD_CARRY(r0b, carry, r0a, 0, carry); |
michael@0 | 126 | r1a += 1+carry; |
michael@0 | 127 | r1b = r2a = r2b = 0; |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | /* set the lower words of r */ |
michael@0 | 131 | if (a != r) { |
michael@0 | 132 | MP_CHECKOK(s_mp_pad(r, 6)); |
michael@0 | 133 | } |
michael@0 | 134 | MP_DIGIT(r, 5) = r2b; |
michael@0 | 135 | MP_DIGIT(r, 4) = r2a; |
michael@0 | 136 | MP_DIGIT(r, 3) = r1b; |
michael@0 | 137 | MP_DIGIT(r, 2) = r1a; |
michael@0 | 138 | MP_DIGIT(r, 1) = r0b; |
michael@0 | 139 | MP_DIGIT(r, 0) = r0a; |
michael@0 | 140 | MP_USED(r) = 6; |
michael@0 | 141 | #else |
michael@0 | 142 | switch (a_used) { |
michael@0 | 143 | case 6: |
michael@0 | 144 | a5 = MP_DIGIT(a, 5); |
michael@0 | 145 | case 5: |
michael@0 | 146 | a4 = MP_DIGIT(a, 4); |
michael@0 | 147 | case 4: |
michael@0 | 148 | a3 = MP_DIGIT(a, 3); |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | r2 = MP_DIGIT(a, 2); |
michael@0 | 152 | r1 = MP_DIGIT(a, 1); |
michael@0 | 153 | r0 = MP_DIGIT(a, 0); |
michael@0 | 154 | |
michael@0 | 155 | /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */ |
michael@0 | 156 | #ifndef MPI_AMD64_ADD |
michael@0 | 157 | MP_ADD_CARRY(r0, a3, r0, 0, carry); |
michael@0 | 158 | MP_ADD_CARRY(r1, a3, r1, carry, carry); |
michael@0 | 159 | MP_ADD_CARRY(r2, a4, r2, carry, carry); |
michael@0 | 160 | r3 = carry; |
michael@0 | 161 | MP_ADD_CARRY(r0, a5, r0, 0, carry); |
michael@0 | 162 | MP_ADD_CARRY(r1, a5, r1, carry, carry); |
michael@0 | 163 | MP_ADD_CARRY(r2, a5, r2, carry, carry); |
michael@0 | 164 | r3 += carry; |
michael@0 | 165 | MP_ADD_CARRY(r1, a4, r1, 0, carry); |
michael@0 | 166 | MP_ADD_CARRY(r2, 0, r2, carry, carry); |
michael@0 | 167 | r3 += carry; |
michael@0 | 168 | |
michael@0 | 169 | #else |
michael@0 | 170 | r2 = MP_DIGIT(a, 2); |
michael@0 | 171 | r1 = MP_DIGIT(a, 1); |
michael@0 | 172 | r0 = MP_DIGIT(a, 0); |
michael@0 | 173 | |
michael@0 | 174 | /* set the lower words of r */ |
michael@0 | 175 | __asm__ ( |
michael@0 | 176 | "xorq %3,%3 \n\t" |
michael@0 | 177 | "addq %4,%0 \n\t" |
michael@0 | 178 | "adcq %4,%1 \n\t" |
michael@0 | 179 | "adcq %5,%2 \n\t" |
michael@0 | 180 | "adcq $0,%3 \n\t" |
michael@0 | 181 | "addq %6,%0 \n\t" |
michael@0 | 182 | "adcq %6,%1 \n\t" |
michael@0 | 183 | "adcq %6,%2 \n\t" |
michael@0 | 184 | "adcq $0,%3 \n\t" |
michael@0 | 185 | "addq %5,%1 \n\t" |
michael@0 | 186 | "adcq $0,%2 \n\t" |
michael@0 | 187 | "adcq $0,%3 \n\t" |
michael@0 | 188 | : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(a3), |
michael@0 | 189 | "=r"(a4), "=r"(a5) |
michael@0 | 190 | : "0" (r0), "1" (r1), "2" (r2), "3" (r3), |
michael@0 | 191 | "4" (a3), "5" (a4), "6"(a5) |
michael@0 | 192 | : "%cc" ); |
michael@0 | 193 | #endif |
michael@0 | 194 | |
michael@0 | 195 | /* reduce out the carry */ |
michael@0 | 196 | while (r3) { |
michael@0 | 197 | #ifndef MPI_AMD64_ADD |
michael@0 | 198 | MP_ADD_CARRY(r0, r3, r0, 0, carry); |
michael@0 | 199 | MP_ADD_CARRY(r1, r3, r1, carry, carry); |
michael@0 | 200 | MP_ADD_CARRY(r2, 0, r2, carry, carry); |
michael@0 | 201 | r3 = carry; |
michael@0 | 202 | #else |
michael@0 | 203 | a3=r3; |
michael@0 | 204 | __asm__ ( |
michael@0 | 205 | "xorq %3,%3 \n\t" |
michael@0 | 206 | "addq %4,%0 \n\t" |
michael@0 | 207 | "adcq %4,%1 \n\t" |
michael@0 | 208 | "adcq $0,%2 \n\t" |
michael@0 | 209 | "adcq $0,%3 \n\t" |
michael@0 | 210 | : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(a3) |
michael@0 | 211 | : "0" (r0), "1" (r1), "2" (r2), "3" (r3), "4"(a3) |
michael@0 | 212 | : "%cc" ); |
michael@0 | 213 | #endif |
michael@0 | 214 | } |
michael@0 | 215 | |
michael@0 | 216 | /* check for final reduction */ |
michael@0 | 217 | /* |
michael@0 | 218 | * our field is 0xffffffffffffffff, 0xfffffffffffffffe, |
michael@0 | 219 | * 0xffffffffffffffff. That means we can only be over and need |
michael@0 | 220 | * one more reduction |
michael@0 | 221 | * if r2 == 0xffffffffffffffffff (same as r2+1 == 0) |
michael@0 | 222 | * and |
michael@0 | 223 | * r1 == 0xffffffffffffffffff or |
michael@0 | 224 | * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff |
michael@0 | 225 | * In all cases, we subtract the field (or add the 2's |
michael@0 | 226 | * complement value (1,1,0)). (r0, r1, r2) |
michael@0 | 227 | */ |
michael@0 | 228 | if (r3 || ((r2 == MP_DIGIT_MAX) && |
michael@0 | 229 | ((r1 == MP_DIGIT_MAX) || |
michael@0 | 230 | ((r1 == (MP_DIGIT_MAX-1)) && (r0 == MP_DIGIT_MAX))))) { |
michael@0 | 231 | /* do a quick subtract */ |
michael@0 | 232 | MP_ADD_CARRY(r0, 1, r0, 0, carry); |
michael@0 | 233 | r1 += 1+carry; |
michael@0 | 234 | r2 = 0; |
michael@0 | 235 | } |
michael@0 | 236 | /* set the lower words of r */ |
michael@0 | 237 | if (a != r) { |
michael@0 | 238 | MP_CHECKOK(s_mp_pad(r, 3)); |
michael@0 | 239 | } |
michael@0 | 240 | MP_DIGIT(r, 2) = r2; |
michael@0 | 241 | MP_DIGIT(r, 1) = r1; |
michael@0 | 242 | MP_DIGIT(r, 0) = r0; |
michael@0 | 243 | MP_USED(r) = 3; |
michael@0 | 244 | #endif |
michael@0 | 245 | } |
michael@0 | 246 | s_mp_clamp(r); |
michael@0 | 247 | CLEANUP: |
michael@0 | 248 | return res; |
michael@0 | 249 | } |
michael@0 | 250 | |
michael@0 | 251 | #ifndef ECL_THIRTY_TWO_BIT |
michael@0 | 252 | /* Compute the sum of 192 bit curves. Do the work in-line since the |
michael@0 | 253 | * number of words are so small, we don't want to overhead of mp function |
michael@0 | 254 | * calls. Uses optimized modular reduction for p192. |
michael@0 | 255 | */ |
michael@0 | 256 | static mp_err |
michael@0 | 257 | ec_GFp_nistp192_add(const mp_int *a, const mp_int *b, mp_int *r, |
michael@0 | 258 | const GFMethod *meth) |
michael@0 | 259 | { |
michael@0 | 260 | mp_err res = MP_OKAY; |
michael@0 | 261 | mp_digit a0 = 0, a1 = 0, a2 = 0; |
michael@0 | 262 | mp_digit r0 = 0, r1 = 0, r2 = 0; |
michael@0 | 263 | mp_digit carry; |
michael@0 | 264 | |
michael@0 | 265 | switch(MP_USED(a)) { |
michael@0 | 266 | case 3: |
michael@0 | 267 | a2 = MP_DIGIT(a,2); |
michael@0 | 268 | case 2: |
michael@0 | 269 | a1 = MP_DIGIT(a,1); |
michael@0 | 270 | case 1: |
michael@0 | 271 | a0 = MP_DIGIT(a,0); |
michael@0 | 272 | } |
michael@0 | 273 | switch(MP_USED(b)) { |
michael@0 | 274 | case 3: |
michael@0 | 275 | r2 = MP_DIGIT(b,2); |
michael@0 | 276 | case 2: |
michael@0 | 277 | r1 = MP_DIGIT(b,1); |
michael@0 | 278 | case 1: |
michael@0 | 279 | r0 = MP_DIGIT(b,0); |
michael@0 | 280 | } |
michael@0 | 281 | |
michael@0 | 282 | #ifndef MPI_AMD64_ADD |
michael@0 | 283 | MP_ADD_CARRY(a0, r0, r0, 0, carry); |
michael@0 | 284 | MP_ADD_CARRY(a1, r1, r1, carry, carry); |
michael@0 | 285 | MP_ADD_CARRY(a2, r2, r2, carry, carry); |
michael@0 | 286 | #else |
michael@0 | 287 | __asm__ ( |
michael@0 | 288 | "xorq %3,%3 \n\t" |
michael@0 | 289 | "addq %4,%0 \n\t" |
michael@0 | 290 | "adcq %5,%1 \n\t" |
michael@0 | 291 | "adcq %6,%2 \n\t" |
michael@0 | 292 | "adcq $0,%3 \n\t" |
michael@0 | 293 | : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(carry) |
michael@0 | 294 | : "r" (a0), "r" (a1), "r" (a2), "0" (r0), |
michael@0 | 295 | "1" (r1), "2" (r2) |
michael@0 | 296 | : "%cc" ); |
michael@0 | 297 | #endif |
michael@0 | 298 | |
michael@0 | 299 | /* Do quick 'subract' if we've gone over |
michael@0 | 300 | * (add the 2's complement of the curve field) */ |
michael@0 | 301 | if (carry || ((r2 == MP_DIGIT_MAX) && |
michael@0 | 302 | ((r1 == MP_DIGIT_MAX) || |
michael@0 | 303 | ((r1 == (MP_DIGIT_MAX-1)) && (r0 == MP_DIGIT_MAX))))) { |
michael@0 | 304 | #ifndef MPI_AMD64_ADD |
michael@0 | 305 | MP_ADD_CARRY(r0, 1, r0, 0, carry); |
michael@0 | 306 | MP_ADD_CARRY(r1, 1, r1, carry, carry); |
michael@0 | 307 | MP_ADD_CARRY(r2, 0, r2, carry, carry); |
michael@0 | 308 | #else |
michael@0 | 309 | __asm__ ( |
michael@0 | 310 | "addq $1,%0 \n\t" |
michael@0 | 311 | "adcq $1,%1 \n\t" |
michael@0 | 312 | "adcq $0,%2 \n\t" |
michael@0 | 313 | : "=r"(r0), "=r"(r1), "=r"(r2) |
michael@0 | 314 | : "0" (r0), "1" (r1), "2" (r2) |
michael@0 | 315 | : "%cc" ); |
michael@0 | 316 | #endif |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | |
michael@0 | 320 | MP_CHECKOK(s_mp_pad(r, 3)); |
michael@0 | 321 | MP_DIGIT(r, 2) = r2; |
michael@0 | 322 | MP_DIGIT(r, 1) = r1; |
michael@0 | 323 | MP_DIGIT(r, 0) = r0; |
michael@0 | 324 | MP_SIGN(r) = MP_ZPOS; |
michael@0 | 325 | MP_USED(r) = 3; |
michael@0 | 326 | s_mp_clamp(r); |
michael@0 | 327 | |
michael@0 | 328 | |
michael@0 | 329 | CLEANUP: |
michael@0 | 330 | return res; |
michael@0 | 331 | } |
michael@0 | 332 | |
michael@0 | 333 | /* Compute the diff of 192 bit curves. Do the work in-line since the |
michael@0 | 334 | * number of words are so small, we don't want to overhead of mp function |
michael@0 | 335 | * calls. Uses optimized modular reduction for p192. |
michael@0 | 336 | */ |
michael@0 | 337 | static mp_err |
michael@0 | 338 | ec_GFp_nistp192_sub(const mp_int *a, const mp_int *b, mp_int *r, |
michael@0 | 339 | const GFMethod *meth) |
michael@0 | 340 | { |
michael@0 | 341 | mp_err res = MP_OKAY; |
michael@0 | 342 | mp_digit b0 = 0, b1 = 0, b2 = 0; |
michael@0 | 343 | mp_digit r0 = 0, r1 = 0, r2 = 0; |
michael@0 | 344 | mp_digit borrow; |
michael@0 | 345 | |
michael@0 | 346 | switch(MP_USED(a)) { |
michael@0 | 347 | case 3: |
michael@0 | 348 | r2 = MP_DIGIT(a,2); |
michael@0 | 349 | case 2: |
michael@0 | 350 | r1 = MP_DIGIT(a,1); |
michael@0 | 351 | case 1: |
michael@0 | 352 | r0 = MP_DIGIT(a,0); |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | switch(MP_USED(b)) { |
michael@0 | 356 | case 3: |
michael@0 | 357 | b2 = MP_DIGIT(b,2); |
michael@0 | 358 | case 2: |
michael@0 | 359 | b1 = MP_DIGIT(b,1); |
michael@0 | 360 | case 1: |
michael@0 | 361 | b0 = MP_DIGIT(b,0); |
michael@0 | 362 | } |
michael@0 | 363 | |
michael@0 | 364 | #ifndef MPI_AMD64_ADD |
michael@0 | 365 | MP_SUB_BORROW(r0, b0, r0, 0, borrow); |
michael@0 | 366 | MP_SUB_BORROW(r1, b1, r1, borrow, borrow); |
michael@0 | 367 | MP_SUB_BORROW(r2, b2, r2, borrow, borrow); |
michael@0 | 368 | #else |
michael@0 | 369 | __asm__ ( |
michael@0 | 370 | "xorq %3,%3 \n\t" |
michael@0 | 371 | "subq %4,%0 \n\t" |
michael@0 | 372 | "sbbq %5,%1 \n\t" |
michael@0 | 373 | "sbbq %6,%2 \n\t" |
michael@0 | 374 | "adcq $0,%3 \n\t" |
michael@0 | 375 | : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(borrow) |
michael@0 | 376 | : "r" (b0), "r" (b1), "r" (b2), "0" (r0), |
michael@0 | 377 | "1" (r1), "2" (r2) |
michael@0 | 378 | : "%cc" ); |
michael@0 | 379 | #endif |
michael@0 | 380 | |
michael@0 | 381 | /* Do quick 'add' if we've gone under 0 |
michael@0 | 382 | * (subtract the 2's complement of the curve field) */ |
michael@0 | 383 | if (borrow) { |
michael@0 | 384 | #ifndef MPI_AMD64_ADD |
michael@0 | 385 | MP_SUB_BORROW(r0, 1, r0, 0, borrow); |
michael@0 | 386 | MP_SUB_BORROW(r1, 1, r1, borrow, borrow); |
michael@0 | 387 | MP_SUB_BORROW(r2, 0, r2, borrow, borrow); |
michael@0 | 388 | #else |
michael@0 | 389 | __asm__ ( |
michael@0 | 390 | "subq $1,%0 \n\t" |
michael@0 | 391 | "sbbq $1,%1 \n\t" |
michael@0 | 392 | "sbbq $0,%2 \n\t" |
michael@0 | 393 | : "=r"(r0), "=r"(r1), "=r"(r2) |
michael@0 | 394 | : "0" (r0), "1" (r1), "2" (r2) |
michael@0 | 395 | : "%cc" ); |
michael@0 | 396 | #endif |
michael@0 | 397 | } |
michael@0 | 398 | |
michael@0 | 399 | MP_CHECKOK(s_mp_pad(r, 3)); |
michael@0 | 400 | MP_DIGIT(r, 2) = r2; |
michael@0 | 401 | MP_DIGIT(r, 1) = r1; |
michael@0 | 402 | MP_DIGIT(r, 0) = r0; |
michael@0 | 403 | MP_SIGN(r) = MP_ZPOS; |
michael@0 | 404 | MP_USED(r) = 3; |
michael@0 | 405 | s_mp_clamp(r); |
michael@0 | 406 | |
michael@0 | 407 | CLEANUP: |
michael@0 | 408 | return res; |
michael@0 | 409 | } |
michael@0 | 410 | |
michael@0 | 411 | #endif |
michael@0 | 412 | |
michael@0 | 413 | /* Compute the square of polynomial a, reduce modulo p192. Store the |
michael@0 | 414 | * result in r. r could be a. Uses optimized modular reduction for p192. |
michael@0 | 415 | */ |
michael@0 | 416 | static mp_err |
michael@0 | 417 | ec_GFp_nistp192_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) |
michael@0 | 418 | { |
michael@0 | 419 | mp_err res = MP_OKAY; |
michael@0 | 420 | |
michael@0 | 421 | MP_CHECKOK(mp_sqr(a, r)); |
michael@0 | 422 | MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth)); |
michael@0 | 423 | CLEANUP: |
michael@0 | 424 | return res; |
michael@0 | 425 | } |
michael@0 | 426 | |
michael@0 | 427 | /* Compute the product of two polynomials a and b, reduce modulo p192. |
michael@0 | 428 | * Store the result in r. r could be a or b; a could be b. Uses |
michael@0 | 429 | * optimized modular reduction for p192. */ |
michael@0 | 430 | static mp_err |
michael@0 | 431 | ec_GFp_nistp192_mul(const mp_int *a, const mp_int *b, mp_int *r, |
michael@0 | 432 | const GFMethod *meth) |
michael@0 | 433 | { |
michael@0 | 434 | mp_err res = MP_OKAY; |
michael@0 | 435 | |
michael@0 | 436 | MP_CHECKOK(mp_mul(a, b, r)); |
michael@0 | 437 | MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth)); |
michael@0 | 438 | CLEANUP: |
michael@0 | 439 | return res; |
michael@0 | 440 | } |
michael@0 | 441 | |
michael@0 | 442 | /* Divides two field elements. If a is NULL, then returns the inverse of |
michael@0 | 443 | * b. */ |
michael@0 | 444 | static mp_err |
michael@0 | 445 | ec_GFp_nistp192_div(const mp_int *a, const mp_int *b, mp_int *r, |
michael@0 | 446 | const GFMethod *meth) |
michael@0 | 447 | { |
michael@0 | 448 | mp_err res = MP_OKAY; |
michael@0 | 449 | mp_int t; |
michael@0 | 450 | |
michael@0 | 451 | /* If a is NULL, then return the inverse of b, otherwise return a/b. */ |
michael@0 | 452 | if (a == NULL) { |
michael@0 | 453 | return mp_invmod(b, &meth->irr, r); |
michael@0 | 454 | } else { |
michael@0 | 455 | /* MPI doesn't support divmod, so we implement it using invmod and |
michael@0 | 456 | * mulmod. */ |
michael@0 | 457 | MP_CHECKOK(mp_init(&t)); |
michael@0 | 458 | MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); |
michael@0 | 459 | MP_CHECKOK(mp_mul(a, &t, r)); |
michael@0 | 460 | MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth)); |
michael@0 | 461 | CLEANUP: |
michael@0 | 462 | mp_clear(&t); |
michael@0 | 463 | return res; |
michael@0 | 464 | } |
michael@0 | 465 | } |
michael@0 | 466 | |
michael@0 | 467 | /* Wire in fast field arithmetic and precomputation of base point for |
michael@0 | 468 | * named curves. */ |
michael@0 | 469 | mp_err |
michael@0 | 470 | ec_group_set_gfp192(ECGroup *group, ECCurveName name) |
michael@0 | 471 | { |
michael@0 | 472 | if (name == ECCurve_NIST_P192) { |
michael@0 | 473 | group->meth->field_mod = &ec_GFp_nistp192_mod; |
michael@0 | 474 | group->meth->field_mul = &ec_GFp_nistp192_mul; |
michael@0 | 475 | group->meth->field_sqr = &ec_GFp_nistp192_sqr; |
michael@0 | 476 | group->meth->field_div = &ec_GFp_nistp192_div; |
michael@0 | 477 | #ifndef ECL_THIRTY_TWO_BIT |
michael@0 | 478 | group->meth->field_add = &ec_GFp_nistp192_add; |
michael@0 | 479 | group->meth->field_sub = &ec_GFp_nistp192_sub; |
michael@0 | 480 | #endif |
michael@0 | 481 | } |
michael@0 | 482 | return MP_OKAY; |
michael@0 | 483 | } |