package profiling;

import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.mixer.proofs.concrete.Mix2nizk;
import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Voting;
import meerkat.mixer.Utils;
import org.spongycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.RandomOracle;
import org.factcenter.qilin.primitives.concrete.DigestOracle;
import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup;

import java.math.BigInteger;
import java.util.Random;

/**
 * Created by Tzlil on 1/20/2016.
 */
public class ZeroKnowledgeProof {

    Random rand;
    ECElGamal.SK key;
    ECGroup group;
    ECElGamalEncryption enc;
    ConcreteCrypto.ElGamalPublicKey serializedPk;
    meerkat.mixer.proofs.Mix2nizk.Prover prover ;
    int n;
    Crypto.EncryptionRandomness[] randomnesses;
    Crypto.RerandomizableEncryptedMessage[] encryptedMessage;
    Crypto.RerandomizableEncryptedMessage[] reencryptedMessage;

    public void setup() throws Exception {
        rand = new Random(1);
        group = new ECGroup("secp256k1");
        BigInteger sk = ECElGamal.generateSecretKey(group, rand);
        key = new ECElGamal.SK(group, sk);
        serializedPk = Util.encodePK(group, key);
        enc = new ECElGamalEncryption();
        enc.init(serializedPk);
        prover = new Mix2nizk(rand,enc);
        int LogVotes = 12;
        int layers = 2*LogVotes - 1;
        n = layers * (1<<LogVotes) / 2;
        randomnesses = new Crypto.EncryptionRandomness[n*2];
        encryptedMessage = new Crypto.RerandomizableEncryptedMessage[n*2];
        reencryptedMessage = new Crypto.RerandomizableEncryptedMessage[n*2];

        Voting.PlaintextBallot msg;


        for (int i = 0; i < n*2 ; i ++){
            msg = Utils.genRandomBallot(2,3,16);
            randomnesses[i] = enc.generateRandomness(rand);
            encryptedMessage[i] = enc.encrypt(msg, enc.generateRandomness(rand));
            reencryptedMessage[i] = enc.rerandomize(encryptedMessage[i], randomnesses[i]);
        }
    }

    private ECPoint convert2ECPoint(ByteString bs){
        return group.decode(bs.toByteArray());
    }

    public void zeroKnowledgeProofTest() throws InvalidProtocolBufferException {

        System.out.println("Prove");
        System.out.println("n is : " + n);
        System.out.println("start n proves");
        long startTime = System.currentTimeMillis();

        for (int i = 0; i < n*2 ; i +=2){
            prover.prove(encryptedMessage[i],encryptedMessage[i+1],reencryptedMessage[i],reencryptedMessage[i+1],
                    false,0,0,0, 0, randomnesses[i],randomnesses[i+1]);
        }

        long finishTime = System.currentTimeMillis();
        System.out.println("    that took: "+(finishTime-startTime)+ " ms");
        System.out.println("    avg of"+((double)(finishTime-startTime))/n + " ms");
    }
}
