Writing tests for new ZKPs

mixer
Tal Moran 2017-01-12 11:05:38 +02:00
parent 723d348443
commit a5cceaa6c0
27 changed files with 997 additions and 688 deletions

View File

@ -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,

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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();

View File

@ -0,0 +1,21 @@
package meerkat.mixer.proofs;
/**
* Created by talm on 11/01/17.
*/
public interface Concatenator {
public interface Pair<OutType, InType1, InType2>{
public OutType concatenate(InType1 msg1, InType2 msg2);
public InType1 getMsg1(OutType msg);
public InType2 getMsg2(OutType msg);
}
public interface Triplet<OutType, InType1, InType2, InType3>{
public OutType concatenate(InType1 msg1, InType2 msg2, InType3 msg3);
public InType1 getMsg1of3(OutType msg);
public InType2 getMsg2of3(OutType msg);
public InType3 getMsg3of3(OutType msg);
}
}

View File

@ -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;

View File

@ -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<DlogProof.FirstMessage, DlogProof.FinalMessage> {
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<DlogProof.FirstMessage, DlogProof.FinalMessage> {
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<DlogProof.FirstMessage, DlogProof.FinalMessage> {
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<AndProof.FirstMessage, DlogProof.FirstMessage, AndProof.FinalMessage, DlogProof.FinalMessage> {
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<AndProof.FirstMessage, DlogProof.FirstMessage, AndProof.FinalMessage, DlogProof.FinalMessage> {
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]));
}
}
}

View File

@ -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<Mixing.Mix2Proof.AndProof.FirstMessage,Mixing.Mix2Proof.DlogProof.FirstMessage,Mixing.Mix2Proof.DlogProof.FirstMessage> {
@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<Mixing.Mix2Proof.AndProof.FinalMessage,Mixing.Mix2Proof.DlogProof.FinalMessage,Mixing.Mix2Proof.DlogProof.FinalMessage> {
@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<Mixing.Mix2Proof.FirstMessage,Mixing.Mix2Proof.AndProof.FirstMessage,Mixing.Mix2Proof.AndProof.FirstMessage> {
@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<Mixing.Mix2Proof.FinalMessage,BigInteger,Mixing.Mix2Proof.AndProof.FinalMessage,Mixing.Mix2Proof.AndProof.FinalMessage> {
@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<Mixing.Mix2Proof, Mixing.Mix2Proof.FirstMessage,Mixing.Mix2Proof.FinalMessage> {
@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();
}
}
}

View File

@ -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<Mixing.Mix2Proof, Mixing.Mix2Proof.FirstMessage, Mixing.Mix2Proof.FinalMessage> 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)):
// * <ol>
// * <li>Prover chooses a random r, and sends g^r, h^r </li>
// * <li>Verifier chooses a random c and sends c</li>
// * <li>Prover computes </li>
// * </ol>
// *
// *
// * @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();
// }
/**
* FiatShamir 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)):
* <ol>
* <li>Prover chooses a random r, and sends g^r, h^r </li>
* <li>Verifier chooses a random c and sends c</li>
* <li>Prover computes </li>
* </ol>
*
*
* @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();
}
}

View File

@ -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<NIZKMsgType, FirstMsgType extends Message, FinalMessageType> {
final RandomOracle randomOracle;
final Concatenator.Pair<NIZKMsgType, FirstMsgType, FinalMessageType> concat;
public SigmaFiatShamir(Concatenator.Pair<NIZKMsgType, FirstMsgType, FinalMessageType> concat, RandomOracle randomOracle) {
this.concat = concat;
this.randomOracle = randomOracle;
}
/**
* FiatShamir 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<FirstMsgType, FinalMessageType> 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<FirstMsgType, FinalMessageType> verifier) {
FirstMsgType firstMessage = concat.getMsg1(NIZK);
BigInteger challenge = hash(firstMessage, randomOracle);
return verifier.verify(firstMessage, challenge, concat.getMsg2(NIZK));
}
}

View File

@ -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 <FirstMsgType, FinalMessageType> {
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 <FirstMsgType, FinalMessageType> {
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 <FirstMsgType, FinalMessageType> {
public boolean verify(FirstMsgType firstMessage, BigInteger challenge, FinalMessageType finalMessage);
}
}

View File

@ -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);
}
}
}

View File

@ -0,0 +1,87 @@
package meerkat.mixer.proofs;
import java.math.BigInteger;
/**
* Generic conjuction of sigma protocols
*/
public class SigmaProtocolAnd2 {
static public class Prover <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
implements SigmaProtocol.Prover<FirstMessageOut, FinalMessageOut> {
final SigmaProtocol.Prover<FirstMessageIn, FinalMessageIn>[] provers;
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
final Concatenator.Pair<FinalMessageOut, FinalMessageIn, FinalMessageIn> finalMessageConcatenator;
public Prover(Concatenator.Pair firstMessageConcatenator, Concatenator.Pair finalMessageConcatenator,
SigmaProtocol.Prover<FirstMessageIn, FinalMessageIn>... 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<FirstMessageOut, FirstMessageIn,
FinalMessageOut, FinalMessageIn>
implements SigmaProtocol.Verifier<FirstMessageOut, FinalMessageOut> {
final SigmaProtocol.Verifier<FirstMessageIn, FinalMessageIn>[] verifiers;
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
final Concatenator.Pair<FinalMessageOut, FinalMessageIn, FinalMessageIn> 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 <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
implements SigmaProtocol.Simulator<FirstMessageOut, FinalMessageOut> {
final SigmaProtocol.Simulator<FirstMessageIn, FinalMessageIn>[] simulators;
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
final Concatenator.Pair<FinalMessageOut, FinalMessageIn, FinalMessageIn> 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(); }
}
}

View File

@ -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 <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
implements SigmaProtocol.Prover<FirstMessageOut, FinalMessageOut> {
final SigmaProtocol.Prover<FirstMessageIn, FinalMessageIn> prover;
final SigmaProtocol.Simulator<FirstMessageIn, FinalMessageIn> simulator;
final int proverIdx;
final Concatenator.Pair<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
final Concatenator.Triplet<FinalMessageOut, BigInteger, FinalMessageIn, FinalMessageIn> 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<FirstMessageIn, FinalMessageIn> prover, SigmaProtocol.Simulator<FirstMessageIn, FinalMessageIn> 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 <FirstMessageOut, FirstMessageIn, FinalMessageOut, FinalMessageIn>
implements SigmaProtocol.Verifier<FirstMessageOut, FinalMessageOut> {
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<FirstMessageOut, FirstMessageIn, FirstMessageIn> firstMessageConcatenator;
final Concatenator.Triplet<FinalMessageOut, BigInteger, FinalMessageIn, FinalMessageIn> finalMessageConcatenator;
final ChallengeGenerator challengeGenerator;
final SigmaProtocol.Verifier<FirstMessageIn, FinalMessageIn>[] 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));
}
}

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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());
// }
// }
}

View File

@ -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<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
System.out.println("start mixing");

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> {
@Override
void generateRandomTrueStatement() {
}
@Override
void generateRandomFalseStatement() {
}
@Override
protected SigmaProtocol.Prover<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewProver() {
return null;
}
@Override
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewVerifier() {
return null;
}
@Override
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.AndProof.FirstMessage, Mixing.Mix2Proof.AndProof.FinalMessage> getNewSimulator() {
return null;
}
@Override
protected RandomOracle getRandomOracle() {
return null;
}
@Override
protected Random getRandom() {
return null;
}
@Override
protected BigInteger getChallengeModulus() {
return null;
}
}

View File

@ -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<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {
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<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewProver() {
prover = prots.new DlogStatementSchnorrProver(statement, witness);
return prover;
}
@Override
protected SigmaProtocol.Verifier<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewVerifier() {
verifier = prots.new DlogStatementSchnorrVerifier(statement);
return verifier;
}
@Override
protected SigmaProtocol.Simulator<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> 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();
}
}

View File

@ -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;
}
}

View File

@ -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<M1 extends Message, M2> {
public final int NUM_REPEAT = 10;
abstract void generateRandomTrueStatement();
abstract void generateRandomFalseStatement();
abstract protected SigmaProtocol.Prover<M1, M2> getNewProver();
abstract protected SigmaProtocol.Verifier<M1, M2> getNewVerifier();
abstract protected SigmaProtocol.Simulator<M1, M2> getNewSimulator();
class NIZKConcat implements Concatenator.Pair<Pair<M1,M2>, M1, M2> {
@Override
public Pair<M1, M2> concatenate(M1 msg1, M2 msg2) { return new Pair<M1, M2>(msg1, msg2); }
@Override
public M1 getMsg1(Pair<M1,M2> msg) { return msg.a; }
@Override
public M2 getMsg2(Pair<M1,M2> msg) { return msg.b; }
}
final NIZKConcat nizkConcat = new NIZKConcat();
abstract protected RandomOracle getRandomOracle();
abstract protected Random getRandom();
abstract protected BigInteger getChallengeModulus();
SigmaProtocol.Prover<M1, M2> prover;
SigmaProtocol.Verifier<M1, M2> verifier;
SigmaProtocol.Simulator<M1, M2> 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<Pair<M1,M2>, M1, M2> fiatShamir = new SigmaFiatShamir<Pair<M1,M2>, M1, M2>(nizkConcat, getRandomOracle());
prover = getNewProver();
Pair<M1,M2> nizk = fiatShamir.generateNizk(prover);
verifier = getNewVerifier();
boolean nizkOk = fiatShamir.verifyNizk(nizk, verifier);
assertTrue(String.format("NIZK Verification error in iteration %d", i), nizkOk);
}
}
}