1 package org.bouncycastle.math.ec; 2 3 import java.math.BigInteger; 4 5 import org.bouncycastle.asn1.x9.X9IntegerConverter; 6 7 /** 8 * base class for points on elliptic curves. 9 */ 10 public abstract class ECPoint 11 { 12 ECCurve curve; 13 ECFieldElement x; 14 ECFieldElement y; 15 16 protected boolean withCompression; 17 18 protected ECMultiplier multiplier = null; 19 20 protected PreCompInfo preCompInfo = null; 21 22 private static X9IntegerConverter converter = new X9IntegerConverter(); 23 ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)24 protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y) 25 { 26 this.curve = curve; 27 this.x = x; 28 this.y = y; 29 } 30 getCurve()31 public ECCurve getCurve() 32 { 33 return curve; 34 } 35 getX()36 public ECFieldElement getX() 37 { 38 return x; 39 } 40 getY()41 public ECFieldElement getY() 42 { 43 return y; 44 } 45 isInfinity()46 public boolean isInfinity() 47 { 48 return x == null && y == null; 49 } 50 isCompressed()51 public boolean isCompressed() 52 { 53 return withCompression; 54 } 55 equals( Object other)56 public boolean equals( 57 Object other) 58 { 59 if (other == this) 60 { 61 return true; 62 } 63 64 if (!(other instanceof ECPoint)) 65 { 66 return false; 67 } 68 69 ECPoint o = (ECPoint)other; 70 71 if (this.isInfinity()) 72 { 73 return o.isInfinity(); 74 } 75 76 return x.equals(o.x) && y.equals(o.y); 77 } 78 hashCode()79 public int hashCode() 80 { 81 if (this.isInfinity()) 82 { 83 return 0; 84 } 85 86 return x.hashCode() ^ y.hashCode(); 87 } 88 89 // /** 90 // * Mainly for testing. Explicitly set the <code>ECMultiplier</code>. 91 // * @param multiplier The <code>ECMultiplier</code> to be used to multiply 92 // * this <code>ECPoint</code>. 93 // */ 94 // public void setECMultiplier(ECMultiplier multiplier) 95 // { 96 // this.multiplier = multiplier; 97 // } 98 99 /** 100 * Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s 101 * to save the precomputation for this <code>ECPoint</code> to store the 102 * precomputation result for use by subsequent multiplication. 103 * @param preCompInfo The values precomputed by the 104 * <code>ECMultiplier</code>. 105 */ setPreCompInfo(PreCompInfo preCompInfo)106 void setPreCompInfo(PreCompInfo preCompInfo) 107 { 108 this.preCompInfo = preCompInfo; 109 } 110 getEncoded()111 public abstract byte[] getEncoded(); 112 add(ECPoint b)113 public abstract ECPoint add(ECPoint b); subtract(ECPoint b)114 public abstract ECPoint subtract(ECPoint b); negate()115 public abstract ECPoint negate(); twice()116 public abstract ECPoint twice(); 117 118 /** 119 * Sets the default <code>ECMultiplier</code>, unless already set. 120 */ assertECMultiplier()121 synchronized void assertECMultiplier() 122 { 123 if (this.multiplier == null) 124 { 125 this.multiplier = new FpNafMultiplier(); 126 } 127 } 128 129 /** 130 * Multiplies this <code>ECPoint</code> by the given number. 131 * @param k The multiplicator. 132 * @return <code>k * this</code>. 133 */ multiply(BigInteger k)134 public ECPoint multiply(BigInteger k) 135 { 136 if (k.signum() < 0) 137 { 138 throw new IllegalArgumentException("The multiplicator cannot be negative"); 139 } 140 141 if (this.isInfinity()) 142 { 143 return this; 144 } 145 146 if (k.signum() == 0) 147 { 148 return this.curve.getInfinity(); 149 } 150 151 assertECMultiplier(); 152 return this.multiplier.multiply(this, k, preCompInfo); 153 } 154 155 /** 156 * Elliptic curve points over Fp 157 */ 158 public static class Fp extends ECPoint 159 { 160 161 /** 162 * Create a point which encodes with point compression. 163 * 164 * @param curve the curve to use 165 * @param x affine x co-ordinate 166 * @param y affine y co-ordinate 167 */ Fp(ECCurve curve, ECFieldElement x, ECFieldElement y)168 public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y) 169 { 170 this(curve, x, y, false); 171 } 172 173 /** 174 * Create a point that encodes with or without point compresion. 175 * 176 * @param curve the curve to use 177 * @param x affine x co-ordinate 178 * @param y affine y co-ordinate 179 * @param withCompression if true encode with point compression 180 */ Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)181 public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) 182 { 183 super(curve, x, y); 184 185 if ((x != null && y == null) || (x == null && y != null)) 186 { 187 throw new IllegalArgumentException("Exactly one of the field elements is null"); 188 } 189 190 this.withCompression = withCompression; 191 } 192 193 /** 194 * return the field element encoded with point compression. (S 4.3.6) 195 */ getEncoded()196 public byte[] getEncoded() 197 { 198 if (this.isInfinity()) 199 { 200 return new byte[1]; 201 } 202 203 int qLength = converter.getByteLength(x); 204 205 if (withCompression) 206 { 207 byte PC; 208 209 if (this.getY().toBigInteger().testBit(0)) 210 { 211 PC = 0x03; 212 } 213 else 214 { 215 PC = 0x02; 216 } 217 218 byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength); 219 byte[] PO = new byte[X.length + 1]; 220 221 PO[0] = PC; 222 System.arraycopy(X, 0, PO, 1, X.length); 223 224 return PO; 225 } 226 else 227 { 228 byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength); 229 byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), qLength); 230 byte[] PO = new byte[X.length + Y.length + 1]; 231 232 PO[0] = 0x04; 233 System.arraycopy(X, 0, PO, 1, X.length); 234 System.arraycopy(Y, 0, PO, X.length + 1, Y.length); 235 236 return PO; 237 } 238 } 239 240 // B.3 pg 62 add(ECPoint b)241 public ECPoint add(ECPoint b) 242 { 243 if (this.isInfinity()) 244 { 245 return b; 246 } 247 248 if (b.isInfinity()) 249 { 250 return this; 251 } 252 253 // Check if b = this or b = -this 254 if (this.x.equals(b.x)) 255 { 256 if (this.y.equals(b.y)) 257 { 258 // this = b, i.e. this must be doubled 259 return this.twice(); 260 } 261 262 // this = -b, i.e. the result is the point at infinity 263 return this.curve.getInfinity(); 264 } 265 266 ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x)); 267 268 ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x); 269 ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y); 270 271 return new ECPoint.Fp(curve, x3, y3); 272 } 273 274 // B.3 pg 62 twice()275 public ECPoint twice() 276 { 277 if (this.isInfinity()) 278 { 279 // Twice identity element (point at infinity) is identity 280 return this; 281 } 282 283 if (this.y.toBigInteger().signum() == 0) 284 { 285 // if y1 == 0, then (x1, y1) == (x1, -y1) 286 // and hence this = -this and thus 2(x1, y1) == infinity 287 return this.curve.getInfinity(); 288 } 289 290 ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2)); 291 ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3)); 292 ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO)); 293 294 ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO)); 295 ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y); 296 297 return new ECPoint.Fp(curve, x3, y3, this.withCompression); 298 } 299 300 // D.3.2 pg 102 (see Note:) subtract(ECPoint b)301 public ECPoint subtract(ECPoint b) 302 { 303 if (b.isInfinity()) 304 { 305 return this; 306 } 307 308 // Add -b 309 return add(b.negate()); 310 } 311 negate()312 public ECPoint negate() 313 { 314 return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression); 315 } 316 317 /** 318 * Sets the default <code>ECMultiplier</code>, unless already set. 319 */ assertECMultiplier()320 synchronized void assertECMultiplier() 321 { 322 if (this.multiplier == null) 323 { 324 this.multiplier = new WNafMultiplier(); 325 } 326 } 327 } 328 329 /** 330 * Elliptic curve points over F2m 331 */ 332 public static class F2m extends ECPoint 333 { 334 /** 335 * @param curve base curve 336 * @param x x point 337 * @param y y point 338 */ F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)339 public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y) 340 { 341 this(curve, x, y, false); 342 } 343 344 /** 345 * @param curve base curve 346 * @param x x point 347 * @param y y point 348 * @param withCompression true if encode with point compression. 349 */ F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)350 public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) 351 { 352 super(curve, x, y); 353 354 if ((x != null && y == null) || (x == null && y != null)) 355 { 356 throw new IllegalArgumentException("Exactly one of the field elements is null"); 357 } 358 359 if (x != null) 360 { 361 // Check if x and y are elements of the same field 362 ECFieldElement.F2m.checkFieldElements(this.x, this.y); 363 364 // Check if x and a are elements of the same field 365 if (curve != null) 366 { 367 ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA()); 368 } 369 } 370 371 this.withCompression = withCompression; 372 } 373 374 /* (non-Javadoc) 375 * @see org.bouncycastle.math.ec.ECPoint#getEncoded() 376 */ getEncoded()377 public byte[] getEncoded() 378 { 379 if (this.isInfinity()) 380 { 381 return new byte[1]; 382 } 383 384 int byteCount = converter.getByteLength(this.x); 385 byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount); 386 byte[] PO; 387 388 if (withCompression) 389 { 390 // See X9.62 4.3.6 and 4.2.2 391 PO = new byte[byteCount + 1]; 392 393 PO[0] = 0x02; 394 // X9.62 4.2.2 and 4.3.6: 395 // if x = 0 then ypTilde := 0, else ypTilde is the rightmost 396 // bit of y * x^(-1) 397 // if ypTilde = 0, then PC := 02, else PC := 03 398 // Note: PC === PO[0] 399 if (!(this.getX().toBigInteger().equals(ECConstants.ZERO))) 400 { 401 if (this.getY().multiply(this.getX().invert()) 402 .toBigInteger().testBit(0)) 403 { 404 // ypTilde = 1, hence PC = 03 405 PO[0] = 0x03; 406 } 407 } 408 409 System.arraycopy(X, 0, PO, 1, byteCount); 410 } 411 else 412 { 413 byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount); 414 415 PO = new byte[byteCount + byteCount + 1]; 416 417 PO[0] = 0x04; 418 System.arraycopy(X, 0, PO, 1, byteCount); 419 System.arraycopy(Y, 0, PO, byteCount + 1, byteCount); 420 } 421 422 return PO; 423 } 424 425 /** 426 * Check, if two <code>ECPoint</code>s can be added or subtracted. 427 * @param a The first <code>ECPoint</code> to check. 428 * @param b The second <code>ECPoint</code> to check. 429 * @throws IllegalArgumentException if <code>a</code> and <code>b</code> 430 * cannot be added. 431 */ checkPoints(ECPoint a, ECPoint b)432 private static void checkPoints(ECPoint a, ECPoint b) 433 { 434 // Check, if points are on the same curve 435 if (!(a.curve.equals(b.curve))) 436 { 437 throw new IllegalArgumentException("Only points on the same " 438 + "curve can be added or subtracted"); 439 } 440 441 // ECFieldElement.F2m.checkFieldElements(a.x, b.x); 442 } 443 444 /* (non-Javadoc) 445 * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint) 446 */ add(ECPoint b)447 public ECPoint add(ECPoint b) 448 { 449 checkPoints(this, b); 450 return addSimple((ECPoint.F2m)b); 451 } 452 453 /** 454 * Adds another <code>ECPoints.F2m</code> to <code>this</code> without 455 * checking if both points are on the same curve. Used by multiplication 456 * algorithms, because there all points are a multiple of the same point 457 * and hence the checks can be omitted. 458 * @param b The other <code>ECPoints.F2m</code> to add to 459 * <code>this</code>. 460 * @return <code>this + b</code> 461 */ addSimple(ECPoint.F2m b)462 public ECPoint.F2m addSimple(ECPoint.F2m b) 463 { 464 ECPoint.F2m other = b; 465 if (this.isInfinity()) 466 { 467 return other; 468 } 469 470 if (other.isInfinity()) 471 { 472 return this; 473 } 474 475 ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX(); 476 ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY(); 477 478 // Check if other = this or other = -this 479 if (this.x.equals(x2)) 480 { 481 if (this.y.equals(y2)) 482 { 483 // this = other, i.e. this must be doubled 484 return (ECPoint.F2m)this.twice(); 485 } 486 487 // this = -other, i.e. the result is the point at infinity 488 return (ECPoint.F2m)this.curve.getInfinity(); 489 } 490 491 ECFieldElement.F2m lambda 492 = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2)); 493 494 ECFieldElement.F2m x3 495 = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA()); 496 497 ECFieldElement.F2m y3 498 = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y); 499 500 return new ECPoint.F2m(curve, x3, y3, withCompression); 501 } 502 503 /* (non-Javadoc) 504 * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint) 505 */ subtract(ECPoint b)506 public ECPoint subtract(ECPoint b) 507 { 508 checkPoints(this, b); 509 return subtractSimple((ECPoint.F2m)b); 510 } 511 512 /** 513 * Subtracts another <code>ECPoints.F2m</code> from <code>this</code> 514 * without checking if both points are on the same curve. Used by 515 * multiplication algorithms, because there all points are a multiple 516 * of the same point and hence the checks can be omitted. 517 * @param b The other <code>ECPoints.F2m</code> to subtract from 518 * <code>this</code>. 519 * @return <code>this - b</code> 520 */ subtractSimple(ECPoint.F2m b)521 public ECPoint.F2m subtractSimple(ECPoint.F2m b) 522 { 523 if (b.isInfinity()) 524 { 525 return this; 526 } 527 528 // Add -b 529 return addSimple((ECPoint.F2m)b.negate()); 530 } 531 532 /* (non-Javadoc) 533 * @see org.bouncycastle.math.ec.ECPoint#twice() 534 */ twice()535 public ECPoint twice() 536 { 537 if (this.isInfinity()) 538 { 539 // Twice identity element (point at infinity) is identity 540 return this; 541 } 542 543 if (this.x.toBigInteger().signum() == 0) 544 { 545 // if x1 == 0, then (x1, y1) == (x1, x1 + y1) 546 // and hence this = -this and thus 2(x1, y1) == infinity 547 return this.curve.getInfinity(); 548 } 549 550 ECFieldElement.F2m lambda 551 = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x)); 552 553 ECFieldElement.F2m x3 554 = (ECFieldElement.F2m)lambda.square().add(lambda). 555 add(this.curve.getA()); 556 557 ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE); 558 ECFieldElement.F2m y3 559 = (ECFieldElement.F2m)this.x.square().add( 560 x3.multiply(lambda.add(ONE))); 561 562 return new ECPoint.F2m(this.curve, x3, y3, withCompression); 563 } 564 negate()565 public ECPoint negate() 566 { 567 return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression); 568 } 569 570 /** 571 * Sets the appropriate <code>ECMultiplier</code>, unless already set. 572 */ assertECMultiplier()573 synchronized void assertECMultiplier() 574 { 575 if (this.multiplier == null) 576 { 577 if (((ECCurve.F2m)this.curve).isKoblitz()) 578 { 579 this.multiplier = new WTauNafMultiplier(); 580 } 581 else 582 { 583 this.multiplier = new WNafMultiplier(); 584 } 585 } 586 } 587 } 588 } 589