/*
 * 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
 */
/* jshint node:true */
'use strict';

var SimplePlaintextEqualityProofTestData =
    require('../data/simple-plaintext-equality-proof-data');
var ProgressMeterTestData = require('../data/progress-meter-data');
var ValidationTestData = require('../data/validation-data');
var zkProof = require('../../lib/index');
var elGamal = require('scytl-elgamal');

describe('The zero-knowledge proof module should be able to ...', function() {
  var proofService_;
  var group_;
  var anotherGroup_;
  var secret_;
  var secretFromAnotherGroup_;
  var primaryPublicKey_;
  var secondaryPublicKey_;
  var primaryPublicKeyWithLessElements_;
  var secondaryPublicKeyWithLessElements_;
  var primaryPublicKeyFromAnotherGroup_;
  var secondaryPublicKeyFromAnotherGroup_;
  var primaryCiphertext_;
  var secondaryCiphertext_;
  var primaryCiphertextWithLessElements_;
  var secondaryCiphertextWithLessElements_;
  var primaryCiphertextFromAnotherGroup_;
  var secondaryCiphertextFromAnotherGroup_;
  var callback_;
  var nonObject_;
  var emptyObject_;
  var nonNumber_;
  var nonPositiveNumber_;
  var nonString_;
  var nonFunction_;
  var nonAuxiliaryData_;
  var nonProofObject_;
  var proofHandler_;
  var proof_;

  beforeAll(function() {
    proofService_ = zkProof.newService();

    var testData = new SimplePlaintextEqualityProofTestData();
    var elGamalService = elGamal.newService();
    group_ = testData.getGroup();
    anotherGroup_ = testData.getAnotherGroup();
    var primaryEncryptedElements = testData.getPrimaryEncryptedElements();
    secret_ = primaryEncryptedElements.secret;
    var primaryEncryptedElementsFromAnotherGroup =
        testData.getPrimaryEncryptedElementsFromAnotherGroup();
    secretFromAnotherGroup_ = primaryEncryptedElementsFromAnotherGroup.secret;
    primaryPublicKey_ = testData.getPrimaryPublicKey();
    secondaryPublicKey_ = testData.getSecondaryPublicKey();
    primaryPublicKeyWithLessElements_ =
        testData.getPrimaryPublicKeyWithLessElements();
    secondaryPublicKeyWithLessElements_ =
        testData.getSecondaryPublicKeyWithLessElements();
    primaryPublicKeyFromAnotherGroup_ =
        testData.getPrimaryPublicKeyFromAnotherGroup();
    secondaryPublicKeyFromAnotherGroup_ =
        testData.getSecondaryPublicKeyFromAnotherGroup();
    primaryCiphertext_ = elGamalService.newEncryptedElements(
        primaryEncryptedElements.gamma, primaryEncryptedElements.phis);
    var secondaryEncryptedElements = testData.getSecondaryEncryptedElements();
    secondaryCiphertext_ = elGamalService.newEncryptedElements(
        secondaryEncryptedElements.gamma, secondaryEncryptedElements.phis);
    var primaryEncryptedElementsWithLessElements =
        testData.getPrimaryEncryptedElementsWithLessElements();
    primaryCiphertextWithLessElements_ = elGamalService.newEncryptedElements(
        primaryEncryptedElementsWithLessElements.gamma,
        primaryEncryptedElementsWithLessElements.phis);
    var secondaryEncryptedElementsWithLessElements =
        testData.getSecondaryEncryptedElementsWithLessElements();
    secondaryCiphertextWithLessElements_ = elGamalService.newEncryptedElements(
        secondaryEncryptedElementsWithLessElements.gamma,
        secondaryEncryptedElementsWithLessElements.phis);
    primaryCiphertextFromAnotherGroup_ = elGamalService.newEncryptedElements(
        primaryEncryptedElementsFromAnotherGroup.gamma,
        primaryEncryptedElementsFromAnotherGroup.phis);
    var secondaryEncryptedElementsFromAnotherGroup =
        testData.getSecondaryEncryptedElementsFromAnotherGroup();
    secondaryCiphertextFromAnotherGroup_ = elGamalService.newEncryptedElements(
        secondaryEncryptedElementsFromAnotherGroup.gamma,
        secondaryEncryptedElementsFromAnotherGroup.phis);


    var progressMeterTestData = new ProgressMeterTestData();
    callback_ = progressMeterTestData.progressCallback;

    var validationTestData = new ValidationTestData();
    nonObject_ = validationTestData.getNonObject();
    emptyObject_ = validationTestData.getEmptyObject();
    nonNumber_ = validationTestData.getNonNumber();
    nonPositiveNumber_ = validationTestData.getNonPositiveNumber();
    nonString_ = validationTestData.getNonString();
    nonFunction_ = validationTestData.getNonFunction();
    nonAuxiliaryData_ = validationTestData.getNonAuxiliaryData();
    nonProofObject_ = validationTestData.getNonProofObject();

    proofHandler_ =
        proofService_.newSimplePlaintextEqualityProofHandler(group_).init(
            primaryPublicKey_, secondaryPublicKey_);
    proof_ = proofHandler_.generate(
        secret_, primaryCiphertext_, secondaryCiphertext_);
  });

  beforeEach(function() {
    proofHandler_ =
        proofService_.newSimplePlaintextEqualityProofHandler(group_).init(
            primaryPublicKey_, secondaryPublicKey_);
  });

  describe('create a zero-knowledge proof service that should be able to ..', function() {
    describe('create a simple plaintext equality proof handler that should be able to', function() {
      it('throw an error when being created, using invalid input data',
         function() {
           expect(function() {
             proofService_.newSimplePlaintextEqualityProofHandler();
           }).toThrow();

           expect(function() {
             proofService_.newSimplePlaintextEqualityProofHandler(undefined);
           }).toThrow();

           expect(function() {
             proofService_.newSimplePlaintextEqualityProofHandler(null);
           }).toThrow();

           expect(function() {
             proofService_.newSimplePlaintextEqualityProofHandler(nonObject_);
           }).toThrow();

           expect(function() {
             proofService_.newSimplePlaintextEqualityProofHandler(emptyObject_);
           }).toThrow();
         });

      it('throw an error when being initialized, using an invalid primary public key',
         function() {
           expect(function() {
             proofHandler_.init(undefined, secondaryPublicKey_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(null, secondaryPublicKey_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(nonObject_, secondaryPublicKey_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(emptyObject_, secondaryPublicKey_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(
                 primaryPublicKeyWithLessElements_, secondaryPublicKey_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(
                 primaryPublicKeyFromAnotherGroup_, secondaryPublicKey_);
           }).toThrow();
         });

      it('throw an error when being initialized, using an invalid secondary public key',
         function() {
           expect(function() {
             proofHandler_.init(primaryPublicKey_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(primaryPublicKey_, undefined);
           }).toThrow();

           expect(function() {
             proofHandler_.init(primaryPublicKey_, null);
           }).toThrow();

           expect(function() {
             proofHandler_.init(primaryPublicKey_, nonObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(primaryPublicKey_, emptyObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.init(
                 primaryPublicKey_, secondaryPublicKeyFromAnotherGroup_);
           }).toThrow();
         });

      it('throw an error when generating a simple plaintext equality proof, using an invalid secret',
         function() {
           expect(function() {
             proofHandler_.generate(
                 undefined, primaryCiphertext_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 null, primaryCiphertext_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 nonObject_, primaryCiphertext_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 emptyObject_, primaryCiphertext_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secretFromAnotherGroup_, primaryCiphertext_,
                 secondaryCiphertext_);
           }).toThrow();
         });

      it('throw an error when generating a simple plaintext equality proof, using an invalid primary ciphertext',
         function() {
           expect(function() {
             proofHandler_.generate(secret_, undefined, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, null, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, nonObject_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, emptyObject_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, primaryCiphertextWithLessElements_,
                 secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, primaryCiphertextFromAnotherGroup_,
                 secondaryCiphertext_);
           }).toThrow();
         });

      it('throw an error when generating a simple plaintext equality proof, using an invalid secondary ciphertext',
         function() {
           expect(function() {
             proofHandler_.generate(secret_, primaryCiphertext_, undefined);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, primaryCiphertext_, null);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, primaryCiphertext_, nonObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(secret_, primaryCiphertext_, emptyObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, primaryCiphertext_,
                 secondaryCiphertextWithLessElements_);
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, primaryCiphertext_,
                 secondaryCiphertextFromAnotherGroup_);
           }).toThrow();
         });

      it('throw an error when generating a simple plaintext equality proof, using invalid optional data',
         function() {
           expect(function() {
             proofHandler_.generate(
                 secret_, primaryCiphertext_, secondaryCiphertext_,
                 {data: nonAuxiliaryData_});
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, primaryCiphertext_, secondaryCiphertext_,
                 {preComputation: nonObject_});
           }).toThrow();

           expect(function() {
             proofHandler_.generate(
                 secret_, primaryCiphertext_, secondaryCiphertext_,
                 {preComputation: nonProofObject_});
           }).toThrow();
         });

      it('throw an error when verifying a simple plaintext equality proof, using an invalid proof',
         function() {
           expect(function() {
             proofHandler_.verify(
                 undefined, primaryCiphertext_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 null, primaryCiphertext_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 nonProofObject_, primaryCiphertext_, secondaryCiphertext_);
           }).toThrow();
         });

      it('throw an error when verifying a simple plaintext equality proof, using an invalid primary ciphertext',
         function() {
           expect(function() {
             proofHandler_.verify(proof_, undefined, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, null, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, nonObject_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, emptyObject_, secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 proof_, primaryCiphertextWithLessElements_,
                 secondaryCiphertext_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 proof_, primaryCiphertextFromAnotherGroup_,
                 secondaryCiphertext_);
           }).toThrow();
         });

      it('throw an error when verifying a simple plaintext equality proof, using an invalid secondary ciphertext',
         function() {
           expect(function() {
             proofHandler_.verify(proof_, primaryCiphertext_, undefined);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, primaryCiphertext_, null);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, primaryCiphertext_, nonObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(proof_, primaryCiphertext_, emptyObject_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 proof_, primaryCiphertext_,
                 secondaryCiphertextWithLessElements_);
           }).toThrow();

           expect(function() {
             proofHandler_.verify(
                 proof_, primaryCiphertext_,
                 secondaryCiphertextFromAnotherGroup_);
           }).toThrow();
         });

      it('throw an error when verifying a simple plaintext equality proof, using invalid optional data',
         function() {
           expect(function() {
             proofHandler_.verify(
                 proof_, primaryCiphertext_, secondaryCiphertext_,
                 {data: nonAuxiliaryData_});
           }).toThrow();
         });

      it('throw an error when measuring simple plaintext equality proof proof progress, using invalid input data',
         function() {
           expect(function() {
             proofHandler_.measureProgress();
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(undefined);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(null);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(nonFunction_);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(callback_, null);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(callback_, nonNumber_);
           }).toThrow();

           expect(function() {
             proofHandler_.measureProgress(callback_, nonPositiveNumber_);
           }).toThrow();
         });
    });
  });
});
