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