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

  /**
   * ElGamal decrypts a collection of quadratic residue group elements that
   * was encrypted using Java, via a short exponent, and checks if the
   * original collection of quadratic residue group elements could be
   * retrieved.
   *
   * @param {String}
   *            elGamalPrivateKeyJson the ElGamal private key, in JSON format.
   * @param {String}
   *            encryptedQrGroupElementsJson the collection of encrypted
   *            quadratic residue group elements, in JSON format.
   * @param {String}
   *            qrGroupElementsJson the original collection of quadratic
   *            residue group elements, in JSON format.
   * @throws {Error}
   *             if the decryption operation fails or the original collection
   *             of quadratic residue group elements could not be retrieved.
   */
  decrypt: function(
      elGamalPrivateKeyJson, encryptedQrGroupElementsJson,
      qrGroupElementsJson) {

    'use strict';

    var errorData = {};
    errorData['ElGamal private key (JSON format) [Java]'] =
        elGamalPrivateKeyJson;
    errorData
        ['Encrypted quadratic residue group elements (JSON format) [Java]'] =
            encryptedQrGroupElementsJson;
    errorData
        ['Quadratic residue group elements that were encrypted (JSON format) [Java]'] =
            qrGroupElementsJson;

    try {
      cryptolib('homomorphic.cipher', 'homomorphic.service', function(box) {
        var elGamalPrivateKeyJsonB64 =
            _converters.base64Encode(elGamalPrivateKeyJson);
        var elGamalPrivateKey = box.homomorphic.service.createElGamalPrivateKey(
            elGamalPrivateKeyJsonB64);

        var encryptedQrGroupElements =
            box.homomorphic.cipher.deserializeElGamalComputationValues(
                encryptedQrGroupElementsJson);

        var qrGroupElements =
            testUtils.deserializeZpGroupElements(qrGroupElementsJson);

        var decryptedQrGroupElements =
            box.homomorphic.service.createDecrypter(elGamalPrivateKey)
                .decrypt(encryptedQrGroupElements, true);

        errorData
            ['Decrypted quadratic residue group elements (JSON format) [JS]'] =
                testUtils.stringifyZpGroupElements(decryptedQrGroupElements);

        var decryptionLengthFound = decryptedQrGroupElements.length;
        var decryptionLengthExpected = qrGroupElements.length;
        if (decryptionLengthFound !== decryptionLengthExpected) {
          throw 'Expected decrypted quadratic residue group element collection length: ' +
              decryptionLengthExpected + ' ; Found: ' + decryptionLengthFound;
        }

        for (var i = 0; i < decryptedQrGroupElements.length; i++) {
          var qrGroupElementFound = decryptedQrGroupElements[i];
          var qrGroupElementExpected = qrGroupElements[i];

          if (!qrGroupElementFound.equals(qrGroupElementExpected)) {
            throw 'Expected decrypted quadratic residue element: ' +
                qrGroupElementExpected.stringify() +
                ' ; Found: ' + qrGroupElementFound.stringify();
          }
        }
      });
    } catch (error) {
      throw testUtils.serializeError(error, errorData);
    }
  },

  /**
   * ElGamal encrypts a collection of quadratic residue group elements, via a
   * short exponent, that will be decrypted using Java.
   *
   * @param {String}
   *            elGamalPublicKeyJson the ElGamal public key, in JSON format.
   * @param {String}
   *            qrGroupElementsJson the collection of quadratic residue group
   *            elements to encrypt, in JSON format.
   * @param {String}
   *            preComputedValuesJson the pre-computed ElGamal encryption
   *            values, in JSON format (if the pre-computation step was
   *            performed).
   * @returns {String} the encrypted collection of quadratic residue group
   *          elements, in JSON format.
   * @throws {Error}
   *             if the encryption operation fails.
   */
  encrypt: function(
      elGamalPublicKeyJson, qrGroupElementsJson, preComputedValuesJson) {

    'use strict';

    var errorData = {};
    errorData['ElGamal public key (JSON format) [Java]'] = elGamalPublicKeyJson;
    errorData
        ['Quadratic residue group elements to encrypt (JSON format) [Java]'] =
            qrGroupElementsJson;
    if (typeof preComputedValuesJson !== 'undefined') {
      errorData['Pre-computed ElGamal encryption values (JSON format) [JS]'] =
          preComputedValuesJson;
    }

    try {
      var encryptedQrGroupElementsJson;
      cryptolib('homomorphic.cipher', 'homomorphic.service', function(box) {
        var elGamalPublicKeyJsonB64 =
            _converters.base64Encode(elGamalPublicKeyJson);
        var elGamalPublicKey = box.homomorphic.service.createElGamalPublicKey(
            elGamalPublicKeyJsonB64);

        var qrGroupElements =
            testUtils.deserializeZpGroupElements(qrGroupElementsJson);

        var encryptedQrGroupElements;
        if (typeof preComputedValuesJson !== 'undefined') {
          var preComputationValues =
              box.homomorphic.cipher.deserializeElGamalComputationValues(
                  preComputedValuesJson);
          var preComputedEncrypterValues =
              new box.homomorphic.cipher.ElGamalEncrypterValues(
                  null, preComputationValues.getGamma(),
                  preComputationValues.getPhis());

          encryptedQrGroupElements =
              box.homomorphic.service.createEncrypter(elGamalPublicKey)
                  .encryptGroupElements(
                      qrGroupElements, preComputedEncrypterValues)
                  .getElGamalComputationValues();
        } else {
          encryptedQrGroupElements =
              box.homomorphic.service.createEncrypter(elGamalPublicKey)
                  .encryptGroupElements(qrGroupElements, true)
                  .getElGamalComputationValues();
        }

        encryptedQrGroupElementsJson = encryptedQrGroupElements.stringify();
      });

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

  /**
   * Generates pre-computed ElGamal encryption values, via a short exponent,
   * that can be used to ElGamal encrypt data, using Java or JavaScript.
   *
   * @param {String}
   *            elGamalPublicKeyJson the ElGamal public key, in JSON format.
   * @returns {String} the generated pre-computed values, in JSON format.
   * @throws {Error}
   *             if the pre-computed values generation operation fails.
   */
  generatePreComputedValues: function(elGamalPublicKeyJson) {

    'use strict';

    var errorData = {};
    errorData['ElGamal public key (JSON format) [Java]'] = elGamalPublicKeyJson;
    try {
      var preComputedValuesJson;
      cryptolib('homomorphic.cipher', 'homomorphic.service', function(box) {
        var elGamalPublicKeyJsonB64 =
            _converters.base64Encode(elGamalPublicKeyJson);
        var elGamalPublicKey = box.homomorphic.service.createElGamalPublicKey(
            elGamalPublicKeyJsonB64);

        var elGamalEncrypter =
            box.homomorphic.service.createEncrypter(elGamalPublicKey);

        var preComputedEncrypterValues = elGamalEncrypter.preCompute(true);

        preComputedValuesJson =
            preComputedEncrypterValues.getElGamalComputationValues()
                .stringify();
      });

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