All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.pqc.math.ntru.polynomial.BigIntPolynomial Maven / Gradle / Ivy

There is a newer version: 1.70_1
Show newest version
package org.bouncycastle.pqc.math.ntru.polynomial;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.util.Arrays;

/**
 * A polynomial with {@link BigInteger} coefficients.
* Some methods (like add) change the polynomial, others (like mult) do * not but return the result as a new polynomial. */ public class BigIntPolynomial { private final static double LOG_10_2 = Math.log10(2); BigInteger[] coeffs; /** * Constructs a new polynomial with N coefficients initialized to 0. * * @param N the number of coefficients */ BigIntPolynomial(int N) { coeffs = new BigInteger[N]; for (int i = 0; i < N; i++) { coeffs[i] = Constants.BIGINT_ZERO; } } /** * Constructs a new polynomial with a given set of coefficients. * * @param coeffs the coefficients */ BigIntPolynomial(BigInteger[] coeffs) { this.coeffs = coeffs; } /** * Constructs a BigIntPolynomial from a IntegerPolynomial. The two polynomials are * independent of each other. * * @param p the original polynomial */ public BigIntPolynomial(IntegerPolynomial p) { coeffs = new BigInteger[p.coeffs.length]; for (int i = 0; i < coeffs.length; i++) { coeffs[i] = BigInteger.valueOf(p.coeffs[i]); } } /** * Generates a random polynomial with numOnes coefficients equal to 1, * numNegOnes coefficients equal to -1, and the rest equal to 0. * * @param N number of coefficients * @param numOnes number of 1's * @param numNegOnes number of -1's * @return a random polynomial. */ static BigIntPolynomial generateRandomSmall(int N, int numOnes, int numNegOnes) { List coeffs = new ArrayList(); for (int i = 0; i < numOnes; i++) { coeffs.add(Constants.BIGINT_ONE); } for (int i = 0; i < numNegOnes; i++) { coeffs.add(BigInteger.valueOf(-1)); } while (coeffs.size() < N) { coeffs.add(Constants.BIGINT_ZERO); } Collections.shuffle(coeffs, CryptoServicesRegistrar.getSecureRandom()); BigIntPolynomial poly = new BigIntPolynomial(N); for (int i = 0; i < coeffs.size(); i++) { poly.coeffs[i] = (BigInteger)coeffs.get(i); } return poly; } /** * Multiplies the polynomial by another, taking the indices mod N. Does not * change this polynomial but returns the result as a new polynomial.
* Both polynomials must have the same number of coefficients. * * @param poly2 the polynomial to multiply by * @return a new polynomial */ public BigIntPolynomial mult(BigIntPolynomial poly2) { int N = coeffs.length; if (poly2.coeffs.length != N) { throw new IllegalArgumentException("Number of coefficients must be the same"); } BigIntPolynomial c = multRecursive(poly2); if (c.coeffs.length > N) { for (int k = N; k < c.coeffs.length; k++) { c.coeffs[k - N] = c.coeffs[k - N].add(c.coeffs[k]); } c.coeffs = Arrays.copyOf(c.coeffs, N); } return c; } /** * Karazuba multiplication */ private BigIntPolynomial multRecursive(BigIntPolynomial poly2) { BigInteger[] a = coeffs; BigInteger[] b = poly2.coeffs; int n = poly2.coeffs.length; if (n <= 1) { BigInteger[] c = Arrays.clone(coeffs); for (int i = 0; i < coeffs.length; i++) { c[i] = c[i].multiply(poly2.coeffs[0]); } return new BigIntPolynomial(c); } else { int n1 = n / 2; BigIntPolynomial a1 = new BigIntPolynomial(Arrays.copyOf(a, n1)); BigIntPolynomial a2 = new BigIntPolynomial(Arrays.copyOfRange(a, n1, n)); BigIntPolynomial b1 = new BigIntPolynomial(Arrays.copyOf(b, n1)); BigIntPolynomial b2 = new BigIntPolynomial(Arrays.copyOfRange(b, n1, n)); BigIntPolynomial A = (BigIntPolynomial)a1.clone(); A.add(a2); BigIntPolynomial B = (BigIntPolynomial)b1.clone(); B.add(b2); BigIntPolynomial c1 = a1.multRecursive(b1); BigIntPolynomial c2 = a2.multRecursive(b2); BigIntPolynomial c3 = A.multRecursive(B); c3.sub(c1); c3.sub(c2); BigIntPolynomial c = new BigIntPolynomial(2 * n - 1); for (int i = 0; i < c1.coeffs.length; i++) { c.coeffs[i] = c1.coeffs[i]; } for (int i = 0; i < c3.coeffs.length; i++) { c.coeffs[n1 + i] = c.coeffs[n1 + i].add(c3.coeffs[i]); } for (int i = 0; i < c2.coeffs.length; i++) { c.coeffs[2 * n1 + i] = c.coeffs[2 * n1 + i].add(c2.coeffs[i]); } return c; } } /** * Adds another polynomial which can have a different number of coefficients, * and takes the coefficient values mod modulus. * * @param b another polynomial */ void add(BigIntPolynomial b, BigInteger modulus) { add(b); mod(modulus); } /** * Adds another polynomial which can have a different number of coefficients. * * @param b another polynomial */ public void add(BigIntPolynomial b) { if (b.coeffs.length > coeffs.length) { int N = coeffs.length; coeffs = Arrays.copyOf(coeffs, b.coeffs.length); for (int i = N; i < coeffs.length; i++) { coeffs[i] = Constants.BIGINT_ZERO; } } for (int i = 0; i < b.coeffs.length; i++) { coeffs[i] = coeffs[i].add(b.coeffs[i]); } } /** * Subtracts another polynomial which can have a different number of coefficients. * * @param b another polynomial */ public void sub(BigIntPolynomial b) { if (b.coeffs.length > coeffs.length) { int N = coeffs.length; coeffs = Arrays.copyOf(coeffs, b.coeffs.length); for (int i = N; i < coeffs.length; i++) { coeffs[i] = Constants.BIGINT_ZERO; } } for (int i = 0; i < b.coeffs.length; i++) { coeffs[i] = coeffs[i].subtract(b.coeffs[i]); } } /** * Multiplies each coefficient by a BigInteger. Does not return a new polynomial but modifies this polynomial. * * @param factor */ public void mult(BigInteger factor) { for (int i = 0; i < coeffs.length; i++) { coeffs[i] = coeffs[i].multiply(factor); } } /** * Multiplies each coefficient by a int. Does not return a new polynomial but modifies this polynomial. * * @param factor */ void mult(int factor) { mult(BigInteger.valueOf(factor)); } /** * Divides each coefficient by a BigInteger and rounds the result to the nearest whole number.
* Does not return a new polynomial but modifies this polynomial. * * @param divisor the number to divide by */ public void div(BigInteger divisor) { BigInteger d = divisor.add(Constants.BIGINT_ONE).divide(BigInteger.valueOf(2)); for (int i = 0; i < coeffs.length; i++) { coeffs[i] = coeffs[i].compareTo(Constants.BIGINT_ZERO) > 0 ? coeffs[i].add(d) : coeffs[i].add(d.negate()); coeffs[i] = coeffs[i].divide(divisor); } } /** * Divides each coefficient by a BigDecimal and rounds the result to decimalPlaces places. * * @param divisor the number to divide by * @param decimalPlaces the number of fractional digits to round the result to * @return a new BigDecimalPolynomial */ public BigDecimalPolynomial div(BigDecimal divisor, int decimalPlaces) { BigInteger max = maxCoeffAbs(); int coeffLength = (int)(max.bitLength() * LOG_10_2) + 1; // factor = 1/divisor BigDecimal factor = Constants.BIGDEC_ONE.divide(divisor, coeffLength + decimalPlaces + 1, BigDecimal.ROUND_HALF_EVEN); // multiply each coefficient by factor BigDecimalPolynomial p = new BigDecimalPolynomial(coeffs.length); for (int i = 0; i < coeffs.length; i++) // multiply, then truncate after decimalPlaces so subsequent operations aren't slowed down { p.coeffs[i] = new BigDecimal(coeffs[i]).multiply(factor).setScale(decimalPlaces, BigDecimal.ROUND_HALF_EVEN); } return p; } /** * Returns the base10 length of the largest coefficient. * * @return length of the longest coefficient */ public int getMaxCoeffLength() { return (int)(maxCoeffAbs().bitLength() * LOG_10_2) + 1; } private BigInteger maxCoeffAbs() { BigInteger max = coeffs[0].abs(); for (int i = 1; i < coeffs.length; i++) { BigInteger coeff = coeffs[i].abs(); if (coeff.compareTo(max) > 0) { max = coeff; } } return max; } /** * Takes each coefficient modulo a number. * * @param modulus */ public void mod(BigInteger modulus) { for (int i = 0; i < coeffs.length; i++) { coeffs[i] = coeffs[i].mod(modulus); } } /** * Returns the sum of all coefficients, i.e. evaluates the polynomial at 0. * * @return the sum of all coefficients */ BigInteger sumCoeffs() { BigInteger sum = Constants.BIGINT_ZERO; for (int i = 0; i < coeffs.length; i++) { sum = sum.add(coeffs[i]); } return sum; } /** * Makes a copy of the polynomial that is independent of the original. */ public Object clone() { return new BigIntPolynomial(coeffs.clone()); } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(coeffs); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } BigIntPolynomial other = (BigIntPolynomial)obj; if (!Arrays.areEqual(coeffs, other.coeffs)) { return false; } return true; } public BigInteger[] getCoeffs() { return Arrays.clone(coeffs); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy