From a5cceaa6c03c29064ca724817c98df6af18802a2 Mon Sep 17 00:00:00 2001 From: Tal Moran Date: Thu, 12 Jan 2017 11:05:38 +0200 Subject: [PATCH] Writing tests for new ZKPs --- .../mixnet/Mix2ZeroKnowledgeProver.java | 2 +- .../mixnet/Mix2ZeroKnowledgeVerifier.java | 2 +- .../meerkat/crypto/mixnet/MixerOutput.java | 2 +- .../meerkat/mixer/main/BatchConverter.java | 8 +- .../main/java/meerkat/mixer/mixing/Mixer.java | 8 +- .../meerkat/mixer/mixing/MixerOutput.java | 10 +- .../meerkat/mixer/proofs/Concatenator.java | 21 ++ .../mixer/proofs/ECElGamalMixParams.java | 10 +- .../mixer/proofs/ECElGamalMixProtocols.java | 233 +++--------- .../mixer/proofs/ProtobufConcatenators.java | 107 ++++++ .../java/meerkat/mixer/proofs/Prover.java | 345 +++++++++--------- .../meerkat/mixer/proofs/SigmaFiatShamir.java | 42 +++ .../meerkat/mixer/proofs/SigmaProtocol.java | 28 +- .../mixer/proofs/SigmaProtocolAnd.java | 91 ----- .../mixer/proofs/SigmaProtocolAnd2.java | 87 +++++ .../mixer/proofs/SigmaProtocolOr2.java | 87 +++-- .../java/meerkat/mixer/proofs/Verifier.java | 89 +---- .../meerkat/mixer/proofs/VerifyTable.java | 10 +- .../proofs/ZeroKnowledgeOrProofParser.java | 142 +++---- .../java/meerkat/mixer/CreateTestVector.java | 6 +- .../java/meerkat/mixer/ECParamTestBase.java | 44 +++ ...ledgeProofTest.java => Mix2ProofTest.java} | 20 +- .../test/java/meerkat/mixer/MixingTest.java | 24 +- .../mixer/proofs/AndStatementSigmaTest.java | 52 +++ .../proofs/DlogStatementSchnorrSigmaTest.java | 86 +++++ .../meerkat/mixer/proofs/NIZKContainers.java | 13 + .../mixer/proofs/SigmaProtocolTest.java | 116 ++++++ 27 files changed, 997 insertions(+), 688 deletions(-) create mode 100644 mixer/src/main/java/meerkat/mixer/proofs/Concatenator.java create mode 100644 mixer/src/main/java/meerkat/mixer/proofs/ProtobufConcatenators.java create mode 100644 mixer/src/main/java/meerkat/mixer/proofs/SigmaFiatShamir.java delete mode 100644 mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd.java create mode 100644 mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd2.java create mode 100644 mixer/src/test/java/meerkat/mixer/ECParamTestBase.java rename mixer/src/test/java/meerkat/mixer/{ZeroKnowledgeProofTest.java => Mix2ProofTest.java} (85%) create mode 100644 mixer/src/test/java/meerkat/mixer/proofs/AndStatementSigmaTest.java create mode 100644 mixer/src/test/java/meerkat/mixer/proofs/DlogStatementSchnorrSigmaTest.java create mode 100644 mixer/src/test/java/meerkat/mixer/proofs/NIZKContainers.java create mode 100644 mixer/src/test/java/meerkat/mixer/proofs/SigmaProtocolTest.java diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java index 487483e..70f611f 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeProver.java @@ -8,7 +8,7 @@ import meerkat.protobuf.Mixing; * Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts. */ public interface Mix2ZeroKnowledgeProver { - public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1, + public Mixing.Mix2Proof prove(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java index f98f0ac..45bf692 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/Mix2ZeroKnowledgeVerifier.java @@ -20,5 +20,5 @@ public interface Mix2ZeroKnowledgeVerifier { Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, - Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException; + Mixing.Mix2Proof proof) throws InvalidProtocolBufferException; } diff --git a/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java b/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java index eb71e61..1de10f5 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java +++ b/meerkat-common/src/main/java/meerkat/crypto/mixnet/MixerOutput.java @@ -7,7 +7,7 @@ import meerkat.protobuf.Mixing; * Created by Tzlil on 1/18/2016. */ public interface MixerOutput { - public Mixing.ZeroKnowledgeProof[][] getProofs(); + public Mixing.Mix2Proof[][] getProofs(); public Crypto.RerandomizableEncryptedMessage[][] getEncryptedMessages(); public int getN(); } diff --git a/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java b/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java index 1ad8204..ea3580d 100644 --- a/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java +++ b/mixer/src/main/java/meerkat/mixer/main/BatchConverter.java @@ -59,8 +59,8 @@ public class BatchConverter { .setData(Integer2ByteString(n)) .build()); - for (Mixing.ZeroKnowledgeProof[] zkpLayer : mixerOutput.getProofs()) { - for (Mixing.ZeroKnowledgeProof zkp : zkpLayer) { + for (Mixing.Mix2Proof[] zkpLayer : mixerOutput.getProofs()) { + for (Mixing.Mix2Proof zkp : zkpLayer) { result.add(BulletinBoardAPI.BatchChunk.newBuilder() .setData(zkp.toByteString()) .build()); @@ -90,12 +90,12 @@ public class BatchConverter { } int nDiv2 = n >>1; - Mixing.ZeroKnowledgeProof[][] proofs = new Mixing.ZeroKnowledgeProof[layers][nDiv2]; + Mixing.Mix2Proof[][] proofs = new Mixing.Mix2Proof[layers][nDiv2]; for (int layer = 0; layer < layers; layer++) { for (int proofIndex = 0 ; proofIndex < nDiv2 ; proofIndex ++) { - proofs[layer][proofIndex] = Mixing.ZeroKnowledgeProof.parseFrom(batchChunkList.remove(0).getData()); + proofs[layer][proofIndex] = Mixing.Mix2Proof.parseFrom(batchChunkList.remove(0).getData()); } } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java b/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java index fbe091c..a304e2f 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/Mixer.java @@ -6,7 +6,7 @@ import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.MixerOutput; import meerkat.protobuf.Crypto.EncryptionRandomness; import meerkat.protobuf.Crypto.RerandomizableEncryptedMessage; -import meerkat.protobuf.Mixing.ZeroKnowledgeProof; +import meerkat.protobuf.Mixing.Mix2Proof; import java.util.List; import java.util.Random; @@ -135,14 +135,14 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { * @return zero knowledge proofs table * @throws InvalidProtocolBufferException */ - private ZeroKnowledgeProof[][] generateZeroKnowledgeProofTable(int n, int layers, MixNetwork mixNetwork + private Mix2Proof[][] generateMix2ProofTable(int n, int layers, MixNetwork mixNetwork , RerandomizableEncryptedMessage[][] encryptionTable , EncryptionRandomness[][] randomnesses) throws InvalidProtocolBufferException { Switch[] switchesLayer; int index1,index2; int switchIndex = 0; int nDiv2 = n >> 1; - ZeroKnowledgeProof[][] proofsTable = new ZeroKnowledgeProof[layers][nDiv2]; + Mix2Proof[][] proofsTable = new Mix2Proof[layers][nDiv2]; RerandomizableEncryptedMessage e1,e2; EncryptionRandomness r1,r2; @@ -185,7 +185,7 @@ public class Mixer implements meerkat.crypto.mixnet.Mixer { EncryptionRandomness[][] randomnesses = generateRandomnessesForRerandomize(n,layers,random); MixNetwork mixNetwork = generateMixNetwork(n,random); rerandomize(layers,mixNetwork,encryptionTable,randomnesses); - ZeroKnowledgeProof[][] proofsTable = generateZeroKnowledgeProofTable(n,layers,mixNetwork,encryptionTable,randomnesses); + Mix2Proof[][] proofsTable = generateMix2ProofTable(n,layers,mixNetwork,encryptionTable,randomnesses); return new meerkat.mixer.mixing.MixerOutput(n,layers,proofsTable, encryptionTable); } diff --git a/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java b/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java index 64636cc..eef60a4 100644 --- a/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java +++ b/mixer/src/main/java/meerkat/mixer/mixing/MixerOutput.java @@ -14,7 +14,7 @@ import java.io.IOException; * container for meerkat.mixer.mixing.mix result. */ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ - private final Mixing.ZeroKnowledgeProof[][] proofs; + private final Mixing.Mix2Proof[][] proofs; private final Crypto.RerandomizableEncryptedMessage[][] encryptedMessages; private final int n; private final int layers; @@ -27,7 +27,7 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ * at each other level contains the re encrypted votes * @param proofs in each cell (level,switch) contains the match zero knowledge proof */ - public MixerOutput(int n,int layers,Mixing.ZeroKnowledgeProof[][] proofs + public MixerOutput(int n,int layers,Mixing.Mix2Proof[][] proofs , Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) { this.proofs = proofs; this.encryptedMessages = encryptedMessages; @@ -38,7 +38,7 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ @Override - public Mixing.ZeroKnowledgeProof[][] getProofs() { + public Mixing.Mix2Proof[][] getProofs() { return proofs; } @@ -91,8 +91,8 @@ public class MixerOutput implements meerkat.crypto.mixnet.MixerOutput{ * @param proof * @throws IOException */ - private void writeProofToFile(String proofsDir, Mixing.ZeroKnowledgeProof proof) throws IOException { - Mixing.ZeroKnowledgeProof.Location location = proof.getLocation(); + private void writeProofToFile(String proofsDir, Mixing.Mix2Proof proof) throws IOException { + Mixing.Mix2Proof.Location location = proof.getLocation(); int layer = location.getLayer(); int i = location.getI(); int j = location.getJ(); diff --git a/mixer/src/main/java/meerkat/mixer/proofs/Concatenator.java b/mixer/src/main/java/meerkat/mixer/proofs/Concatenator.java new file mode 100644 index 0000000..470fced --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/proofs/Concatenator.java @@ -0,0 +1,21 @@ +package meerkat.mixer.proofs; + +/** + * Created by talm on 11/01/17. + */ + + +public interface Concatenator { + public interface Pair{ + public OutType concatenate(InType1 msg1, InType2 msg2); + public InType1 getMsg1(OutType msg); + public InType2 getMsg2(OutType msg); + } + + public interface Triplet{ + public OutType concatenate(InType1 msg1, InType2 msg2, InType3 msg3); + public InType1 getMsg1of3(OutType msg); + public InType2 getMsg2of3(OutType msg); + public InType3 getMsg3of3(OutType msg); + } +} diff --git a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java b/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java index 56c02d6..273d435 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java @@ -91,7 +91,7 @@ public class ECElGamalMixParams { public final AndStatement[] clauses = new AndStatement[2]; - private Mix2Statement(ElGamalCiphertext a, ElGamalCiphertext b, + Mix2Statement(ElGamalCiphertext a, ElGamalCiphertext b, ElGamalCiphertext c, ElGamalCiphertext d){ ECPoint a1 = encryptor.decodeElement(a.getC1()); @@ -137,7 +137,7 @@ public class ECElGamalMixParams { public final AndStatementWitness witness; - private Mix2StatementWitness(int trueClauseIndex, AndStatementWitness witness) { + Mix2StatementWitness(int trueClauseIndex, AndStatementWitness witness) { this.trueClauseIndex = trueClauseIndex; assert (trueClauseIndex >= 0 && trueClauseIndex < 2); @@ -152,7 +152,7 @@ public class ECElGamalMixParams { public class AndStatement { public final DlogStatement[] clauses = new DlogStatement[2]; - private AndStatement(DlogStatement clause0, DlogStatement clause1) { + AndStatement(DlogStatement clause0, DlogStatement clause1) { this.clauses[0] = clause0; this.clauses[1] = clause1; } @@ -161,7 +161,7 @@ public class ECElGamalMixParams { public class AndStatementWitness { public final DlogStatementWitness[] witnesses = new DlogStatementWitness[2]; - private AndStatementWitness(DlogStatementWitness witness0, DlogStatementWitness witness1) { + AndStatementWitness(DlogStatementWitness witness0, DlogStatementWitness witness1) { this.witnesses[0] = witness0; this.witnesses[1] = witness1; } @@ -179,7 +179,7 @@ public class ECElGamalMixParams { public final ECPoint b; - private DlogStatement(ECPoint a, ECPoint b) { + DlogStatement(ECPoint a, ECPoint b) { this.g = ECElGamalMixParams.this.g; this.a = a; this.h = ECElGamalMixParams.this.h; diff --git a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixProtocols.java b/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixProtocols.java index b657cfb..bfebbc8 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixProtocols.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixProtocols.java @@ -1,18 +1,18 @@ package meerkat.mixer.proofs; -import com.google.protobuf.Message; import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.concrete.Util; -import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto.GroupElement; -import meerkat.protobuf.Crypto; -import meerkat.protobuf.Mixing; +import meerkat.protobuf.Mixing.Mix2Proof.AndProof; +import meerkat.protobuf.Mixing.Mix2Proof.DlogProof; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.concrete.ECGroup; import java.math.BigInteger; import java.util.Random; +import static meerkat.protobuf.Mixing.Mix2Proof.DlogProof.*; + /** * Prover, Simulator and Verifier */ @@ -25,6 +25,8 @@ public class ECElGamalMixProtocols { final Random rand; + final ChallengeGenerator challengeGenerator = new ChallengeGenerator(); + public ECElGamalMixProtocols(ECElGamalMixParams params, Random rand) { this.params = params; this.rand = rand; @@ -34,8 +36,16 @@ public class ECElGamalMixProtocols { h = params.h; } + public class ChallengeGenerator implements SigmaProtocolOr2.ChallengeGenerator { + @Override + public BigInteger generateChallenge() { return encryptor.generateRandomExponent(rand); } - public class DlogStatementSchnorrProver implements SigmaProtocol.Prover { + @Override + public BigInteger subtractChallenge(BigInteger c1, BigInteger c2) { return c1.subtract(c2).mod(group.orderUpperBound()); } + } + + + public class DlogStatementSchnorrProver implements SigmaProtocol.Prover { ECElGamalMixParams.DlogStatement statement; ECElGamalMixParams.DlogStatementWitness witness; @@ -47,12 +57,12 @@ public class ECElGamalMixProtocols { } @Override - public Mixing.Mix2Proof.DlogProof.FirstMessage getFirstMessage() { + public FirstMessage getFirstMessage() { r = encryptor.generateRandomExponent(rand); ECPoint gr = group.multiply(statement.g, r); ECPoint hr = group.multiply(statement.h, r); - Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage = Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder() + FirstMessage firstMessage = FirstMessage.newBuilder() .setGr(encryptor.encodeElement(gr)) .setHr(encryptor.encodeElement(hr)) .build(); @@ -61,12 +71,17 @@ public class ECElGamalMixProtocols { } @Override - public Crypto.BigInteger getFinalMessage(BigInteger challenge) { - return Util.encodeBigInteger(challenge.multiply(witness.x).add(r).mod(group.orderUpperBound())); + public FinalMessage getFinalMessage(BigInteger challenge) { + return FinalMessage.newBuilder() + .setXcr(Util.encodeBigInteger(challenge.multiply(witness.x).add(r).mod(group.orderUpperBound()))) + .build(); } + + @Override + public void reset() { r = null; } } - public class DlogStatementSchnorrVerifier implements SigmaProtocol.Verifier { + public class DlogStatementSchnorrVerifier implements SigmaProtocol.Verifier { final ECElGamalMixParams.DlogStatement statement; public DlogStatementSchnorrVerifier(ECElGamalMixParams.DlogStatement statement) { @@ -74,20 +89,13 @@ public class ECElGamalMixProtocols { } @Override - public boolean verify(Message firstMessage, BigInteger challenge, Message finalMessage) { - assert(firstMessage instanceof Mixing.Mix2Proof.DlogProof.FirstMessage && - finalMessage instanceof Mixing.Mix2Proof.DlogProof.FinalMessage); - return verify((Mixing.Mix2Proof.DlogProof.FirstMessage) firstMessage, challenge, - (Mixing.Mix2Proof.DlogProof.FinalMessage) finalMessage); - } - - public boolean verify(Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage, BigInteger challenge, - Mixing.Mix2Proof.DlogProof.FinalMessage finalMessage) { + public boolean verify(FirstMessage firstMessage, BigInteger challenge, + FinalMessage finalMessage) { GroupElement grEncoded = firstMessage.getGr(); - ECPoint gr = group.decode(grEncoded.toByteArray()); + ECPoint gr = encryptor.decodeElement(grEncoded); GroupElement hrEncoded = firstMessage.getHr(); - ECPoint hr = group.decode(hrEncoded.toByteArray()); + ECPoint hr = encryptor.decodeElement(hrEncoded); BigInteger xcr = Util.decodeBigInteger(finalMessage.getXcr()); @@ -98,7 +106,7 @@ public class ECElGamalMixProtocols { } - public class DlogStatementSchnorrSimulator implements SigmaProtocol.Simulator { + public class DlogStatementSchnorrSimulator implements SigmaProtocol.Simulator { ECElGamalMixParams.DlogStatement statement; BigInteger response = null; @@ -107,190 +115,69 @@ public class ECElGamalMixProtocols { } @Override - public Mixing.Mix2Proof.DlogProof.FirstMessage getFirstMessage(BigInteger challenge) { + public FirstMessage getFirstMessage(BigInteger challenge) { response = encryptor.generateRandomExponent(rand); ECPoint u = group.multiply(statement.g, response).subtract(group.multiply(statement.a,challenge)); ECPoint v = group.multiply(statement.h, response).subtract(group.multiply(statement.b,challenge)); - return Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder() + return FirstMessage.newBuilder() .setGr(encryptor.encodeElement(u)) .setHr(encryptor.encodeElement(v)) .build(); } @Override - public Crypto.BigInteger getFinalMessage() { - return Util.encodeBigInteger(response); + public FinalMessage getFinalMessage() { + + return FinalMessage.newBuilder() + .setXcr(Util.encodeBigInteger(response)) + .build(); } + + @Override + public void reset() { response = null; } } /** * Prover for plaintext equivalence of a pair of ciphertexts. */ - public class CiphertextPairEquivalenceProver extends SigmaProtocolAnd.Prover { - public CiphertextPairEquivalenceProver(ECElGamalMixParams.AndStatement statement, - ECElGamalMixParams.AndStatementWitness witness) { - super(new DlogStatementSchnorrProver(statement.clauses[0], witness.witnesses[0]), + public class AndStatementProver + extends SigmaProtocolAnd2.Prover { + public AndStatementProver(ECElGamalMixParams.AndStatement statement, + ECElGamalMixParams.AndStatementWitness witness) { + super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, new DlogStatementSchnorrProver(statement.clauses[0], witness.witnesses[0]), new DlogStatementSchnorrProver(statement.clauses[1], witness.witnesses[1])); } + } - @Override - protected Mixing.Mix2Proof.AndProof.FirstMessage buildConcatenatedFirstMessage(Message... firstMessages) { - assert (firstMessages.length == 2); - assert (firstMessages[0] instanceof Mixing.Mix2Proof.DlogProof.FirstMessage && - firstMessages[1] instanceof Mixing.Mix2Proof.DlogProof.FirstMessage); - - return Mixing.Mix2Proof.AndProof.FirstMessage.newBuilder() - .setClause0((Mixing.Mix2Proof.DlogProof.FirstMessage)firstMessages[0]) - .setClause1((Mixing.Mix2Proof.DlogProof.FirstMessage)firstMessages[1]) - .build(); - } - - @Override - protected Mixing.Mix2Proof.AndProof.FinalMessage buildConcatenatedFinalMessage(Message... finalMessages) { - assert(finalMessages.length == 2); - assert (finalMessages[0] instanceof Mixing.Mix2Proof.DlogProof.FinalMessage && - finalMessages[1] instanceof Mixing.Mix2Proof.DlogProof.FinalMessage); - - return Mixing.Mix2Proof.AndProof.FinalMessage.newBuilder() - .setClause0((Mixing.Mix2Proof.DlogProof.FinalMessage)finalMessages[0]) - .setClause1((Mixing.Mix2Proof.DlogProof.FinalMessage)finalMessages[1]) - .build(); + public class AndStatementVerifier + extends SigmaProtocolAnd2.Verifier { + public AndStatementVerifier(ECElGamalMixParams.AndStatement statement) { + super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, + new DlogStatementSchnorrVerifier(statement.clauses[0]), new DlogStatementSchnorrVerifier(statement.clauses[1])); } } - public class CiphertextPairEquivalenceVerifier extends SigmaProtocolAnd.Verifier { - public CiphertextPairEquivalenceVerifier(ECElGamalMixParams.AndStatement statement) { - super(new DlogStatementSchnorrVerifier(statement.clauses[0]), new DlogStatementSchnorrVerifier(statement.clauses[1])); - } - - @Override - protected Mixing.Mix2Proof.DlogProof.FirstMessage getFirstMessage(Message concatenated, int verifier) { - assert(concatenated instanceof Mixing.Mix2Proof.AndProof.FirstMessage); - Mixing.Mix2Proof.AndProof.FirstMessage msg = (Mixing.Mix2Proof.AndProof.FirstMessage) concatenated; - if (verifier == 0) - return msg.getClause0(); - else - return msg.getClause1(); - } - - @Override - protected Mixing.Mix2Proof.DlogProof.FinalMessage getFinalMessage(Message concatenated, int verifier) { - assert(concatenated instanceof Mixing.Mix2Proof.AndProof.FinalMessage); - Mixing.Mix2Proof.AndProof.FinalMessage msg = (Mixing.Mix2Proof.AndProof.FinalMessage) concatenated; - if (verifier == 0) - return msg.getClause0(); - else - return msg.getClause1(); - } - } - - public class CiphertextPairEquivalenceSimulator extends SigmaProtocolAnd.Simulator { - public CiphertextPairEquivalenceSimulator(ECElGamalMixParams.AndStatement statement) { - super(new DlogStatementSchnorrSimulator(statement.clauses[0]), new DlogStatementSchnorrSimulator(statement.clauses[1])); - } - - @Override - protected Mixing.Mix2Proof.AndProof.FirstMessage buildConcatenatedFirstMessage(Message... firstMessages) { - assert (firstMessages.length == 2); - assert (firstMessages[0] instanceof Mixing.Mix2Proof.DlogProof.FirstMessage && - firstMessages[1] instanceof Mixing.Mix2Proof.DlogProof.FirstMessage); - - return Mixing.Mix2Proof.AndProof.FirstMessage.newBuilder() - .setClause0((Mixing.Mix2Proof.DlogProof.FirstMessage)firstMessages[0]) - .setClause1((Mixing.Mix2Proof.DlogProof.FirstMessage)firstMessages[1]) - .build(); - } - - @Override - protected Mixing.Mix2Proof.AndProof.FinalMessage buildConcatenatedFinalMessage(Message... finalMessages) { - assert(finalMessages.length == 2); - assert (finalMessages[0] instanceof Mixing.Mix2Proof.DlogProof.FinalMessage && - finalMessages[1] instanceof Mixing.Mix2Proof.DlogProof.FinalMessage); - - return Mixing.Mix2Proof.AndProof.FinalMessage.newBuilder() - .setClause0((Mixing.Mix2Proof.DlogProof.FinalMessage)finalMessages[0]) - .setClause1((Mixing.Mix2Proof.DlogProof.FinalMessage)finalMessages[1]) - .build(); + public class AndStatementSimulator extends SigmaProtocolAnd2.Simulator { + public AndStatementSimulator(ECElGamalMixParams.AndStatement statement) { + super(ProtobufConcatenators.concatAnd1, ProtobufConcatenators.concatAnd2, + new DlogStatementSchnorrSimulator(statement.clauses[0]), new DlogStatementSchnorrSimulator(statement.clauses[1])); } } public class Mix2Prover extends SigmaProtocolOr2.Prover { public Mix2Prover(ECElGamalMixParams.Mix2Statement statement, ECElGamalMixParams.Mix2StatementWitness witness) { - super(new CiphertextPairEquivalenceProver(statement.clauses[witness.trueClauseIndex], witness.witness), - new CiphertextPairEquivalenceSimulator(statement.clauses[1 - witness.trueClauseIndex]), + super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, ECElGamalMixProtocols.this.challengeGenerator, + new AndStatementProver(statement.clauses[witness.trueClauseIndex], witness.witness), + new AndStatementSimulator(statement.clauses[1 - witness.trueClauseIndex]), witness.trueClauseIndex); } - - @Override - protected Mixing.Mix2Proof.FirstMessage buildConcatenatedFirstMessage(Message... firstMessages) { - assert(firstMessages.length == 2); - - assert (firstMessages[0] instanceof Mixing.Mix2Proof.AndProof.FirstMessage && - firstMessages[1] instanceof Mixing.Mix2Proof.AndProof.FirstMessage); - - return Mixing.Mix2Proof.FirstMessage.newBuilder() - .setClause0((Mixing.Mix2Proof.AndProof.FirstMessage)firstMessages[0]) - .setClause1((Mixing.Mix2Proof.AndProof.FirstMessage)firstMessages[1]) - .build(); - } - - @Override - protected Mixing.Mix2Proof.FinalMessage buildConcatenatedFinalMessage(BigInteger firstChallenge, - Message... finalMessages) { - assert(finalMessages.length == 2); - assert (finalMessages[0] instanceof Mixing.Mix2Proof.AndProof.FinalMessage && - finalMessages[1] instanceof Mixing.Mix2Proof.AndProof.FinalMessage); - - return Mixing.Mix2Proof.FinalMessage.newBuilder() - .setClause0((Mixing.Mix2Proof.AndProof.FinalMessage)finalMessages[0]) - .setClause1((Mixing.Mix2Proof.AndProof.FinalMessage)finalMessages[1]) - .setC0(Util.encodeBigInteger(firstChallenge)) - .build(); - } - - @Override - protected BigInteger generateChallenge() { - return encryptor.generateRandomExponent(rand); - } - - @Override - protected BigInteger subtractChallenge(BigInteger c1, BigInteger c2) { - return c1.subtract(c2).mod(group.orderUpperBound()); - } } public class Mix2Verifier extends SigmaProtocolOr2.Verifier { public Mix2Verifier(ECElGamalMixParams.Mix2Statement statement) { - super(new CiphertextPairEquivalenceVerifier(statement.clauses[0]), new CiphertextPairEquivalenceVerifier(statement.clauses[1])); - } - - @Override - protected Mixing.Mix2Proof.AndProof.FirstMessage getFirstMessage(Message concatenated, int verifier) { - assert(concatenated instanceof Mixing.Mix2Proof.FirstMessage); - Mixing.Mix2Proof.FirstMessage msg = (Mixing.Mix2Proof.FirstMessage) concatenated; - if (verifier == 0) - return msg.getClause0(); - else - return msg.getClause1(); - } - - @Override - protected BigInteger getFirstChallenge(Message concatenated) { - assert(concatenated instanceof Mixing.Mix2Proof.FinalMessage); - Mixing.Mix2Proof.FinalMessage msg = (Mixing.Mix2Proof.FinalMessage) concatenated; - - return Util.decodeBigInteger(msg.getC0()); - } - - @Override - protected Mixing.Mix2Proof.AndProof.FinalMessage getFinalMessage(Message concatenated, int verifier) { - assert(concatenated instanceof Mixing.Mix2Proof.FinalMessage); - Mixing.Mix2Proof.FinalMessage msg = (Mixing.Mix2Proof.FinalMessage) concatenated; - if (verifier == 0) - return msg.getClause0(); - else - return msg.getClause1(); + super(ProtobufConcatenators.concatMix1, ProtobufConcatenators.concatMix2, ECElGamalMixProtocols.this.challengeGenerator, + new AndStatementVerifier(statement.clauses[0]), new AndStatementVerifier(statement.clauses[1])); } } } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/ProtobufConcatenators.java b/mixer/src/main/java/meerkat/mixer/proofs/ProtobufConcatenators.java new file mode 100644 index 0000000..98c74ef --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/proofs/ProtobufConcatenators.java @@ -0,0 +1,107 @@ +package meerkat.mixer.proofs; + +import meerkat.crypto.concrete.Util; +import meerkat.protobuf.Mixing; + +import java.math.BigInteger; + +/** + * Created by talm on 12/01/17. + */ +public class ProtobufConcatenators { + public final static ConcatAnd1 concatAnd1 = new ConcatAnd1(); + public final static ConcatAnd2 concatAnd2 = new ConcatAnd2(); + public final static ConcatMix1 concatMix1 = new ConcatMix1(); + public final static ConcatMix2 concatMix2 = new ConcatMix2(); + public final static ConcatNIZK concatNIZK = new ConcatNIZK(); + + public static class ConcatAnd1 implements Concatenator.Pair { + @Override + public Mixing.Mix2Proof.AndProof.FirstMessage concatenate(Mixing.Mix2Proof.DlogProof.FirstMessage msg1, Mixing.Mix2Proof.DlogProof.FirstMessage msg2) { + return Mixing.Mix2Proof.AndProof.FirstMessage.newBuilder() + .setClause0(msg1) + .setClause1(msg2) + .build(); + } + + @Override + public Mixing.Mix2Proof.DlogProof.FirstMessage getMsg1(Mixing.Mix2Proof.AndProof.FirstMessage msg) { return msg.getClause0(); } + + @Override + public Mixing.Mix2Proof.DlogProof.FirstMessage getMsg2(Mixing.Mix2Proof.AndProof.FirstMessage msg) { return msg.getClause1(); } + } + + public static class ConcatAnd2 implements Concatenator.Pair { + @Override + public Mixing.Mix2Proof.AndProof.FinalMessage concatenate(Mixing.Mix2Proof.DlogProof.FinalMessage msg1, Mixing.Mix2Proof.DlogProof.FinalMessage msg2) { + return Mixing.Mix2Proof.AndProof.FinalMessage.newBuilder() + .setClause0(msg1) + .setClause1(msg2) + .build(); + } + + @Override + public Mixing.Mix2Proof.DlogProof.FinalMessage getMsg1(Mixing.Mix2Proof.AndProof.FinalMessage msg) { return msg.getClause0(); } + + @Override + public Mixing.Mix2Proof.DlogProof.FinalMessage getMsg2(Mixing.Mix2Proof.AndProof.FinalMessage msg) { return msg.getClause1(); } + } + + public static class ConcatMix1 implements Concatenator.Pair { + @Override + public Mixing.Mix2Proof.FirstMessage concatenate(Mixing.Mix2Proof.AndProof.FirstMessage msg1, Mixing.Mix2Proof.AndProof.FirstMessage msg2) { + return Mixing.Mix2Proof.FirstMessage.newBuilder() + .setClause0(msg1) + .setClause1(msg2) + .build(); + } + + @Override + public Mixing.Mix2Proof.AndProof.FirstMessage getMsg1(Mixing.Mix2Proof.FirstMessage msg) { return msg.getClause0(); } + + @Override + public Mixing.Mix2Proof.AndProof.FirstMessage getMsg2(Mixing.Mix2Proof.FirstMessage msg) { return msg.getClause1(); } + } + + public static class ConcatMix2 implements Concatenator.Triplet { + @Override + public Mixing.Mix2Proof.FinalMessage concatenate(BigInteger msg1, Mixing.Mix2Proof.AndProof.FinalMessage msg2, Mixing.Mix2Proof.AndProof.FinalMessage msg3) { + return Mixing.Mix2Proof.FinalMessage.newBuilder() + .setC0(Util.encodeBigInteger(msg1)) + .setClause0(msg2) + .setClause1(msg3) + .build(); + } + + @Override + public BigInteger getMsg1of3(Mixing.Mix2Proof.FinalMessage msg) { return Util.decodeBigInteger(msg.getC0()); } + + @Override + public Mixing.Mix2Proof.AndProof.FinalMessage getMsg2of3(Mixing.Mix2Proof.FinalMessage msg) { return msg.getClause0(); } + + @Override + public Mixing.Mix2Proof.AndProof.FinalMessage getMsg3of3(Mixing.Mix2Proof.FinalMessage msg) { return msg.getClause1(); } + } + + + public static class ConcatNIZK implements Concatenator.Pair { + + @Override + public Mixing.Mix2Proof concatenate(Mixing.Mix2Proof.FirstMessage msg1, Mixing.Mix2Proof.FinalMessage msg2) { + return Mixing.Mix2Proof.newBuilder() + .setFirstMessage(msg1) + .setFinalMessage(msg2) + .build(); + } + + @Override + public Mixing.Mix2Proof.FirstMessage getMsg1(Mixing.Mix2Proof msg) { + return msg.getFirstMessage(); + } + + @Override + public Mixing.Mix2Proof.FinalMessage getMsg2(Mixing.Mix2Proof msg) { + return msg.getFinalMessage(); + } + } +} diff --git a/mixer/src/main/java/meerkat/mixer/proofs/Prover.java b/mixer/src/main/java/meerkat/mixer/proofs/Prover.java index 91a3c24..9a8a2f3 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/Prover.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/Prover.java @@ -19,7 +19,7 @@ import java.util.Random; * this implementation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext */ public class Prover implements Mix2ZeroKnowledgeProver { - +// private final ECGroup group; private final RandomOracle randomOracle; private final Random rand; @@ -27,6 +27,8 @@ public class Prover implements Mix2ZeroKnowledgeProver { private final ECPoint g,h; private final BigInteger groupOrderUpperBound; private final ECElGamalMixParams mixParams; + final ECElGamalMixProtocols mixProtocols; + final SigmaFiatShamir mix2NIZK; /** * @param rand @@ -43,6 +45,8 @@ public class Prover implements Mix2ZeroKnowledgeProver { this.h = this.encryptor.getElGamalPK().getPK(); this.mixParams = new ECElGamalMixParams(encryptor); this.groupOrderUpperBound = group.orderUpperBound(); + this.mixProtocols = new ECElGamalMixProtocols(mixParams, rand); // We don't need randomness for the verifier + this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle); } /** @@ -66,182 +70,179 @@ public class Prover implements Mix2ZeroKnowledgeProver { boolean switched,int i,int j, int layer, Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { - Mixing.Mix2Proof first,second,third,fourth; - ECElGamalMixParams.MixStatementWitness statement = mixParams.createProverStatement(a,b,c,d,r1,r2,switched); - first = createOrProof(statement.getDlogStatement(0)); - second = createOrProof(statement.getDlogStatement(1)); - third = createOrProof(statement.getDlogStatement(2)); - fourth = createOrProof(statement.getDlogStatement(3)); + ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(a,b,c,d); + ECElGamalMixParams.Mix2StatementWitness witness = mixParams.createMix2Witness(r1, r2, switched); - Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() - .setI(i) - .setJ(j) - .setLayer(layer) - .build(); + ECElGamalMixProtocols.Mix2Prover prover = mixProtocols.new Mix2Prover(statement, witness); - Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder() - .setFirst(first) - .setSecond(second) - .setThird(third) - .setFourth(fourth) - .setLocation(location) - .build(); - return result; + return mix2NIZK.generateNizk(prover); + +// Mixing.Mix2Proof first,second,third,fourth; +// +// ECElGamalMixParams.MixStatementWitness statement = mixParams.createProverStatement(a,b,c,d,r1,r2,switched); +// +// first = createOrProof(statement.getDlogStatement(0)); +// second = createOrProof(statement.getDlogStatement(1)); +// third = createOrProof(statement.getDlogStatement(2)); +// fourth = createOrProof(statement.getDlogStatement(3)); +// +// Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() +// .setI(i) +// .setJ(j) +// .setLayer(layer) +// .build(); +// +// Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder() +// .setFirst(first) +// .setSecond(second) +// .setThird(third) +// .setFourth(fourth) +// .setLocation(location) +// .build(); +// return result; } +// +// +// Mixing.Mix2Proof.DlogProof.FirstMessage createDlogProof(ECElGamalMixParams.DlogStatement statement, ECElGamalMixParams.DlogStatementWitness witness) { +// +// BigInteger r = encryptor.generateRandomExponent(rand); +// ECPoint gr = group.multiply(statement.g, r); +// ECPoint hr = group.multiply(statement.h, r); +// +// Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage = Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder() +// .setGr(group.encode(gr)) +// .setHr(group.encode(hr)) +// .build(); +// +// BigInteger challenge = Prover.hash() +// } +// +// +// +// +// /** +// * Generate a ZK proof that there exists x s.t (g ^ x == a and h ^ x == b) or (g' ^ x == a and h' ^ x == b). +// * +// * For each clause of the disjunction, we use the following sigma-protocol for DLOG equality (i.e. log_{g}(a)==log_{g}(b)): +// *
    +// *
  1. Prover chooses a random r, and sends g^r, h^r
  2. +// *
  3. Verifier chooses a random c and sends c
  4. +// *
  5. Prover computes
  6. +// *
+// * +// * +// * @param orStatement +// * @return ZKP OrProof: +// * assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.proofs +// */ +// private Mixing.ZeroKnowledgeProof.OrProof createOrProof(ECElGamalMixParams.OrProverStatement orStatement) { +// +// ECPoint g1 = orStatement.g1; +// ECPoint h1 = orStatement.h1; +// ECPoint g2 = orStatement.g2; +// ECPoint h2 = orStatement.h2; +// +// ECPoint g1Tag = orStatement.g1Tag; +// ECPoint h1Tag = orStatement.h1Tag; +// ECPoint g2Tag = orStatement.g2Tag; +// ECPoint h2Tag = orStatement.h2Tag; +// +// // Randomness for the ZK proof +// BigInteger r = encryptor.generateRandomExponent(rand); +// +// +// BigInteger c1,c2,z,zTag; +// ECPoint u,v,uTag,vTag; +// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage; +// +// +// switch (orStatement.trueClauseIndex) { +// case left: +// c2 = encryptor.generateRandomExponent(rand); +// zTag = encryptor.generateRandomExponent(rand); +// //step 1 +// u = group.multiply(g1, r); +// v = group.multiply(g2, r); +// uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2))); +// vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2))); +// //step 2 +// // c1 = (hash(input + step1) + group size - c2)% group size +// firstMessage = +// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder() +// .setG1(orStatement.g1Encoded) +// .setH1(orStatement.h1Encoded) +// .setG2(orStatement.g2Encoded) +// .setH2(orStatement.h2Encoded) +// .setG1Tag(orStatement.g1TagEncoded) +// .setH1Tag(orStatement.h1TagEncoded) +// .setG2Tag(orStatement.g2TagEncoded) +// .setH2Tag(orStatement.h2TagEncoded) +// .setU(encryptor.encodeElement(u)) +// .setV(encryptor.encodeElement(v)) +// .setUTag(encryptor.encodeElement(uTag)) +// .setVTag(encryptor.encodeElement(vTag)) +// .build(); +// c1 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound); +// //step 3 +// //z = (r + c1 * x) % group size; +// z = r.add(c1.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound); +// break; +// case right: +// c1 = encryptor.generateRandomExponent(rand); +// z = encryptor.generateRandomExponent(rand); +// //step 1 +// uTag = group.multiply(g1Tag, r); +// vTag = group.multiply(g2Tag, r); +// u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1))); +// v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1))); +// //step 2 +// // c1 = (hash(input + step1) + group size - c1)% group size +// firstMessage = +// Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder() +// .setG1(orStatement.g1Encoded) +// .setH1(orStatement.h1Encoded) +// .setG2(orStatement.g2Encoded) +// .setH2(orStatement.h2Encoded) +// .setG1Tag(orStatement.g1TagEncoded) +// .setH1Tag(orStatement.h1TagEncoded) +// .setG2Tag(orStatement.g2TagEncoded) +// .setH2Tag(orStatement.h2TagEncoded) +// .setU(encryptor.encodeElement(u)) +// .setV(encryptor.encodeElement(v)) +// .setUTag(encryptor.encodeElement(uTag)) +// .setVTag(encryptor.encodeElement(vTag)) +// .build(); +// c2 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound); +// //step 3 +// //zTag = (r + c2 * x) % group size; +// zTag = r.add(c2.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound); +// break; +// default: +// return null; +// } +// +// +// return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() +// .setG1(firstMessage.getG1()) +// .setH1(firstMessage.getH1()) +// .setG2(firstMessage.getG2()) +// .setH2(firstMessage.getH2()) +// .setG1Tag(firstMessage.getG1()) +// .setH1Tag(firstMessage.getH1Tag()) +// .setG2Tag(firstMessage.getG2Tag()) +// .setH2Tag(firstMessage.getH2Tag()) +// .setU(firstMessage.getU()) +// .setV(firstMessage.getV()) +// .setUTag(firstMessage.getUTag()) +// .setVTag(firstMessage.getVTag()) +// .setC1(Util.encodeBigInteger(c1)) +// .setC2(Util.encodeBigInteger(c2)) +// .setZ(Util.encodeBigInteger(z)) +// .setZTag(Util.encodeBigInteger(zTag)) +// .build(); +// } - - /** - * Fiat–Shamir heuristic - * @param input - protobuf contains all parameters from the first step of the current proof - * @param randomOracle - * @return randomOracle.hash(input) - */ - public static BigInteger hash(Mixing.Mix2Proof.FirstMessage input, RandomOracle randomOracle) { - byte[] arr = input.toByteArray(); - return new BigInteger(1,randomOracle.hash(arr,arr.length)); - } - - - - Mixing.Mix2Proof.DlogProof.FirstMessage createDlogProof(ECElGamalMixParams.DlogStatement statement, ECElGamalMixParams.DlogStatementWitness witness) { - - BigInteger r = encryptor.generateRandomExponent(rand); - ECPoint gr = group.multiply(statement.g, r); - ECPoint hr = group.multiply(statement.h, r); - - Mixing.Mix2Proof.DlogProof.FirstMessage firstMessage = Mixing.Mix2Proof.DlogProof.FirstMessage.newBuilder() - .setGr(group.encode(gr)) - .setHr(group.encode(hr)) - .build(); - - BigInteger challenge = Prover.hash() - } - - - - - /** - * Generate a ZK proof that there exists x s.t (g ^ x == a and h ^ x == b) or (g' ^ x == a and h' ^ x == b). - * - * For each clause of the disjunction, we use the following sigma-protocol for DLOG equality (i.e. log_{g}(a)==log_{g}(b)): - *
    - *
  1. Prover chooses a random r, and sends g^r, h^r
  2. - *
  3. Verifier chooses a random c and sends c
  4. - *
  5. Prover computes
  6. - *
- * - * - * @param orStatement - * @return ZKP OrProof: - * assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.proofs - */ - private Mixing.ZeroKnowledgeProof.OrProof createOrProof(ECElGamalMixParams.OrProverStatement orStatement) { - - ECPoint g1 = orStatement.g1; - ECPoint h1 = orStatement.h1; - ECPoint g2 = orStatement.g2; - ECPoint h2 = orStatement.h2; - - ECPoint g1Tag = orStatement.g1Tag; - ECPoint h1Tag = orStatement.h1Tag; - ECPoint g2Tag = orStatement.g2Tag; - ECPoint h2Tag = orStatement.h2Tag; - - // Randomness for the ZK proof - BigInteger r = encryptor.generateRandomExponent(rand); - - - BigInteger c1,c2,z,zTag; - ECPoint u,v,uTag,vTag; - Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage; - - - switch (orStatement.trueClauseIndex) { - case left: - c2 = encryptor.generateRandomExponent(rand); - zTag = encryptor.generateRandomExponent(rand); - //step 1 - u = group.multiply(g1, r); - v = group.multiply(g2, r); - uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2))); - vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2))); - //step 2 - // c1 = (hash(input + step1) + group size - c2)% group size - firstMessage = - Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder() - .setG1(orStatement.g1Encoded) - .setH1(orStatement.h1Encoded) - .setG2(orStatement.g2Encoded) - .setH2(orStatement.h2Encoded) - .setG1Tag(orStatement.g1TagEncoded) - .setH1Tag(orStatement.h1TagEncoded) - .setG2Tag(orStatement.g2TagEncoded) - .setH2Tag(orStatement.h2TagEncoded) - .setU(encryptor.encodeElement(u)) - .setV(encryptor.encodeElement(v)) - .setUTag(encryptor.encodeElement(uTag)) - .setVTag(encryptor.encodeElement(vTag)) - .build(); - c1 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound); - //step 3 - //z = (r + c1 * x) % group size; - z = r.add(c1.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound); - break; - case right: - c1 = encryptor.generateRandomExponent(rand); - z = encryptor.generateRandomExponent(rand); - //step 1 - uTag = group.multiply(g1Tag, r); - vTag = group.multiply(g2Tag, r); - u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1))); - v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1))); - //step 2 - // c1 = (hash(input + step1) + group size - c1)% group size - firstMessage = - Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder() - .setG1(orStatement.g1Encoded) - .setH1(orStatement.h1Encoded) - .setG2(orStatement.g2Encoded) - .setH2(orStatement.h2Encoded) - .setG1Tag(orStatement.g1TagEncoded) - .setH1Tag(orStatement.h1TagEncoded) - .setG2Tag(orStatement.g2TagEncoded) - .setH2Tag(orStatement.h2TagEncoded) - .setU(encryptor.encodeElement(u)) - .setV(encryptor.encodeElement(v)) - .setUTag(encryptor.encodeElement(uTag)) - .setVTag(encryptor.encodeElement(vTag)) - .build(); - c2 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound); - //step 3 - //zTag = (r + c2 * x) % group size; - zTag = r.add(c2.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound); - break; - default: - return null; - } - - - return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() - .setG1(firstMessage.getG1()) - .setH1(firstMessage.getH1()) - .setG2(firstMessage.getG2()) - .setH2(firstMessage.getH2()) - .setG1Tag(firstMessage.getG1()) - .setH1Tag(firstMessage.getH1Tag()) - .setG2Tag(firstMessage.getG2Tag()) - .setH2Tag(firstMessage.getH2Tag()) - .setU(firstMessage.getU()) - .setV(firstMessage.getV()) - .setUTag(firstMessage.getUTag()) - .setVTag(firstMessage.getVTag()) - .setC1(Util.encodeBigInteger(c1)) - .setC2(Util.encodeBigInteger(c2)) - .setZ(Util.encodeBigInteger(z)) - .setZTag(Util.encodeBigInteger(zTag)) - .build(); - } } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/SigmaFiatShamir.java b/mixer/src/main/java/meerkat/mixer/proofs/SigmaFiatShamir.java new file mode 100644 index 0000000..409ea02 --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/proofs/SigmaFiatShamir.java @@ -0,0 +1,42 @@ +package meerkat.mixer.proofs; + +import com.google.protobuf.Message; +import org.factcenter.qilin.primitives.RandomOracle; + +import java.math.BigInteger; + +/** + * Transform a Sigma protocol into a NIZK using Fiat-Shamir + */ +public class SigmaFiatShamir { + final RandomOracle randomOracle; + final Concatenator.Pair concat; + + public SigmaFiatShamir(Concatenator.Pair concat, RandomOracle randomOracle) { + this.concat = concat; + this.randomOracle = randomOracle; + } + + /** + * Fiat–Shamir heuristic + * @param input - protobuf contains all parameters from the first step of the current proof + * @return randomOracle.hash(input) + */ + public static BigInteger hash(Message input, RandomOracle randomOracle) { + byte[] arr = input.toByteArray(); + return new BigInteger(1,randomOracle.hash(arr,arr.length)); + } + + public NIZKMsgType generateNizk(SigmaProtocol.Prover prover) { + FirstMsgType firstMessage = prover.getFirstMessage(); + BigInteger challenge = hash(firstMessage, randomOracle); + FinalMessageType finalMessage = prover.getFinalMessage(challenge); + return concat.concatenate(firstMessage, finalMessage); + } + + public boolean verifyNizk(NIZKMsgType NIZK, SigmaProtocol.Verifier verifier) { + FirstMsgType firstMessage = concat.getMsg1(NIZK); + BigInteger challenge = hash(firstMessage, randomOracle); + return verifier.verify(firstMessage, challenge, concat.getMsg2(NIZK)); + } +} diff --git a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocol.java b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocol.java index b3b09c6..6dbac42 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocol.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocol.java @@ -9,17 +9,29 @@ import java.math.BigInteger; * The challenge is always a {@link java.math.BigInteger}. */ public interface SigmaProtocol { - public interface Prover { - public Message getFirstMessage(); - public Message getFinalMessage(BigInteger challenge); + public interface Prover { + public FirstMsgType getFirstMessage(); + public FinalMessageType getFinalMessage(BigInteger challenge); + + /** + * Reset the prover (so the next calls to {@link #getFirstMessage()} will + * start a new proof. + */ + public void reset(); } - public interface Simulator { - public Message getFirstMessage(BigInteger challenge); - public Message getFinalMessage(); + public interface Simulator { + public FirstMsgType getFirstMessage(BigInteger challenge); + public FinalMessageType getFinalMessage(); + + /** + * Reset the prover (so the next calls to {@link #getFirstMessage(BigInteger)} will + * start a new proof. + */ + public void reset(); } - public interface Verifier { - public boolean verify(Message firstMessage, BigInteger challenge, Message finalMessage); + public interface Verifier { + public boolean verify(FirstMsgType firstMessage, BigInteger challenge, FinalMessageType finalMessage); } } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd.java b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd.java deleted file mode 100644 index 4837b75..0000000 --- a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd.java +++ /dev/null @@ -1,91 +0,0 @@ -package meerkat.mixer.proofs; - -import com.google.protobuf.Message; - -import java.math.BigInteger; - -/** - * Generic conjuction of sigma protocols - */ -public class SigmaProtocolAnd { - static abstract public class Prover implements SigmaProtocol.Prover { - final SigmaProtocol.Prover[] provers; - - abstract protected Message buildConcatenatedFirstMessage(Message... firstMessages); - abstract protected Message buildConcatenatedFinalMessage(Message... finalMessages); - - public Prover(SigmaProtocol.Prover... provers) { - this.provers = provers; - } - - @Override - public Message getFirstMessage() { - Message[] firstMessages = new Message[provers.length]; - for (int i = 0; i < firstMessages.length; ++i) { - firstMessages[i] = provers[i].getFirstMessage(); - } - return buildConcatenatedFirstMessage(firstMessages); - } - - @Override - public Message getFinalMessage(BigInteger challenge) { - Message[] finalMessages = new Message[provers.length]; - for (int i = 0; i < finalMessages.length; ++i) { - finalMessages[i] = provers[i].getFinalMessage(challenge); - } - return buildConcatenatedFinalMessage(finalMessages); - } - } - - static abstract public class Verifier implements SigmaProtocol.Verifier { - final SigmaProtocol.Verifier[] verifiers; - - abstract protected Message getFirstMessage(Message concatenated, int verifier); - abstract protected Message getFinalMessage(Message concatenated, int verifier); - - public Verifier(SigmaProtocol.Verifier... verifiers) { - this.verifiers = verifiers; - } - - public boolean verify(Message firstMessage, BigInteger challenge, Message finalMessage) { - boolean ok = true; - - for (int i = 0; i < verifiers.length; ++i) { - ok &= verifiers[i].verify(getFirstMessage(firstMessage, i), challenge, getFinalMessage(finalMessage, i)); - } - return ok; - } - } - - static abstract public class Simulator implements SigmaProtocol.Simulator { - final SigmaProtocol.Simulator[] simulators; - - abstract protected Message buildConcatenatedFirstMessage(Message... firstMessages); - abstract protected Message buildConcatenatedFinalMessage(Message... finalMessages); - - public Simulator(SigmaProtocol.Simulator... simulators) { - this.simulators = simulators; - } - - @Override - public Message getFirstMessage(BigInteger challenge) { - Message[] firstMessages = new Message[simulators.length]; - - for (int i = 0; i < firstMessages.length; ++i) { - firstMessages[i] = simulators[i].getFirstMessage(challenge); - } - return buildConcatenatedFirstMessage(firstMessages); - } - - @Override - public Message getFinalMessage() { - Message[] finalMessages = new Message[simulators.length]; - - for (int i = 0; i < finalMessages.length; ++i) { - finalMessages[i] = simulators[i].getFinalMessage(); - } - return buildConcatenatedFinalMessage(finalMessages); - } - } - -} diff --git a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd2.java b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd2.java new file mode 100644 index 0000000..d9e473b --- /dev/null +++ b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolAnd2.java @@ -0,0 +1,87 @@ +package meerkat.mixer.proofs; + +import java.math.BigInteger; + +/** + * Generic conjuction of sigma protocols + */ +public class SigmaProtocolAnd2 { + static public class Prover + implements SigmaProtocol.Prover { + final SigmaProtocol.Prover[] provers; + + final Concatenator.Pair firstMessageConcatenator; + final Concatenator.Pair finalMessageConcatenator; + + public Prover(Concatenator.Pair firstMessageConcatenator, Concatenator.Pair finalMessageConcatenator, + SigmaProtocol.Prover... provers) { + this.firstMessageConcatenator = firstMessageConcatenator; + this.finalMessageConcatenator = finalMessageConcatenator; + this.provers = provers; + } + + @Override + public FirstMessageOut getFirstMessage() { + return firstMessageConcatenator.concatenate(provers[0].getFirstMessage(), provers[1].getFirstMessage()); + } + + @Override + public FinalMessageOut getFinalMessage(BigInteger challenge) { + return finalMessageConcatenator.concatenate(provers[0].getFinalMessage(challenge), provers[1].getFinalMessage(challenge)); + } + + + @Override + public void reset() { provers[0].reset(); provers[1].reset(); } + } + + static public class Verifier + implements SigmaProtocol.Verifier { + final SigmaProtocol.Verifier[] verifiers; + + final Concatenator.Pair firstMessageConcatenator; + final Concatenator.Pair finalMessageConcatenator; + + public Verifier(Concatenator.Pair firstMessageConcatenator, Concatenator.Pair finalMessageConcatenator, + SigmaProtocol.Verifier... verifiers) { + this.firstMessageConcatenator = firstMessageConcatenator; + this.finalMessageConcatenator = finalMessageConcatenator; + this.verifiers = verifiers; + } + + @Override + public boolean verify(FirstMessageOut firstMessage, BigInteger challenge, FinalMessageOut finalMessage) { + return verifiers[0].verify(firstMessageConcatenator.getMsg1(firstMessage), challenge, finalMessageConcatenator.getMsg1(finalMessage)) && + verifiers[1].verify(firstMessageConcatenator.getMsg2(firstMessage), challenge, finalMessageConcatenator.getMsg2(finalMessage)); + } + } + + static public class Simulator + implements SigmaProtocol.Simulator { + final SigmaProtocol.Simulator[] simulators; + + final Concatenator.Pair firstMessageConcatenator; + final Concatenator.Pair finalMessageConcatenator; + + public Simulator(Concatenator.Pair firstMessageConcatenator, Concatenator.Pair finalMessageConcatenator, SigmaProtocol.Simulator... simulators) { + this.firstMessageConcatenator = firstMessageConcatenator; + this.finalMessageConcatenator = finalMessageConcatenator; + this.simulators = simulators; + } + + @Override + public FirstMessageOut getFirstMessage(BigInteger challenge) { + return firstMessageConcatenator.concatenate(simulators[0].getFirstMessage(challenge), simulators[1].getFirstMessage(challenge)); + } + + @Override + public FinalMessageOut getFinalMessage() { + return finalMessageConcatenator.concatenate(simulators[0].getFinalMessage(), simulators[1].getFinalMessage()); + } + + @Override + public void reset() { simulators[0].reset(); simulators[1].reset(); } + } + +} diff --git a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolOr2.java b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolOr2.java index 889c51d..cf2c4ff 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolOr2.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/SigmaProtocolOr2.java @@ -1,29 +1,18 @@ package meerkat.mixer.proofs; -import com.google.protobuf.Message; - import java.math.BigInteger; /** * Disjunction of 2 Sigma protocol statements */ public class SigmaProtocolOr2 { - static abstract public class Prover implements SigmaProtocol.Prover { - final SigmaProtocol.Prover prover; - final SigmaProtocol.Simulator simulator; - final int proverIdx; - - abstract protected Message buildConcatenatedFirstMessage(Message... firstMessages); - abstract protected Message buildConcatenatedFinalMessage(BigInteger firstChallenge, Message... finalMessages); - - BigInteger simChallenge; + public interface ChallengeGenerator { /** * Generate a random challenge in an appropriate way (e.g., mod group order) * @return */ - abstract protected BigInteger generateChallenge(); - + public BigInteger generateChallenge(); /** * Subtract two challenges in an appropriate way (e.g., mod group order) @@ -31,7 +20,20 @@ public class SigmaProtocolOr2 { * @param c2 * @return */ - abstract protected BigInteger subtractChallenge(BigInteger c1, BigInteger c2); + public BigInteger subtractChallenge(BigInteger c1, BigInteger c2); + } + + static public class Prover + implements SigmaProtocol.Prover { + final SigmaProtocol.Prover prover; + final SigmaProtocol.Simulator simulator; + final int proverIdx; + + final Concatenator.Pair firstMessageConcatenator; + final Concatenator.Triplet finalMessageConcatenator; + final ChallengeGenerator challengeGenerator; + + BigInteger simChallenge; /** * @@ -39,7 +41,11 @@ public class SigmaProtocolOr2 { * @param simulator * @param proverIdx Which index should the prover be inserted at (0 means first, 1 means second) */ - public Prover(SigmaProtocol.Prover prover, SigmaProtocol.Simulator simulator, int proverIdx) { + public Prover(Concatenator.Pair firstMessageConcatenator, Concatenator.Triplet finalMessageConcatenator, ChallengeGenerator challengeGenerator, + SigmaProtocol.Prover prover, SigmaProtocol.Simulator simulator, int proverIdx) { + this.firstMessageConcatenator = firstMessageConcatenator; + this.finalMessageConcatenator = finalMessageConcatenator; + this.challengeGenerator = challengeGenerator; this.prover = prover; this.simulator = simulator; this.proverIdx = proverIdx; @@ -47,45 +53,56 @@ public class SigmaProtocolOr2 { } @Override - public Message getFirstMessage() { - simChallenge = generateChallenge(); + public FirstMessageOut getFirstMessage() { + simChallenge = challengeGenerator.generateChallenge(); if (proverIdx == 0) { - return buildConcatenatedFirstMessage(prover.getFirstMessage(), simulator.getFirstMessage(simChallenge)); + return firstMessageConcatenator.concatenate(prover.getFirstMessage(), simulator.getFirstMessage(simChallenge)); } else { - return buildConcatenatedFirstMessage(simulator.getFirstMessage(simChallenge), prover.getFirstMessage()); + return firstMessageConcatenator.concatenate(simulator.getFirstMessage(simChallenge), prover.getFirstMessage()); } } @Override - public Message getFinalMessage(BigInteger challenge) { - BigInteger realchallenge = subtractChallenge(challenge, simChallenge); + public FinalMessageOut getFinalMessage(BigInteger challenge) { + BigInteger realchallenge = challengeGenerator.subtractChallenge(challenge, simChallenge); if (proverIdx == 0) { - return buildConcatenatedFinalMessage(realchallenge, prover.getFinalMessage(realchallenge), simulator.getFinalMessage()); + return finalMessageConcatenator.concatenate(realchallenge, prover.getFinalMessage(realchallenge), simulator.getFinalMessage()); } else { - return buildConcatenatedFinalMessage(simChallenge, simulator.getFinalMessage(), prover.getFinalMessage(realchallenge)); + return finalMessageConcatenator.concatenate(simChallenge, simulator.getFinalMessage(), prover.getFinalMessage(realchallenge)); } } + + @Override + public void reset() { prover.reset(); simulator.reset(); simChallenge = null; } } - static abstract public class Verifier implements SigmaProtocol.Verifier { - final SigmaProtocol.Verifier[] verifiers; + static public class Verifier + implements SigmaProtocol.Verifier { - abstract protected Message getFirstMessage(Message concatenated, int verifier); - abstract protected BigInteger getFirstChallenge(Message concatenated); - abstract protected Message getFinalMessage(Message concatenated, int verifier); + final Concatenator.Pair firstMessageConcatenator; + final Concatenator.Triplet finalMessageConcatenator; + + final ChallengeGenerator challengeGenerator; + + final SigmaProtocol.Verifier[] verifiers; - public Verifier(SigmaProtocol.Verifier... verifiers) { + public Verifier(Concatenator.Pair firstMessageConcatenator, Concatenator.Triplet finalMessageConcatenator, + ChallengeGenerator challengeGenerator, + SigmaProtocol.Verifier... verifiers) { + this.firstMessageConcatenator = firstMessageConcatenator; + this.finalMessageConcatenator = finalMessageConcatenator; + this.challengeGenerator = challengeGenerator; + this.verifiers = verifiers; } - public boolean verify(Message firstMessage, BigInteger challenge, Message finalMessage) { - - BigInteger firstChallenge = getFirstChallenge(finalMessage); - BigInteger secondChallenge = challenge.subtract(firstChallenge); - return verifiers[0].verify(getFirstMessage(firstMessage, 0), firstChallenge, getFinalMessage(finalMessage, 0)) & - verifiers[0].verify(getFirstMessage(firstMessage, 1), secondChallenge, getFinalMessage(finalMessage, 1)); + public boolean verify(FirstMessageOut firstMessage, BigInteger challenge, FinalMessageOut finalMessage) { + BigInteger firstChallenge = finalMessageConcatenator.getMsg1of3(finalMessage); + BigInteger secondChallenge = challengeGenerator.subtractChallenge(challenge, firstChallenge); + return verifiers[0].verify(firstMessageConcatenator.getMsg1(firstMessage), firstChallenge, finalMessageConcatenator.getMsg2of3(finalMessage)) & + verifiers[1].verify(firstMessageConcatenator.getMsg2(firstMessage), secondChallenge, finalMessageConcatenator.getMsg3of3(finalMessage)); } } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java b/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java index 6c0034d..5cf98d9 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java @@ -2,16 +2,13 @@ package meerkat.mixer.proofs; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.concrete.ECElGamalEncryption; -import meerkat.crypto.concrete.Util; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; -import meerkat.protobuf.ConcreteCrypto.GroupElement; import meerkat.protobuf.Crypto; import meerkat.protobuf.Mixing; import org.bouncycastle.math.ec.ECPoint; import org.factcenter.qilin.primitives.RandomOracle; import org.factcenter.qilin.primitives.concrete.ECGroup; - -import java.math.BigInteger; +import meerkat.mixer.proofs.ECElGamalMixProtocols.Mix2Verifier; /** * implements Mix2ZeroKnowledgeVerifier @@ -23,7 +20,11 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { private final RandomOracle randomOracle; private final ECPoint g,h; private final ECElGamalMixParams mixParams; - private final ZeroKnowledgeOrProofParser parser; + final ECElGamalMixProtocols mixProtocols; + final SigmaFiatShamir mix2NIZK; + + +// private final ZeroKnowledgeOrProofParser parser; /** * constructor @@ -36,7 +37,9 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { this.h = encryptor.getElGamalPK().getPK(); this.randomOracle = randomOracle; this.mixParams = new ECElGamalMixParams(encryptor); - this.parser = new ZeroKnowledgeOrProofParser(group); + this.mixProtocols = new ECElGamalMixProtocols(mixParams, null); // We don't need randomness for the verifier + this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle); +// this.parser = new ZeroKnowledgeOrProofParser(group); } /** @@ -55,77 +58,11 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier { Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2, - Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException { + Mixing.Mix2Proof proof) throws InvalidProtocolBufferException { + ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2); - return verifyFiatShamirOrProof(statement, proof.getFirst(), proof.getSecond()); + Mix2Verifier verifier = mixProtocols.new Mix2Verifier(statement); - } - - - /** - * Verify a Schnorr proof of discrete log equality, given the entire transcript of the ZKP. - * @param statement - * @param firstMessage - * @param challenge - * @param finalMessage - * @return - */ - boolean verifyInteractiveDlogProof(ECElGamalMixParams.DlogStatement statement, - Mixing.ZeroKnowledgeProof.DlogProof.FirstMessage firstMessage, - BigInteger challenge, - Mixing.ZeroKnowledgeProof.DlogProof.FinalMessage finalMessage) { - GroupElement grEncoded = firstMessage.getGr(); - ECPoint gr = group.decode(grEncoded.toByteArray()); - - GroupElement hrEncoded = firstMessage.getHr(); - ECPoint hr = group.decode(hrEncoded.toByteArray()); - - BigInteger xcr = Util.decodeBigInteger(finalMessage.getXcr()); - - boolean gGood = group.add(gr, group.multiply(statement.a,challenge)).equals(group.multiply(statement.g,xcr)); - boolean hGood = group.add(hr, group.multiply(statement.b,challenge)).equals(group.multiply(statement.h,xcr)); - return gGood && hGood; - } - - /** - * Verify a conjuction of two Dlog Proofs, given a complete transcript of the ZKP - * @param statement - * @param firstMessage - * @param challenge - * @param finalMessage - * @return - */ - boolean verifyInteractiveAndProof(ECElGamalMixParams.AndStatement statement, - Mixing.ZeroKnowledgeProof.AndProof.FirstMessage firstMessage, - BigInteger challenge, - Mixing.ZeroKnowledgeProof.AndProof.FinalMessage finalMessage) { - return verifyInteractiveDlogProof(statement.clauses[0], firstMessage.getClause0(), challenge, finalMessage.getClause0()) && - verifyInteractiveDlogProof(statement.clauses[1], firstMessage.getClause1(), challenge, finalMessage.getClause1()); - } - - /** - * Verify a disjunction of two Dlog-equality statement conjuctions, given the entire transcript of the ZKP. - * @param statement - * @param firstMessage - * @param challenge - * @param finalMessage - * @return - */ - boolean verifyInteractiveMix2Proof(ECElGamalMixParams.Mix2Statement statement, - Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage, - BigInteger challenge, - Mixing.ZeroKnowledgeProof.OrProof.FinalMessage finalMessage) { - BigInteger c0 = Util.decodeBigInteger(finalMessage.getC0()); - BigInteger c1 = challenge.subtract(c0).mod(group.orderUpperBound()); - - return verifyInteractiveAndProof(statement.clauses[0], firstMessage.getClause0(), c0, finalMessage.getClause0()) && - verifyInteractiveAndProof(statement.clauses[1], firstMessage.getClause1(), c1, finalMessage.getClause1()); - } - - - boolean verifyFiatShamirOrProof(ECElGamalMixParams.Mix2Statement statement, Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage, - Mixing.ZeroKnowledgeProof.OrProof.FinalMessage finalMessage) { - BigInteger challenge = Prover.hash(firstMessage, randomOracle).mod(group.orderUpperBound()); - return verifyInteractiveMix2Proof(statement, firstMessage, challenge, finalMessage); + return mix2NIZK.verifyNizk(proof, verifier); } } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/VerifyTable.java b/mixer/src/main/java/meerkat/mixer/proofs/VerifyTable.java index ac3f6a5..36d39ac 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/VerifyTable.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/VerifyTable.java @@ -37,13 +37,13 @@ public final class VerifyTable { Arrays.fill(locationChecksumLayer,false); } - Mixing.ZeroKnowledgeProof[][] zeroKnowledgeProofs = mixerOutput.getProofs(); + Mixing.Mix2Proof[][] Mix2Proofs = mixerOutput.getProofs(); Crypto.RerandomizableEncryptedMessage[][] rerandomizableEncryptedMessages = mixerOutput.getEncryptedMessages(); - for (int i = 0; i < zeroKnowledgeProofs.length ; i++){ - for (int j = 0; j < zeroKnowledgeProofs[i].length ; j ++){ - Mixing.ZeroKnowledgeProof zkp = zeroKnowledgeProofs[i][j]; - Mixing.ZeroKnowledgeProof.Location location = zkp.getLocation(); + for (int i = 0; i < Mix2Proofs.length ; i++){ + for (int j = 0; j < Mix2Proofs[i].length ; j ++){ + Mixing.Mix2Proof zkp = Mix2Proofs[i][j]; + Mixing.Mix2Proof.Location location = zkp.getLocation(); index1 = location.getI(); index2 = location.getJ(); layer = location.getLayer(); diff --git a/mixer/src/main/java/meerkat/mixer/proofs/ZeroKnowledgeOrProofParser.java b/mixer/src/main/java/meerkat/mixer/proofs/ZeroKnowledgeOrProofParser.java index a2ab318..5c3d6c8 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/ZeroKnowledgeOrProofParser.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/ZeroKnowledgeOrProofParser.java @@ -13,75 +13,75 @@ import java.math.BigInteger; * zero knowledge proof parser */ public class ZeroKnowledgeOrProofParser { - - private final ECGroup group; - - /** - * parse or proof message and return the result in zero knowledge or proof container - * @param orProof - * @return zero knowledge or proof container - */ - public ZeroKnowledgeOrProofContainer parseOrProof(Mixing.ZeroKnowledgeProof.OrProof orProof){ - return new ZeroKnowledgeOrProofContainer(orProof); - } - - /** - * getter - * @param group - */ - public ZeroKnowledgeOrProofParser(ECGroup group) { - this.group = group; - } - - - /** - * inner class - * container for parsed zero knowledge or proof - * constructor is private, can be construct using ZeroKnowledgeOrProofParser.parseOrProof - */ - public class ZeroKnowledgeOrProofContainer{ - public final ECPoint g1,g2,h1,h2; - public final ECPoint g1Tag,g2Tag,h1Tag,h2Tag; - public final ECPoint u,v,uTag,vTag; - public final BigInteger c1,c2,z,zTag; - public final Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage; - - /** - * constructor - * @param orProof - */ - private ZeroKnowledgeOrProofContainer(Mixing.ZeroKnowledgeProof.OrProof orProof){ - this.firstMessage = - Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder() - .setG1(orProof.getG1()) - .setH1(orProof.getH1()) - .setG2(orProof.getG2()) - .setH2(orProof.getH2()) - .setG1Tag(orProof.getG1Tag()) - .setH1Tag(orProof.getH1Tag()) - .setG2Tag(orProof.getG2Tag()) - .setH2Tag(orProof.getH2Tag()) - .setU(orProof.getU()) - .setV(orProof.getV()) - .setUTag(orProof.getUTag()) - .setVTag(orProof.getVTag()) - .build(); - this.g1 = ECElGamalEncryption.decodeElement(group, orProof.getG1()); - this.g2 = ECElGamalEncryption.decodeElement(group, orProof.getG2()); - this.h1 = ECElGamalEncryption.decodeElement(group, orProof.getH1()); - this.h2 = ECElGamalEncryption.decodeElement(group, orProof.getH2()); - this.g1Tag = ECElGamalEncryption.decodeElement(group, orProof.getG1Tag()); - this.g2Tag = ECElGamalEncryption.decodeElement(group, orProof.getG2Tag()); - this.h1Tag = ECElGamalEncryption.decodeElement(group, orProof.getH1Tag()); - this.h2Tag = ECElGamalEncryption.decodeElement(group, orProof.getH2Tag()); - this.u = ECElGamalEncryption.decodeElement(group, orProof.getU()); - this.v = ECElGamalEncryption.decodeElement(group, orProof.getV()); - this.uTag = ECElGamalEncryption.decodeElement(group, orProof.getUTag()); - this.vTag = ECElGamalEncryption.decodeElement(group, orProof.getVTag()); - this.c1 = Util.decodeBigInteger(orProof.getC1()); - this.c2 = Util.decodeBigInteger(orProof.getC2()); - this.z = Util.decodeBigInteger(orProof.getZ()); - this.zTag = Util.decodeBigInteger(orProof.getZTag()); - } - } +// +// private final ECGroup group; +// +// /** +// * parse or proof message and return the result in zero knowledge or proof container +// * @param orProof +// * @return zero knowledge or proof container +// */ +// public ZeroKnowledgeOrProofContainer parseOrProof(Mixing.Mix2Proof.OrProof orProof){ +// return new ZeroKnowledgeOrProofContainer(orProof); +// } +// +// /** +// * getter +// * @param group +// */ +// public ZeroKnowledgeOrProofParser(ECGroup group) { +// this.group = group; +// } +// +// +// /** +// * inner class +// * container for parsed zero knowledge or proof +// * constructor is private, can be construct using ZeroKnowledgeOrProofParser.parseOrProof +// */ +// public class ZeroKnowledgeOrProofContainer{ +// public final ECPoint g1,g2,h1,h2; +// public final ECPoint g1Tag,g2Tag,h1Tag,h2Tag; +// public final ECPoint u,v,uTag,vTag; +// public final BigInteger c1,c2,z,zTag; +// public final Mixing.Mix2Proof.OrProof.FirstMessage firstMessage; +// +// /** +// * constructor +// * @param orProof +// */ +// private ZeroKnowledgeOrProofContainer(Mixing.Mix2Proof.OrProof orProof){ +// this.firstMessage = +// Mixing.Mix2Proof.OrProof.FirstMessage.newBuilder() +// .setG1(orProof.getG1()) +// .setH1(orProof.getH1()) +// .setG2(orProof.getG2()) +// .setH2(orProof.getH2()) +// .setG1Tag(orProof.getG1Tag()) +// .setH1Tag(orProof.getH1Tag()) +// .setG2Tag(orProof.getG2Tag()) +// .setH2Tag(orProof.getH2Tag()) +// .setU(orProof.getU()) +// .setV(orProof.getV()) +// .setUTag(orProof.getUTag()) +// .setVTag(orProof.getVTag()) +// .build(); +// this.g1 = ECElGamalEncryption.decodeElement(group, orProof.getG1()); +// this.g2 = ECElGamalEncryption.decodeElement(group, orProof.getG2()); +// this.h1 = ECElGamalEncryption.decodeElement(group, orProof.getH1()); +// this.h2 = ECElGamalEncryption.decodeElement(group, orProof.getH2()); +// this.g1Tag = ECElGamalEncryption.decodeElement(group, orProof.getG1Tag()); +// this.g2Tag = ECElGamalEncryption.decodeElement(group, orProof.getG2Tag()); +// this.h1Tag = ECElGamalEncryption.decodeElement(group, orProof.getH1Tag()); +// this.h2Tag = ECElGamalEncryption.decodeElement(group, orProof.getH2Tag()); +// this.u = ECElGamalEncryption.decodeElement(group, orProof.getU()); +// this.v = ECElGamalEncryption.decodeElement(group, orProof.getV()); +// this.uTag = ECElGamalEncryption.decodeElement(group, orProof.getUTag()); +// this.vTag = ECElGamalEncryption.decodeElement(group, orProof.getVTag()); +// this.c1 = Util.decodeBigInteger(orProof.getC1()); +// this.c2 = Util.decodeBigInteger(orProof.getC2()); +// this.z = Util.decodeBigInteger(orProof.getZ()); +// this.zTag = Util.decodeBigInteger(orProof.getZTag()); +// } +// } } diff --git a/mixer/src/test/java/meerkat/mixer/CreateTestVector.java b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java index af6a865..1690aa5 100644 --- a/mixer/src/test/java/meerkat/mixer/CreateTestVector.java +++ b/mixer/src/test/java/meerkat/mixer/CreateTestVector.java @@ -84,9 +84,9 @@ public class CreateTestVector { //@SimpleRerandomizeTest public void createInvalidTest() throws IOException { - //Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(encryptor,randomOracle,true); - //Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,encryptor,randomOracle,true); - //mixer = new Mixer(randomMixer,corruptedProver,encryptor,corruptedVerifier); + //Mix2ZeroKnowledgeVerifier corruptedVerifier = new Verifier(enc,randomOracle,true); + //Mix2ZeroKnowledgeProver corruptedProver = new Prover(randomProver,enc,randomOracle,true); + //mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier); List mixerInput = generateMixerInput(); System.out.println("start mixing"); diff --git a/mixer/src/test/java/meerkat/mixer/ECParamTestBase.java b/mixer/src/test/java/meerkat/mixer/ECParamTestBase.java new file mode 100644 index 0000000..98c11aa --- /dev/null +++ b/mixer/src/test/java/meerkat/mixer/ECParamTestBase.java @@ -0,0 +1,44 @@ +package meerkat.mixer; + +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.mixer.proofs.Prover; +import meerkat.mixer.proofs.Verifier; +import meerkat.protobuf.ConcreteCrypto; +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.security.spec.InvalidKeySpecException; +import java.util.Random; + +/** + * Base class with common parameters. + */ +public class ECParamTestBase { + + public Random rand; + public ECElGamal.SK key; + public ECGroup group; + public ECElGamalEncryption enc; + public RandomOracle randomOracle = new DigestOracle(); + public ConcreteCrypto.ElGamalPublicKey serializedPk; + + public ECParamTestBase() { + rand = new Random(1); + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = Utils.serializePk(group, key); + enc = new ECElGamalEncryption(); + try { + enc.init(serializedPk); + } catch (InvalidKeySpecException e) { + e.printStackTrace(); + assert(false); + } + } +} diff --git a/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/meerkat/mixer/Mix2ProofTest.java similarity index 85% rename from mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java rename to mixer/src/test/java/meerkat/mixer/Mix2ProofTest.java index 0f7e729..aec3619 100644 --- a/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/meerkat/mixer/Mix2ProofTest.java @@ -28,26 +28,12 @@ import java.util.Random; /** * Created by Tzlil on 12/31/2015. */ -public class ZeroKnowledgeProofTest { - - Random rand; - ECElGamal.SK key; - ECGroup group; - ECElGamalEncryption enc; - ConcreteCrypto.ElGamalPublicKey serializedPk; +public class Mix2ProofTest extends ECParamTestBase { Mix2ZeroKnowledgeVerifier verifier ; Mix2ZeroKnowledgeProver prover ; @Before public void setup() throws Exception { - rand = new Random(); - group = new ECGroup("secp256k1"); - BigInteger sk = ECElGamal.generateSecretKey(group, rand); - key = new ECElGamal.SK(group, sk); - serializedPk = Utils.serializePk(group, key); - enc = new ECElGamalEncryption(); - enc.init(serializedPk); - RandomOracle randomOracle = new DigestOracle(); verifier = new Verifier(enc,randomOracle); prover = new Prover(new Random(),enc,randomOracle); } @@ -91,13 +77,13 @@ public class ZeroKnowledgeProofTest { group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2())))); - Mixing.ZeroKnowledgeProof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0,r1,r2); + Mixing.Mix2Proof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0,r1,r2); assertTrue (verifier.verify(e1,e2,e1New,e2New, proof)); } @Test - public void zeroKnowledgeProofTest() throws InvalidProtocolBufferException { + public void Mix2ProofTest() throws InvalidProtocolBufferException { int tests = 1000; diff --git a/mixer/src/test/java/meerkat/mixer/MixingTest.java b/mixer/src/test/java/meerkat/mixer/MixingTest.java index 229196c..87eb4e8 100644 --- a/mixer/src/test/java/meerkat/mixer/MixingTest.java +++ b/mixer/src/test/java/meerkat/mixer/MixingTest.java @@ -25,12 +25,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -public class MixingTest { - - ECElGamalEncryption encryptor; - ECGroup group; +public class MixingTest extends ECParamTestBase { Random random,randomMixer,randomProver; - RandomOracle randomOracle; Mix2ZeroKnowledgeVerifier verifier; Prover prover; meerkat.crypto.mixnet.Mixer mixer; @@ -41,16 +37,12 @@ public class MixingTest { @Before public void setup() throws InvalidKeySpecException { // initialization - random = new Random(); - group = new ECGroup("secp256k1"); - encryptor = new ECElGamalEncryption(); - encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); - randomMixer = new Random(); - randomProver = new Random(); - randomOracle = new DigestOracle(); - verifier = new Verifier(encryptor,randomOracle); - prover = new Prover(randomProver,encryptor,randomOracle); - mixer = new Mixer(prover,encryptor); + random = new Random(1); + randomMixer = new Random(2); + randomProver = new Random(3); + verifier = new Verifier(enc,randomOracle); + prover = new Prover(randomProver, enc,randomOracle); + mixer = new Mixer(prover, enc); // generate n int logN = 8; // + random.nextInt(8) @@ -63,7 +55,7 @@ public class MixingTest { Voting.PlaintextBallot msg; for (int i = 0; i < n ; i++){ msg = Utils.genRandomBallot(2,3,16); - result.add(encryptor.encrypt(msg, encryptor.generateRandomness(random))); + result.add(enc.encrypt(msg, enc.generateRandomness(random))); } return result; } diff --git a/mixer/src/test/java/meerkat/mixer/proofs/AndStatementSigmaTest.java b/mixer/src/test/java/meerkat/mixer/proofs/AndStatementSigmaTest.java new file mode 100644 index 0000000..bcc5100 --- /dev/null +++ b/mixer/src/test/java/meerkat/mixer/proofs/AndStatementSigmaTest.java @@ -0,0 +1,52 @@ +package meerkat.mixer.proofs; + +import meerkat.protobuf.Mixing; +import org.factcenter.qilin.primitives.RandomOracle; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by talm on 12/01/17. + */ +public class AndStatementSigmaTest extends SigmaProtocolTest { + @Override + void generateRandomTrueStatement() { + + } + + @Override + void generateRandomFalseStatement() { + + } + + @Override + protected SigmaProtocol.Prover getNewProver() { + return null; + } + + @Override + protected SigmaProtocol.Verifier getNewVerifier() { + return null; + } + + @Override + protected SigmaProtocol.Simulator getNewSimulator() { + return null; + } + + @Override + protected RandomOracle getRandomOracle() { + return null; + } + + @Override + protected Random getRandom() { + return null; + } + + @Override + protected BigInteger getChallengeModulus() { + return null; + } +} diff --git a/mixer/src/test/java/meerkat/mixer/proofs/DlogStatementSchnorrSigmaTest.java b/mixer/src/test/java/meerkat/mixer/proofs/DlogStatementSchnorrSigmaTest.java new file mode 100644 index 0000000..bec9c23 --- /dev/null +++ b/mixer/src/test/java/meerkat/mixer/proofs/DlogStatementSchnorrSigmaTest.java @@ -0,0 +1,86 @@ +package meerkat.mixer.proofs; + +import meerkat.mixer.ECParamTestBase; +import meerkat.protobuf.Mixing; +import org.bouncycastle.math.ec.ECPoint; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.util.Pair; +import org.junit.Before; + +import java.math.BigInteger; +import java.util.Random; + +import static org.junit.Assert.*; + +/** + * Created by talm on 12/01/17. + */ +public class DlogStatementSchnorrSigmaTest extends + SigmaProtocolTest { + + ECParamTestBase ecParams = new ECParamTestBase(); + ECElGamalMixParams params; + ECElGamalMixProtocols prots; + + ECElGamalMixParams.DlogStatement statement; + ECElGamalMixParams.DlogStatementWitness witness; + ECElGamalMixProtocols.DlogStatementSchnorrProver prover; + ECElGamalMixProtocols.DlogStatementSchnorrVerifier verifier; + ECElGamalMixProtocols.DlogStatementSchnorrSimulator simulator; + + public DlogStatementSchnorrSigmaTest() { + + this.params = new ECElGamalMixParams(ecParams.enc); + this.prots = new ECElGamalMixProtocols(params, ecParams.rand); // We don't need randomness for the verifier +// this.mix2NIZK = new SigmaFiatShamir(ProtobufConcatenators.concatNIZK, randomOracle); + } + + + void generateRandomTrueStatement() { + BigInteger x = prots.encryptor.generateRandomExponent(rand); + ECPoint a = prots.group.multiply(prots.g, x); + ECPoint b = prots.group.multiply(prots.h, x); + statement = params.new DlogStatement(a, b); + witness = params.new DlogStatementWitness(x); + } + + void generateRandomFalseStatement() { + ECPoint a = prots.group.sample(rand); + ECPoint b = prots.group.sample(rand); + witness = null; + statement = params.new DlogStatement(a, b); + } + + @Override + protected SigmaProtocol.Prover getNewProver() { + prover = prots.new DlogStatementSchnorrProver(statement, witness); + return prover; + } + + @Override + protected SigmaProtocol.Verifier getNewVerifier() { + verifier = prots.new DlogStatementSchnorrVerifier(statement); + return verifier; + } + + @Override + protected SigmaProtocol.Simulator getNewSimulator() { + simulator = prots.new DlogStatementSchnorrSimulator(statement); + return simulator; + } + + @Override + protected RandomOracle getRandomOracle() { + return ecParams.randomOracle; + } + + @Override + protected Random getRandom() { + return ecParams.rand; + } + + @Override + protected BigInteger getChallengeModulus() { + return prots.group.orderUpperBound(); + } +} \ No newline at end of file diff --git a/mixer/src/test/java/meerkat/mixer/proofs/NIZKContainers.java b/mixer/src/test/java/meerkat/mixer/proofs/NIZKContainers.java new file mode 100644 index 0000000..dbbea17 --- /dev/null +++ b/mixer/src/test/java/meerkat/mixer/proofs/NIZKContainers.java @@ -0,0 +1,13 @@ +package meerkat.mixer.proofs; + +import meerkat.protobuf.Mixing; + +/** + * Created by talm on 12/01/17. + */ +public class NIZKContainers { + public static class DlogNIZK { + public Mixing.Mix2Proof.DlogProof.FirstMessage m1; + + } +} diff --git a/mixer/src/test/java/meerkat/mixer/proofs/SigmaProtocolTest.java b/mixer/src/test/java/meerkat/mixer/proofs/SigmaProtocolTest.java new file mode 100644 index 0000000..3b826b5 --- /dev/null +++ b/mixer/src/test/java/meerkat/mixer/proofs/SigmaProtocolTest.java @@ -0,0 +1,116 @@ +package meerkat.mixer.proofs; + +import com.google.protobuf.Message; +import org.factcenter.qilin.primitives.RandomOracle; +import org.factcenter.qilin.util.Pair; +import org.junit.Before; +import org.junit.Test; + +import java.math.BigInteger; +import java.util.Random; + +import static org.junit.Assert.*; + +/** + * Generic test for Sigma Protocol + */ +abstract public class SigmaProtocolTest { + public final int NUM_REPEAT = 10; + + + abstract void generateRandomTrueStatement(); + + abstract void generateRandomFalseStatement(); + + abstract protected SigmaProtocol.Prover getNewProver(); + abstract protected SigmaProtocol.Verifier getNewVerifier(); + abstract protected SigmaProtocol.Simulator getNewSimulator(); + + class NIZKConcat implements Concatenator.Pair, M1, M2> { + @Override + public Pair concatenate(M1 msg1, M2 msg2) { return new Pair(msg1, msg2); } + + @Override + public M1 getMsg1(Pair msg) { return msg.a; } + + @Override + public M2 getMsg2(Pair msg) { return msg.b; } + } + + final NIZKConcat nizkConcat = new NIZKConcat(); + + abstract protected RandomOracle getRandomOracle(); + + + abstract protected Random getRandom(); + abstract protected BigInteger getChallengeModulus(); + + SigmaProtocol.Prover prover; + SigmaProtocol.Verifier verifier; + SigmaProtocol.Simulator simulator; + BigInteger challengeModulus; + int challengeBits; + + Random rand; + + @Before + public void setup() { + simulator = getNewSimulator(); + rand = getRandom(); + challengeModulus = getChallengeModulus(); + challengeBits = challengeModulus.bitLength() + 1; + } + + @Test + public void testProverCompleteness() { + for (int i = 0; i < NUM_REPEAT; ++i) { + generateRandomTrueStatement(); + + prover = getNewProver(); + verifier = getNewVerifier(); + + M1 msg1 = prover.getFirstMessage(); + BigInteger c = new BigInteger(challengeBits, rand).mod(challengeModulus); + M2 msg2 = prover.getFinalMessage(c); + + assertTrue(String.format("Verification error in iteration %d", i), verifier.verify(msg1, c, msg2)); + } + } + + + @Test + public void testSimulatorCompleteness() { + for (int i = 0; i < NUM_REPEAT; ++i) { + generateRandomFalseStatement(); + + simulator = getNewSimulator(); + verifier = getNewVerifier(); + + BigInteger c = new BigInteger(challengeBits, rand).mod(challengeModulus); + + M1 msg1 = simulator.getFirstMessage(c); + M2 msg2 = simulator.getFinalMessage(); + + assertTrue(String.format("Simulator Verification error in iteration %d", i), verifier.verify(msg1, c, msg2)); + } + } + + @Test + public void testNIZKCompleteness() { + for (int i = 0; i < NUM_REPEAT; ++i) { + generateRandomTrueStatement(); + + SigmaFiatShamir, M1, M2> fiatShamir = new SigmaFiatShamir, M1, M2>(nizkConcat, getRandomOracle()); + + prover = getNewProver(); + Pair nizk = fiatShamir.generateNizk(prover); + + verifier = getNewVerifier(); + boolean nizkOk = fiatShamir.verifyNizk(nizk, verifier); + + assertTrue(String.format("NIZK Verification error in iteration %d", i), nizkOk); + } + } + + +} \ No newline at end of file