1package org.bouncycastle.math.ec;
2
3import java.math.BigInteger;
4import java.util.Random;
5
6import org.bouncycastle.math.raw.Mod;
7import org.bouncycastle.math.raw.Nat;
8import org.bouncycastle.util.Arrays;
9import org.bouncycastle.util.BigIntegers;
10
11public abstract class ECFieldElement
12    implements ECConstants
13{
14    public abstract BigInteger     toBigInteger();
15    public abstract String         getFieldName();
16    public abstract int            getFieldSize();
17    public abstract ECFieldElement add(ECFieldElement b);
18    public abstract ECFieldElement addOne();
19    public abstract ECFieldElement subtract(ECFieldElement b);
20    public abstract ECFieldElement multiply(ECFieldElement b);
21    public abstract ECFieldElement divide(ECFieldElement b);
22    public abstract ECFieldElement negate();
23    public abstract ECFieldElement square();
24    public abstract ECFieldElement invert();
25    public abstract ECFieldElement sqrt();
26
27    public int bitLength()
28    {
29        return toBigInteger().bitLength();
30    }
31
32    public boolean isOne()
33    {
34        return bitLength() == 1;
35    }
36
37    public boolean isZero()
38    {
39        return 0 == toBigInteger().signum();
40    }
41
42    public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
43    {
44        return multiply(b).subtract(x.multiply(y));
45    }
46
47    public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
48    {
49        return multiply(b).add(x.multiply(y));
50    }
51
52    public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y)
53    {
54        return square().subtract(x.multiply(y));
55    }
56
57    public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y)
58    {
59        return square().add(x.multiply(y));
60    }
61
62    public ECFieldElement squarePow(int pow)
63    {
64        ECFieldElement r = this;
65        for (int i = 0; i < pow; ++i)
66        {
67            r = r.square();
68        }
69        return r;
70    }
71
72    public boolean testBitZero()
73    {
74        return toBigInteger().testBit(0);
75    }
76
77    public String toString()
78    {
79        return this.toBigInteger().toString(16);
80    }
81
82    public byte[] getEncoded()
83    {
84        return BigIntegers.asUnsignedByteArray((getFieldSize() + 7) / 8, toBigInteger());
85    }
86
87    public static class Fp extends ECFieldElement
88    {
89        BigInteger q, r, x;
90
91        static BigInteger calculateResidue(BigInteger p)
92        {
93            int bitLength = p.bitLength();
94            if (bitLength >= 96)
95            {
96                BigInteger firstWord = p.shiftRight(bitLength - 64);
97                if (firstWord.longValue() == -1L)
98                {
99                    return ONE.shiftLeft(bitLength).subtract(p);
100                }
101            }
102            return null;
103        }
104
105        /**
106         * @deprecated Use ECCurve.fromBigInteger to construct field elements
107         */
108        public Fp(BigInteger q, BigInteger x)
109        {
110            this(q, calculateResidue(q), x);
111        }
112
113        Fp(BigInteger q, BigInteger r, BigInteger x)
114        {
115            if (x == null || x.signum() < 0 || x.compareTo(q) >= 0)
116            {
117                throw new IllegalArgumentException("x value invalid in Fp field element");
118            }
119
120            this.q = q;
121            this.r = r;
122            this.x = x;
123        }
124
125        public BigInteger toBigInteger()
126        {
127            return x;
128        }
129
130        /**
131         * return the field name for this field.
132         *
133         * @return the string "Fp".
134         */
135        public String getFieldName()
136        {
137            return "Fp";
138        }
139
140        public int getFieldSize()
141        {
142            return q.bitLength();
143        }
144
145        public BigInteger getQ()
146        {
147            return q;
148        }
149
150        public ECFieldElement add(ECFieldElement b)
151        {
152            return new Fp(q, r, modAdd(x, b.toBigInteger()));
153        }
154
155        public ECFieldElement addOne()
156        {
157            BigInteger x2 = x.add(ECConstants.ONE);
158            if (x2.compareTo(q) == 0)
159            {
160                x2 = ECConstants.ZERO;
161            }
162            return new Fp(q, r, x2);
163        }
164
165        public ECFieldElement subtract(ECFieldElement b)
166        {
167            return new Fp(q, r, modSubtract(x, b.toBigInteger()));
168        }
169
170        public ECFieldElement multiply(ECFieldElement b)
171        {
172            return new Fp(q, r, modMult(x, b.toBigInteger()));
173        }
174
175        public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
176        {
177            BigInteger ax = this.x, bx = b.toBigInteger(), xx = x.toBigInteger(), yx = y.toBigInteger();
178            BigInteger ab = ax.multiply(bx);
179            BigInteger xy = xx.multiply(yx);
180            return new Fp(q, r, modReduce(ab.subtract(xy)));
181        }
182
183        public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
184        {
185            BigInteger ax = this.x, bx = b.toBigInteger(), xx = x.toBigInteger(), yx = y.toBigInteger();
186            BigInteger ab = ax.multiply(bx);
187            BigInteger xy = xx.multiply(yx);
188            return new Fp(q, r, modReduce(ab.add(xy)));
189        }
190
191        public ECFieldElement divide(ECFieldElement b)
192        {
193            return new Fp(q, r, modMult(x, modInverse(b.toBigInteger())));
194        }
195
196        public ECFieldElement negate()
197        {
198            return x.signum() == 0 ? this : new Fp(q, r, q.subtract(x));
199        }
200
201        public ECFieldElement square()
202        {
203            return new Fp(q, r, modMult(x, x));
204        }
205
206        public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y)
207        {
208            BigInteger ax = this.x, xx = x.toBigInteger(), yx = y.toBigInteger();
209            BigInteger aa = ax.multiply(ax);
210            BigInteger xy = xx.multiply(yx);
211            return new Fp(q, r, modReduce(aa.subtract(xy)));
212        }
213
214        public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y)
215        {
216            BigInteger ax = this.x, xx = x.toBigInteger(), yx = y.toBigInteger();
217            BigInteger aa = ax.multiply(ax);
218            BigInteger xy = xx.multiply(yx);
219            return new Fp(q, r, modReduce(aa.add(xy)));
220        }
221
222        public ECFieldElement invert()
223        {
224            // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime.
225            return new Fp(q, r, modInverse(x));
226        }
227
228        // D.1.4 91
229        /**
230         * return a sqrt root - the routine verifies that the calculation
231         * returns the right value - if none exists it returns null.
232         */
233        public ECFieldElement sqrt()
234        {
235            if (this.isZero() || this.isOne()) // earlier JDK compatibility
236            {
237                return this;
238            }
239
240            if (!q.testBit(0))
241            {
242                throw new RuntimeException("not done yet");
243            }
244
245            // note: even though this class implements ECConstants don't be tempted to
246            // remove the explicit declaration, some J2ME environments don't cope.
247
248            if (q.testBit(1)) // q == 4m + 3
249            {
250                BigInteger e = q.shiftRight(2).add(ECConstants.ONE);
251                return checkSqrt(new Fp(q, r, x.modPow(e, q)));
252            }
253
254            if (q.testBit(2)) // q == 8m + 5
255            {
256                BigInteger t1 = x.modPow(q.shiftRight(3), q);
257                BigInteger t2 = modMult(t1, x);
258                BigInteger t3 = modMult(t2, t1);
259
260                if (t3.equals(ECConstants.ONE))
261                {
262                    return checkSqrt(new Fp(q, r, t2));
263                }
264
265                // TODO This is constant and could be precomputed
266                BigInteger t4 = ECConstants.TWO.modPow(q.shiftRight(2), q);
267
268                BigInteger y = modMult(t2, t4);
269
270                return checkSqrt(new Fp(q, r, y));
271            }
272
273            // q == 8m + 1
274
275            BigInteger legendreExponent = q.shiftRight(1);
276            if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE)))
277            {
278                return null;
279            }
280
281            BigInteger X = this.x;
282            BigInteger fourX = modDouble(modDouble(X));
283
284            BigInteger k = legendreExponent.add(ECConstants.ONE), qMinusOne = q.subtract(ECConstants.ONE);
285
286            BigInteger U, V;
287            Random rand = new Random();
288            do
289            {
290                BigInteger P;
291                do
292                {
293                    P = new BigInteger(q.bitLength(), rand);
294                }
295                while (P.compareTo(q) >= 0
296                    || !modReduce(P.multiply(P).subtract(fourX)).modPow(legendreExponent, q).equals(qMinusOne));
297
298                BigInteger[] result = lucasSequence(P, X, k);
299                U = result[0];
300                V = result[1];
301
302                if (modMult(V, V).equals(fourX))
303                {
304                    return new ECFieldElement.Fp(q, r, modHalfAbs(V));
305                }
306            }
307            while (U.equals(ECConstants.ONE) || U.equals(qMinusOne));
308
309            return null;
310        }
311
312        private ECFieldElement checkSqrt(ECFieldElement z)
313        {
314            return z.square().equals(this) ? z : null;
315        }
316
317        private BigInteger[] lucasSequence(
318            BigInteger  P,
319            BigInteger  Q,
320            BigInteger  k)
321        {
322            // TODO Research and apply "common-multiplicand multiplication here"
323
324            int n = k.bitLength();
325            int s = k.getLowestSetBit();
326
327            // assert k.testBit(s);
328
329            BigInteger Uh = ECConstants.ONE;
330            BigInteger Vl = ECConstants.TWO;
331            BigInteger Vh = P;
332            BigInteger Ql = ECConstants.ONE;
333            BigInteger Qh = ECConstants.ONE;
334
335            for (int j = n - 1; j >= s + 1; --j)
336            {
337                Ql = modMult(Ql, Qh);
338
339                if (k.testBit(j))
340                {
341                    Qh = modMult(Ql, Q);
342                    Uh = modMult(Uh, Vh);
343                    Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
344                    Vh = modReduce(Vh.multiply(Vh).subtract(Qh.shiftLeft(1)));
345                }
346                else
347                {
348                    Qh = Ql;
349                    Uh = modReduce(Uh.multiply(Vl).subtract(Ql));
350                    Vh = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
351                    Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
352                }
353            }
354
355            Ql = modMult(Ql, Qh);
356            Qh = modMult(Ql, Q);
357            Uh = modReduce(Uh.multiply(Vl).subtract(Ql));
358            Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
359            Ql = modMult(Ql, Qh);
360
361            for (int j = 1; j <= s; ++j)
362            {
363                Uh = modMult(Uh, Vl);
364                Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
365                Ql = modMult(Ql, Ql);
366            }
367
368            return new BigInteger[]{ Uh, Vl };
369        }
370
371        protected BigInteger modAdd(BigInteger x1, BigInteger x2)
372        {
373            BigInteger x3 = x1.add(x2);
374            if (x3.compareTo(q) >= 0)
375            {
376                x3 = x3.subtract(q);
377            }
378            return x3;
379        }
380
381        protected BigInteger modDouble(BigInteger x)
382        {
383            BigInteger _2x = x.shiftLeft(1);
384            if (_2x.compareTo(q) >= 0)
385            {
386                _2x = _2x.subtract(q);
387            }
388            return _2x;
389        }
390
391        protected BigInteger modHalf(BigInteger x)
392        {
393            if (x.testBit(0))
394            {
395                x = q.add(x);
396            }
397            return x.shiftRight(1);
398        }
399
400        protected BigInteger modHalfAbs(BigInteger x)
401        {
402            if (x.testBit(0))
403            {
404                x = q.subtract(x);
405            }
406            return x.shiftRight(1);
407        }
408
409        protected BigInteger modInverse(BigInteger x)
410        {
411            int bits = getFieldSize();
412            int len = (bits + 31) >> 5;
413            int[] p = Nat.fromBigInteger(bits, q);
414            int[] n = Nat.fromBigInteger(bits, x);
415            int[] z = Nat.create(len);
416            Mod.invert(p, n, z);
417            return Nat.toBigInteger(len, z);
418        }
419
420        protected BigInteger modMult(BigInteger x1, BigInteger x2)
421        {
422            return modReduce(x1.multiply(x2));
423        }
424
425        protected BigInteger modReduce(BigInteger x)
426        {
427            if (r != null)
428            {
429                boolean negative = x.signum() < 0;
430                if (negative)
431                {
432                    x = x.abs();
433                }
434                int qLen = q.bitLength();
435                boolean rIsOne = r.equals(ECConstants.ONE);
436                while (x.bitLength() > (qLen + 1))
437                {
438                    BigInteger u = x.shiftRight(qLen);
439                    BigInteger v = x.subtract(u.shiftLeft(qLen));
440                    if (!rIsOne)
441                    {
442                        u = u.multiply(r);
443                    }
444                    x = u.add(v);
445                }
446                while (x.compareTo(q) >= 0)
447                {
448                    x = x.subtract(q);
449                }
450                if (negative && x.signum() != 0)
451                {
452                    x = q.subtract(x);
453                }
454            }
455            else
456            {
457                x = x.mod(q);
458            }
459            return x;
460        }
461
462        protected BigInteger modSubtract(BigInteger x1, BigInteger x2)
463        {
464            BigInteger x3 = x1.subtract(x2);
465            if (x3.signum() < 0)
466            {
467                x3 = x3.add(q);
468            }
469            return x3;
470        }
471
472        public boolean equals(Object other)
473        {
474            if (other == this)
475            {
476                return true;
477            }
478
479            if (!(other instanceof ECFieldElement.Fp))
480            {
481                return false;
482            }
483
484            ECFieldElement.Fp o = (ECFieldElement.Fp)other;
485            return q.equals(o.q) && x.equals(o.x);
486        }
487
488        public int hashCode()
489        {
490            return q.hashCode() ^ x.hashCode();
491        }
492    }
493
494    /**
495     * Class representing the Elements of the finite field
496     * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB)
497     * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial
498     * basis representations are supported. Gaussian normal basis (GNB)
499     * representation is not supported.
500     */
501    public static class F2m extends ECFieldElement
502    {
503        /**
504         * Indicates gaussian normal basis representation (GNB). Number chosen
505         * according to X9.62. GNB is not implemented at present.
506         */
507        public static final int GNB = 1;
508
509        /**
510         * Indicates trinomial basis representation (TPB). Number chosen
511         * according to X9.62.
512         */
513        public static final int TPB = 2;
514
515        /**
516         * Indicates pentanomial basis representation (PPB). Number chosen
517         * according to X9.62.
518         */
519        public static final int PPB = 3;
520
521        /**
522         * TPB or PPB.
523         */
524        private int representation;
525
526        /**
527         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
528         */
529        private int m;
530
531        private int[] ks;
532
533        /**
534         * The <code>LongArray</code> holding the bits.
535         */
536        private LongArray x;
537
538        /**
539         * Constructor for PPB.
540         * @param m  The exponent <code>m</code> of
541         * <code>F<sub>2<sup>m</sup></sub></code>.
542         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
543         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
544         * represents the reduction polynomial <code>f(z)</code>.
545         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
546         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
547         * represents the reduction polynomial <code>f(z)</code>.
548         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
549         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
550         * represents the reduction polynomial <code>f(z)</code>.
551         * @param x The BigInteger representing the value of the field element.
552         * @deprecated Use ECCurve.fromBigInteger to construct field elements
553         */
554        public F2m(
555            int m,
556            int k1,
557            int k2,
558            int k3,
559            BigInteger x)
560        {
561            if (x == null || x.signum() < 0 || x.bitLength() > m)
562            {
563                throw new IllegalArgumentException("x value invalid in F2m field element");
564            }
565
566            if ((k2 == 0) && (k3 == 0))
567            {
568                this.representation = TPB;
569                this.ks = new int[]{ k1 };
570            }
571            else
572            {
573                if (k2 >= k3)
574                {
575                    throw new IllegalArgumentException(
576                            "k2 must be smaller than k3");
577                }
578                if (k2 <= 0)
579                {
580                    throw new IllegalArgumentException(
581                            "k2 must be larger than 0");
582                }
583                this.representation = PPB;
584                this.ks = new int[]{ k1, k2, k3 };
585            }
586
587            this.m = m;
588            this.x = new LongArray(x);
589        }
590
591        /**
592         * Constructor for TPB.
593         * @param m  The exponent <code>m</code> of
594         * <code>F<sub>2<sup>m</sup></sub></code>.
595         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
596         * x<sup>k</sup> + 1</code> represents the reduction
597         * polynomial <code>f(z)</code>.
598         * @param x The BigInteger representing the value of the field element.
599         * @deprecated Use ECCurve.fromBigInteger to construct field elements
600         */
601        public F2m(int m, int k, BigInteger x)
602        {
603            // Set k1 to k, and set k2 and k3 to 0
604            this(m, k, 0, 0, x);
605        }
606
607        private F2m(int m, int[] ks, LongArray x)
608        {
609            this.m = m;
610            this.representation = (ks.length == 1) ? TPB : PPB;
611            this.ks = ks;
612            this.x = x;
613        }
614
615        public int bitLength()
616        {
617            return x.degree();
618        }
619
620        public boolean isOne()
621        {
622            return x.isOne();
623        }
624
625        public boolean isZero()
626        {
627            return x.isZero();
628        }
629
630        public boolean testBitZero()
631        {
632            return x.testBitZero();
633        }
634
635        public BigInteger toBigInteger()
636        {
637            return x.toBigInteger();
638        }
639
640        public String getFieldName()
641        {
642            return "F2m";
643        }
644
645        public int getFieldSize()
646        {
647            return m;
648        }
649
650        /**
651         * Checks, if the ECFieldElements <code>a</code> and <code>b</code>
652         * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>
653         * (having the same representation).
654         * @param a field element.
655         * @param b field element to be compared.
656         * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
657         * are not elements of the same field
658         * <code>F<sub>2<sup>m</sup></sub></code> (having the same
659         * representation).
660         */
661        public static void checkFieldElements(
662            ECFieldElement a,
663            ECFieldElement b)
664        {
665            if ((!(a instanceof F2m)) || (!(b instanceof F2m)))
666            {
667                throw new IllegalArgumentException("Field elements are not "
668                        + "both instances of ECFieldElement.F2m");
669            }
670
671            ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a;
672            ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b;
673
674            if (aF2m.representation != bF2m.representation)
675            {
676                // Should never occur
677                throw new IllegalArgumentException("One of the F2m field elements has incorrect representation");
678            }
679
680            if ((aF2m.m != bF2m.m) || !Arrays.areEqual(aF2m.ks, bF2m.ks))
681            {
682                throw new IllegalArgumentException("Field elements are not elements of the same field F2m");
683            }
684        }
685
686        public ECFieldElement add(final ECFieldElement b)
687        {
688            // No check performed here for performance reasons. Instead the
689            // elements involved are checked in ECPoint.F2m
690            // checkFieldElements(this, b);
691            LongArray iarrClone = (LongArray)this.x.clone();
692            F2m bF2m = (F2m)b;
693            iarrClone.addShiftedByWords(bF2m.x, 0);
694            return new F2m(m, ks, iarrClone);
695        }
696
697        public ECFieldElement addOne()
698        {
699            return new F2m(m, ks, x.addOne());
700        }
701
702        public ECFieldElement subtract(final ECFieldElement b)
703        {
704            // Addition and subtraction are the same in F2m
705            return add(b);
706        }
707
708        public ECFieldElement multiply(final ECFieldElement b)
709        {
710            // Right-to-left comb multiplication in the LongArray
711            // Input: Binary polynomials a(z) and b(z) of degree at most m-1
712            // Output: c(z) = a(z) * b(z) mod f(z)
713
714            // No check performed here for performance reasons. Instead the
715            // elements involved are checked in ECPoint.F2m
716            // checkFieldElements(this, b);
717            return new F2m(m, ks, x.modMultiply(((F2m)b).x, m, ks));
718        }
719
720        public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
721        {
722            return multiplyPlusProduct(b, x, y);
723        }
724
725        public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
726        {
727            LongArray ax = this.x, bx = ((F2m)b).x, xx = ((F2m)x).x, yx = ((F2m)y).x;
728
729            LongArray ab = ax.multiply(bx, m, ks);
730            LongArray xy = xx.multiply(yx, m, ks);
731
732            if (ab == ax || ab == bx)
733            {
734                ab = (LongArray)ab.clone();
735            }
736
737            ab.addShiftedByWords(xy, 0);
738            ab.reduce(m, ks);
739
740            return new F2m(m, ks, ab);
741        }
742
743        public ECFieldElement divide(final ECFieldElement b)
744        {
745            // There may be more efficient implementations
746            ECFieldElement bInv = b.invert();
747            return multiply(bInv);
748        }
749
750        public ECFieldElement negate()
751        {
752            // -x == x holds for all x in F2m
753            return this;
754        }
755
756        public ECFieldElement square()
757        {
758            return new F2m(m, ks, x.modSquare(m, ks));
759        }
760
761        public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y)
762        {
763            return squarePlusProduct(x, y);
764        }
765
766        public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y)
767        {
768            LongArray ax = this.x, xx = ((F2m)x).x, yx = ((F2m)y).x;
769
770            LongArray aa = ax.square(m, ks);
771            LongArray xy = xx.multiply(yx, m, ks);
772
773            if (aa == ax)
774            {
775                aa = (LongArray)aa.clone();
776            }
777
778            aa.addShiftedByWords(xy, 0);
779            aa.reduce(m, ks);
780
781            return new F2m(m, ks, aa);
782        }
783
784        public ECFieldElement squarePow(int pow)
785        {
786            return pow < 1 ? this : new F2m(m, ks, x.modSquareN(pow, m, ks));
787        }
788
789        public ECFieldElement invert()
790        {
791            return new ECFieldElement.F2m(this.m, this.ks, this.x.modInverse(m, ks));
792        }
793
794        public ECFieldElement sqrt()
795        {
796            return (x.isZero() || x.isOne()) ? this : squarePow(m - 1);
797        }
798
799        /**
800         * @return the representation of the field
801         * <code>F<sub>2<sup>m</sup></sub></code>, either of
802         * TPB (trinomial
803         * basis representation) or
804         * PPB (pentanomial
805         * basis representation).
806         */
807        public int getRepresentation()
808        {
809            return this.representation;
810        }
811
812        /**
813         * @return the degree <code>m</code> of the reduction polynomial
814         * <code>f(z)</code>.
815         */
816        public int getM()
817        {
818            return this.m;
819        }
820
821        /**
822         * @return TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
823         * x<sup>k</sup> + 1</code> represents the reduction polynomial
824         * <code>f(z)</code>.<br>
825         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
826         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
827         * represents the reduction polynomial <code>f(z)</code>.<br>
828         */
829        public int getK1()
830        {
831            return this.ks[0];
832        }
833
834        /**
835         * @return TPB: Always returns <code>0</code><br>
836         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
837         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
838         * represents the reduction polynomial <code>f(z)</code>.<br>
839         */
840        public int getK2()
841        {
842            return this.ks.length >= 2 ? this.ks[1] : 0;
843        }
844
845        /**
846         * @return TPB: Always set to <code>0</code><br>
847         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
848         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
849         * represents the reduction polynomial <code>f(z)</code>.<br>
850         */
851        public int getK3()
852        {
853            return this.ks.length >= 3 ? this.ks[2] : 0;
854        }
855
856        public boolean equals(Object anObject)
857        {
858            if (anObject == this)
859            {
860                return true;
861            }
862
863            if (!(anObject instanceof ECFieldElement.F2m))
864            {
865                return false;
866            }
867
868            ECFieldElement.F2m b = (ECFieldElement.F2m)anObject;
869
870            return ((this.m == b.m)
871                && (this.representation == b.representation)
872                && Arrays.areEqual(this.ks, b.ks)
873                && (this.x.equals(b.x)));
874        }
875
876        public int hashCode()
877        {
878            return x.hashCode() ^ m ^ Arrays.hashCode(ks);
879        }
880    }
881}
882