• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.math.ec;
2 
3 import java.math.BigInteger;
4 import java.util.Random;
5 
6 import org.bouncycastle.util.BigIntegers;
7 
8 /**
9  * base class for an elliptic curve
10  */
11 public abstract class ECCurve
12 {
13     public static final int COORD_AFFINE = 0;
14     public static final int COORD_HOMOGENEOUS = 1;
15     public static final int COORD_JACOBIAN = 2;
16     public static final int COORD_JACOBIAN_CHUDNOVSKY = 3;
17     public static final int COORD_JACOBIAN_MODIFIED = 4;
18     public static final int COORD_LAMBDA_AFFINE = 5;
19     public static final int COORD_LAMBDA_PROJECTIVE = 6;
20     public static final int COORD_SKEWED = 7;
21 
getAllCoordinateSystems()22     public static int[] getAllCoordinateSystems()
23     {
24         return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
25             COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
26     }
27 
28     public class Config
29     {
30         protected int coord;
31         protected ECMultiplier multiplier;
32 
Config(int coord, ECMultiplier multiplier)33         Config(int coord, ECMultiplier multiplier)
34         {
35             this.coord = coord;
36             this.multiplier = multiplier;
37         }
38 
setCoordinateSystem(int coord)39         public Config setCoordinateSystem(int coord)
40         {
41             this.coord = coord;
42             return this;
43         }
44 
setMultiplier(ECMultiplier multiplier)45         public Config setMultiplier(ECMultiplier multiplier)
46         {
47             this.multiplier = multiplier;
48             return this;
49         }
50 
create()51         public ECCurve create()
52         {
53             if (!supportsCoordinateSystem(coord))
54             {
55                 throw new IllegalStateException("unsupported coordinate system");
56             }
57 
58             ECCurve c = cloneCurve();
59             if (c == ECCurve.this)
60             {
61                 throw new IllegalStateException("implementation returned current curve");
62             }
63 
64             c.coord = coord;
65             c.multiplier = multiplier;
66 
67             return c;
68         }
69     }
70 
71     protected ECFieldElement a, b;
72     protected int coord = COORD_AFFINE;
73     protected ECMultiplier multiplier = null;
74 
getFieldSize()75     public abstract int getFieldSize();
76 
fromBigInteger(BigInteger x)77     public abstract ECFieldElement fromBigInteger(BigInteger x);
78 
configure()79     public Config configure()
80     {
81         return new Config(this.coord, this.multiplier);
82     }
83 
createPoint(BigInteger x, BigInteger y)84     public ECPoint createPoint(BigInteger x, BigInteger y)
85     {
86         return createPoint(x, y, false);
87     }
88 
89     /**
90      * @deprecated per-point compression property will be removed, use {@link #createPoint(BigInteger, BigInteger)}
91      * and refer {@link ECPoint#getEncoded(boolean)}
92      */
createPoint(BigInteger x, BigInteger y, boolean withCompression)93     public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
94     {
95         return createRawPoint(fromBigInteger(x), fromBigInteger(y), withCompression);
96     }
97 
cloneCurve()98     protected abstract ECCurve cloneCurve();
99 
createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)100     protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression);
101 
createDefaultMultiplier()102     protected ECMultiplier createDefaultMultiplier()
103     {
104         return new WNafL2RMultiplier();
105     }
106 
supportsCoordinateSystem(int coord)107     public boolean supportsCoordinateSystem(int coord)
108     {
109         return coord == COORD_AFFINE;
110     }
111 
getPreCompInfo(ECPoint p)112     public PreCompInfo getPreCompInfo(ECPoint p)
113     {
114         checkPoint(p);
115         return p.preCompInfo;
116     }
117 
118     /**
119      * Sets the <code>PreCompInfo</code> for a point on this curve. Used by
120      * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
121      * by subsequent multiplication.
122      *
123      * @param point
124      *            The <code>ECPoint</code> to store precomputations for.
125      * @param preCompInfo
126      *            The values precomputed by the <code>ECMultiplier</code>.
127      */
setPreCompInfo(ECPoint point, PreCompInfo preCompInfo)128     public void setPreCompInfo(ECPoint point, PreCompInfo preCompInfo)
129     {
130         checkPoint(point);
131         point.preCompInfo = preCompInfo;
132     }
133 
importPoint(ECPoint p)134     public ECPoint importPoint(ECPoint p)
135     {
136         if (this == p.getCurve())
137         {
138             return p;
139         }
140         if (p.isInfinity())
141         {
142             return getInfinity();
143         }
144 
145         // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
146         p = p.normalize();
147 
148         return createPoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression);
149     }
150 
151     /**
152      * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
153      * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
154      * than one point is to be normalized, this method will generally be more efficient than
155      * normalizing each point separately.
156      *
157      * @param points
158      *            An array of points that will be updated in place with their normalized versions,
159      *            where necessary
160      */
normalizeAll(ECPoint[] points)161     public void normalizeAll(ECPoint[] points)
162     {
163         checkPoints(points);
164 
165         if (this.getCoordinateSystem() == ECCurve.COORD_AFFINE)
166         {
167             return;
168         }
169 
170         /*
171          * Figure out which of the points actually need to be normalized
172          */
173         ECFieldElement[] zs = new ECFieldElement[points.length];
174         int[] indices = new int[points.length];
175         int count = 0;
176         for (int i = 0; i < points.length; ++i)
177         {
178             ECPoint p = points[i];
179             if (null != p && !p.isNormalized())
180             {
181                 zs[count] = p.getZCoord(0);
182                 indices[count++] = i;
183             }
184         }
185 
186         if (count == 0)
187         {
188             return;
189         }
190 
191         ECAlgorithms.implMontgomeryTrick(zs, 0, count);
192 
193         for (int j = 0; j < count; ++j)
194         {
195             int index = indices[j];
196             points[index] = points[index].normalize(zs[j]);
197         }
198     }
199 
getInfinity()200     public abstract ECPoint getInfinity();
201 
getA()202     public ECFieldElement getA()
203     {
204         return a;
205     }
206 
getB()207     public ECFieldElement getB()
208     {
209         return b;
210     }
211 
getCoordinateSystem()212     public int getCoordinateSystem()
213     {
214         return coord;
215     }
216 
decompressPoint(int yTilde, BigInteger X1)217     protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1);
218 
219     /**
220      * Sets the default <code>ECMultiplier</code>, unless already set.
221      */
getMultiplier()222     public ECMultiplier getMultiplier()
223     {
224         if (this.multiplier == null)
225         {
226             this.multiplier = createDefaultMultiplier();
227         }
228         return this.multiplier;
229     }
230 
231     /**
232      * Decode a point on this curve from its ASN.1 encoding. The different
233      * encodings are taken account of, including point compression for
234      * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
235      * @return The decoded point.
236      */
decodePoint(byte[] encoded)237     public ECPoint decodePoint(byte[] encoded)
238     {
239         ECPoint p = null;
240         int expectedLength = (getFieldSize() + 7) / 8;
241 
242         switch (encoded[0])
243         {
244         case 0x00: // infinity
245         {
246             if (encoded.length != 1)
247             {
248                 throw new IllegalArgumentException("Incorrect length for infinity encoding");
249             }
250 
251             p = getInfinity();
252             break;
253         }
254         case 0x02: // compressed
255         case 0x03: // compressed
256         {
257             if (encoded.length != (expectedLength + 1))
258             {
259                 throw new IllegalArgumentException("Incorrect length for compressed encoding");
260             }
261 
262             int yTilde = encoded[0] & 1;
263             BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
264 
265             p = decompressPoint(yTilde, X);
266             break;
267         }
268         case 0x04: // uncompressed
269         case 0x06: // hybrid
270         case 0x07: // hybrid
271         {
272             if (encoded.length != (2 * expectedLength + 1))
273             {
274                 throw new IllegalArgumentException("Incorrect length for uncompressed/hybrid encoding");
275             }
276 
277             BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
278             BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength);
279 
280             p = createPoint(X, Y);
281             break;
282         }
283         default:
284             throw new IllegalArgumentException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
285         }
286 
287         return p;
288     }
289 
checkPoint(ECPoint point)290     protected void checkPoint(ECPoint point)
291     {
292         if (null == point || (this != point.getCurve()))
293         {
294             throw new IllegalArgumentException("'point' must be non-null and on this curve");
295         }
296     }
297 
checkPoints(ECPoint[] points)298     protected void checkPoints(ECPoint[] points)
299     {
300         if (points == null)
301         {
302             throw new IllegalArgumentException("'points' cannot be null");
303         }
304 
305         for (int i = 0; i < points.length; ++i)
306         {
307             ECPoint point = points[i];
308             if (null != point && this != point.getCurve())
309             {
310                 throw new IllegalArgumentException("'points' entries must be null or on this curve");
311             }
312         }
313     }
314 
315     /**
316      * Elliptic curve over Fp
317      */
318     public static class Fp extends ECCurve
319     {
320         private static final int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
321 
322         BigInteger q, r;
323         ECPoint.Fp infinity;
324 
Fp(BigInteger q, BigInteger a, BigInteger b)325         public Fp(BigInteger q, BigInteger a, BigInteger b)
326         {
327             this.q = q;
328             this.r = ECFieldElement.Fp.calculateResidue(q);
329             this.infinity = new ECPoint.Fp(this, null, null);
330 
331             this.a = fromBigInteger(a);
332             this.b = fromBigInteger(b);
333             this.coord = FP_DEFAULT_COORDS;
334         }
335 
Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)336         protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
337         {
338             this.q = q;
339             this.r = r;
340             this.infinity = new ECPoint.Fp(this, null, null);
341 
342             this.a = a;
343             this.b = b;
344             this.coord = FP_DEFAULT_COORDS;
345         }
346 
cloneCurve()347         protected ECCurve cloneCurve()
348         {
349             return new Fp(q, r, a, b);
350         }
351 
supportsCoordinateSystem(int coord)352         public boolean supportsCoordinateSystem(int coord)
353         {
354             switch (coord)
355             {
356             case COORD_AFFINE:
357             case COORD_HOMOGENEOUS:
358             case COORD_JACOBIAN:
359             case COORD_JACOBIAN_MODIFIED:
360                 return true;
361             default:
362                 return false;
363             }
364         }
365 
getQ()366         public BigInteger getQ()
367         {
368             return q;
369         }
370 
getFieldSize()371         public int getFieldSize()
372         {
373             return q.bitLength();
374         }
375 
fromBigInteger(BigInteger x)376         public ECFieldElement fromBigInteger(BigInteger x)
377         {
378             return new ECFieldElement.Fp(this.q, this.r, x);
379         }
380 
createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)381         protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
382         {
383             return new ECPoint.Fp(this, x, y, withCompression);
384         }
385 
importPoint(ECPoint p)386         public ECPoint importPoint(ECPoint p)
387         {
388             if (this != p.getCurve() && this.getCoordinateSystem() == COORD_JACOBIAN && !p.isInfinity())
389             {
390                 switch (p.getCurve().getCoordinateSystem())
391                 {
392                 case COORD_JACOBIAN:
393                 case COORD_JACOBIAN_CHUDNOVSKY:
394                 case COORD_JACOBIAN_MODIFIED:
395                     return new ECPoint.Fp(this,
396                         fromBigInteger(p.x.toBigInteger()),
397                         fromBigInteger(p.y.toBigInteger()),
398                         new ECFieldElement[]{ fromBigInteger(p.zs[0].toBigInteger()) },
399                         p.withCompression);
400                 default:
401                     break;
402                 }
403             }
404 
405             return super.importPoint(p);
406         }
407 
decompressPoint(int yTilde, BigInteger X1)408         protected ECPoint decompressPoint(int yTilde, BigInteger X1)
409         {
410             ECFieldElement x = fromBigInteger(X1);
411             ECFieldElement alpha = x.multiply(x.square().add(a)).add(b);
412             ECFieldElement beta = alpha.sqrt();
413 
414             //
415             // if we can't find a sqrt we haven't got a point on the
416             // curve - run!
417             //
418             if (beta == null)
419             {
420                 throw new RuntimeException("Invalid point compression");
421             }
422 
423             BigInteger betaValue = beta.toBigInteger();
424             if (betaValue.testBit(0) != (yTilde == 1))
425             {
426                 // Use the other root
427                 beta = fromBigInteger(q.subtract(betaValue));
428             }
429 
430             return new ECPoint.Fp(this, x, beta, true);
431         }
432 
getInfinity()433         public ECPoint getInfinity()
434         {
435             return infinity;
436         }
437 
equals( Object anObject)438         public boolean equals(
439             Object anObject)
440         {
441             if (anObject == this)
442             {
443                 return true;
444             }
445 
446             if (!(anObject instanceof ECCurve.Fp))
447             {
448                 return false;
449             }
450 
451             ECCurve.Fp other = (ECCurve.Fp) anObject;
452 
453             return this.q.equals(other.q)
454                     && a.equals(other.a) && b.equals(other.b);
455         }
456 
hashCode()457         public int hashCode()
458         {
459             return a.hashCode() ^ b.hashCode() ^ q.hashCode();
460         }
461     }
462 
463     /**
464      * Elliptic curves over F2m. The Weierstrass equation is given by
465      * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
466      */
467     public static class F2m extends ECCurve
468     {
469         private static final int F2M_DEFAULT_COORDS = COORD_AFFINE;
470 
471         /**
472          * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
473          */
474         private int m;  // can't be final - JDK 1.1
475 
476         /**
477          * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
478          * x<sup>k</sup> + 1</code> represents the reduction polynomial
479          * <code>f(z)</code>.<br>
480          * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
481          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
482          * represents the reduction polynomial <code>f(z)</code>.<br>
483          */
484         private int k1;  // can't be final - JDK 1.1
485 
486         /**
487          * TPB: Always set to <code>0</code><br>
488          * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
489          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
490          * represents the reduction polynomial <code>f(z)</code>.<br>
491          */
492         private int k2;  // can't be final - JDK 1.1
493 
494         /**
495          * TPB: Always set to <code>0</code><br>
496          * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
497          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
498          * represents the reduction polynomial <code>f(z)</code>.<br>
499          */
500         private int k3;  // can't be final - JDK 1.1
501 
502         /**
503          * The order of the base point of the curve.
504          */
505         private BigInteger n;  // can't be final - JDK 1.1
506 
507         /**
508          * The cofactor of the curve.
509          */
510         private BigInteger h;  // can't be final - JDK 1.1
511 
512          /**
513          * The point at infinity on this curve.
514          */
515         private ECPoint.F2m infinity;  // can't be final - JDK 1.1
516 
517         /**
518          * The parameter <code>&mu;</code> of the elliptic curve if this is
519          * a Koblitz curve.
520          */
521         private byte mu = 0;
522 
523         /**
524          * The auxiliary values <code>s<sub>0</sub></code> and
525          * <code>s<sub>1</sub></code> used for partial modular reduction for
526          * Koblitz curves.
527          */
528         private BigInteger[] si = null;
529 
530         /**
531          * Constructor for Trinomial Polynomial Basis (TPB).
532          * @param m  The exponent <code>m</code> of
533          * <code>F<sub>2<sup>m</sup></sub></code>.
534          * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
535          * x<sup>k</sup> + 1</code> represents the reduction
536          * polynomial <code>f(z)</code>.
537          * @param a The coefficient <code>a</code> in the Weierstrass equation
538          * for non-supersingular elliptic curves over
539          * <code>F<sub>2<sup>m</sup></sub></code>.
540          * @param b The coefficient <code>b</code> in the Weierstrass equation
541          * for non-supersingular elliptic curves over
542          * <code>F<sub>2<sup>m</sup></sub></code>.
543          */
F2m( int m, int k, BigInteger a, BigInteger b)544         public F2m(
545             int m,
546             int k,
547             BigInteger a,
548             BigInteger b)
549         {
550             this(m, k, 0, 0, a, b, null, null);
551         }
552 
553         /**
554          * Constructor for Trinomial Polynomial Basis (TPB).
555          * @param m  The exponent <code>m</code> of
556          * <code>F<sub>2<sup>m</sup></sub></code>.
557          * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
558          * x<sup>k</sup> + 1</code> represents the reduction
559          * polynomial <code>f(z)</code>.
560          * @param a The coefficient <code>a</code> in the Weierstrass equation
561          * for non-supersingular elliptic curves over
562          * <code>F<sub>2<sup>m</sup></sub></code>.
563          * @param b The coefficient <code>b</code> in the Weierstrass equation
564          * for non-supersingular elliptic curves over
565          * <code>F<sub>2<sup>m</sup></sub></code>.
566          * @param n The order of the main subgroup of the elliptic curve.
567          * @param h The cofactor of the elliptic curve, i.e.
568          * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
569          */
F2m( int m, int k, BigInteger a, BigInteger b, BigInteger n, BigInteger h)570         public F2m(
571             int m,
572             int k,
573             BigInteger a,
574             BigInteger b,
575             BigInteger n,
576             BigInteger h)
577         {
578             this(m, k, 0, 0, a, b, n, h);
579         }
580 
581         /**
582          * Constructor for Pentanomial Polynomial Basis (PPB).
583          * @param m  The exponent <code>m</code> of
584          * <code>F<sub>2<sup>m</sup></sub></code>.
585          * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
586          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
587          * represents the reduction polynomial <code>f(z)</code>.
588          * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
589          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
590          * represents the reduction polynomial <code>f(z)</code>.
591          * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
592          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
593          * represents the reduction polynomial <code>f(z)</code>.
594          * @param a The coefficient <code>a</code> in the Weierstrass equation
595          * for non-supersingular elliptic curves over
596          * <code>F<sub>2<sup>m</sup></sub></code>.
597          * @param b The coefficient <code>b</code> in the Weierstrass equation
598          * for non-supersingular elliptic curves over
599          * <code>F<sub>2<sup>m</sup></sub></code>.
600          */
F2m( int m, int k1, int k2, int k3, BigInteger a, BigInteger b)601         public F2m(
602             int m,
603             int k1,
604             int k2,
605             int k3,
606             BigInteger a,
607             BigInteger b)
608         {
609             this(m, k1, k2, k3, a, b, null, null);
610         }
611 
612         /**
613          * Constructor for Pentanomial Polynomial Basis (PPB).
614          * @param m  The exponent <code>m</code> of
615          * <code>F<sub>2<sup>m</sup></sub></code>.
616          * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
617          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
618          * represents the reduction polynomial <code>f(z)</code>.
619          * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
620          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
621          * represents the reduction polynomial <code>f(z)</code>.
622          * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
623          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
624          * represents the reduction polynomial <code>f(z)</code>.
625          * @param a The coefficient <code>a</code> in the Weierstrass equation
626          * for non-supersingular elliptic curves over
627          * <code>F<sub>2<sup>m</sup></sub></code>.
628          * @param b The coefficient <code>b</code> in the Weierstrass equation
629          * for non-supersingular elliptic curves over
630          * <code>F<sub>2<sup>m</sup></sub></code>.
631          * @param n The order of the main subgroup of the elliptic curve.
632          * @param h The cofactor of the elliptic curve, i.e.
633          * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
634          */
F2m( int m, int k1, int k2, int k3, BigInteger a, BigInteger b, BigInteger n, BigInteger h)635         public F2m(
636             int m,
637             int k1,
638             int k2,
639             int k3,
640             BigInteger a,
641             BigInteger b,
642             BigInteger n,
643             BigInteger h)
644         {
645             this.m = m;
646             this.k1 = k1;
647             this.k2 = k2;
648             this.k3 = k3;
649             this.n = n;
650             this.h = h;
651 
652             if (k1 == 0)
653             {
654                 throw new IllegalArgumentException("k1 must be > 0");
655             }
656 
657             if (k2 == 0)
658             {
659                 if (k3 != 0)
660                 {
661                     throw new IllegalArgumentException("k3 must be 0 if k2 == 0");
662                 }
663             }
664             else
665             {
666                 if (k2 <= k1)
667                 {
668                     throw new IllegalArgumentException("k2 must be > k1");
669                 }
670 
671                 if (k3 <= k2)
672                 {
673                     throw new IllegalArgumentException("k3 must be > k2");
674                 }
675             }
676 
677             this.infinity = new ECPoint.F2m(this, null, null);
678             this.a = fromBigInteger(a);
679             this.b = fromBigInteger(b);
680             this.coord = F2M_DEFAULT_COORDS;
681         }
682 
F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger n, BigInteger h)683         protected F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger n, BigInteger h)
684         {
685             this.m = m;
686             this.k1 = k1;
687             this.k2 = k2;
688             this.k3 = k3;
689             this.n = n;
690             this.h = h;
691 
692             this.infinity = new ECPoint.F2m(this, null, null);
693             this.a = a;
694             this.b = b;
695             this.coord = F2M_DEFAULT_COORDS;
696         }
697 
cloneCurve()698         protected ECCurve cloneCurve()
699         {
700             return new F2m(m, k1, k2, k3, a, b, n, h);
701         }
702 
supportsCoordinateSystem(int coord)703         public boolean supportsCoordinateSystem(int coord)
704         {
705             switch (coord)
706             {
707             case COORD_AFFINE:
708             case COORD_HOMOGENEOUS:
709             case COORD_LAMBDA_PROJECTIVE:
710                 return true;
711             default:
712                 return false;
713             }
714         }
715 
createDefaultMultiplier()716         protected ECMultiplier createDefaultMultiplier()
717         {
718             if (isKoblitz())
719             {
720                 return new WTauNafMultiplier();
721             }
722 
723             return super.createDefaultMultiplier();
724         }
725 
getFieldSize()726         public int getFieldSize()
727         {
728             return m;
729         }
730 
fromBigInteger(BigInteger x)731         public ECFieldElement fromBigInteger(BigInteger x)
732         {
733             return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);
734         }
735 
createPoint(BigInteger x, BigInteger y, boolean withCompression)736         public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
737         {
738             ECFieldElement X = fromBigInteger(x), Y = fromBigInteger(y);
739 
740             switch (this.getCoordinateSystem())
741             {
742             case COORD_LAMBDA_AFFINE:
743             case COORD_LAMBDA_PROJECTIVE:
744             {
745                 if (!X.isZero())
746                 {
747                     // Y becomes Lambda (X + Y/X) here
748                     Y = Y.divide(X).add(X);
749                 }
750                 break;
751             }
752             default:
753             {
754                 break;
755             }
756             }
757 
758             return createRawPoint(X, Y, withCompression);
759         }
760 
createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)761         protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
762         {
763             return new ECPoint.F2m(this, x, y, withCompression);
764         }
765 
getInfinity()766         public ECPoint getInfinity()
767         {
768             return infinity;
769         }
770 
771         /**
772          * Returns true if this is a Koblitz curve (ABC curve).
773          * @return true if this is a Koblitz curve (ABC curve), false otherwise
774          */
isKoblitz()775         public boolean isKoblitz()
776         {
777             return n != null && h != null && a.bitLength() <= 1 && b.bitLength() == 1;
778         }
779 
780         /**
781          * Returns the parameter <code>&mu;</code> of the elliptic curve.
782          * @return <code>&mu;</code> of the elliptic curve.
783          * @throws IllegalArgumentException if the given ECCurve is not a
784          * Koblitz curve.
785          */
getMu()786         synchronized byte getMu()
787         {
788             if (mu == 0)
789             {
790                 mu = Tnaf.getMu(this);
791             }
792             return mu;
793         }
794 
795         /**
796          * @return the auxiliary values <code>s<sub>0</sub></code> and
797          * <code>s<sub>1</sub></code> used for partial modular reduction for
798          * Koblitz curves.
799          */
getSi()800         synchronized BigInteger[] getSi()
801         {
802             if (si == null)
803             {
804                 si = Tnaf.getSi(this);
805             }
806             return si;
807         }
808 
809         /**
810          * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
811          *
812          * @param yTilde
813          *            ~yp, an indication bit for the decompression of yp.
814          * @param X1
815          *            The field element xp.
816          * @return the decompressed point.
817          */
decompressPoint(int yTilde, BigInteger X1)818         protected ECPoint decompressPoint(int yTilde, BigInteger X1)
819         {
820             ECFieldElement xp = fromBigInteger(X1);
821             ECFieldElement yp = null;
822             if (xp.isZero())
823             {
824                 yp = (ECFieldElement.F2m)b;
825                 for (int i = 0; i < m - 1; i++)
826                 {
827                     yp = yp.square();
828                 }
829             }
830             else
831             {
832                 ECFieldElement beta = xp.add(a).add(b.multiply(xp.square().invert()));
833                 ECFieldElement z = solveQuadraticEquation(beta);
834                 if (z == null)
835                 {
836                     throw new IllegalArgumentException("Invalid point compression");
837                 }
838                 if (z.testBitZero() != (yTilde == 1))
839                 {
840                     z = z.addOne();
841                 }
842 
843                 yp = xp.multiply(z);
844 
845                 switch (this.getCoordinateSystem())
846                 {
847                 case COORD_LAMBDA_AFFINE:
848                 case COORD_LAMBDA_PROJECTIVE:
849                 {
850                     yp = yp.divide(xp).add(xp);
851                     break;
852                 }
853                 default:
854                 {
855                     break;
856                 }
857                 }
858             }
859 
860             return new ECPoint.F2m(this, xp, yp, true);
861         }
862 
863         /**
864          * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
865          * D.1.6) The other solution is <code>z + 1</code>.
866          *
867          * @param beta
868          *            The value to solve the quadratic equation for.
869          * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
870          *         <code>null</code> if no solution exists.
871          */
solveQuadraticEquation(ECFieldElement beta)872         private ECFieldElement solveQuadraticEquation(ECFieldElement beta)
873         {
874             if (beta.isZero())
875             {
876                 return beta;
877             }
878 
879             ECFieldElement zeroElement = fromBigInteger(ECConstants.ZERO);
880 
881             ECFieldElement z = null;
882             ECFieldElement gamma = null;
883 
884             Random rand = new Random();
885             do
886             {
887                 ECFieldElement t = fromBigInteger(new BigInteger(m, rand));
888                 z = zeroElement;
889                 ECFieldElement w = beta;
890                 for (int i = 1; i <= m - 1; i++)
891                 {
892                     ECFieldElement w2 = w.square();
893                     z = z.square().add(w2.multiply(t));
894                     w = w2.add(beta);
895                 }
896                 if (!w.isZero())
897                 {
898                     return null;
899                 }
900                 gamma = z.square().add(z);
901             }
902             while (gamma.isZero());
903 
904             return z;
905         }
906 
equals( Object anObject)907         public boolean equals(
908             Object anObject)
909         {
910             if (anObject == this)
911             {
912                 return true;
913             }
914 
915             if (!(anObject instanceof ECCurve.F2m))
916             {
917                 return false;
918             }
919 
920             ECCurve.F2m other = (ECCurve.F2m)anObject;
921 
922             return (this.m == other.m) && (this.k1 == other.k1)
923                 && (this.k2 == other.k2) && (this.k3 == other.k3)
924                 && a.equals(other.a) && b.equals(other.b);
925         }
926 
hashCode()927         public int hashCode()
928         {
929             return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3;
930         }
931 
getM()932         public int getM()
933         {
934             return m;
935         }
936 
937         /**
938          * Return true if curve uses a Trinomial basis.
939          *
940          * @return true if curve Trinomial, false otherwise.
941          */
isTrinomial()942         public boolean isTrinomial()
943         {
944             return k2 == 0 && k3 == 0;
945         }
946 
getK1()947         public int getK1()
948         {
949             return k1;
950         }
951 
getK2()952         public int getK2()
953         {
954             return k2;
955         }
956 
getK3()957         public int getK3()
958         {
959             return k3;
960         }
961 
getN()962         public BigInteger getN()
963         {
964             return n;
965         }
966 
getH()967         public BigInteger getH()
968         {
969             return h;
970         }
971     }
972 }
973