1 package org.bouncycastle.math.ec; 2 3 import java.math.BigInteger; 4 import java.util.Random; 5 6 /** 7 * base class for an elliptic curve 8 */ 9 public abstract class ECCurve 10 { 11 ECFieldElement a, b; 12 13 public abstract int getFieldSize(); 14 15 public abstract ECFieldElement fromBigInteger(BigInteger x); 16 17 public abstract ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression); 18 19 public abstract ECPoint decodePoint(byte[] encoded); 20 21 public abstract ECPoint getInfinity(); 22 23 public ECFieldElement getA() 24 { 25 return a; 26 } 27 28 public ECFieldElement getB() 29 { 30 return b; 31 } 32 33 /** 34 * Elliptic curve over Fp 35 */ 36 public static class Fp extends ECCurve 37 { 38 BigInteger q; 39 ECPoint.Fp infinity; 40 41 public Fp(BigInteger q, BigInteger a, BigInteger b) 42 { 43 this.q = q; 44 this.a = fromBigInteger(a); 45 this.b = fromBigInteger(b); 46 this.infinity = new ECPoint.Fp(this, null, null); 47 } 48 49 public BigInteger getQ() 50 { 51 return q; 52 } 53 54 public int getFieldSize() 55 { 56 return q.bitLength(); 57 } 58 59 public ECFieldElement fromBigInteger(BigInteger x) 60 { 61 return new ECFieldElement.Fp(this.q, x); 62 } 63 64 public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) 65 { 66 return new ECPoint.Fp(this, fromBigInteger(x), fromBigInteger(y), withCompression); 67 } 68 69 /** 70 * Decode a point on this curve from its ASN.1 encoding. The different 71 * encodings are taken account of, including point compression for 72 * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17). 73 * @return The decoded point. 74 */ 75 public ECPoint decodePoint(byte[] encoded) 76 { 77 ECPoint p = null; 78 79 switch (encoded[0]) 80 { 81 // infinity 82 case 0x00: 83 if (encoded.length > 1) 84 { 85 throw new RuntimeException("Invalid point encoding"); 86 } 87 p = getInfinity(); 88 break; 89 // compressed 90 case 0x02: 91 case 0x03: 92 int ytilde = encoded[0] & 1; 93 byte[] i = new byte[encoded.length - 1]; 94 95 System.arraycopy(encoded, 1, i, 0, i.length); 96 97 ECFieldElement x = new ECFieldElement.Fp(this.q, new BigInteger(1, i)); 98 ECFieldElement alpha = x.multiply(x.square().add(a)).add(b); 99 ECFieldElement beta = alpha.sqrt(); 100 101 // 102 // if we can't find a sqrt we haven't got a point on the 103 // curve - run! 104 // 105 if (beta == null) 106 { 107 throw new RuntimeException("Invalid point compression"); 108 } 109 110 int bit0 = (beta.toBigInteger().testBit(0) ? 1 : 0); 111 112 if (bit0 == ytilde) 113 { 114 p = new ECPoint.Fp(this, x, beta, true); 115 } 116 else 117 { 118 p = new ECPoint.Fp(this, x, 119 new ECFieldElement.Fp(this.q, q.subtract(beta.toBigInteger())), true); 120 } 121 break; 122 // uncompressed 123 case 0x04: 124 // hybrid 125 case 0x06: 126 case 0x07: 127 byte[] xEnc = new byte[(encoded.length - 1) / 2]; 128 byte[] yEnc = new byte[(encoded.length - 1) / 2]; 129 130 System.arraycopy(encoded, 1, xEnc, 0, xEnc.length); 131 System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length); 132 133 p = new ECPoint.Fp(this, 134 new ECFieldElement.Fp(this.q, new BigInteger(1, xEnc)), 135 new ECFieldElement.Fp(this.q, new BigInteger(1, yEnc))); 136 break; 137 default: 138 throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16)); 139 } 140 141 return p; 142 } 143 144 public ECPoint getInfinity() 145 { 146 return infinity; 147 } 148 149 public boolean equals( 150 Object anObject) 151 { 152 if (anObject == this) 153 { 154 return true; 155 } 156 157 if (!(anObject instanceof ECCurve.Fp)) 158 { 159 return false; 160 } 161 162 ECCurve.Fp other = (ECCurve.Fp) anObject; 163 164 return this.q.equals(other.q) 165 && a.equals(other.a) && b.equals(other.b); 166 } 167 168 public int hashCode() 169 { 170 return a.hashCode() ^ b.hashCode() ^ q.hashCode(); 171 } 172 } 173 174 /** 175 * Elliptic curves over F2m. The Weierstrass equation is given by 176 * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>. 177 */ 178 public static class F2m extends ECCurve 179 { 180 /** 181 * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>. 182 */ 183 private int m; // can't be final - JDK 1.1 184 185 /** 186 * TPB: The integer <code>k</code> where <code>x<sup>m</sup> + 187 * x<sup>k</sup> + 1</code> represents the reduction polynomial 188 * <code>f(z)</code>.<br> 189 * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> + 190 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 191 * represents the reduction polynomial <code>f(z)</code>.<br> 192 */ 193 private int k1; // can't be final - JDK 1.1 194 195 /** 196 * TPB: Always set to <code>0</code><br> 197 * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> + 198 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 199 * represents the reduction polynomial <code>f(z)</code>.<br> 200 */ 201 private int k2; // can't be final - JDK 1.1 202 203 /** 204 * TPB: Always set to <code>0</code><br> 205 * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> + 206 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 207 * represents the reduction polynomial <code>f(z)</code>.<br> 208 */ 209 private int k3; // can't be final - JDK 1.1 210 211 /** 212 * The order of the base point of the curve. 213 */ 214 private BigInteger n; // can't be final - JDK 1.1 215 216 /** 217 * The cofactor of the curve. 218 */ 219 private BigInteger h; // can't be final - JDK 1.1 220 221 /** 222 * The point at infinity on this curve. 223 */ 224 private ECPoint.F2m infinity; // can't be final - JDK 1.1 225 226 /** 227 * The parameter <code>μ</code> of the elliptic curve if this is 228 * a Koblitz curve. 229 */ 230 private byte mu = 0; 231 232 /** 233 * The auxiliary values <code>s<sub>0</sub></code> and 234 * <code>s<sub>1</sub></code> used for partial modular reduction for 235 * Koblitz curves. 236 */ 237 private BigInteger[] si = null; 238 239 /** 240 * Constructor for Trinomial Polynomial Basis (TPB). 241 * @param m The exponent <code>m</code> of 242 * <code>F<sub>2<sup>m</sup></sub></code>. 243 * @param k The integer <code>k</code> where <code>x<sup>m</sup> + 244 * x<sup>k</sup> + 1</code> represents the reduction 245 * polynomial <code>f(z)</code>. 246 * @param a The coefficient <code>a</code> in the Weierstrass equation 247 * for non-supersingular elliptic curves over 248 * <code>F<sub>2<sup>m</sup></sub></code>. 249 * @param b The coefficient <code>b</code> in the Weierstrass equation 250 * for non-supersingular elliptic curves over 251 * <code>F<sub>2<sup>m</sup></sub></code>. 252 */ 253 public F2m( 254 int m, 255 int k, 256 BigInteger a, 257 BigInteger b) 258 { 259 this(m, k, 0, 0, a, b, null, null); 260 } 261 262 /** 263 * Constructor for Trinomial Polynomial Basis (TPB). 264 * @param m The exponent <code>m</code> of 265 * <code>F<sub>2<sup>m</sup></sub></code>. 266 * @param k The integer <code>k</code> where <code>x<sup>m</sup> + 267 * x<sup>k</sup> + 1</code> represents the reduction 268 * polynomial <code>f(z)</code>. 269 * @param a The coefficient <code>a</code> in the Weierstrass equation 270 * for non-supersingular elliptic curves over 271 * <code>F<sub>2<sup>m</sup></sub></code>. 272 * @param b The coefficient <code>b</code> in the Weierstrass equation 273 * for non-supersingular elliptic curves over 274 * <code>F<sub>2<sup>m</sup></sub></code>. 275 * @param n The order of the main subgroup of the elliptic curve. 276 * @param h The cofactor of the elliptic curve, i.e. 277 * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>. 278 */ 279 public F2m( 280 int m, 281 int k, 282 BigInteger a, 283 BigInteger b, 284 BigInteger n, 285 BigInteger h) 286 { 287 this(m, k, 0, 0, a, b, n, h); 288 } 289 290 /** 291 * Constructor for Pentanomial Polynomial Basis (PPB). 292 * @param m The exponent <code>m</code> of 293 * <code>F<sub>2<sup>m</sup></sub></code>. 294 * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> + 295 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 296 * represents the reduction polynomial <code>f(z)</code>. 297 * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> + 298 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 299 * represents the reduction polynomial <code>f(z)</code>. 300 * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> + 301 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 302 * represents the reduction polynomial <code>f(z)</code>. 303 * @param a The coefficient <code>a</code> in the Weierstrass equation 304 * for non-supersingular elliptic curves over 305 * <code>F<sub>2<sup>m</sup></sub></code>. 306 * @param b The coefficient <code>b</code> in the Weierstrass equation 307 * for non-supersingular elliptic curves over 308 * <code>F<sub>2<sup>m</sup></sub></code>. 309 */ 310 public F2m( 311 int m, 312 int k1, 313 int k2, 314 int k3, 315 BigInteger a, 316 BigInteger b) 317 { 318 this(m, k1, k2, k3, a, b, null, null); 319 } 320 321 /** 322 * Constructor for Pentanomial Polynomial Basis (PPB). 323 * @param m The exponent <code>m</code> of 324 * <code>F<sub>2<sup>m</sup></sub></code>. 325 * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> + 326 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 327 * represents the reduction polynomial <code>f(z)</code>. 328 * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> + 329 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 330 * represents the reduction polynomial <code>f(z)</code>. 331 * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> + 332 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 333 * represents the reduction polynomial <code>f(z)</code>. 334 * @param a The coefficient <code>a</code> in the Weierstrass equation 335 * for non-supersingular elliptic curves over 336 * <code>F<sub>2<sup>m</sup></sub></code>. 337 * @param b The coefficient <code>b</code> in the Weierstrass equation 338 * for non-supersingular elliptic curves over 339 * <code>F<sub>2<sup>m</sup></sub></code>. 340 * @param n The order of the main subgroup of the elliptic curve. 341 * @param h The cofactor of the elliptic curve, i.e. 342 * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>. 343 */ 344 public F2m( 345 int m, 346 int k1, 347 int k2, 348 int k3, 349 BigInteger a, 350 BigInteger b, 351 BigInteger n, 352 BigInteger h) 353 { 354 this.m = m; 355 this.k1 = k1; 356 this.k2 = k2; 357 this.k3 = k3; 358 this.n = n; 359 this.h = h; 360 361 if (k1 == 0) 362 { 363 throw new IllegalArgumentException("k1 must be > 0"); 364 } 365 366 if (k2 == 0) 367 { 368 if (k3 != 0) 369 { 370 throw new IllegalArgumentException("k3 must be 0 if k2 == 0"); 371 } 372 } 373 else 374 { 375 if (k2 <= k1) 376 { 377 throw new IllegalArgumentException("k2 must be > k1"); 378 } 379 380 if (k3 <= k2) 381 { 382 throw new IllegalArgumentException("k3 must be > k2"); 383 } 384 } 385 386 this.a = fromBigInteger(a); 387 this.b = fromBigInteger(b); 388 this.infinity = new ECPoint.F2m(this, null, null); 389 } 390 391 public int getFieldSize() 392 { 393 return m; 394 } 395 396 public ECFieldElement fromBigInteger(BigInteger x) 397 { 398 return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x); 399 } 400 401 public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) 402 { 403 return new ECPoint.F2m(this, fromBigInteger(x), fromBigInteger(y), withCompression); 404 } 405 406 /* (non-Javadoc) 407 * @see org.bouncycastle.math.ec.ECCurve#decodePoint(byte[]) 408 */ 409 public ECPoint decodePoint(byte[] encoded) 410 { 411 ECPoint p = null; 412 413 switch (encoded[0]) 414 { 415 // infinity 416 case 0x00: 417 if (encoded.length > 1) 418 { 419 throw new RuntimeException("Invalid point encoding"); 420 } 421 p = getInfinity(); 422 break; 423 // compressed 424 case 0x02: 425 case 0x03: 426 byte[] enc = new byte[encoded.length - 1]; 427 System.arraycopy(encoded, 1, enc, 0, enc.length); 428 if (encoded[0] == 0x02) 429 { 430 p = decompressPoint(enc, 0); 431 } 432 else 433 { 434 p = decompressPoint(enc, 1); 435 } 436 break; 437 // uncompressed 438 case 0x04: 439 // hybrid 440 case 0x06: 441 case 0x07: 442 byte[] xEnc = new byte[(encoded.length - 1) / 2]; 443 byte[] yEnc = new byte[(encoded.length - 1) / 2]; 444 445 System.arraycopy(encoded, 1, xEnc, 0, xEnc.length); 446 System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length); 447 448 p = new ECPoint.F2m(this, 449 new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, 450 new BigInteger(1, xEnc)), 451 new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, 452 new BigInteger(1, yEnc)), false); 453 break; 454 455 default: 456 throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16)); 457 } 458 459 return p; 460 } 461 462 public ECPoint getInfinity() 463 { 464 return infinity; 465 } 466 467 /** 468 * Returns true if this is a Koblitz curve (ABC curve). 469 * @return true if this is a Koblitz curve (ABC curve), false otherwise 470 */ 471 public boolean isKoblitz() 472 { 473 return ((n != null) && (h != null) && 474 ((a.toBigInteger().equals(ECConstants.ZERO)) || 475 (a.toBigInteger().equals(ECConstants.ONE))) && 476 (b.toBigInteger().equals(ECConstants.ONE))); 477 } 478 479 /** 480 * Returns the parameter <code>μ</code> of the elliptic curve. 481 * @return <code>μ</code> of the elliptic curve. 482 * @throws IllegalArgumentException if the given ECCurve is not a 483 * Koblitz curve. 484 */ 485 synchronized byte getMu() 486 { 487 if (mu == 0) 488 { 489 mu = Tnaf.getMu(this); 490 } 491 return mu; 492 } 493 494 /** 495 * @return the auxiliary values <code>s<sub>0</sub></code> and 496 * <code>s<sub>1</sub></code> used for partial modular reduction for 497 * Koblitz curves. 498 */ 499 synchronized BigInteger[] getSi() 500 { 501 if (si == null) 502 { 503 si = Tnaf.getSi(this); 504 } 505 return si; 506 } 507 508 /** 509 * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). 510 * 511 * @param xEnc 512 * The encoding of field element xp. 513 * @param ypBit 514 * ~yp, an indication bit for the decompression of yp. 515 * @return the decompressed point. 516 */ 517 private ECPoint decompressPoint( 518 byte[] xEnc, 519 int ypBit) 520 { 521 ECFieldElement xp = new ECFieldElement.F2m( 522 this.m, this.k1, this.k2, this.k3, new BigInteger(1, xEnc)); 523 ECFieldElement yp = null; 524 if (xp.toBigInteger().equals(ECConstants.ZERO)) 525 { 526 yp = (ECFieldElement.F2m)b; 527 for (int i = 0; i < m - 1; i++) 528 { 529 yp = yp.square(); 530 } 531 } 532 else 533 { 534 ECFieldElement beta = xp.add(a).add( 535 b.multiply(xp.square().invert())); 536 ECFieldElement z = solveQuadradicEquation(beta); 537 if (z == null) 538 { 539 throw new RuntimeException("Invalid point compression"); 540 } 541 int zBit = 0; 542 if (z.toBigInteger().testBit(0)) 543 { 544 zBit = 1; 545 } 546 if (zBit != ypBit) 547 { 548 z = z.add(new ECFieldElement.F2m(this.m, this.k1, this.k2, 549 this.k3, ECConstants.ONE)); 550 } 551 yp = xp.multiply(z); 552 } 553 554 return new ECPoint.F2m(this, xp, yp); 555 } 556 557 /** 558 * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 559 * D.1.6) The other solution is <code>z + 1</code>. 560 * 561 * @param beta 562 * The value to solve the qradratic equation for. 563 * @return the solution for <code>z<sup>2</sup> + z = beta</code> or 564 * <code>null</code> if no solution exists. 565 */ 566 private ECFieldElement solveQuadradicEquation(ECFieldElement beta) 567 { 568 ECFieldElement zeroElement = new ECFieldElement.F2m( 569 this.m, this.k1, this.k2, this.k3, ECConstants.ZERO); 570 571 if (beta.toBigInteger().equals(ECConstants.ZERO)) 572 { 573 return zeroElement; 574 } 575 576 ECFieldElement z = null; 577 ECFieldElement gamma = zeroElement; 578 579 Random rand = new Random(); 580 do 581 { 582 ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1, 583 this.k2, this.k3, new BigInteger(m, rand)); 584 z = zeroElement; 585 ECFieldElement w = beta; 586 for (int i = 1; i <= m - 1; i++) 587 { 588 ECFieldElement w2 = w.square(); 589 z = z.square().add(w2.multiply(t)); 590 w = w2.add(beta); 591 } 592 if (!w.toBigInteger().equals(ECConstants.ZERO)) 593 { 594 return null; 595 } 596 gamma = z.square().add(z); 597 } 598 while (gamma.toBigInteger().equals(ECConstants.ZERO)); 599 600 return z; 601 } 602 603 public boolean equals( 604 Object anObject) 605 { 606 if (anObject == this) 607 { 608 return true; 609 } 610 611 if (!(anObject instanceof ECCurve.F2m)) 612 { 613 return false; 614 } 615 616 ECCurve.F2m other = (ECCurve.F2m)anObject; 617 618 return (this.m == other.m) && (this.k1 == other.k1) 619 && (this.k2 == other.k2) && (this.k3 == other.k3) 620 && a.equals(other.a) && b.equals(other.b); 621 } 622 623 public int hashCode() 624 { 625 return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3; 626 } 627 628 public int getM() 629 { 630 return m; 631 } 632 633 /** 634 * Return true if curve uses a Trinomial basis. 635 * 636 * @return true if curve Trinomial, false otherwise. 637 */ 638 public boolean isTrinomial() 639 { 640 return k2 == 0 && k3 == 0; 641 } 642 643 public int getK1() 644 { 645 return k1; 646 } 647 648 public int getK2() 649 { 650 return k2; 651 } 652 653 public int getK3() 654 { 655 return k3; 656 } 657 658 public BigInteger getN() 659 { 660 return n; 661 } 662 663 public BigInteger getH() 664 { 665 return h; 666 } 667 } 668 } 669