Пример #1
0
  /**
   * Method based on FFT to find the determinant and the first coefficient of w(x) this suffices to
   * find w(x) completely
   *
   * @param q the polynomial
   * @param n the degree
   * @return The determinant and the first coefficient of w(x).
   */
  static BigInteger[] gzModZ2(Polynomial q, int n) {
    int i;
    int N = 1 << n;

    Polynomial V = new Polynomial(q.coeffs); // V = q
    Polynomial U = new Polynomial(1); // U = 1
    U.setCoeff(0, new BigInteger("1"));
    Polynomial F = new Polynomial(N); // F(x) = x^N +1
    F.setCoeff(0, new BigInteger("1"));
    F.setCoeff(N, new BigInteger("1"));
    Polynomial V2 = new Polynomial(N);

    while (N > 1) {
      V2 = new Polynomial(V.coeffs);
      for (i = 1; i <= V2.degree; i += 2) { // set V2(x) := V(-x)
        V2.coeffs[i] = V2.coeffs[i].negate(); // negate odd coefficients
      }
      V = Polynomial.mod(Polynomial.mult(V, V2), F); // V := V(x) * V(-x) mod f(x)
      U = Polynomial.mod(Polynomial.mult(U, V2), F); // U := U(x) * V(-x) mod f(x)

      // Sanity-check: verify that the odd coefficients in V are zero
      for (i = 1; i <= V.degree; i += 2)
        if (!V.coeffs[i].equals(new BigInteger("0"))) {
          return null;
        }

      // "Compress" the non-zero coefficients of V
      for (i = 1; i <= V.degree / 2; i++) V.coeffs[i] = V.coeffs[2 * i];
      for (; i <= V.degree; i++) V.coeffs[i] = new BigInteger("0");
      V.normalize();

      // Set U to the "compressed" ( U(x) + U(-x) ) /2
      for (i = 0; i <= U.degree / 2; i++) U.coeffs[i] = U.coeffs[2 * i];
      for (; i <= U.degree; i++) U.coeffs[i] = new BigInteger("0");
      U.normalize();

      // Set N := N/2 and update F accordingly
      F.coeffs[N] = new BigInteger("0");
      N >>= 1;
      F.coeffs[N] = new BigInteger("1");
      F.normalize();
    }

    return new BigInteger[] {V.coeffs[0], U.coeffs[0]};
  }
Пример #2
0
  /**
   * Verifies whether the polynomial q yields a lattice with the correct HNF and odd resultant,
   * computes the determinant (or resultant), root and inverse polynomial w(x)
   *
   * @param q the polynomial yielding the lattice
   * @param n the dimension
   * @return True if the polynomial suffices, false otherwise.
   */
  boolean invModFx(Polynomial q, int n) {
    int N = 1 << n;
    BigInteger res, wi = null;

    if (q.degree >= N) return false;

    // compute resultant and w0
    BigInteger w0, w1;
    BigInteger rw[] = gzModZ2(q, n);
    res = rw[0];
    w0 = rw[1];

    if (Functions.isEven(res)) { // Resultant must be odd
      return false;
    }

    // repeat for the polynomial x*q(x) mod x^N+1
    Polynomial qx = new Polynomial(N);
    for (int i = N - 1; i > 0; i--) {
      qx.setCoeff(i, q.coeffs[i - 1]); // copy 1st N-1 coeffs
    }
    qx.setCoeff(0, q.coeffs[N - 1].negate()); // negate last coeff
    qx.normalize();
    rw = gzModZ2(qx, n);
    res = rw[0];
    w1 = rw[1];

    // now that we have res, w0, w1, set root = w1/w0 mod res
    // make sure things are positive
    if (res.signum() == -1) {
      res = res.negate();
      w0 = w0.negate();
      w1 = w1.negate();
    }
    if (w0.signum() < 0) w0 = w0.add(res);
    if (w1.signum() < 0) w1 = w1.add(res);

    BigInteger inv =
        Functions.xgcd(w0, res); // returns a = w0^{-1} if w0 invertible, null otherwise
    if (inv == null) {
      return false; // verify that w0^{-1} exists
    }
    root = w1.multiply(inv).divideAndRemainder(res)[1]; // root= w1 * w0^{-1} mod res

    BigInteger tmp = root.modPow(new BigInteger(Integer.toString(N)), res);
    // it should hold that root^n = -1 mod res
    if (!tmp.add(new BigInteger("1")).equals(res)) {
      return false;
    }
    W = new BigInteger[N]; // get the entire polynomial w(x), for debug purposes
    W[0] = w0;
    W[1] = w1;
    for (int k = 2; k < N; k++) {
      W[k] = W[k - 1].multiply(root).mod(res);
    }
    // for decryption only a single odd coefficient of w(x) is necessary
    int i = 0;
    if (((w0.compareTo(res.shiftRight(1)) <= 0) && Functions.isOdd(w0))
        || ((w0.compareTo(res.shiftRight(1)) > 0) && Functions.isEven(w0))) {
      wi = w0;
    } else {
      if (((w1.compareTo(res.shiftRight(1)) <= 0) && Functions.isOdd(w1))
          || ((w1.compareTo(res.shiftRight(1)) > 0) && Functions.isEven(w1))) {
        wi = w1;
      } else {
        for (i = 2; i < N; i++) {
          w1 = w1.multiply(root).mod(res); // (w1.multiply(root)).divideAndRemainder(res)[1];
          if (((w1.compareTo(res.shiftRight(1)) <= 0) && Functions.isOdd(w1))
              || ((w1.compareTo(res.shiftRight(1)) > 0) && Functions.isEven(w1))) {
            wi = w1;
            break;
          }
        }
      }
    }

    det = res;
    w = wi;
    return ((i == N) ? false : true); // We get i==N only if all the wi's are even
  }