/**
   * Verifies the proof.
   *
   * @param z second message from prover
   * @param input MUST be an instance of SigmaDJEncryptedValueCommonInput.
   * @return true if the proof has been verified; false, otherwise.
   * @throws IllegalArgumentException if input is not an instance of
   *     SigmaDJEncryptedValueCommonInput.
   * @throws IllegalArgumentException if the messages of the prover are not an instance of
   *     SigmaBIMsg
   */
  public boolean verify(SigmaCommonInput in, SigmaProtocolMsg a, SigmaProtocolMsg z) {
    /*
     * Converts the input (n, c, x) to (n, c') where c' = c*(1+n)^(-x) mod N'.
     */
    if (!(in instanceof SigmaDJEncryptedValueCommonInput)) {
      throw new IllegalArgumentException(
          "the given input must be an instance of SigmaDJEncryptedValueCommonInput");
    }
    SigmaDJEncryptedValueCommonInput input = (SigmaDJEncryptedValueCommonInput) in;

    // Get public key, cipher and plaintext.
    DamgardJurikPublicKey pubKey = input.getPublicKey();
    BigIntegerPlainText plaintext = input.getPlaintext();
    BigIntegerCiphertext cipher = input.getCiphertext();

    // Convert the cipher c to c' = c*(1+n)^(-x)
    BigInteger n = pubKey.getModulus();
    BigInteger nPlusOne = n.add(BigInteger.ONE);

    // calculate N' = n^(s+1).
    BigInteger NTag = n.pow(lengthParameter + 1);

    // Calculate (n+1)^(-x)
    BigInteger minusX = plaintext.getX().negate();
    BigInteger multVal = nPlusOne.modPow(minusX, NTag);

    // Calculate the ciphertext for DamgardJurikEncryptedZero - c*(n+1)^(-x).
    BigInteger newCipher = cipher.getCipher().multiply(multVal).mod(NTag);
    BigIntegerCiphertext cipherTag = new BigIntegerCiphertext(newCipher);

    // Create an input object to the underlying sigmaDamgardJurik verifier.
    SigmaDJEncryptedZeroCommonInput underlyingInput =
        new SigmaDJEncryptedZeroCommonInput(pubKey, cipherTag);

    // Delegates to the underlying sigmaDamgardJurik verifier.
    return sigmaDamgardJurik.verify(underlyingInput, a, z);
  }