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