/*
 * 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 orProofTest = {

  /**
   * Verifies an OR 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}
   *            publicKeyJson the public key, in JSON format.
   * @param {String}
   *            ciphertextJson the ciphertext, in JSON format.
   * @param (String)
   *            elementsJson the elements, in JSON format.
   * @param (String)
   *            data the string data.
   * @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, publicKeyJson, ciphertextJson, elementsJson, data,
      proofJson, preComputedValuesJson) {

    'use strict';

    var errorData = {};
    errorData['Zp Subgroup (JSON format) [Java]'] = zpSubgroupJson;
    errorData['Public key (JSON format) [Java]'] = publicKeyJson;
    errorData['Ciphertext (JSON format) [Java]'] = ciphertextJson;
    errorData['Elements (JSON format) [Java]'] = elementsJson;
    errorData['Data (String) [Java]'] = data;
    errorData['OR zero knowledge proof (JSON format) [Java]'] = proofJson;

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

            var publicKeyJsonB64 = _converters.base64Encode(publicKeyJson);
            var publicKey = box.homomorphic.service.createElGamalPublicKey(
                publicKeyJsonB64);

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

            var elements = testUtils.deserializeZpGroupElements(elementsJson);

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

            var verified = box.proofs.service.verifyORProof(
                publicKey, ciphertext, elements, data, proof, zpSubgroup);

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

  /**
   * Generates an OR zero knowledge proof of knowledge that will be verified
   * using Java.
   *
   * @param {String}
   *            zpSubgroupJson the Zp subgroup, in JSON format.
   * @param {String}
   *            publicKeyJson the public key, in JSON format.
   * @param {String}
   *            ciphertextJson the ciphertext, in JSON format.
   * @param {String}
   *            witnessJson the witness that was used to generate the OR
   *            proof, in JSON format.
   * @param (String)
   *            elementsJson the elements, in JSON format.
   * @param (Number)
   *            index the selected element index.
   * @param (String)
   *            data the data, as a String.
   * @param {String}
   *            preComputedValuesJson the pre-computed OR proof values, in
   *            JSON format (if the pre-computation step was performed).
   * @returns {String} the generated OR zero knowledge proof, in JSON format.
   * @throws {Error}
   *             if the proof generation operation fails.
   */
  generate: function(
      zpSubgroupJson, publicKeyJson, ciphertextJson, witnessJson, elementsJson,
      index, data, preComputedValuesJson) {

    'use strict';

    var errorData = {};
    errorData['Zp Subgroup (JSON format) [Java]'] = zpSubgroupJson;
    errorData['Public key (JSON format) [Java]'] = publicKeyJson;
    errorData['Ciphertext (JSON format) [Java]'] = ciphertextJson;
    errorData['Witness (JSON format) [Java]'] = witnessJson;
    errorData['Elements (JSON format) [Java]'] = elementsJson;
    errorData['Index [Java]'] = index;
    errorData['Data [Java]'] = data;
    if (typeof preComputedValuesJson !== 'undefined') {
      errorData['Pre-computed OR proof values (JSON format) [JS]'] =
          preComputedValuesJson;
    }

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

            var publicKeyJsonB64 = _converters.base64Encode(publicKeyJson);
            var publicKey = box.homomorphic.service.createElGamalPublicKey(
                publicKeyJsonB64);

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

            var witness =
                box.commons.mathematical.groupUtils.deserializeExponent(
                    witnessJson);

            var elements = testUtils.deserializeZpGroupElements(elementsJson);

            var proof;
            if (typeof preComputedValuesJson !== 'undefined') {
              var preComputedValues =
                  box.proofs.utils.deserializeProofPreComputedValues(
                      preComputedValuesJson);
              proof = box.proofs.service.createORProof(
                  publicKey, ciphertext, witness, elements, index, data,
                  zpSubgroup, preComputedValues);
            } else {
              proof = box.proofs.service.createORProof(
                  publicKey, ciphertext, witness, elements, index, data,
                  zpSubgroup);
            }

            proofJson = proof.stringify();
          });

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

  /**
   * Generates pre-computed values that can be used to generate an OR zero
   * knowledge proof of knowledge, using Java or JavaScript.
   *
   * @param {String}
   *            zpSubgroupJson the Zp subgroup, in JSON format.
   * @param {String}
   *            publicKeyJson the public key, in JSON format.
   * @param {Number}
   *            numElements the number of elements.
   * @throws {Error}
   *             if the pre-computed values generation operation fails.
   */
  generatePreComputedValues: function(
      zpSubgroupJson, publicKeyJson, numElements) {

    'use strict';

    var errorData = {};
    errorData['Zp Subgroup (JSON format) [Java]'] = zpSubgroupJson;
    errorData['Public key (JSON format) [Java]'] = publicKeyJson;
    errorData['Number of elements [Java]'] = numElements;

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

            var publicKeyJsonB64 = _converters.base64Encode(publicKeyJson);
            var publicKey = box.homomorphic.service.createElGamalPublicKey(
                publicKeyJsonB64);

            var preComputedValues = box.proofs.service.preComputeORProof(
                publicKey, numElements, zpSubgroup);

            preComputedValuesJson = preComputedValues.stringify();
          });

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