package org.bouncycastle.pqc.math.ntru.util; import java.io.IOException; import java.io.InputStream; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.bouncycastle.pqc.math.ntru.euclid.IntEuclidean; import org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial; import org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial; import org.bouncycastle.pqc.math.ntru.polynomial.TernaryPolynomial; import org.bouncycastle.util.Integers; public class Util { private static volatile boolean IS_64_BITNESS_KNOWN; private static volatile boolean IS_64_BIT_JVM; /** * Calculates the inverse of n mod modulus */ public static int invert(int n, int modulus) { n %= modulus; if (n < 0) { n += modulus; } return IntEuclidean.calculate(n, modulus).x; } /** * Calculates a^b mod modulus */ public static int pow(int a, int b, int modulus) { int p = 1; for (int i = 0; i < b; i++) { p = (p * a) % modulus; } return p; } /** * Calculates a^b mod modulus */ public static long pow(long a, int b, long modulus) { long p = 1; for (int i = 0; i < b; i++) { p = (p * a) % modulus; } return p; } /** * Generates a "sparse" or "dense" polynomial containing numOnes ints equal to 1, * numNegOnes int equal to -1, and the rest equal to 0. * * @param N * @param numOnes * @param numNegOnes * @param sparse whether to create a {@link SparseTernaryPolynomial} or {@link DenseTernaryPolynomial} * @return a ternary polynomial */ public static TernaryPolynomial generateRandomTernary(int N, int numOnes, int numNegOnes, boolean sparse, SecureRandom random) { if (sparse) { return SparseTernaryPolynomial.generateRandom(N, numOnes, numNegOnes, random); } else { return DenseTernaryPolynomial.generateRandom(N, numOnes, numNegOnes, random); } } /** * Generates an array containing numOnes ints equal to 1, * numNegOnes int equal to -1, and the rest equal to 0. * * @param N * @param numOnes * @param numNegOnes * @return an array of integers */ public static int[] generateRandomTernary(int N, int numOnes, int numNegOnes, SecureRandom random) { Integer one = Integers.valueOf(1); Integer minusOne = Integers.valueOf(-1); Integer zero = Integers.valueOf(0); List list = new ArrayList(); for (int i = 0; i < numOnes; i++) { list.add(one); } for (int i = 0; i < numNegOnes; i++) { list.add(minusOne); } while (list.size() < N) { list.add(zero); } Collections.shuffle(list, random); int[] arr = new int[N]; for (int i = 0; i < N; i++) { arr[i] = ((Integer)list.get(i)).intValue(); } return arr; } /** * Takes an educated guess as to whether 64 bits are supported by the JVM. * * @return <code>true</code> if 64-bit support detected, <code>false</code> otherwise */ public static boolean is64BitJVM() { if (!IS_64_BITNESS_KNOWN) { String arch = System.getProperty("os.arch"); String sunModel = System.getProperty("sun.arch.data.model"); IS_64_BIT_JVM = "amd64".equals(arch) || "x86_64".equals(arch) || "ppc64".equals(arch) || "64".equals(sunModel); IS_64_BITNESS_KNOWN = true; } return IS_64_BIT_JVM; } /** * Reads a given number of bytes from an <code>InputStream</code>. * If there are not enough bytes in the stream, an <code>IOException</code> * is thrown. * * @param is * @param length * @return an array of length <code>length</code> * @throws IOException */ public static byte[] readFullLength(InputStream is, int length) throws IOException { byte[] arr = new byte[length]; if (is.read(arr) != arr.length) { throw new IOException("Not enough bytes to read."); } return arr; } }