1package org.bouncycastle.math.ec;
2
3import java.math.BigInteger;
4import java.util.Random;
5
6/**
7 * base class for an elliptic curve
8 */
9public abstract class ECCurve
10{
11    ECFieldElement a, b;
12
13    public abstract int getFieldSize();
14
15    public abstract ECFieldElement fromBigInteger(BigInteger x);
16
17    public abstract ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression);
18
19    public abstract ECPoint decodePoint(byte[] encoded);
20
21    public abstract ECPoint getInfinity();
22
23    public ECFieldElement getA()
24    {
25        return a;
26    }
27
28    public ECFieldElement getB()
29    {
30        return b;
31    }
32
33    /**
34     * Elliptic curve over Fp
35     */
36    public static class Fp extends ECCurve
37    {
38        BigInteger q;
39        ECPoint.Fp infinity;
40
41        public Fp(BigInteger q, BigInteger a, BigInteger b)
42        {
43            this.q = q;
44            this.a = fromBigInteger(a);
45            this.b = fromBigInteger(b);
46            this.infinity = new ECPoint.Fp(this, null, null);
47        }
48
49        public BigInteger getQ()
50        {
51            return q;
52        }
53
54        public int getFieldSize()
55        {
56            return q.bitLength();
57        }
58
59        public ECFieldElement fromBigInteger(BigInteger x)
60        {
61            return new ECFieldElement.Fp(this.q, x);
62        }
63
64        public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
65        {
66            return new ECPoint.Fp(this, fromBigInteger(x), fromBigInteger(y), withCompression);
67        }
68
69        /**
70         * Decode a point on this curve from its ASN.1 encoding. The different
71         * encodings are taken account of, including point compression for
72         * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
73         * @return The decoded point.
74         */
75        public ECPoint decodePoint(byte[] encoded)
76        {
77            ECPoint p = null;
78
79            switch (encoded[0])
80            {
81                // infinity
82            case 0x00:
83                if (encoded.length > 1)
84                {
85                    throw new RuntimeException("Invalid point encoding");
86                }
87                p = getInfinity();
88                break;
89                // compressed
90            case 0x02:
91            case 0x03:
92                int ytilde = encoded[0] & 1;
93                byte[]  i = new byte[encoded.length - 1];
94
95                System.arraycopy(encoded, 1, i, 0, i.length);
96
97                ECFieldElement x = new ECFieldElement.Fp(this.q, new BigInteger(1, i));
98                ECFieldElement alpha = x.multiply(x.square().add(a)).add(b);
99                ECFieldElement beta = alpha.sqrt();
100
101                //
102                // if we can't find a sqrt we haven't got a point on the
103                // curve - run!
104                //
105                if (beta == null)
106                {
107                    throw new RuntimeException("Invalid point compression");
108                }
109
110                int bit0 = (beta.toBigInteger().testBit(0) ? 1 : 0);
111
112                if (bit0 == ytilde)
113                {
114                    p = new ECPoint.Fp(this, x, beta, true);
115                }
116                else
117                {
118                    p = new ECPoint.Fp(this, x,
119                        new ECFieldElement.Fp(this.q, q.subtract(beta.toBigInteger())), true);
120                }
121                break;
122                // uncompressed
123            case 0x04:
124                // hybrid
125            case 0x06:
126            case 0x07:
127                byte[]  xEnc = new byte[(encoded.length - 1) / 2];
128                byte[]  yEnc = new byte[(encoded.length - 1) / 2];
129
130                System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
131                System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
132
133                p = new ECPoint.Fp(this,
134                        new ECFieldElement.Fp(this.q, new BigInteger(1, xEnc)),
135                        new ECFieldElement.Fp(this.q, new BigInteger(1, yEnc)));
136                break;
137            default:
138                throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
139            }
140
141            return p;
142        }
143
144        public ECPoint getInfinity()
145        {
146            return infinity;
147        }
148
149        public boolean equals(
150            Object anObject)
151        {
152            if (anObject == this)
153            {
154                return true;
155            }
156
157            if (!(anObject instanceof ECCurve.Fp))
158            {
159                return false;
160            }
161
162            ECCurve.Fp other = (ECCurve.Fp) anObject;
163
164            return this.q.equals(other.q)
165                    && a.equals(other.a) && b.equals(other.b);
166        }
167
168        public int hashCode()
169        {
170            return a.hashCode() ^ b.hashCode() ^ q.hashCode();
171        }
172    }
173
174    /**
175     * Elliptic curves over F2m. The Weierstrass equation is given by
176     * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
177     */
178    public static class F2m extends ECCurve
179    {
180        /**
181         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
182         */
183        private int m;  // can't be final - JDK 1.1
184
185        /**
186         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
187         * x<sup>k</sup> + 1</code> represents the reduction polynomial
188         * <code>f(z)</code>.<br>
189         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
190         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
191         * represents the reduction polynomial <code>f(z)</code>.<br>
192         */
193        private int k1;  // can't be final - JDK 1.1
194
195        /**
196         * TPB: Always set to <code>0</code><br>
197         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
198         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
199         * represents the reduction polynomial <code>f(z)</code>.<br>
200         */
201        private int k2;  // can't be final - JDK 1.1
202
203        /**
204         * TPB: Always set to <code>0</code><br>
205         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
206         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
207         * represents the reduction polynomial <code>f(z)</code>.<br>
208         */
209        private int k3;  // can't be final - JDK 1.1
210
211        /**
212         * The order of the base point of the curve.
213         */
214        private BigInteger n;  // can't be final - JDK 1.1
215
216        /**
217         * The cofactor of the curve.
218         */
219        private BigInteger h;  // can't be final - JDK 1.1
220
221         /**
222         * The point at infinity on this curve.
223         */
224        private ECPoint.F2m infinity;  // can't be final - JDK 1.1
225
226        /**
227         * The parameter <code>&mu;</code> of the elliptic curve if this is
228         * a Koblitz curve.
229         */
230        private byte mu = 0;
231
232        /**
233         * The auxiliary values <code>s<sub>0</sub></code> and
234         * <code>s<sub>1</sub></code> used for partial modular reduction for
235         * Koblitz curves.
236         */
237        private BigInteger[] si = null;
238
239        /**
240         * Constructor for Trinomial Polynomial Basis (TPB).
241         * @param m  The exponent <code>m</code> of
242         * <code>F<sub>2<sup>m</sup></sub></code>.
243         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
244         * x<sup>k</sup> + 1</code> represents the reduction
245         * polynomial <code>f(z)</code>.
246         * @param a The coefficient <code>a</code> in the Weierstrass equation
247         * for non-supersingular elliptic curves over
248         * <code>F<sub>2<sup>m</sup></sub></code>.
249         * @param b The coefficient <code>b</code> in the Weierstrass equation
250         * for non-supersingular elliptic curves over
251         * <code>F<sub>2<sup>m</sup></sub></code>.
252         */
253        public F2m(
254            int m,
255            int k,
256            BigInteger a,
257            BigInteger b)
258        {
259            this(m, k, 0, 0, a, b, null, null);
260        }
261
262        /**
263         * Constructor for Trinomial Polynomial Basis (TPB).
264         * @param m  The exponent <code>m</code> of
265         * <code>F<sub>2<sup>m</sup></sub></code>.
266         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
267         * x<sup>k</sup> + 1</code> represents the reduction
268         * polynomial <code>f(z)</code>.
269         * @param a The coefficient <code>a</code> in the Weierstrass equation
270         * for non-supersingular elliptic curves over
271         * <code>F<sub>2<sup>m</sup></sub></code>.
272         * @param b The coefficient <code>b</code> in the Weierstrass equation
273         * for non-supersingular elliptic curves over
274         * <code>F<sub>2<sup>m</sup></sub></code>.
275         * @param n The order of the main subgroup of the elliptic curve.
276         * @param h The cofactor of the elliptic curve, i.e.
277         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
278         */
279        public F2m(
280            int m,
281            int k,
282            BigInteger a,
283            BigInteger b,
284            BigInteger n,
285            BigInteger h)
286        {
287            this(m, k, 0, 0, a, b, n, h);
288        }
289
290        /**
291         * Constructor for Pentanomial Polynomial Basis (PPB).
292         * @param m  The exponent <code>m</code> of
293         * <code>F<sub>2<sup>m</sup></sub></code>.
294         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
295         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
296         * represents the reduction polynomial <code>f(z)</code>.
297         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
298         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
299         * represents the reduction polynomial <code>f(z)</code>.
300         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
301         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
302         * represents the reduction polynomial <code>f(z)</code>.
303         * @param a The coefficient <code>a</code> in the Weierstrass equation
304         * for non-supersingular elliptic curves over
305         * <code>F<sub>2<sup>m</sup></sub></code>.
306         * @param b The coefficient <code>b</code> in the Weierstrass equation
307         * for non-supersingular elliptic curves over
308         * <code>F<sub>2<sup>m</sup></sub></code>.
309         */
310        public F2m(
311            int m,
312            int k1,
313            int k2,
314            int k3,
315            BigInteger a,
316            BigInteger b)
317        {
318            this(m, k1, k2, k3, a, b, null, null);
319        }
320
321        /**
322         * Constructor for Pentanomial Polynomial Basis (PPB).
323         * @param m  The exponent <code>m</code> of
324         * <code>F<sub>2<sup>m</sup></sub></code>.
325         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
326         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
327         * represents the reduction polynomial <code>f(z)</code>.
328         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
329         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
330         * represents the reduction polynomial <code>f(z)</code>.
331         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
332         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
333         * represents the reduction polynomial <code>f(z)</code>.
334         * @param a The coefficient <code>a</code> in the Weierstrass equation
335         * for non-supersingular elliptic curves over
336         * <code>F<sub>2<sup>m</sup></sub></code>.
337         * @param b The coefficient <code>b</code> in the Weierstrass equation
338         * for non-supersingular elliptic curves over
339         * <code>F<sub>2<sup>m</sup></sub></code>.
340         * @param n The order of the main subgroup of the elliptic curve.
341         * @param h The cofactor of the elliptic curve, i.e.
342         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
343         */
344        public F2m(
345            int m,
346            int k1,
347            int k2,
348            int k3,
349            BigInteger a,
350            BigInteger b,
351            BigInteger n,
352            BigInteger h)
353        {
354            this.m = m;
355            this.k1 = k1;
356            this.k2 = k2;
357            this.k3 = k3;
358            this.n = n;
359            this.h = h;
360
361            if (k1 == 0)
362            {
363                throw new IllegalArgumentException("k1 must be > 0");
364            }
365
366            if (k2 == 0)
367            {
368                if (k3 != 0)
369                {
370                    throw new IllegalArgumentException("k3 must be 0 if k2 == 0");
371                }
372            }
373            else
374            {
375                if (k2 <= k1)
376                {
377                    throw new IllegalArgumentException("k2 must be > k1");
378                }
379
380                if (k3 <= k2)
381                {
382                    throw new IllegalArgumentException("k3 must be > k2");
383                }
384            }
385
386            this.a = fromBigInteger(a);
387            this.b = fromBigInteger(b);
388            this.infinity = new ECPoint.F2m(this, null, null);
389        }
390
391        public int getFieldSize()
392        {
393            return m;
394        }
395
396        public ECFieldElement fromBigInteger(BigInteger x)
397        {
398            return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);
399        }
400
401        public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
402        {
403            return new ECPoint.F2m(this, fromBigInteger(x), fromBigInteger(y), withCompression);
404        }
405
406        /* (non-Javadoc)
407         * @see org.bouncycastle.math.ec.ECCurve#decodePoint(byte[])
408         */
409        public ECPoint decodePoint(byte[] encoded)
410        {
411            ECPoint p = null;
412
413            switch (encoded[0])
414            {
415                // infinity
416            case 0x00:
417                if (encoded.length > 1)
418                {
419                    throw new RuntimeException("Invalid point encoding");
420                }
421                p = getInfinity();
422                break;
423                // compressed
424            case 0x02:
425            case 0x03:
426                byte[] enc = new byte[encoded.length - 1];
427                System.arraycopy(encoded, 1, enc, 0, enc.length);
428                if (encoded[0] == 0x02)
429                {
430                        p = decompressPoint(enc, 0);
431                }
432                else
433                {
434                        p = decompressPoint(enc, 1);
435                }
436                break;
437                // uncompressed
438            case 0x04:
439                // hybrid
440            case 0x06:
441            case 0x07:
442                byte[] xEnc = new byte[(encoded.length - 1) / 2];
443                byte[] yEnc = new byte[(encoded.length - 1) / 2];
444
445                System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
446                System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
447
448                p = new ECPoint.F2m(this,
449                    new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
450                        new BigInteger(1, xEnc)),
451                    new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
452                        new BigInteger(1, yEnc)), false);
453                break;
454
455            default:
456                throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
457            }
458
459            return p;
460        }
461
462        public ECPoint getInfinity()
463        {
464            return infinity;
465        }
466
467        /**
468         * Returns true if this is a Koblitz curve (ABC curve).
469         * @return true if this is a Koblitz curve (ABC curve), false otherwise
470         */
471        public boolean isKoblitz()
472        {
473            return ((n != null) && (h != null) &&
474                    ((a.toBigInteger().equals(ECConstants.ZERO)) ||
475                    (a.toBigInteger().equals(ECConstants.ONE))) &&
476                    (b.toBigInteger().equals(ECConstants.ONE)));
477        }
478
479        /**
480         * Returns the parameter <code>&mu;</code> of the elliptic curve.
481         * @return <code>&mu;</code> of the elliptic curve.
482         * @throws IllegalArgumentException if the given ECCurve is not a
483         * Koblitz curve.
484         */
485        synchronized byte getMu()
486        {
487            if (mu == 0)
488            {
489                mu = Tnaf.getMu(this);
490            }
491            return mu;
492        }
493
494        /**
495         * @return the auxiliary values <code>s<sub>0</sub></code> and
496         * <code>s<sub>1</sub></code> used for partial modular reduction for
497         * Koblitz curves.
498         */
499        synchronized BigInteger[] getSi()
500        {
501            if (si == null)
502            {
503                si = Tnaf.getSi(this);
504            }
505            return si;
506        }
507
508        /**
509         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
510         *
511         * @param xEnc
512         *            The encoding of field element xp.
513         * @param ypBit
514         *            ~yp, an indication bit for the decompression of yp.
515         * @return the decompressed point.
516         */
517        private ECPoint decompressPoint(
518            byte[] xEnc,
519            int ypBit)
520        {
521            ECFieldElement xp = new ECFieldElement.F2m(
522                    this.m, this.k1, this.k2, this.k3, new BigInteger(1, xEnc));
523            ECFieldElement yp = null;
524            if (xp.toBigInteger().equals(ECConstants.ZERO))
525            {
526                yp = (ECFieldElement.F2m)b;
527                for (int i = 0; i < m - 1; i++)
528                {
529                    yp = yp.square();
530                }
531            }
532            else
533            {
534                ECFieldElement beta = xp.add(a).add(
535                        b.multiply(xp.square().invert()));
536                ECFieldElement z = solveQuadradicEquation(beta);
537                if (z == null)
538                {
539                    throw new RuntimeException("Invalid point compression");
540                }
541                int zBit = 0;
542                if (z.toBigInteger().testBit(0))
543                {
544                    zBit = 1;
545                }
546                if (zBit != ypBit)
547                {
548                    z = z.add(new ECFieldElement.F2m(this.m, this.k1, this.k2,
549                            this.k3, ECConstants.ONE));
550                }
551                yp = xp.multiply(z);
552            }
553
554            return new ECPoint.F2m(this, xp, yp);
555        }
556
557        /**
558         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
559         * D.1.6) The other solution is <code>z + 1</code>.
560         *
561         * @param beta
562         *            The value to solve the qradratic equation for.
563         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
564         *         <code>null</code> if no solution exists.
565         */
566        private ECFieldElement solveQuadradicEquation(ECFieldElement beta)
567        {
568            ECFieldElement zeroElement = new ECFieldElement.F2m(
569                    this.m, this.k1, this.k2, this.k3, ECConstants.ZERO);
570
571            if (beta.toBigInteger().equals(ECConstants.ZERO))
572            {
573                return zeroElement;
574            }
575
576            ECFieldElement z = null;
577            ECFieldElement gamma = zeroElement;
578
579            Random rand = new Random();
580            do
581            {
582                ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1,
583                        this.k2, this.k3, new BigInteger(m, rand));
584                z = zeroElement;
585                ECFieldElement w = beta;
586                for (int i = 1; i <= m - 1; i++)
587                {
588                    ECFieldElement w2 = w.square();
589                    z = z.square().add(w2.multiply(t));
590                    w = w2.add(beta);
591                }
592                if (!w.toBigInteger().equals(ECConstants.ZERO))
593                {
594                    return null;
595                }
596                gamma = z.square().add(z);
597            }
598            while (gamma.toBigInteger().equals(ECConstants.ZERO));
599
600            return z;
601        }
602
603        public boolean equals(
604            Object anObject)
605        {
606            if (anObject == this)
607            {
608                return true;
609            }
610
611            if (!(anObject instanceof ECCurve.F2m))
612            {
613                return false;
614            }
615
616            ECCurve.F2m other = (ECCurve.F2m)anObject;
617
618            return (this.m == other.m) && (this.k1 == other.k1)
619                && (this.k2 == other.k2) && (this.k3 == other.k3)
620                && a.equals(other.a) && b.equals(other.b);
621        }
622
623        public int hashCode()
624        {
625            return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3;
626        }
627
628        public int getM()
629        {
630            return m;
631        }
632
633        /**
634         * Return true if curve uses a Trinomial basis.
635         *
636         * @return true if curve Trinomial, false otherwise.
637         */
638        public boolean isTrinomial()
639        {
640            return k2 == 0 && k3 == 0;
641        }
642
643        public int getK1()
644        {
645            return k1;
646        }
647
648        public int getK2()
649        {
650            return k2;
651        }
652
653        public int getK3()
654        {
655            return k3;
656        }
657
658        public BigInteger getN()
659        {
660            return n;
661        }
662
663        public BigInteger getH()
664        {
665            return h;
666        }
667    }
668}
669