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