Writing tests for new ZKPs
parent
723d348443
commit
a5cceaa6c0
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 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)):
|
||||
* <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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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(); }
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue