package meerkat.mixer.proofs.concrete;

import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.mixer.proofs.generic.SigmaProtocolOr2;
import meerkat.protobuf.Mixing;
import org.factcenter.qilin.primitives.concrete.ECGroup;

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

/**
 * Sigma protocol for proving correctness of a 2x2 switch
 */
public class Mix2 {
    public static class ChallengeGenerator implements SigmaProtocolOr2.ChallengeGenerator {
        ECElGamalEncryption encryptor;
        ECGroup group;
        Random rand;

        public ChallengeGenerator(ECElGamalEncryption encryptor, Random rand) {
            this.encryptor = encryptor;
            this.rand = rand;
            group = encryptor.getGroup();
        }

        @Override
        public BigInteger generateChallenge() { return encryptor.generateRandomExponent(rand); }

        @Override
        public BigInteger subtractChallenge(BigInteger c1, BigInteger c2) { return c1.subtract(c2).mod(group.orderUpperBound()); }
    }

    public static class Prover extends SigmaProtocolOr2.Prover<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
        public Prover(ECElGamalEncryption encryptor, Random rand, Statements.Mix2Statement statement, Statements.Mix2StatementWitness witness) {
            super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, new ChallengeGenerator(encryptor, rand),
                    new DlogConjunction.Prover(encryptor, rand, statement.clauses[witness.trueClauseIndex], witness.witness),
                    new DlogConjunction.Simulator(encryptor, rand, statement.clauses[1 - witness.trueClauseIndex]),
                    witness.trueClauseIndex);
        }
    }

    public static class Verifier extends SigmaProtocolOr2.Verifier<Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.FinalMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
        public Verifier(ECElGamalEncryption encryptor, Statements.Mix2Statement statement) {
            super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, new ChallengeGenerator(encryptor, null),
                    new DlogConjunction.Verifier(encryptor, statement.clauses[0]), new DlogConjunction.Verifier(encryptor, statement.clauses[1]));
        }
    }
}
