• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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