/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.util.math.intpoly;
import java.math.BigInteger;
import java.nio.ByteBuffer;
The field of integers modulo a binomial prime. This is a general-purpose
field implementation, that is much slower than more specialized classes
like IntegerPolynomial25519. It is suitable when only a small number of
arithmetic operations are required in some field. For example, this class
can be used for operations on scalars/exponents in signature operations.
This class may only be used for primes of the form 2^a + b.
/**
* The field of integers modulo a binomial prime. This is a general-purpose
* field implementation, that is much slower than more specialized classes
* like IntegerPolynomial25519. It is suitable when only a small number of
* arithmetic operations are required in some field. For example, this class
* can be used for operations on scalars/exponents in signature operations.
*
* This class may only be used for primes of the form 2^a + b.
*/
public class IntegerPolynomialModBinP extends IntegerPolynomial {
private final long[] reduceLimbs;
private final int bitOffset;
private final int limbMask;
private final int rightBitOffset;
private final int power;
public IntegerPolynomialModBinP(int bitsPerLimb,
int numLimbs,
int power,
BigInteger subtrahend) {
super(bitsPerLimb, numLimbs, 1,
BigInteger.valueOf(2).pow(power).subtract(subtrahend));
boolean negate = false;
if (subtrahend.compareTo(BigInteger.ZERO) < 0) {
negate = true;
subtrahend = subtrahend.negate();
}
int reduceLimbsLength = subtrahend.bitLength() / bitsPerLimb + 1;
reduceLimbs = new long[reduceLimbsLength];
ImmutableElement reduceElem = getElement(subtrahend);
if (negate) {
reduceElem = reduceElem.additiveInverse();
}
System.arraycopy(reduceElem.limbs, 0, reduceLimbs, 0,
reduceLimbs.length);
// begin test code
System.out.println("reduce limbs:");
for (int i = 0; i < reduceLimbs.length; i++) {
System.out.println(i + ":" + reduceLimbs[i]);
}
// end test code
this.power = power;
this.bitOffset = numLimbs * bitsPerLimb - power;
this.limbMask = -1 >>> (64 - bitsPerLimb);
this.rightBitOffset = bitsPerLimb - bitOffset;
}
@Override
protected void finalCarryReduceLast(long[] limbs) {
int extraBits = bitsPerLimb * numLimbs - power;
int highBits = bitsPerLimb - extraBits;
long c = limbs[numLimbs - 1] >> highBits;
limbs[numLimbs - 1] -= c << highBits;
for (int j = 0; j < reduceLimbs.length; j++) {
int reduceBits = power + extraBits - j * bitsPerLimb;
modReduceInBits(limbs, numLimbs, reduceBits, c * reduceLimbs[j]);
}
}
Allow more general (and slower) input conversion that takes a large
value and reduces it.
/**
* Allow more general (and slower) input conversion that takes a large
* value and reduces it.
*/
@Override
public ImmutableElement getElement(byte[] v, int offset, int length,
byte highByte) {
long[] result = new long[numLimbs];
int numHighBits = 32 - Integer.numberOfLeadingZeros(highByte);
int numBits = 8 * length + numHighBits;
int requiredLimbs = (numBits + bitsPerLimb - 1) / bitsPerLimb;
if (requiredLimbs > numLimbs) {
long[] temp = new long[requiredLimbs];
encode(v, offset, length, highByte, temp);
// encode does a full carry/reduce
System.arraycopy(temp, 0, result, 0, result.length);
} else {
encode(v, offset, length, highByte, result);
}
return new ImmutableElement(result, 0);
}
Multiply a and b, and store the result in c. Requires that
a.length == b.length == numLimbs and c.length >= 2 * numLimbs - 1.
It is allowed for a and b to be the same array.
/**
* Multiply a and b, and store the result in c. Requires that
* a.length == b.length == numLimbs and c.length >= 2 * numLimbs - 1.
* It is allowed for a and b to be the same array.
*/
private void multOnly(long[] a, long[] b, long[] c) {
for (int i = 0; i < numLimbs; i++) {
for (int j = 0; j < numLimbs; j++) {
c[i + j] += a[i] * b[j];
}
}
}
@Override
protected void mult(long[] a, long[] b, long[] r) {
long[] c = new long[2 * numLimbs];
multOnly(a, b, c);
carryReduce(c, r);
}
private void modReduceInBits(long[] limbs, int index, int bits, long x) {
if (bits % bitsPerLimb == 0) {
int pos = bits / bitsPerLimb;
limbs[index - pos] += x;
}
else {
int secondPos = bits / (bitsPerLimb);
int bitOffset = (secondPos + 1) * bitsPerLimb - bits;
int rightBitOffset = bitsPerLimb - bitOffset;
limbs[index - (secondPos + 1)] += (x << bitOffset) & limbMask;
limbs[index - secondPos] += x >> rightBitOffset;
}
}
protected void reduceIn(long[] c, long v, int i) {
for (int j = 0; j < reduceLimbs.length; j++) {
modReduceInBits(c, i, power - bitsPerLimb * j, reduceLimbs[j] * v);
}
}
private void carryReduce(long[] c, long[] r) {
// full carry to prevent overflow during reduce
carry(c);
// Reduce in from all high positions
for (int i = c.length - 1; i >= numLimbs; i--) {
reduceIn(c, c[i], i);
c[i] = 0;
}
// carry on lower positions that possibly carries out one position
carry(c, 0, numLimbs);
// reduce in a single position
reduceIn(c, c[numLimbs], numLimbs);
c[numLimbs] = 0;
// final carry
carry(c, 0, numLimbs - 1);
System.arraycopy(c, 0, r, 0, r.length);
}
@Override
protected void reduce(long[] a) {
// TODO: optimize this
long[] c = new long[a.length + 2];
System.arraycopy(a, 0, c, 0, a.length);
carryReduce(c, a);
}
@Override
protected void square(long[] a, long[] r) {
long[] c = new long[2 * numLimbs];
for (int i = 0; i < numLimbs; i++) {
c[2 * i] += a[i] * a[i];
for (int j = i + 1; j < numLimbs; j++) {
c[i + j] += 2 * a[i] * a[j];
}
}
carryReduce(c, r);
}
The field of integers modulo the order of the Curve25519 subgroup
/**
* The field of integers modulo the order of the Curve25519 subgroup
*/
public static class Curve25519OrderField extends IntegerPolynomialModBinP {
public Curve25519OrderField() {
super(26, 10, 252,
new BigInteger("-27742317777372353535851937790883648493"));
}
}
The field of integers modulo the order of the Curve448 subgroup
/**
* The field of integers modulo the order of the Curve448 subgroup
*/
public static class Curve448OrderField extends IntegerPolynomialModBinP {
public Curve448OrderField() {
super(28, 16, 446,
new BigInteger("138180668098951153520073867485154268803366" +
"92474882178609894547503885"));
}
}
}