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