1 /*
2  * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.util.math.intpoly;
27 
28 import sun.security.util.math.*;
29 
30 import java.math.BigInteger;
31 import java.nio.ByteBuffer;
32 import java.nio.ByteOrder;
33 import java.util.Arrays;
34 
35 /**
36  * A large number polynomial representation using sparse limbs of signed
37  * long (64-bit) values. Limb values will always fit within a long, so inputs
38  * to multiplication must be less than 32 bits. All IntegerPolynomial
39  * implementations allow at most one addition before multiplication. Additions
40  * after that will result in an ArithmeticException.
41  *
42  * The following element operations are branch-free for all subclasses:
43  *
44  * fixed
45  * mutable
46  * add
47  * additiveInverse
48  * multiply
49  * square
50  * subtract
51  * conditionalSwapWith
52  * setValue (may branch on high-order byte parameter only)
53  * setSum
54  * setDifference
55  * setProduct
56  * setSquare
57  * addModPowerTwo
58  * asByteArray
59  *
60  * All other operations may branch in some subclasses.
61  *
62  */
63 
64 public abstract class IntegerPolynomial implements IntegerFieldModuloP {
65 
66     protected static final BigInteger TWO = BigInteger.valueOf(2);
67 
68     protected final int numLimbs;
69     private final BigInteger modulus;
70     protected final int bitsPerLimb;
71     private final long[] posModLimbs;
72     private final int maxAdds;
73 
74     /**
75      * Reduce an IntegerPolynomial representation (a) and store the result
76      * in a. Requires that a.length == numLimbs.
77      */
reduce(long[] a)78     protected abstract void reduce(long[] a);
79 
80     /**
81      * Multiply an IntegerPolynomial representation (a) with a long (b) and
82      * store the result in an IntegerPolynomial representation in a. Requires
83      * that a.length == numLimbs.
84      */
multByInt(long[] a, long b)85     protected void multByInt(long[] a, long b) {
86         for (int i = 0; i < a.length; i++) {
87             a[i] *= b;
88         }
89         reduce(a);
90     }
91 
92     /**
93      * Multiply two IntegerPolynomial representations (a and b) and store the
94      * result in an IntegerPolynomial representation (r). Requires that
95      * a.length == b.length == r.length == numLimbs. It is allowed for a and r
96      * to be the same array.
97      */
mult(long[] a, long[] b, long[] r)98     protected abstract void mult(long[] a, long[] b, long[] r);
99 
100     /**
101      * Multiply an IntegerPolynomial representation (a) with itself and store
102      * the result in an IntegerPolynomialRepresentation (r). Requires that
103      * a.length == r.length == numLimbs. It is allowed for a and r
104      * to be the same array.
105      */
square(long[] a, long[] r)106     protected abstract void square(long[] a, long[] r);
107 
IntegerPolynomial(int bitsPerLimb, int numLimbs, int maxAdds, BigInteger modulus)108     IntegerPolynomial(int bitsPerLimb,
109                       int numLimbs,
110                       int maxAdds,
111                       BigInteger modulus) {
112 
113 
114         this.numLimbs = numLimbs;
115         this.modulus = modulus;
116         this.bitsPerLimb = bitsPerLimb;
117         this.maxAdds = maxAdds;
118 
119         posModLimbs = setPosModLimbs();
120     }
121 
setPosModLimbs()122     private long[] setPosModLimbs() {
123         long[] result = new long[numLimbs];
124         setLimbsValuePositive(modulus, result);
125         return result;
126     }
127 
getNumLimbs()128     protected int getNumLimbs() {
129         return numLimbs;
130     }
131 
getMaxAdds()132     public int getMaxAdds() {
133         return maxAdds;
134     }
135 
136     @Override
getSize()137     public BigInteger getSize() {
138         return modulus;
139     }
140 
141     @Override
get0()142     public ImmutableElement get0() {
143         return new ImmutableElement(false);
144     }
145 
146     @Override
get1()147     public ImmutableElement get1() {
148         return new ImmutableElement(true);
149     }
150 
151     @Override
getElement(BigInteger v)152     public ImmutableElement getElement(BigInteger v) {
153         return new ImmutableElement(v);
154     }
155 
156     @Override
getSmallValue(int value)157     public SmallValue getSmallValue(int value) {
158         int maxMag = 1 << (bitsPerLimb - 1);
159         if (Math.abs(value) >= maxMag) {
160             throw new IllegalArgumentException("max magnitude is " + maxMag);
161         }
162         return new Limb(value);
163     }
164 
reduceIn(long[] c, long v, int i)165     protected abstract void reduceIn(long[] c, long v, int i);
166 
reduceHigh(long[] limbs)167     private void reduceHigh(long[] limbs) {
168 
169         // conservatively calculate how many reduce operations can be done
170         // before a carry is needed
171         int extraBits = 63 - 2 * bitsPerLimb;
172         int allowedAdds = 1 << extraBits;
173         int carryPeriod = allowedAdds / numLimbs;
174         int reduceCount = 0;
175         for (int i = limbs.length - 1; i >= numLimbs; i--) {
176             reduceIn(limbs, limbs[i], i);
177             limbs[i] = 0;
178 
179             reduceCount++;
180             if (reduceCount % carryPeriod == 0) {
181                 carry(limbs, 0, i);
182                 reduceIn(limbs, limbs[i], i);
183                 limbs[i] = 0;
184             }
185         }
186     }
187 
188     /**
189      * This version of encode takes a ByteBuffer that is properly ordered, and
190      * may extract larger values (e.g. long) from the ByteBuffer for better
191      * performance. The implementation below only extracts bytes from the
192      * buffer, but this method may be overridden in field-specific
193      * implementations.
194      */
encode(ByteBuffer buf, int length, byte highByte, long[] result)195     protected void encode(ByteBuffer buf, int length, byte highByte,
196                           long[] result) {
197 
198         int numHighBits = 32 - Integer.numberOfLeadingZeros(highByte);
199         int numBits = 8 * length + numHighBits;
200         int requiredLimbs = (numBits + bitsPerLimb - 1) / bitsPerLimb;
201         if (requiredLimbs > numLimbs) {
202             long[] temp = new long[requiredLimbs];
203             encodeSmall(buf, length, highByte, temp);
204             reduceHigh(temp);
205             System.arraycopy(temp, 0, result, 0, result.length);
206             reduce(result);
207         } else {
208             encodeSmall(buf, length, highByte, result);
209             postEncodeCarry(result);
210         }
211     }
212 
encodeSmall(ByteBuffer buf, int length, byte highByte, long[] result)213     protected void encodeSmall(ByteBuffer buf, int length, byte highByte,
214                                long[] result) {
215 
216         int limbIndex = 0;
217         long curLimbValue = 0;
218         int bitPos = 0;
219         for (int i = 0; i < length; i++) {
220             long curV = buf.get() & 0xFF;
221 
222             if (bitPos + 8 >= bitsPerLimb) {
223                 int bitsThisLimb = bitsPerLimb - bitPos;
224                 curLimbValue += (curV & (0xFF >> (8 - bitsThisLimb))) << bitPos;
225                 result[limbIndex++] = curLimbValue;
226                 curLimbValue = curV >> bitsThisLimb;
227                 bitPos = 8 - bitsThisLimb;
228             }
229             else {
230                 curLimbValue += curV << bitPos;
231                 bitPos += 8;
232             }
233         }
234 
235         // one more for the high byte
236         if (highByte != 0) {
237             long curV = highByte & 0xFF;
238             if (bitPos + 8 >= bitsPerLimb) {
239                 int bitsThisLimb = bitsPerLimb - bitPos;
240                 curLimbValue += (curV & (0xFF >> (8 - bitsThisLimb))) << bitPos;
241                 result[limbIndex++] = curLimbValue;
242                 curLimbValue = curV >> bitsThisLimb;
243             }
244             else {
245                 curLimbValue += curV << bitPos;
246             }
247         }
248 
249         if (limbIndex < result.length) {
250             result[limbIndex++] = curLimbValue;
251         }
252         Arrays.fill(result, limbIndex, result.length, 0);
253     }
254 
encode(byte[] v, int offset, int length, byte highByte, long[] result)255     protected void encode(byte[] v, int offset, int length, byte highByte,
256                           long[] result) {
257 
258         ByteBuffer buf = ByteBuffer.wrap(v, offset, length);
259         buf.order(ByteOrder.LITTLE_ENDIAN);
260         encode(buf, length, highByte, result);
261     }
262 
263     // Encode does not produce compressed limbs. A simplified carry/reduce
264     // operation can be used to compress the limbs.
postEncodeCarry(long[] v)265     protected void postEncodeCarry(long[] v) {
266         reduce(v);
267     }
268 
getElement(byte[] v, int offset, int length, byte highByte)269     public ImmutableElement getElement(byte[] v, int offset, int length,
270                                        byte highByte) {
271 
272         long[] result = new long[numLimbs];
273 
274         encode(v, offset, length, highByte, result);
275 
276         return new ImmutableElement(result, 0);
277     }
278 
evaluate(long[] limbs)279     protected BigInteger evaluate(long[] limbs) {
280         BigInteger result = BigInteger.ZERO;
281         for (int i = limbs.length - 1; i >= 0; i--) {
282             result = result.shiftLeft(bitsPerLimb)
283                 .add(BigInteger.valueOf(limbs[i]));
284         }
285         return result.mod(modulus);
286     }
287 
carryValue(long x)288     protected long carryValue(long x) {
289         // compressing carry operation
290         // if large positive number, carry one more to make it negative
291         // if large negative number (closer to zero), carry one fewer
292         return (x + (1 << (bitsPerLimb - 1))) >> bitsPerLimb;
293     }
294 
carry(long[] limbs, int start, int end)295     protected void carry(long[] limbs, int start, int end) {
296 
297         for (int i = start; i < end; i++) {
298 
299             long carry = carryOut(limbs, i);
300             limbs[i + 1] += carry;
301         }
302     }
303 
carry(long[] limbs)304     protected void carry(long[] limbs) {
305 
306         carry(limbs, 0, limbs.length - 1);
307     }
308 
309     /**
310      * Carry out of the specified position and return the carry value.
311      */
carryOut(long[] limbs, int index)312     protected long carryOut(long[] limbs, int index) {
313         long carry = carryValue(limbs[index]);
314         limbs[index] -= (carry << bitsPerLimb);
315         return carry;
316     }
317 
setLimbsValue(BigInteger v, long[] limbs)318     private void setLimbsValue(BigInteger v, long[] limbs) {
319         // set all limbs positive, and then carry
320         setLimbsValuePositive(v, limbs);
321         carry(limbs);
322     }
323 
setLimbsValuePositive(BigInteger v, long[] limbs)324     protected void setLimbsValuePositive(BigInteger v, long[] limbs) {
325         BigInteger mod = BigInteger.valueOf(1 << bitsPerLimb);
326         for (int i = 0; i < limbs.length; i++) {
327             limbs[i] = v.mod(mod).longValue();
328             v = v.shiftRight(bitsPerLimb);
329         }
330     }
331 
332     /**
333      * Carry out of the last limb and reduce back in. This method will be
334      * called as part of the "finalReduce" operation that puts the
335      * representation into a fully-reduced form. It is representation-
336      * specific, because representations have different amounts of empty
337      * space in the high-order limb. Requires that limbs.length=numLimbs.
338      */
finalCarryReduceLast(long[] limbs)339     protected abstract void finalCarryReduceLast(long[] limbs);
340 
341     /**
342      * Convert reduced limbs into a number between 0 and MODULUS-1.
343      * Requires that limbs.length == numLimbs. This method only works if the
344      * modulus has at most three terms.
345      */
finalReduce(long[] limbs)346     protected void finalReduce(long[] limbs) {
347 
348         // This method works by doing several full carry/reduce operations.
349         // Some representations have extra high bits, so the carry/reduce out
350         // of the high position is implementation-specific. The "unsigned"
351         // carry operation always carries some (negative) value out of a
352         // position occupied by a negative value. So after a number of
353         // passes, all negative values are removed.
354 
355         // The first pass may leave a negative value in the high position, but
356         // this only happens if something was carried out of the previous
357         // position. So the previous position must have a "small" value. The
358         // next full carry is guaranteed not to carry out of that position.
359 
360         for (int pass = 0; pass < 2; pass++) {
361             // unsigned carry out of last position and reduce in to
362             // first position
363             finalCarryReduceLast(limbs);
364 
365             // unsigned carry on all positions
366             long carry = 0;
367             for (int i = 0; i < numLimbs - 1; i++) {
368                 limbs[i] += carry;
369                 carry = limbs[i] >> bitsPerLimb;
370                 limbs[i] -= carry << bitsPerLimb;
371             }
372             limbs[numLimbs - 1] += carry;
373         }
374 
375         // Limbs are positive and all less than 2^bitsPerLimb, and the
376         // high-order limb may be even smaller due to the representation-
377         // specific carry/reduce out of the high position.
378         // The value may still be greater than the modulus.
379         // Subtract the max limb values only if all limbs end up non-negative
380         // This only works if there is at most one position where posModLimbs
381         // is less than 2^bitsPerLimb - 1 (not counting the high-order limb,
382         // if it has extra bits that are cleared by finalCarryReduceLast).
383         int smallerNonNegative = 1;
384         long[] smaller = new long[numLimbs];
385         for (int i = numLimbs - 1; i >= 0; i--) {
386             smaller[i] = limbs[i] - posModLimbs[i];
387             // expression on right is 1 if smaller[i] is nonnegative,
388             // 0 otherwise
389             smallerNonNegative *= (int) (smaller[i] >> 63) + 1;
390         }
391         conditionalSwap(smallerNonNegative, limbs, smaller);
392 
393     }
394 
395     /**
396      * Decode the value in v and store it in dst. Requires that v is final
397      * reduced. I.e. all limbs in [0, 2^bitsPerLimb) and value in [0, modulus).
398      */
decode(long[] v, byte[] dst, int offset, int length)399     protected void decode(long[] v, byte[] dst, int offset, int length) {
400 
401         int nextLimbIndex = 0;
402         long curLimbValue = v[nextLimbIndex++];
403         int bitPos = 0;
404         for (int i = 0; i < length; i++) {
405 
406             int dstIndex = i + offset;
407             if (bitPos + 8 >= bitsPerLimb) {
408                 dst[dstIndex] = (byte) curLimbValue;
409                 curLimbValue = 0;
410                 if (nextLimbIndex < v.length) {
411                     curLimbValue = v[nextLimbIndex++];
412                 }
413                 int bitsAdded = bitsPerLimb - bitPos;
414                 int bitsLeft = 8 - bitsAdded;
415 
416                 dst[dstIndex] += (curLimbValue & (0xFF >> bitsAdded))
417                     << bitsAdded;
418                 curLimbValue >>= bitsLeft;
419                 bitPos = bitsLeft;
420             } else {
421                 dst[dstIndex] = (byte) curLimbValue;
422                 curLimbValue >>= 8;
423                 bitPos += 8;
424             }
425         }
426     }
427 
428     /**
429      * Add two IntegerPolynomial representations (a and b) and store the result
430      * in an IntegerPolynomialRepresentation (dst). Requires that
431      * a.length == b.length == dst.length. It is allowed for a and
432      * dst to be the same array.
433      */
addLimbs(long[] a, long[] b, long[] dst)434     protected void addLimbs(long[] a, long[] b, long[] dst) {
435         for (int i = 0; i < dst.length; i++) {
436             dst[i] = a[i] + b[i];
437         }
438     }
439 
440     /**
441      * Branch-free conditional assignment of b to a. Requires that set is 0 or
442      * 1, and that a.length == b.length. If set==0, then the values of a and b
443      * will be unchanged. If set==1, then the values of b will be assigned to a.
444      * The behavior is undefined if swap has any value other than 0 or 1.
445      */
conditionalAssign(int set, long[] a, long[] b)446     protected static void conditionalAssign(int set, long[] a, long[] b) {
447         int maskValue = 0 - set;
448         for (int i = 0; i < a.length; i++) {
449             long dummyLimbs = maskValue & (a[i] ^ b[i]);
450             a[i] = dummyLimbs ^ a[i];
451         }
452     }
453 
454     /**
455      * Branch-free conditional swap of a and b. Requires that swap is 0 or 1,
456      * and that a.length == b.length. If swap==0, then the values of a and b
457      * will be unchanged. If swap==1, then the values of a and b will be
458      * swapped. The behavior is undefined if swap has any value other than
459      * 0 or 1.
460      */
conditionalSwap(int swap, long[] a, long[] b)461     protected static void conditionalSwap(int swap, long[] a, long[] b) {
462         int maskValue = 0 - swap;
463         for (int i = 0; i < a.length; i++) {
464             long dummyLimbs = maskValue & (a[i] ^ b[i]);
465             a[i] = dummyLimbs ^ a[i];
466             b[i] = dummyLimbs ^ b[i];
467         }
468     }
469 
470     /**
471      * Stores the reduced, little-endian value of limbs in result.
472      */
limbsToByteArray(long[] limbs, byte[] result)473     protected void limbsToByteArray(long[] limbs, byte[] result) {
474 
475         long[] reducedLimbs = limbs.clone();
476         finalReduce(reducedLimbs);
477 
478         decode(reducedLimbs, result, 0, result.length);
479     }
480 
481     /**
482      * Add the reduced number corresponding to limbs and other, and store
483      * the low-order bytes of the sum in result. Requires that
484      * limbs.length==other.length. The result array may have any length.
485      */
addLimbsModPowerTwo(long[] limbs, long[] other, byte[] result)486     protected void addLimbsModPowerTwo(long[] limbs, long[] other,
487                                        byte[] result) {
488 
489         long[] reducedOther = other.clone();
490         long[] reducedLimbs = limbs.clone();
491         finalReduce(reducedOther);
492         finalReduce(reducedLimbs);
493 
494         addLimbs(reducedLimbs, reducedOther, reducedLimbs);
495 
496         // may carry out a value which can be ignored
497         long carry = 0;
498         for (int i = 0; i < numLimbs; i++) {
499             reducedLimbs[i] += carry;
500             carry  = reducedLimbs[i] >> bitsPerLimb;
501             reducedLimbs[i] -= carry << bitsPerLimb;
502         }
503 
504         decode(reducedLimbs, result, 0, result.length);
505     }
506 
507     private abstract class Element implements IntegerModuloP {
508 
509         protected long[] limbs;
510         protected int numAdds;
511 
Element(BigInteger v)512         public Element(BigInteger v) {
513             limbs = new long[numLimbs];
514             setValue(v);
515         }
516 
Element(boolean v)517         public Element(boolean v) {
518             this.limbs = new long[numLimbs];
519             this.limbs[0] = v ? 1l : 0l;
520             this.numAdds = 0;
521         }
522 
Element(long[] limbs, int numAdds)523         private Element(long[] limbs, int numAdds) {
524             this.limbs = limbs;
525             this.numAdds = numAdds;
526         }
527 
setValue(BigInteger v)528         private void setValue(BigInteger v) {
529             setLimbsValue(v, limbs);
530             this.numAdds = 0;
531         }
532 
533         @Override
getField()534         public IntegerFieldModuloP getField() {
535             return IntegerPolynomial.this;
536         }
537 
538         @Override
asBigInteger()539         public BigInteger asBigInteger() {
540             return evaluate(limbs);
541         }
542 
543         @Override
mutable()544         public MutableElement mutable() {
545             return new MutableElement(limbs.clone(), numAdds);
546         }
547 
isSummand()548         protected boolean isSummand() {
549             return numAdds < maxAdds;
550         }
551 
552         @Override
add(IntegerModuloP genB)553         public ImmutableElement add(IntegerModuloP genB) {
554 
555             Element b = (Element) genB;
556             if (!(isSummand() && b.isSummand())) {
557                 throw new ArithmeticException("Not a valid summand");
558             }
559 
560             long[] newLimbs = new long[limbs.length];
561             for (int i = 0; i < limbs.length; i++) {
562                 newLimbs[i] = limbs[i] + b.limbs[i];
563             }
564 
565             int newNumAdds = Math.max(numAdds, b.numAdds) + 1;
566             return new ImmutableElement(newLimbs, newNumAdds);
567         }
568 
569         @Override
additiveInverse()570         public ImmutableElement additiveInverse() {
571 
572             long[] newLimbs = new long[limbs.length];
573             for (int i = 0; i < limbs.length; i++) {
574                 newLimbs[i] = -limbs[i];
575             }
576 
577             ImmutableElement result = new ImmutableElement(newLimbs, numAdds);
578             return result;
579         }
580 
cloneLow(long[] limbs)581         protected long[] cloneLow(long[] limbs) {
582             long[] newLimbs = new long[numLimbs];
583             copyLow(limbs, newLimbs);
584             return newLimbs;
585         }
copyLow(long[] limbs, long[] out)586         protected void copyLow(long[] limbs, long[] out) {
587             System.arraycopy(limbs, 0, out, 0, out.length);
588         }
589 
590         @Override
multiply(IntegerModuloP genB)591         public ImmutableElement multiply(IntegerModuloP genB) {
592 
593             Element b = (Element) genB;
594 
595             long[] newLimbs = new long[limbs.length];
596             mult(limbs, b.limbs, newLimbs);
597             return new ImmutableElement(newLimbs, 0);
598         }
599 
600         @Override
square()601         public ImmutableElement square() {
602             long[] newLimbs = new long[limbs.length];
603             IntegerPolynomial.this.square(limbs, newLimbs);
604             return new ImmutableElement(newLimbs, 0);
605         }
606 
addModPowerTwo(IntegerModuloP arg, byte[] result)607         public void addModPowerTwo(IntegerModuloP arg, byte[] result) {
608 
609             Element other = (Element) arg;
610             if (!(isSummand() && other.isSummand())) {
611                 throw new ArithmeticException("Not a valid summand");
612             }
613             addLimbsModPowerTwo(limbs, other.limbs, result);
614         }
615 
asByteArray(byte[] result)616         public void asByteArray(byte[] result) {
617             if (!isSummand()) {
618                 throw new ArithmeticException("Not a valid summand");
619             }
620             limbsToByteArray(limbs, result);
621         }
622     }
623 
624     protected class MutableElement extends Element
625         implements MutableIntegerModuloP {
626 
MutableElement(long[] limbs, int numAdds)627         protected MutableElement(long[] limbs, int numAdds) {
628             super(limbs, numAdds);
629         }
630 
631         @Override
fixed()632         public ImmutableElement fixed() {
633             return new ImmutableElement(limbs.clone(), numAdds);
634         }
635 
636         @Override
conditionalSet(IntegerModuloP b, int set)637         public void conditionalSet(IntegerModuloP b, int set) {
638 
639             Element other = (Element) b;
640 
641             conditionalAssign(set, limbs, other.limbs);
642             numAdds = other.numAdds;
643         }
644 
645         @Override
conditionalSwapWith(MutableIntegerModuloP b, int swap)646         public void conditionalSwapWith(MutableIntegerModuloP b, int swap) {
647 
648             MutableElement other = (MutableElement) b;
649 
650             conditionalSwap(swap, limbs, other.limbs);
651             int numAddsTemp = numAdds;
652             numAdds = other.numAdds;
653             other.numAdds = numAddsTemp;
654         }
655 
656 
657         @Override
setValue(IntegerModuloP v)658         public MutableElement setValue(IntegerModuloP v) {
659             Element other = (Element) v;
660 
661             System.arraycopy(other.limbs, 0, limbs, 0, other.limbs.length);
662             numAdds = other.numAdds;
663             return this;
664         }
665 
666         @Override
setValue(byte[] arr, int offset, int length, byte highByte)667         public MutableElement setValue(byte[] arr, int offset,
668                                        int length, byte highByte) {
669 
670             encode(arr, offset, length, highByte, limbs);
671             this.numAdds = 0;
672 
673             return this;
674         }
675 
676         @Override
setValue(ByteBuffer buf, int length, byte highByte)677         public MutableElement setValue(ByteBuffer buf, int length,
678                                        byte highByte) {
679 
680             encode(buf, length, highByte, limbs);
681             numAdds = 0;
682 
683             return this;
684         }
685 
686         @Override
setProduct(IntegerModuloP genB)687         public MutableElement setProduct(IntegerModuloP genB) {
688             Element b = (Element) genB;
689             mult(limbs, b.limbs, limbs);
690             numAdds = 0;
691             return this;
692         }
693 
694         @Override
setProduct(SmallValue v)695         public MutableElement setProduct(SmallValue v) {
696             int value = ((Limb) v).value;
697             multByInt(limbs, value);
698             numAdds = 0;
699             return this;
700         }
701 
702         @Override
setSum(IntegerModuloP genB)703         public MutableElement setSum(IntegerModuloP genB) {
704 
705             Element b = (Element) genB;
706             if (!(isSummand() && b.isSummand())) {
707                 throw new ArithmeticException("Not a valid summand");
708             }
709 
710             for (int i = 0; i < limbs.length; i++) {
711                 limbs[i] = limbs[i] + b.limbs[i];
712             }
713 
714             numAdds = Math.max(numAdds, b.numAdds) + 1;
715             return this;
716         }
717 
718         @Override
setDifference(IntegerModuloP genB)719         public MutableElement setDifference(IntegerModuloP genB) {
720 
721             Element b = (Element) genB;
722             if (!(isSummand() && b.isSummand())) {
723                 throw new ArithmeticException("Not a valid summand");
724             }
725 
726             for (int i = 0; i < limbs.length; i++) {
727                 limbs[i] = limbs[i] - b.limbs[i];
728             }
729 
730             numAdds = Math.max(numAdds, b.numAdds) + 1;
731             return this;
732         }
733 
734         @Override
setSquare()735         public MutableElement setSquare() {
736             IntegerPolynomial.this.square(limbs, limbs);
737             numAdds = 0;
738             return this;
739         }
740 
741         @Override
setAdditiveInverse()742         public MutableElement setAdditiveInverse() {
743 
744             for (int i = 0; i < limbs.length; i++) {
745                 limbs[i] = -limbs[i];
746             }
747             return this;
748         }
749 
750         @Override
setReduced()751         public MutableElement setReduced() {
752 
753             reduce(limbs);
754             numAdds = 0;
755             return this;
756         }
757     }
758 
759     class ImmutableElement extends Element implements ImmutableIntegerModuloP {
760 
ImmutableElement(BigInteger v)761         protected ImmutableElement(BigInteger v) {
762             super(v);
763         }
764 
ImmutableElement(boolean v)765         protected ImmutableElement(boolean v) {
766             super(v);
767         }
768 
ImmutableElement(long[] limbs, int numAdds)769         protected ImmutableElement(long[] limbs, int numAdds) {
770             super(limbs, numAdds);
771         }
772 
773         @Override
fixed()774         public ImmutableElement fixed() {
775             return this;
776         }
777 
778     }
779 
780     static class Limb implements SmallValue {
781         int value;
782 
Limb(int value)783         Limb(int value) {
784             this.value = value;
785         }
786     }
787 
788 
789 }
790