1 package org.bouncycastle.math.ec; 2 3 import java.math.BigInteger; 4 import java.util.Hashtable; 5 import java.util.Random; 6 7 import org.bouncycastle.math.ec.endo.ECEndomorphism; 8 import org.bouncycastle.math.ec.endo.GLVEndomorphism; 9 import org.bouncycastle.math.field.FiniteField; 10 import org.bouncycastle.math.field.FiniteFields; 11 import org.bouncycastle.util.BigIntegers; 12 import org.bouncycastle.util.Integers; 13 14 /** 15 * base class for an elliptic curve 16 */ 17 public abstract class ECCurve 18 { 19 public static final int COORD_AFFINE = 0; 20 public static final int COORD_HOMOGENEOUS = 1; 21 public static final int COORD_JACOBIAN = 2; 22 public static final int COORD_JACOBIAN_CHUDNOVSKY = 3; 23 public static final int COORD_JACOBIAN_MODIFIED = 4; 24 public static final int COORD_LAMBDA_AFFINE = 5; 25 public static final int COORD_LAMBDA_PROJECTIVE = 6; 26 public static final int COORD_SKEWED = 7; 27 getAllCoordinateSystems()28 public static int[] getAllCoordinateSystems() 29 { 30 return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY, 31 COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED }; 32 } 33 34 public class Config 35 { 36 protected int coord; 37 protected ECEndomorphism endomorphism; 38 protected ECMultiplier multiplier; 39 Config(int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)40 Config(int coord, ECEndomorphism endomorphism, ECMultiplier multiplier) 41 { 42 this.coord = coord; 43 this.endomorphism = endomorphism; 44 this.multiplier = multiplier; 45 } 46 setCoordinateSystem(int coord)47 public Config setCoordinateSystem(int coord) 48 { 49 this.coord = coord; 50 return this; 51 } 52 setEndomorphism(ECEndomorphism endomorphism)53 public Config setEndomorphism(ECEndomorphism endomorphism) 54 { 55 this.endomorphism = endomorphism; 56 return this; 57 } 58 setMultiplier(ECMultiplier multiplier)59 public Config setMultiplier(ECMultiplier multiplier) 60 { 61 this.multiplier = multiplier; 62 return this; 63 } 64 create()65 public ECCurve create() 66 { 67 if (!supportsCoordinateSystem(coord)) 68 { 69 throw new IllegalStateException("unsupported coordinate system"); 70 } 71 72 ECCurve c = cloneCurve(); 73 if (c == ECCurve.this) 74 { 75 throw new IllegalStateException("implementation returned current curve"); 76 } 77 78 c.coord = coord; 79 c.endomorphism = endomorphism; 80 c.multiplier = multiplier; 81 82 return c; 83 } 84 } 85 86 protected FiniteField field; 87 protected ECFieldElement a, b; 88 protected BigInteger order, cofactor; 89 90 protected int coord = COORD_AFFINE; 91 protected ECEndomorphism endomorphism = null; 92 protected ECMultiplier multiplier = null; 93 ECCurve(FiniteField field)94 protected ECCurve(FiniteField field) 95 { 96 this.field = field; 97 } 98 getFieldSize()99 public abstract int getFieldSize(); 100 fromBigInteger(BigInteger x)101 public abstract ECFieldElement fromBigInteger(BigInteger x); 102 configure()103 public Config configure() 104 { 105 return new Config(this.coord, this.endomorphism, this.multiplier); 106 } 107 validatePoint(BigInteger x, BigInteger y)108 public ECPoint validatePoint(BigInteger x, BigInteger y) 109 { 110 ECPoint p = createPoint(x, y); 111 if (!p.isValid()) 112 { 113 throw new IllegalArgumentException("Invalid point coordinates"); 114 } 115 return p; 116 } 117 118 /** 119 * @deprecated per-point compression property will be removed, use {@link #validatePoint(BigInteger, BigInteger)} 120 * and refer {@link ECPoint#getEncoded(boolean)} 121 */ validatePoint(BigInteger x, BigInteger y, boolean withCompression)122 public ECPoint validatePoint(BigInteger x, BigInteger y, boolean withCompression) 123 { 124 ECPoint p = createPoint(x, y, withCompression); 125 if (!p.isValid()) 126 { 127 throw new IllegalArgumentException("Invalid point coordinates"); 128 } 129 return p; 130 } 131 createPoint(BigInteger x, BigInteger y)132 public ECPoint createPoint(BigInteger x, BigInteger y) 133 { 134 return createPoint(x, y, false); 135 } 136 137 /** 138 * @deprecated per-point compression property will be removed, use {@link #createPoint(BigInteger, BigInteger)} 139 * and refer {@link ECPoint#getEncoded(boolean)} 140 */ createPoint(BigInteger x, BigInteger y, boolean withCompression)141 public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) 142 { 143 return createRawPoint(fromBigInteger(x), fromBigInteger(y), withCompression); 144 } 145 cloneCurve()146 protected abstract ECCurve cloneCurve(); 147 createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)148 protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression); 149 createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)150 protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression); 151 createDefaultMultiplier()152 protected ECMultiplier createDefaultMultiplier() 153 { 154 if (endomorphism instanceof GLVEndomorphism) 155 { 156 return new GLVMultiplier(this, (GLVEndomorphism)endomorphism); 157 } 158 159 return new WNafL2RMultiplier(); 160 } 161 supportsCoordinateSystem(int coord)162 public boolean supportsCoordinateSystem(int coord) 163 { 164 return coord == COORD_AFFINE; 165 } 166 getPreCompInfo(ECPoint point, String name)167 public PreCompInfo getPreCompInfo(ECPoint point, String name) 168 { 169 checkPoint(point); 170 synchronized (point) 171 { 172 Hashtable table = point.preCompTable; 173 return table == null ? null : (PreCompInfo)table.get(name); 174 } 175 } 176 177 /** 178 * Adds <code>PreCompInfo</code> for a point on this curve, under a given name. Used by 179 * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use 180 * by subsequent multiplication. 181 * 182 * @param point 183 * The <code>ECPoint</code> to store precomputations for. 184 * @param name 185 * A <code>String</code> used to index precomputations of different types. 186 * @param preCompInfo 187 * The values precomputed by the <code>ECMultiplier</code>. 188 */ setPreCompInfo(ECPoint point, String name, PreCompInfo preCompInfo)189 public void setPreCompInfo(ECPoint point, String name, PreCompInfo preCompInfo) 190 { 191 checkPoint(point); 192 synchronized (point) 193 { 194 Hashtable table = point.preCompTable; 195 if (null == table) 196 { 197 point.preCompTable = table = new Hashtable(4); 198 } 199 table.put(name, preCompInfo); 200 } 201 } 202 importPoint(ECPoint p)203 public ECPoint importPoint(ECPoint p) 204 { 205 if (this == p.getCurve()) 206 { 207 return p; 208 } 209 if (p.isInfinity()) 210 { 211 return getInfinity(); 212 } 213 214 // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates. 215 p = p.normalize(); 216 217 return validatePoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression); 218 } 219 220 /** 221 * Normalization ensures that any projective coordinate is 1, and therefore that the x, y 222 * coordinates reflect those of the equivalent point in an affine coordinate system. Where more 223 * than one point is to be normalized, this method will generally be more efficient than 224 * normalizing each point separately. 225 * 226 * @param points 227 * An array of points that will be updated in place with their normalized versions, 228 * where necessary 229 */ normalizeAll(ECPoint[] points)230 public void normalizeAll(ECPoint[] points) 231 { 232 normalizeAll(points, 0, points.length, null); 233 } 234 235 /** 236 * Normalization ensures that any projective coordinate is 1, and therefore that the x, y 237 * coordinates reflect those of the equivalent point in an affine coordinate system. Where more 238 * than one point is to be normalized, this method will generally be more efficient than 239 * normalizing each point separately. An (optional) z-scaling factor can be applied; effectively 240 * each z coordinate is scaled by this value prior to normalization (but only one 241 * actual multiplication is needed). 242 * 243 * @param points 244 * An array of points that will be updated in place with their normalized versions, 245 * where necessary 246 * @param off 247 * The start of the range of points to normalize 248 * @param len 249 * The length of the range of points to normalize 250 * @param iso 251 * The (optional) z-scaling factor - can be null 252 */ normalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso)253 public void normalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso) 254 { 255 checkPoints(points, off, len); 256 257 switch (this.getCoordinateSystem()) 258 { 259 case ECCurve.COORD_AFFINE: 260 case ECCurve.COORD_LAMBDA_AFFINE: 261 { 262 if (iso != null) 263 { 264 throw new IllegalArgumentException("'iso' not valid for affine coordinates"); 265 } 266 return; 267 } 268 } 269 270 /* 271 * Figure out which of the points actually need to be normalized 272 */ 273 ECFieldElement[] zs = new ECFieldElement[len]; 274 int[] indices = new int[len]; 275 int count = 0; 276 for (int i = 0; i < len; ++i) 277 { 278 ECPoint p = points[off + i]; 279 if (null != p && (iso != null || !p.isNormalized())) 280 { 281 zs[count] = p.getZCoord(0); 282 indices[count++] = off + i; 283 } 284 } 285 286 if (count == 0) 287 { 288 return; 289 } 290 291 ECAlgorithms.montgomeryTrick(zs, 0, count, iso); 292 293 for (int j = 0; j < count; ++j) 294 { 295 int index = indices[j]; 296 points[index] = points[index].normalize(zs[j]); 297 } 298 } 299 getInfinity()300 public abstract ECPoint getInfinity(); 301 getField()302 public FiniteField getField() 303 { 304 return field; 305 } 306 getA()307 public ECFieldElement getA() 308 { 309 return a; 310 } 311 getB()312 public ECFieldElement getB() 313 { 314 return b; 315 } 316 getOrder()317 public BigInteger getOrder() 318 { 319 return order; 320 } 321 getCofactor()322 public BigInteger getCofactor() 323 { 324 return cofactor; 325 } 326 getCoordinateSystem()327 public int getCoordinateSystem() 328 { 329 return coord; 330 } 331 decompressPoint(int yTilde, BigInteger X1)332 protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1); 333 getEndomorphism()334 public ECEndomorphism getEndomorphism() 335 { 336 return endomorphism; 337 } 338 339 /** 340 * Sets the default <code>ECMultiplier</code>, unless already set. 341 */ getMultiplier()342 public synchronized ECMultiplier getMultiplier() 343 { 344 if (this.multiplier == null) 345 { 346 this.multiplier = createDefaultMultiplier(); 347 } 348 return this.multiplier; 349 } 350 351 /** 352 * Decode a point on this curve from its ASN.1 encoding. The different 353 * encodings are taken account of, including point compression for 354 * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17). 355 * @return The decoded point. 356 */ decodePoint(byte[] encoded)357 public ECPoint decodePoint(byte[] encoded) 358 { 359 ECPoint p = null; 360 int expectedLength = (getFieldSize() + 7) / 8; 361 362 byte type = encoded[0]; 363 switch (type) 364 { 365 case 0x00: // infinity 366 { 367 if (encoded.length != 1) 368 { 369 throw new IllegalArgumentException("Incorrect length for infinity encoding"); 370 } 371 372 p = getInfinity(); 373 break; 374 } 375 case 0x02: // compressed 376 case 0x03: // compressed 377 { 378 if (encoded.length != (expectedLength + 1)) 379 { 380 throw new IllegalArgumentException("Incorrect length for compressed encoding"); 381 } 382 383 int yTilde = type & 1; 384 BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); 385 386 p = decompressPoint(yTilde, X); 387 if (!p.satisfiesCofactor()) 388 { 389 throw new IllegalArgumentException("Invalid point"); 390 } 391 392 break; 393 } 394 case 0x04: // uncompressed 395 { 396 if (encoded.length != (2 * expectedLength + 1)) 397 { 398 throw new IllegalArgumentException("Incorrect length for uncompressed encoding"); 399 } 400 401 BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); 402 BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength); 403 404 p = validatePoint(X, Y); 405 break; 406 } 407 case 0x06: // hybrid 408 case 0x07: // hybrid 409 { 410 if (encoded.length != (2 * expectedLength + 1)) 411 { 412 throw new IllegalArgumentException("Incorrect length for hybrid encoding"); 413 } 414 415 BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); 416 BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength); 417 418 if (Y.testBit(0) != (type == 0x07)) 419 { 420 throw new IllegalArgumentException("Inconsistent Y coordinate in hybrid encoding"); 421 } 422 423 p = validatePoint(X, Y); 424 break; 425 } 426 default: 427 throw new IllegalArgumentException("Invalid point encoding 0x" + Integer.toString(type, 16)); 428 } 429 430 if (type != 0x00 && p.isInfinity()) 431 { 432 throw new IllegalArgumentException("Invalid infinity encoding"); 433 } 434 435 return p; 436 } 437 checkPoint(ECPoint point)438 protected void checkPoint(ECPoint point) 439 { 440 if (null == point || (this != point.getCurve())) 441 { 442 throw new IllegalArgumentException("'point' must be non-null and on this curve"); 443 } 444 } 445 checkPoints(ECPoint[] points)446 protected void checkPoints(ECPoint[] points) 447 { 448 checkPoints(points, 0, points.length); 449 } 450 checkPoints(ECPoint[] points, int off, int len)451 protected void checkPoints(ECPoint[] points, int off, int len) 452 { 453 if (points == null) 454 { 455 throw new IllegalArgumentException("'points' cannot be null"); 456 } 457 if (off < 0 || len < 0 || (off > (points.length - len))) 458 { 459 throw new IllegalArgumentException("invalid range specified for 'points'"); 460 } 461 462 for (int i = 0; i < len; ++i) 463 { 464 ECPoint point = points[off + i]; 465 if (null != point && this != point.getCurve()) 466 { 467 throw new IllegalArgumentException("'points' entries must be null or on this curve"); 468 } 469 } 470 } 471 equals(ECCurve other)472 public boolean equals(ECCurve other) 473 { 474 return this == other 475 || (null != other 476 && getField().equals(other.getField()) 477 && getA().toBigInteger().equals(other.getA().toBigInteger()) 478 && getB().toBigInteger().equals(other.getB().toBigInteger())); 479 } 480 equals(Object obj)481 public boolean equals(Object obj) 482 { 483 return this == obj || (obj instanceof ECCurve && equals((ECCurve)obj)); 484 } 485 hashCode()486 public int hashCode() 487 { 488 return getField().hashCode() 489 ^ Integers.rotateLeft(getA().toBigInteger().hashCode(), 8) 490 ^ Integers.rotateLeft(getB().toBigInteger().hashCode(), 16); 491 } 492 493 public static abstract class AbstractFp extends ECCurve 494 { AbstractFp(BigInteger q)495 protected AbstractFp(BigInteger q) 496 { 497 super(FiniteFields.getPrimeField(q)); 498 } 499 decompressPoint(int yTilde, BigInteger X1)500 protected ECPoint decompressPoint(int yTilde, BigInteger X1) 501 { 502 ECFieldElement x = this.fromBigInteger(X1); 503 ECFieldElement rhs = x.square().add(a).multiply(x).add(b); 504 ECFieldElement y = rhs.sqrt(); 505 506 /* 507 * If y is not a square, then we haven't got a point on the curve 508 */ 509 if (y == null) 510 { 511 throw new IllegalArgumentException("Invalid point compression"); 512 } 513 514 if (y.testBitZero() != (yTilde == 1)) 515 { 516 // Use the other root 517 y = y.negate(); 518 } 519 520 return this.createRawPoint(x, y, true); 521 } 522 } 523 524 /** 525 * Elliptic curve over Fp 526 */ 527 public static class Fp extends AbstractFp 528 { 529 private static final int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED; 530 531 BigInteger q, r; 532 ECPoint.Fp infinity; 533 Fp(BigInteger q, BigInteger a, BigInteger b)534 public Fp(BigInteger q, BigInteger a, BigInteger b) 535 { 536 this(q, a, b, null, null); 537 } 538 Fp(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)539 public Fp(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor) 540 { 541 super(q); 542 543 this.q = q; 544 this.r = ECFieldElement.Fp.calculateResidue(q); 545 this.infinity = new ECPoint.Fp(this, null, null); 546 547 this.a = fromBigInteger(a); 548 this.b = fromBigInteger(b); 549 this.order = order; 550 this.cofactor = cofactor; 551 this.coord = FP_DEFAULT_COORDS; 552 } 553 Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)554 protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b) 555 { 556 this(q, r, a, b, null, null); 557 } 558 Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)559 protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor) 560 { 561 super(q); 562 563 this.q = q; 564 this.r = r; 565 this.infinity = new ECPoint.Fp(this, null, null); 566 567 this.a = a; 568 this.b = b; 569 this.order = order; 570 this.cofactor = cofactor; 571 this.coord = FP_DEFAULT_COORDS; 572 } 573 cloneCurve()574 protected ECCurve cloneCurve() 575 { 576 return new Fp(q, r, a, b, order, cofactor); 577 } 578 supportsCoordinateSystem(int coord)579 public boolean supportsCoordinateSystem(int coord) 580 { 581 switch (coord) 582 { 583 case COORD_AFFINE: 584 case COORD_HOMOGENEOUS: 585 case COORD_JACOBIAN: 586 case COORD_JACOBIAN_MODIFIED: 587 return true; 588 default: 589 return false; 590 } 591 } 592 getQ()593 public BigInteger getQ() 594 { 595 return q; 596 } 597 getFieldSize()598 public int getFieldSize() 599 { 600 return q.bitLength(); 601 } 602 fromBigInteger(BigInteger x)603 public ECFieldElement fromBigInteger(BigInteger x) 604 { 605 return new ECFieldElement.Fp(this.q, this.r, x); 606 } 607 createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)608 protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) 609 { 610 return new ECPoint.Fp(this, x, y, withCompression); 611 } 612 createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)613 protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) 614 { 615 return new ECPoint.Fp(this, x, y, zs, withCompression); 616 } 617 importPoint(ECPoint p)618 public ECPoint importPoint(ECPoint p) 619 { 620 if (this != p.getCurve() && this.getCoordinateSystem() == COORD_JACOBIAN && !p.isInfinity()) 621 { 622 switch (p.getCurve().getCoordinateSystem()) 623 { 624 case COORD_JACOBIAN: 625 case COORD_JACOBIAN_CHUDNOVSKY: 626 case COORD_JACOBIAN_MODIFIED: 627 return new ECPoint.Fp(this, 628 fromBigInteger(p.x.toBigInteger()), 629 fromBigInteger(p.y.toBigInteger()), 630 new ECFieldElement[]{ fromBigInteger(p.zs[0].toBigInteger()) }, 631 p.withCompression); 632 default: 633 break; 634 } 635 } 636 637 return super.importPoint(p); 638 } 639 getInfinity()640 public ECPoint getInfinity() 641 { 642 return infinity; 643 } 644 } 645 646 public static abstract class AbstractF2m extends ECCurve 647 { buildField(int m, int k1, int k2, int k3)648 private static FiniteField buildField(int m, int k1, int k2, int k3) 649 { 650 if (k1 == 0) 651 { 652 throw new IllegalArgumentException("k1 must be > 0"); 653 } 654 655 if (k2 == 0) 656 { 657 if (k3 != 0) 658 { 659 throw new IllegalArgumentException("k3 must be 0 if k2 == 0"); 660 } 661 662 return FiniteFields.getBinaryExtensionField(new int[]{ 0, k1, m }); 663 } 664 665 if (k2 <= k1) 666 { 667 throw new IllegalArgumentException("k2 must be > k1"); 668 } 669 670 if (k3 <= k2) 671 { 672 throw new IllegalArgumentException("k3 must be > k2"); 673 } 674 675 return FiniteFields.getBinaryExtensionField(new int[]{ 0, k1, k2, k3, m }); 676 } 677 AbstractF2m(int m, int k1, int k2, int k3)678 protected AbstractF2m(int m, int k1, int k2, int k3) 679 { 680 super(buildField(m, k1, k2, k3)); 681 } 682 } 683 684 /** 685 * Elliptic curves over F2m. The Weierstrass equation is given by 686 * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>. 687 */ 688 public static class F2m extends AbstractF2m 689 { 690 private static final int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; 691 692 /** 693 * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>. 694 */ 695 private int m; // can't be final - JDK 1.1 696 697 /** 698 * TPB: The integer <code>k</code> where <code>x<sup>m</sup> + 699 * x<sup>k</sup> + 1</code> represents the reduction polynomial 700 * <code>f(z)</code>.<br> 701 * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> + 702 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 703 * represents the reduction polynomial <code>f(z)</code>.<br> 704 */ 705 private int k1; // can't be final - JDK 1.1 706 707 /** 708 * TPB: Always set to <code>0</code><br> 709 * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> + 710 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 711 * represents the reduction polynomial <code>f(z)</code>.<br> 712 */ 713 private int k2; // can't be final - JDK 1.1 714 715 /** 716 * TPB: Always set to <code>0</code><br> 717 * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> + 718 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 719 * represents the reduction polynomial <code>f(z)</code>.<br> 720 */ 721 private int k3; // can't be final - JDK 1.1 722 723 /** 724 * The point at infinity on this curve. 725 */ 726 private ECPoint.F2m infinity; // can't be final - JDK 1.1 727 728 /** 729 * The parameter <code>μ</code> of the elliptic curve if this is 730 * a Koblitz curve. 731 */ 732 private byte mu = 0; 733 734 /** 735 * The auxiliary values <code>s<sub>0</sub></code> and 736 * <code>s<sub>1</sub></code> used for partial modular reduction for 737 * Koblitz curves. 738 */ 739 private BigInteger[] si = null; 740 741 /** 742 * Constructor for Trinomial Polynomial Basis (TPB). 743 * @param m The exponent <code>m</code> of 744 * <code>F<sub>2<sup>m</sup></sub></code>. 745 * @param k The integer <code>k</code> where <code>x<sup>m</sup> + 746 * x<sup>k</sup> + 1</code> represents the reduction 747 * polynomial <code>f(z)</code>. 748 * @param a The coefficient <code>a</code> in the Weierstrass equation 749 * for non-supersingular elliptic curves over 750 * <code>F<sub>2<sup>m</sup></sub></code>. 751 * @param b The coefficient <code>b</code> in the Weierstrass equation 752 * for non-supersingular elliptic curves over 753 * <code>F<sub>2<sup>m</sup></sub></code>. 754 */ F2m( int m, int k, BigInteger a, BigInteger b)755 public F2m( 756 int m, 757 int k, 758 BigInteger a, 759 BigInteger b) 760 { 761 this(m, k, 0, 0, a, b, null, null); 762 } 763 764 /** 765 * Constructor for Trinomial Polynomial Basis (TPB). 766 * @param m The exponent <code>m</code> of 767 * <code>F<sub>2<sup>m</sup></sub></code>. 768 * @param k The integer <code>k</code> where <code>x<sup>m</sup> + 769 * x<sup>k</sup> + 1</code> represents the reduction 770 * polynomial <code>f(z)</code>. 771 * @param a The coefficient <code>a</code> in the Weierstrass equation 772 * for non-supersingular elliptic curves over 773 * <code>F<sub>2<sup>m</sup></sub></code>. 774 * @param b The coefficient <code>b</code> in the Weierstrass equation 775 * for non-supersingular elliptic curves over 776 * <code>F<sub>2<sup>m</sup></sub></code>. 777 * @param order The order of the main subgroup of the elliptic curve. 778 * @param cofactor The cofactor of the elliptic curve, i.e. 779 * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>. 780 */ F2m( int m, int k, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)781 public F2m( 782 int m, 783 int k, 784 BigInteger a, 785 BigInteger b, 786 BigInteger order, 787 BigInteger cofactor) 788 { 789 this(m, k, 0, 0, a, b, order, cofactor); 790 } 791 792 /** 793 * Constructor for Pentanomial Polynomial Basis (PPB). 794 * @param m The exponent <code>m</code> of 795 * <code>F<sub>2<sup>m</sup></sub></code>. 796 * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> + 797 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 798 * represents the reduction polynomial <code>f(z)</code>. 799 * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> + 800 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 801 * represents the reduction polynomial <code>f(z)</code>. 802 * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> + 803 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 804 * represents the reduction polynomial <code>f(z)</code>. 805 * @param a The coefficient <code>a</code> in the Weierstrass equation 806 * for non-supersingular elliptic curves over 807 * <code>F<sub>2<sup>m</sup></sub></code>. 808 * @param b The coefficient <code>b</code> in the Weierstrass equation 809 * for non-supersingular elliptic curves over 810 * <code>F<sub>2<sup>m</sup></sub></code>. 811 */ F2m( int m, int k1, int k2, int k3, BigInteger a, BigInteger b)812 public F2m( 813 int m, 814 int k1, 815 int k2, 816 int k3, 817 BigInteger a, 818 BigInteger b) 819 { 820 this(m, k1, k2, k3, a, b, null, null); 821 } 822 823 /** 824 * Constructor for Pentanomial Polynomial Basis (PPB). 825 * @param m The exponent <code>m</code> of 826 * <code>F<sub>2<sup>m</sup></sub></code>. 827 * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> + 828 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 829 * represents the reduction polynomial <code>f(z)</code>. 830 * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> + 831 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 832 * represents the reduction polynomial <code>f(z)</code>. 833 * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> + 834 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> 835 * represents the reduction polynomial <code>f(z)</code>. 836 * @param a The coefficient <code>a</code> in the Weierstrass equation 837 * for non-supersingular elliptic curves over 838 * <code>F<sub>2<sup>m</sup></sub></code>. 839 * @param b The coefficient <code>b</code> in the Weierstrass equation 840 * for non-supersingular elliptic curves over 841 * <code>F<sub>2<sup>m</sup></sub></code>. 842 * @param order The order of the main subgroup of the elliptic curve. 843 * @param cofactor The cofactor of the elliptic curve, i.e. 844 * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>. 845 */ F2m( int m, int k1, int k2, int k3, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)846 public F2m( 847 int m, 848 int k1, 849 int k2, 850 int k3, 851 BigInteger a, 852 BigInteger b, 853 BigInteger order, 854 BigInteger cofactor) 855 { 856 super(m, k1, k2, k3); 857 858 this.m = m; 859 this.k1 = k1; 860 this.k2 = k2; 861 this.k3 = k3; 862 this.order = order; 863 this.cofactor = cofactor; 864 865 this.infinity = new ECPoint.F2m(this, null, null); 866 this.a = fromBigInteger(a); 867 this.b = fromBigInteger(b); 868 this.coord = F2M_DEFAULT_COORDS; 869 } 870 F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)871 protected F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor) 872 { 873 super(m, k1, k2, k3); 874 875 this.m = m; 876 this.k1 = k1; 877 this.k2 = k2; 878 this.k3 = k3; 879 this.order = order; 880 this.cofactor = cofactor; 881 882 this.infinity = new ECPoint.F2m(this, null, null); 883 this.a = a; 884 this.b = b; 885 this.coord = F2M_DEFAULT_COORDS; 886 } 887 cloneCurve()888 protected ECCurve cloneCurve() 889 { 890 return new F2m(m, k1, k2, k3, a, b, order, cofactor); 891 } 892 supportsCoordinateSystem(int coord)893 public boolean supportsCoordinateSystem(int coord) 894 { 895 switch (coord) 896 { 897 case COORD_AFFINE: 898 case COORD_HOMOGENEOUS: 899 case COORD_LAMBDA_PROJECTIVE: 900 return true; 901 default: 902 return false; 903 } 904 } 905 createDefaultMultiplier()906 protected ECMultiplier createDefaultMultiplier() 907 { 908 if (isKoblitz()) 909 { 910 return new WTauNafMultiplier(); 911 } 912 913 return super.createDefaultMultiplier(); 914 } 915 getFieldSize()916 public int getFieldSize() 917 { 918 return m; 919 } 920 fromBigInteger(BigInteger x)921 public ECFieldElement fromBigInteger(BigInteger x) 922 { 923 return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x); 924 } 925 createPoint(BigInteger x, BigInteger y, boolean withCompression)926 public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) 927 { 928 ECFieldElement X = fromBigInteger(x), Y = fromBigInteger(y); 929 930 switch (this.getCoordinateSystem()) 931 { 932 case COORD_LAMBDA_AFFINE: 933 case COORD_LAMBDA_PROJECTIVE: 934 { 935 if (X.isZero()) 936 { 937 if (!Y.square().equals(this.getB())) 938 { 939 throw new IllegalArgumentException(); 940 } 941 } 942 else 943 { 944 // Y becomes Lambda (X + Y/X) here 945 Y = Y.divide(X).add(X); 946 } 947 break; 948 } 949 default: 950 { 951 break; 952 } 953 } 954 955 return createRawPoint(X, Y, withCompression); 956 } 957 createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)958 protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) 959 { 960 return new ECPoint.F2m(this, x, y, withCompression); 961 } 962 createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)963 protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) 964 { 965 return new ECPoint.F2m(this, x, y, zs, withCompression); 966 } 967 getInfinity()968 public ECPoint getInfinity() 969 { 970 return infinity; 971 } 972 973 /** 974 * Returns true if this is a Koblitz curve (ABC curve). 975 * @return true if this is a Koblitz curve (ABC curve), false otherwise 976 */ isKoblitz()977 public boolean isKoblitz() 978 { 979 return order != null && cofactor != null && b.isOne() && (a.isZero() || a.isOne()); 980 } 981 982 /** 983 * Returns the parameter <code>μ</code> of the elliptic curve. 984 * @return <code>μ</code> of the elliptic curve. 985 * @throws IllegalArgumentException if the given ECCurve is not a 986 * Koblitz curve. 987 */ getMu()988 synchronized byte getMu() 989 { 990 if (mu == 0) 991 { 992 mu = Tnaf.getMu(this); 993 } 994 return mu; 995 } 996 997 /** 998 * @return the auxiliary values <code>s<sub>0</sub></code> and 999 * <code>s<sub>1</sub></code> used for partial modular reduction for 1000 * Koblitz curves. 1001 */ getSi()1002 synchronized BigInteger[] getSi() 1003 { 1004 if (si == null) 1005 { 1006 si = Tnaf.getSi(this); 1007 } 1008 return si; 1009 } 1010 1011 /** 1012 * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). 1013 * 1014 * @param yTilde 1015 * ~yp, an indication bit for the decompression of yp. 1016 * @param X1 1017 * The field element xp. 1018 * @return the decompressed point. 1019 */ decompressPoint(int yTilde, BigInteger X1)1020 protected ECPoint decompressPoint(int yTilde, BigInteger X1) 1021 { 1022 ECFieldElement x = fromBigInteger(X1), y = null; 1023 if (x.isZero()) 1024 { 1025 y = b.sqrt(); 1026 } 1027 else 1028 { 1029 ECFieldElement beta = x.square().invert().multiply(b).add(a).add(x); 1030 ECFieldElement z = solveQuadraticEquation(beta); 1031 if (z != null) 1032 { 1033 if (z.testBitZero() != (yTilde == 1)) 1034 { 1035 z = z.addOne(); 1036 } 1037 1038 switch (this.getCoordinateSystem()) 1039 { 1040 case COORD_LAMBDA_AFFINE: 1041 case COORD_LAMBDA_PROJECTIVE: 1042 { 1043 y = z.add(x); 1044 break; 1045 } 1046 default: 1047 { 1048 y = z.multiply(x); 1049 break; 1050 } 1051 } 1052 } 1053 } 1054 1055 if (y == null) 1056 { 1057 throw new IllegalArgumentException("Invalid point compression"); 1058 } 1059 1060 return this.createRawPoint(x, y, true); 1061 } 1062 1063 /** 1064 * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 1065 * D.1.6) The other solution is <code>z + 1</code>. 1066 * 1067 * @param beta 1068 * The value to solve the quadratic equation for. 1069 * @return the solution for <code>z<sup>2</sup> + z = beta</code> or 1070 * <code>null</code> if no solution exists. 1071 */ solveQuadraticEquation(ECFieldElement beta)1072 private ECFieldElement solveQuadraticEquation(ECFieldElement beta) 1073 { 1074 if (beta.isZero()) 1075 { 1076 return beta; 1077 } 1078 1079 ECFieldElement zeroElement = fromBigInteger(ECConstants.ZERO); 1080 1081 ECFieldElement z = null; 1082 ECFieldElement gamma = null; 1083 1084 Random rand = new Random(); 1085 do 1086 { 1087 ECFieldElement t = fromBigInteger(new BigInteger(m, rand)); 1088 z = zeroElement; 1089 ECFieldElement w = beta; 1090 for (int i = 1; i <= m - 1; i++) 1091 { 1092 ECFieldElement w2 = w.square(); 1093 z = z.square().add(w2.multiply(t)); 1094 w = w2.add(beta); 1095 } 1096 if (!w.isZero()) 1097 { 1098 return null; 1099 } 1100 gamma = z.square().add(z); 1101 } 1102 while (gamma.isZero()); 1103 1104 return z; 1105 } 1106 getM()1107 public int getM() 1108 { 1109 return m; 1110 } 1111 1112 /** 1113 * Return true if curve uses a Trinomial basis. 1114 * 1115 * @return true if curve Trinomial, false otherwise. 1116 */ isTrinomial()1117 public boolean isTrinomial() 1118 { 1119 return k2 == 0 && k3 == 0; 1120 } 1121 getK1()1122 public int getK1() 1123 { 1124 return k1; 1125 } 1126 getK2()1127 public int getK2() 1128 { 1129 return k2; 1130 } 1131 getK3()1132 public int getK3() 1133 { 1134 return k3; 1135 } 1136 1137 /** 1138 * @deprecated use {@link #getOrder()} instead 1139 */ getN()1140 public BigInteger getN() 1141 { 1142 return order; 1143 } 1144 1145 /** 1146 * @deprecated use {@link #getCofactor()} instead 1147 */ getH()1148 public BigInteger getH() 1149 { 1150 return cofactor; 1151 } 1152 } 1153 } 1154