ECPoint.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
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 abstract byte[] getEncoded();
112
113    public abstract ECPoint add(ECPoint b);
114    public abstract ECPoint subtract(ECPoint b);
115    public abstract ECPoint negate();
116    public abstract ECPoint twice();
117
118    /**
119     * Sets the default <code>ECMultiplier</code>, unless already set.
120     */
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     */
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         */
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         */
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         */
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
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
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:)
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
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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
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         */
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