/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
var plaintextEqualityProofTest = {

  /**
   * Verifies a plaintext equality zero knowledge proof of knowledge that was
   * generated using Java and checks if the verification was true.
   *
   * @param {String}
   *            zpSubgroupJson the Zp subgroup, in JSON format.
   * @param {String}
   *            primaryPublicKeyJson the primary public key, in JSON format.
   * @param {String}
   *            primaryCiphertextJson the primary ciphertext, in JSON format.
   * @param {String}
   *            secondaryPublicKeyJson the secondary public key, in JSON
   *            format. *
   * @param {String}
   *            secondaryCiphertextJson the secondary ciphertext, in JSON
   *            format.
   * @param {String}
   *            proofJson the proof to verify, in JSON format.
   * @throws {Error}
   *             if the proof verification operation fails or the verification
   *             is false.
   */
  verify: function(
      zpSubgroupJson, primaryPublicKeyJson, primaryCiphertextJson,
      secondaryPublicKeyJson, secondaryCiphertextJson, proofJson) {

    'use strict';

    var errorData = {};
    errorData['Zp Subgroup (JSON format) [Java]'] = zpSubgroupJson;
    errorData['Primary ElGamal public key (JSON format) [Java]'] =
        primaryPublicKeyJson;
    errorData['Primary ciphertext (JSON format) [Java]'] =
        primaryCiphertextJson;
    errorData['Secondary ElGamal public key (JSON format) [Java]'] =
        secondaryPublicKeyJson;
    errorData['Secondary ciphertext (JSON format) [Java]'] =
        secondaryCiphertextJson;
    errorData['Plaintext equality zero knowledge proof (JSON format) [Java]'] =
        proofJson;

    try {
      cryptolib(
          'commons.mathematical', 'homomorphic.cipher', 'homomorphic.service',
          'proofs', 'proofs.service', function(box) {
            var zpSubgroup =
                box.commons.mathematical.groupUtils.deserializeGroup(
                    zpSubgroupJson);
            var primaryPublicKeyJsonB64 =
                _converters.base64Encode(primaryPublicKeyJson);
            var primaryPublicKey =
                box.homomorphic.service.createElGamalPublicKey(
                    primaryPublicKeyJsonB64);

            var computationValues =
                box.homomorphic.cipher.deserializeElGamalComputationValues(
                    primaryCiphertextJson);
            var primaryCiphertext =
                new box.homomorphic.cipher.ElGamalEncrypterValues(
                    null, computationValues.getGamma(),
                    computationValues.getPhis());

            var secondaryPublicKeyJsonB64 =
                _converters.base64Encode(secondaryPublicKeyJson);
            var secondaryPublicKey =
                box.homomorphic.service.createElGamalPublicKey(
                    secondaryPublicKeyJsonB64);

            computationValues =
                box.homomorphic.cipher.deserializeElGamalComputationValues(
                    secondaryCiphertextJson);
            var secondaryCiphertext =
                new box.homomorphic.cipher.ElGamalEncrypterValues(
                    null, computationValues.getGamma(),
                    computationValues.getPhis());

            var proof = box.proofs.utils.deserializeProof(proofJson);

            var verified = box.proofs.service.verifyPlaintextEqualityProof(
                primaryCiphertext, primaryPublicKey, secondaryCiphertext,
                secondaryPublicKey, proof, zpSubgroup);

            if (!verified) {
              throw 'Verification of plaintext equality zero knowledge proof was false.';
            }
          });
    } catch (error) {
      throw testUtils.serializeError(error, errorData);
    }
  },

  /**
   * Generates a plaintext equality zero knowledge proof of knowledge that
   * will be verified using Java.
   *
   * @param {String}
   *            zpSubgroupJson the Zp subgroup, in JSON format.
   * @param {String}
   *            primaryPublicKeyJson the primary public key, in JSON format.
   * @param {String}
   *            primaryWitnessJson the primary witness, in JSON format.
   * @param {String}
   *            primaryCiphertextJson the primary ciphertext, in JSON format.
   * @param {String}
   *            secondaryPublicKeyJson the secondary public key, in JSON
   *            format.
   * @param {String}
   *            secondaryWitnessJson the secondary witness, in JSON format.
   * @param {String}
   *            secondaryCiphertextJson the secondary ciphertext, in JSON
   *            format.
   * @param {String}
   *            preComputedValuesJson the pre-computed plaintext equality
   *            proof values, in JSON format (if the pre-computation step was
   *            performed).
   * @returns {String} the generated plaintext equality zero knowledge proof,
   *          in JSON format.
   * @throws {Error}
   *             if the proof generation operation fails.
   */
  generate: function(
      zpSubgroupJson, primaryPublicKeyJson, primaryWitnessJson,
      primaryCiphertextJson, secondaryPublicKeyJson, secondaryWitnessJson,
      secondaryCiphertextJson, preComputedValuesJson) {

    'use strict';

    var errorData = {};
    errorData['Zp Subgroup (JSON format) [Java]'] = zpSubgroupJson;
    errorData['Primary ElGamal public key (JSON format) [Java]'] =
        primaryPublicKeyJson;
    errorData['Primary witness (JSON format) [Java]'] = primaryWitnessJson;
    errorData['Primary ciphertext (JSON format) [Java]'] =
        primaryCiphertextJson;
    errorData['Secondary ElGamal public key (JSON format) [Java]'] =
        secondaryPublicKeyJson;
    errorData['Secondary witness (JSON format) [Java]'] = secondaryWitnessJson;
    errorData['Secondary ciphertext (JSON format) [Java]'] =
        secondaryCiphertextJson;
    if (typeof preComputedValuesJson !== 'undefined') {
      errorData
          ['Pre-computed plaintext equality proof values (JSON format) [JS]'] =
              preComputedValuesJson;
    }

    try {
      var proofJson;
      cryptolib(
          'commons.mathematical', 'homomorphic.cipher', 'homomorphic.service',
          'proofs', 'proofs.service', function(box) {
            var zpSubgroup =
                box.commons.mathematical.groupUtils.deserializeGroup(
                    zpSubgroupJson);

            var primaryPublicKeyJsonB64 =
                _converters.base64Encode(primaryPublicKeyJson);
            var primaryPublicKey =
                box.homomorphic.service.createElGamalPublicKey(
                    primaryPublicKeyJsonB64);

            var primaryWitness =
                box.commons.mathematical.groupUtils.deserializeExponent(
                    primaryWitnessJson);

            var computationValues =
                box.homomorphic.cipher.deserializeElGamalComputationValues(
                    primaryCiphertextJson);
            var primaryCiphertext =
                new box.homomorphic.cipher.ElGamalEncrypterValues(
                    null, computationValues.getGamma(),
                    computationValues.getPhis());

            var secondaryPublicKeyJsonB64 =
                _converters.base64Encode(secondaryPublicKeyJson);
            var secondaryPublicKey =
                box.homomorphic.service.createElGamalPublicKey(
                    secondaryPublicKeyJsonB64);

            var secondaryWitness =
                box.commons.mathematical.groupUtils.deserializeExponent(
                    secondaryWitnessJson);

            computationValues =
                box.homomorphic.cipher.deserializeElGamalComputationValues(
                    secondaryCiphertextJson);
            var secondaryCiphertext =
                new box.homomorphic.cipher.ElGamalEncrypterValues(
                    null, computationValues.getGamma(),
                    computationValues.getPhis());

            var proof;
            if (typeof preComputedValuesJson !== 'undefined') {
              var preComputedValues =
                  box.proofs.utils.deserializeProofPreComputedValues(
                      preComputedValuesJson);
              proof = box.proofs.service.createPlaintextEqualityProof(
                  primaryCiphertext, primaryPublicKey, primaryWitness,
                  secondaryCiphertext, secondaryPublicKey, secondaryWitness,
                  zpSubgroup, preComputedValues);
            } else {
              proof = box.proofs.service.createPlaintextEqualityProof(
                  primaryCiphertext, primaryPublicKey, primaryWitness,
                  secondaryCiphertext, secondaryPublicKey, secondaryWitness,
                  zpSubgroup);
            }

            proofJson = proof.stringify();
          });

      return proofJson;
    } catch (error) {
      throw testUtils.serializeError(error, errorData);
    }
  },

  /**
   * Generates pre-computed values that can be used to generate a plaintext
   * equality zero knowledge proof of knowledge, using Java or JavaScript.
   *
   * @param {String}
   *            zpSubgroupJson the Zp subgroup, in JSON format.
   * @param {String}
   *            primaryPublicKeyJson the primary public key, in JSON format.
   * @param {String}
   *            secondaryPublicKeyJson the secondary public key, in JSON
   *            format.
   * @returns {String} the pre-computed plaintext equality proof values, in
   *          JSON format.
   * @throws {Error}
   *             if the pre-computed values generation operation fails.
   */
  generatePreComputedValues: function(
      zpSubgroupJson, primaryPublicKeyJson, secondaryPublicKeyJson) {

    'use strict';

    var errorData = {};
    errorData['Zp Subgroup (JSON format) [Java]'] = zpSubgroupJson;
    errorData['Primary ElGamal public key (JSON format) [Java]'] =
        primaryPublicKeyJson;
    errorData['Secondary ElGamal public key (JSON format) [Java]'] =
        secondaryPublicKeyJson;

    try {
      var preComputedValuesJson;
      cryptolib(
          'commons.mathematical', 'homomorphic.service', 'proofs.service',
          function(box) {
            var zpSubgroup =
                box.commons.mathematical.groupUtils.deserializeGroup(
                    zpSubgroupJson);

            var primaryPublicKeyJsonB64 =
                _converters.base64Encode(primaryPublicKeyJson);
            var primaryPublicKey =
                box.homomorphic.service.createElGamalPublicKey(
                    primaryPublicKeyJsonB64);

            var secondaryPublicKeyJsonB64 =
                _converters.base64Encode(secondaryPublicKeyJson);
            var secondaryPublicKey =
                box.homomorphic.service.createElGamalPublicKey(
                    secondaryPublicKeyJsonB64);

            var preComputedValues =
                box.proofs.service.preComputePlaintextEqualityProof(
                    primaryPublicKey, secondaryPublicKey, zpSubgroup);

            preComputedValuesJson = preComputedValues.stringify();
          });

      return preComputedValuesJson;
    } catch (error) {
      throw testUtils.serializeError(error, errorData);
    }
  }
};