• 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.math.raw.Mod;
7 import org.bouncycastle.math.raw.Nat;
8 import org.bouncycastle.util.Arrays;
9 import org.bouncycastle.util.BigIntegers;
10 
11 public abstract class ECFieldElement
12     implements ECConstants
13 {
toBigInteger()14     public abstract BigInteger     toBigInteger();
getFieldName()15     public abstract String         getFieldName();
getFieldSize()16     public abstract int            getFieldSize();
add(ECFieldElement b)17     public abstract ECFieldElement add(ECFieldElement b);
addOne()18     public abstract ECFieldElement addOne();
subtract(ECFieldElement b)19     public abstract ECFieldElement subtract(ECFieldElement b);
multiply(ECFieldElement b)20     public abstract ECFieldElement multiply(ECFieldElement b);
divide(ECFieldElement b)21     public abstract ECFieldElement divide(ECFieldElement b);
negate()22     public abstract ECFieldElement negate();
square()23     public abstract ECFieldElement square();
invert()24     public abstract ECFieldElement invert();
sqrt()25     public abstract ECFieldElement sqrt();
26 
bitLength()27     public int bitLength()
28     {
29         return toBigInteger().bitLength();
30     }
31 
isOne()32     public boolean isOne()
33     {
34         return bitLength() == 1;
35     }
36 
isZero()37     public boolean isZero()
38     {
39         return 0 == toBigInteger().signum();
40     }
41 
multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)42     public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
43     {
44         return multiply(b).subtract(x.multiply(y));
45     }
46 
multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)47     public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
48     {
49         return multiply(b).add(x.multiply(y));
50     }
51 
squareMinusProduct(ECFieldElement x, ECFieldElement y)52     public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y)
53     {
54         return square().subtract(x.multiply(y));
55     }
56 
squarePlusProduct(ECFieldElement x, ECFieldElement y)57     public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y)
58     {
59         return square().add(x.multiply(y));
60     }
61 
squarePow(int pow)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 
testBitZero()72     public boolean testBitZero()
73     {
74         return toBigInteger().testBit(0);
75     }
76 
toString()77     public String toString()
78     {
79         return this.toBigInteger().toString(16);
80     }
81 
getEncoded()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 
calculateResidue(BigInteger p)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          */
Fp(BigInteger q, BigInteger x)108         public Fp(BigInteger q, BigInteger x)
109         {
110             this(q, calculateResidue(q), x);
111         }
112 
Fp(BigInteger q, BigInteger r, BigInteger x)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 
toBigInteger()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          */
getFieldName()135         public String getFieldName()
136         {
137             return "Fp";
138         }
139 
getFieldSize()140         public int getFieldSize()
141         {
142             return q.bitLength();
143         }
144 
getQ()145         public BigInteger getQ()
146         {
147             return q;
148         }
149 
add(ECFieldElement b)150         public ECFieldElement add(ECFieldElement b)
151         {
152             return new Fp(q, r, modAdd(x, b.toBigInteger()));
153         }
154 
addOne()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 
subtract(ECFieldElement b)165         public ECFieldElement subtract(ECFieldElement b)
166         {
167             return new Fp(q, r, modSubtract(x, b.toBigInteger()));
168         }
169 
multiply(ECFieldElement b)170         public ECFieldElement multiply(ECFieldElement b)
171         {
172             return new Fp(q, r, modMult(x, b.toBigInteger()));
173         }
174 
multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)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 
multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)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 
divide(ECFieldElement b)191         public ECFieldElement divide(ECFieldElement b)
192         {
193             return new Fp(q, r, modMult(x, modInverse(b.toBigInteger())));
194         }
195 
negate()196         public ECFieldElement negate()
197         {
198             return x.signum() == 0 ? this : new Fp(q, r, q.subtract(x));
199         }
200 
square()201         public ECFieldElement square()
202         {
203             return new Fp(q, r, modMult(x, x));
204         }
205 
squareMinusProduct(ECFieldElement x, ECFieldElement y)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 
squarePlusProduct(ECFieldElement x, ECFieldElement y)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 
invert()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          */
sqrt()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 
checkSqrt(ECFieldElement z)312         private ECFieldElement checkSqrt(ECFieldElement z)
313         {
314             return z.square().equals(this) ? z : null;
315         }
316 
lucasSequence( BigInteger P, BigInteger Q, BigInteger k)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 
modAdd(BigInteger x1, BigInteger x2)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 
modDouble(BigInteger x)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 
modHalf(BigInteger x)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 
modHalfAbs(BigInteger x)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 
modInverse(BigInteger x)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 
modMult(BigInteger x1, BigInteger x2)420         protected BigInteger modMult(BigInteger x1, BigInteger x2)
421         {
422             return modReduce(x1.multiply(x2));
423         }
424 
modReduce(BigInteger x)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 
modSubtract(BigInteger x1, BigInteger x2)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 
equals(Object other)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 
hashCode()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          */
F2m( int m, int k1, int k2, int k3, BigInteger x)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          */
F2m(int m, int k, BigInteger x)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 
F2m(int m, int[] ks, LongArray x)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 
bitLength()615         public int bitLength()
616         {
617             return x.degree();
618         }
619 
isOne()620         public boolean isOne()
621         {
622             return x.isOne();
623         }
624 
isZero()625         public boolean isZero()
626         {
627             return x.isZero();
628         }
629 
testBitZero()630         public boolean testBitZero()
631         {
632             return x.testBitZero();
633         }
634 
toBigInteger()635         public BigInteger toBigInteger()
636         {
637             return x.toBigInteger();
638         }
639 
getFieldName()640         public String getFieldName()
641         {
642             return "F2m";
643         }
644 
getFieldSize()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          */
checkFieldElements( ECFieldElement a, ECFieldElement b)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 
add(final ECFieldElement b)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 
addOne()697         public ECFieldElement addOne()
698         {
699             return new F2m(m, ks, x.addOne());
700         }
701 
subtract(final ECFieldElement b)702         public ECFieldElement subtract(final ECFieldElement b)
703         {
704             // Addition and subtraction are the same in F2m
705             return add(b);
706         }
707 
multiply(final ECFieldElement b)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 
multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)720         public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
721         {
722             return multiplyPlusProduct(b, x, y);
723         }
724 
multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)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 
divide(final ECFieldElement b)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 
negate()750         public ECFieldElement negate()
751         {
752             // -x == x holds for all x in F2m
753             return this;
754         }
755 
square()756         public ECFieldElement square()
757         {
758             return new F2m(m, ks, x.modSquare(m, ks));
759         }
760 
squareMinusProduct(ECFieldElement x, ECFieldElement y)761         public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y)
762         {
763             return squarePlusProduct(x, y);
764         }
765 
squarePlusProduct(ECFieldElement x, ECFieldElement y)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 
squarePow(int pow)784         public ECFieldElement squarePow(int pow)
785         {
786             return pow < 1 ? this : new F2m(m, ks, x.modSquareN(pow, m, ks));
787         }
788 
invert()789         public ECFieldElement invert()
790         {
791             return new ECFieldElement.F2m(this.m, this.ks, this.x.modInverse(m, ks));
792         }
793 
sqrt()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          */
getRepresentation()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          */
getM()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          */
getK1()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          */
getK2()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          */
getK3()851         public int getK3()
852         {
853             return this.ks.length >= 3 ? this.ks[2] : 0;
854         }
855 
equals(Object anObject)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 
hashCode()876         public int hashCode()
877         {
878             return x.hashCode() ^ m ^ Arrays.hashCode(ks);
879         }
880     }
881 }
882