Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/java/org/spongycastle/pqc/math/ntru/polynomial/SparseTernaryPolynomial.java')
-rw-r--r--core/src/main/java/org/spongycastle/pqc/math/ntru/polynomial/SparseTernaryPolynomial.java320
1 files changed, 320 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/pqc/math/ntru/polynomial/SparseTernaryPolynomial.java b/core/src/main/java/org/spongycastle/pqc/math/ntru/polynomial/SparseTernaryPolynomial.java
new file mode 100644
index 00000000..2fbd70a4
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/pqc/math/ntru/polynomial/SparseTernaryPolynomial.java
@@ -0,0 +1,320 @@
+package org.spongycastle.pqc.math.ntru.polynomial;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.spongycastle.pqc.math.ntru.util.ArrayEncoder;
+import org.spongycastle.pqc.math.ntru.util.Util;
+import org.spongycastle.util.Arrays;
+
+/**
+ * A <code>TernaryPolynomial</code> with a "low" number of nonzero coefficients.
+ */
+public class SparseTernaryPolynomial
+ implements TernaryPolynomial
+{
+ /**
+ * Number of bits to use for each coefficient. Determines the upper bound for <code>N</code>.
+ */
+ private static final int BITS_PER_INDEX = 11;
+
+ private int N;
+ private int[] ones;
+ private int[] negOnes;
+
+ /**
+ * Constructs a new polynomial.
+ *
+ * @param N total number of coefficients including zeros
+ * @param ones indices of coefficients equal to 1
+ * @param negOnes indices of coefficients equal to -1
+ */
+ SparseTernaryPolynomial(int N, int[] ones, int[] negOnes)
+ {
+ this.N = N;
+ this.ones = ones;
+ this.negOnes = negOnes;
+ }
+
+ /**
+ * Constructs a <code>DenseTernaryPolynomial</code> from a <code>IntegerPolynomial</code>. The two polynomials are
+ * independent of each other.
+ *
+ * @param intPoly the original polynomial
+ */
+ public SparseTernaryPolynomial(IntegerPolynomial intPoly)
+ {
+ this(intPoly.coeffs);
+ }
+
+ /**
+ * Constructs a new <code>SparseTernaryPolynomial</code> with a given set of coefficients.
+ *
+ * @param coeffs the coefficients
+ */
+ public SparseTernaryPolynomial(int[] coeffs)
+ {
+ N = coeffs.length;
+ ones = new int[N];
+ negOnes = new int[N];
+ int onesIdx = 0;
+ int negOnesIdx = 0;
+ for (int i = 0; i < N; i++)
+ {
+ int c = coeffs[i];
+ switch (c)
+ {
+ case 1:
+ ones[onesIdx++] = i;
+ break;
+ case -1:
+ negOnes[negOnesIdx++] = i;
+ break;
+ case 0:
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal value: " + c + ", must be one of {-1, 0, 1}");
+ }
+ }
+ ones = Arrays.copyOf(ones, onesIdx);
+ negOnes = Arrays.copyOf(negOnes, negOnesIdx);
+ }
+
+ /**
+ * Decodes a byte array encoded with {@link #toBinary()} to a ploynomial.
+ *
+ * @param is an input stream containing an encoded polynomial
+ * @param N number of coefficients including zeros
+ * @param numOnes number of coefficients equal to 1
+ * @param numNegOnes number of coefficients equal to -1
+ * @return the decoded polynomial
+ * @throws IOException
+ */
+ public static SparseTernaryPolynomial fromBinary(InputStream is, int N, int numOnes, int numNegOnes)
+ throws IOException
+ {
+ int maxIndex = 1 << BITS_PER_INDEX;
+ int bitsPerIndex = 32 - Integer.numberOfLeadingZeros(maxIndex - 1);
+
+ int data1Len = (numOnes * bitsPerIndex + 7) / 8;
+ byte[] data1 = Util.readFullLength(is, data1Len);
+ int[] ones = ArrayEncoder.decodeModQ(data1, numOnes, maxIndex);
+
+ int data2Len = (numNegOnes * bitsPerIndex + 7) / 8;
+ byte[] data2 = Util.readFullLength(is, data2Len);
+ int[] negOnes = ArrayEncoder.decodeModQ(data2, numNegOnes, maxIndex);
+
+ return new SparseTernaryPolynomial(N, ones, negOnes);
+ }
+
+ /**
+ * Generates a random polynomial with <code>numOnes</code> coefficients equal to 1,
+ * <code>numNegOnes</code> 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
+ */
+ public static SparseTernaryPolynomial generateRandom(int N, int numOnes, int numNegOnes, SecureRandom random)
+ {
+ int[] coeffs = Util.generateRandomTernary(N, numOnes, numNegOnes, random);
+ return new SparseTernaryPolynomial(coeffs);
+ }
+
+ public IntegerPolynomial mult(IntegerPolynomial poly2)
+ {
+ int[] b = poly2.coeffs;
+ if (b.length != N)
+ {
+ throw new IllegalArgumentException("Number of coefficients must be the same");
+ }
+
+ int[] c = new int[N];
+ for (int idx = 0; idx != ones.length; idx++)
+ {
+ int i = ones[idx];
+ int j = N - 1 - i;
+ for (int k = N - 1; k >= 0; k--)
+ {
+ c[k] += b[j];
+ j--;
+ if (j < 0)
+ {
+ j = N - 1;
+ }
+ }
+ }
+
+ for (int idx = 0; idx != negOnes.length; idx++)
+ {
+ int i = negOnes[idx];
+ int j = N - 1 - i;
+ for (int k = N - 1; k >= 0; k--)
+ {
+ c[k] -= b[j];
+ j--;
+ if (j < 0)
+ {
+ j = N - 1;
+ }
+ }
+ }
+
+ return new IntegerPolynomial(c);
+ }
+
+ public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus)
+ {
+ IntegerPolynomial c = mult(poly2);
+ c.mod(modulus);
+ return c;
+ }
+
+ public BigIntPolynomial mult(BigIntPolynomial poly2)
+ {
+ BigInteger[] b = poly2.coeffs;
+ if (b.length != N)
+ {
+ throw new IllegalArgumentException("Number of coefficients must be the same");
+ }
+
+ BigInteger[] c = new BigInteger[N];
+ for (int i = 0; i < N; i++)
+ {
+ c[i] = BigInteger.ZERO;
+ }
+
+ for (int idx = 0; idx != ones.length; idx++)
+ {
+ int i = ones[idx];
+ int j = N - 1 - i;
+ for (int k = N - 1; k >= 0; k--)
+ {
+ c[k] = c[k].add(b[j]);
+ j--;
+ if (j < 0)
+ {
+ j = N - 1;
+ }
+ }
+ }
+
+ for (int idx = 0; idx != negOnes.length; idx++)
+ {
+ int i = negOnes[idx];
+ int j = N - 1 - i;
+ for (int k = N - 1; k >= 0; k--)
+ {
+ c[k] = c[k].subtract(b[j]);
+ j--;
+ if (j < 0)
+ {
+ j = N - 1;
+ }
+ }
+ }
+
+ return new BigIntPolynomial(c);
+ }
+
+ public int[] getOnes()
+ {
+ return ones;
+ }
+
+ public int[] getNegOnes()
+ {
+ return negOnes;
+ }
+
+ /**
+ * Encodes the polynomial to a byte array writing <code>BITS_PER_INDEX</code> bits for each coefficient.
+ *
+ * @return the encoded polynomial
+ */
+ public byte[] toBinary()
+ {
+ int maxIndex = 1 << BITS_PER_INDEX;
+ byte[] bin1 = ArrayEncoder.encodeModQ(ones, maxIndex);
+ byte[] bin2 = ArrayEncoder.encodeModQ(negOnes, maxIndex);
+
+ byte[] bin = Arrays.copyOf(bin1, bin1.length + bin2.length);
+ System.arraycopy(bin2, 0, bin, bin1.length, bin2.length);
+ return bin;
+ }
+
+ public IntegerPolynomial toIntegerPolynomial()
+ {
+ int[] coeffs = new int[N];
+ for (int idx = 0; idx != ones.length; idx++)
+ {
+ int i = ones[idx];
+ coeffs[i] = 1;
+ }
+ for (int idx = 0; idx != negOnes.length; idx++)
+ {
+ int i = negOnes[idx];
+ coeffs[i] = -1;
+ }
+ return new IntegerPolynomial(coeffs);
+ }
+
+ public int size()
+ {
+ return N;
+ }
+
+ public void clear()
+ {
+ for (int i = 0; i < ones.length; i++)
+ {
+ ones[i] = 0;
+ }
+ for (int i = 0; i < negOnes.length; i++)
+ {
+ negOnes[i] = 0;
+ }
+ }
+
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + N;
+ result = prime * result + Arrays.hashCode(negOnes);
+ result = prime * result + Arrays.hashCode(ones);
+ return result;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ SparseTernaryPolynomial other = (SparseTernaryPolynomial)obj;
+ if (N != other.N)
+ {
+ return false;
+ }
+ if (!Arrays.areEqual(negOnes, other.negOnes))
+ {
+ return false;
+ }
+ if (!Arrays.areEqual(ones, other.ones))
+ {
+ return false;
+ }
+ return true;
+ }
+}