rewriting mixing proofs
parent
aac7a50a94
commit
b7ef2c10e1
|
@ -11,43 +11,37 @@ message Plaintext {
|
|||
bytes data = 1;
|
||||
}
|
||||
|
||||
message ZeroKnowledgeProof {
|
||||
message OrProof {
|
||||
message Mix2Proof {
|
||||
// Proof that log_g(a) = log_h(b) = x
|
||||
message DlogProof {
|
||||
message FirstMessage {
|
||||
GroupElement g1 = 1;
|
||||
GroupElement h1 = 2;
|
||||
GroupElement g2 = 3;
|
||||
GroupElement h2 = 4;
|
||||
GroupElement g1Tag = 5;
|
||||
GroupElement h1Tag = 6;
|
||||
GroupElement g2Tag = 7;
|
||||
GroupElement h2Tag = 8;
|
||||
GroupElement u = 9;
|
||||
GroupElement v = 10;
|
||||
GroupElement uTag = 11;
|
||||
GroupElement vTag = 12;
|
||||
GroupElement gr = 1; // g^r
|
||||
GroupElement hr = 2; // h^r
|
||||
}
|
||||
//statement parameters : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag;
|
||||
GroupElement g1 = 1;
|
||||
GroupElement h1 = 2;
|
||||
GroupElement g2 = 3;
|
||||
GroupElement h2 = 4;
|
||||
GroupElement g1Tag = 5;
|
||||
GroupElement h1Tag = 6;
|
||||
GroupElement g2Tag = 7;
|
||||
GroupElement h2Tag = 8;
|
||||
message FinalMessage {
|
||||
BigInteger xcr = 1; // xc+r, where c is the challenge
|
||||
}
|
||||
}
|
||||
|
||||
//calc: u, v, uTag, vTag;
|
||||
GroupElement u = 9;
|
||||
GroupElement v = 10;
|
||||
GroupElement uTag = 11;
|
||||
GroupElement vTag = 12;
|
||||
message AndProof {
|
||||
message FirstMessage {
|
||||
DlogProof.FirstMessage clause0 = 1;
|
||||
DlogProof.FirstMessage clause1 = 2;
|
||||
}
|
||||
message FinalMessage {
|
||||
DlogProof.FinalMessage clause0 = 1;
|
||||
DlogProof.FinalMessage clause1 = 2;
|
||||
}
|
||||
}
|
||||
|
||||
//generated: c1,c2,z,zTag
|
||||
BigInteger c1 = 13;
|
||||
BigInteger c2 = 14;
|
||||
BigInteger z = 15;
|
||||
BigInteger zTag = 16;
|
||||
message FirstMessage {
|
||||
AndProof.FirstMessage clause0 = 1;
|
||||
AndProof.FirstMessage clause1 = 2;
|
||||
}
|
||||
message FinalMessage {
|
||||
AndProof.FinalMessage clause0 = 1;
|
||||
AndProof.FinalMessage clause1 = 2;
|
||||
BigInteger c0 = 3; // Challenge for clause 0; challenge for clause 1 is computed from real challenge and c0
|
||||
}
|
||||
|
||||
message Location{
|
||||
|
@ -56,9 +50,7 @@ message ZeroKnowledgeProof {
|
|||
int32 layer = 3;
|
||||
}
|
||||
|
||||
OrProof first = 1;
|
||||
OrProof second = 2;
|
||||
OrProof third = 3;
|
||||
OrProof fourth = 4;
|
||||
FirstMessage firstMessage = 1;
|
||||
FinalMessage finalMessage = 2;
|
||||
Location location = 5;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.google.protobuf.GeneratedMessage;
|
|||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.ConcreteCrypto.GroupElement;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||
|
@ -66,8 +67,8 @@ public class ECElGamalUtils {
|
|||
public static <T extends Message> T decrypt(Class<T> plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher)
|
||||
throws InvalidProtocolBufferException {
|
||||
ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData());
|
||||
ByteString c1encoded = cipherText.getC1();
|
||||
ByteString c2encoded = cipherText.getC2();
|
||||
GroupElement c1encoded = cipherText.getC1();
|
||||
GroupElement c2encoded = cipherText.getC2();
|
||||
|
||||
ECPoint c1 = group.decode(c1encoded.toByteArray());
|
||||
ECPoint c2 = group.decode(c2encoded.toByteArray());
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.ConcreteCrypto.ElGamalCiphertext;
|
||||
import meerkat.protobuf.ConcreteCrypto.GroupElement;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Crypto.EncryptionRandomness;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* use for organize the input for each ZKP
|
||||
* used for organizing the input for each ZKP
|
||||
*
|
||||
* both meerkat.mixer.proofs and meerkat.mixer.verifier implementation use it
|
||||
*/
|
||||
public class ECElGamalMixParams {
|
||||
|
||||
private final ECElGamalEncryption encryptor;
|
||||
private final ECGroup group;
|
||||
private final ECPoint g;
|
||||
private final ECPoint h;
|
||||
final ECElGamalEncryption encryptor;
|
||||
final ECGroup group;
|
||||
final ECPoint g;
|
||||
final ECPoint h;
|
||||
|
||||
// Cache encoded formats to save multiple re-encodings
|
||||
private final ConcreteCrypto.GroupElement gEncoded;
|
||||
private final ConcreteCrypto.GroupElement hEncoded;
|
||||
private final GroupElement gEncoded;
|
||||
private final GroupElement hEncoded;
|
||||
|
||||
/**
|
||||
* @param encryptor encryptor used for encoding/decoding serialized ciphertexts. The group, default generator and
|
||||
|
@ -45,297 +48,156 @@ public class ECElGamalMixParams {
|
|||
/**
|
||||
* can be used by anyone, e.g meerkat.mixer.verifier
|
||||
*
|
||||
* call to the meerkat.mixer.main overload with flag = false
|
||||
* call to the meerkat.mixer.main overload with trueClauseIndex = false
|
||||
*/
|
||||
public Statement createStatement(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2
|
||||
, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2) throws InvalidProtocolBufferException {
|
||||
public Mix2Statement createStatement(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2) throws InvalidProtocolBufferException {
|
||||
|
||||
ConcreteCrypto.ElGamalCiphertext in1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in1);
|
||||
ConcreteCrypto.ElGamalCiphertext in2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in2);
|
||||
ConcreteCrypto.ElGamalCiphertext out1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out1);
|
||||
ConcreteCrypto.ElGamalCiphertext out2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out2);
|
||||
return new Statement(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal);
|
||||
ElGamalCiphertext in1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in1);
|
||||
ElGamalCiphertext in2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in2);
|
||||
ElGamalCiphertext out1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out1);
|
||||
ElGamalCiphertext out2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out2);
|
||||
return new Mix2Statement(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* convert each encrypted message to ElGamalCiphertext
|
||||
*
|
||||
* @throws InvalidProtocolBufferException - in case that at least one of the encrypted messages isn't
|
||||
* @throws InvalidProtocolBufferException - in case one or more of the encrypted messages isn't
|
||||
* ElGamalCiphertext
|
||||
*/
|
||||
protected ProverStatement createProverStatement(Crypto.RerandomizableEncryptedMessage in1, Crypto.RerandomizableEncryptedMessage in2
|
||||
, Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out2
|
||||
, Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched)
|
||||
throws InvalidProtocolBufferException {
|
||||
protected Mix2StatementWitness createMix2Witness(EncryptionRandomness r1, EncryptionRandomness r2, boolean switched) {
|
||||
// if (!switched), dlogW1 is witness for a ~ c, dlogW2 is witness for b ~ d,
|
||||
// otherwise, dlogW1 is witness for a ~ d, dlogW2 is witness for b ~ c
|
||||
DlogStatementWitness dlogW1 = new DlogStatementWitness(encryptor.extractRandomness(r1));
|
||||
DlogStatementWitness dlogW2 = new DlogStatementWitness(encryptor.extractRandomness(r2));
|
||||
|
||||
//convert RerandomizableEncryptedMessage to ElGamalCiphertext
|
||||
ConcreteCrypto.ElGamalCiphertext in1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in1);
|
||||
ConcreteCrypto.ElGamalCiphertext in2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(in2);
|
||||
ConcreteCrypto.ElGamalCiphertext out1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out1);
|
||||
ConcreteCrypto.ElGamalCiphertext out2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(out2);
|
||||
AndStatementWitness andW = new AndStatementWitness(dlogW1, dlogW2);
|
||||
|
||||
return new ProverStatement(in1ElGamal, in2ElGamal, out1ElGamal, out2ElGamal, r1, r2, switched);
|
||||
return new Mix2StatementWitness(switched ? 1 : 0, andW);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Statement to be proved.
|
||||
* Mix2Statement to be proved.
|
||||
*
|
||||
* The actual stored data is a cached representation for use in proofs and verification. This consists of the four substatements that are ORs of the DLOG equality.
|
||||
*
|
||||
* A Statement can be constructed only by calling the {@link #createStatement} factory method on an instance of ECElGamalMixParams (all constructors are private)
|
||||
* A Mix2Statement can be constructed only by calling the {@link #createStatement} factory method on an instance of ECElGamalMixParams (all constructors are private)
|
||||
*
|
||||
*/
|
||||
public class Statement {
|
||||
public class Mix2Statement {
|
||||
|
||||
/**
|
||||
* Denote the first ciphertext pair e1=(e1c1,e1c2), e2=(e2c1,e2c2) and the second
|
||||
* e1N=(e1Nc1, e1Nc2) and e2N=(e2Nc1,e2Nc2).
|
||||
* Then ci_ejNDivek = ejNci/ekci
|
||||
*/
|
||||
ECPoint c1_e1NDive1;
|
||||
/**
|
||||
* See {@link #c1_e1NDive1}
|
||||
*/
|
||||
ECPoint c1_e2NDive1;
|
||||
public final AndStatement[] clauses = new AndStatement[2];
|
||||
|
||||
/**
|
||||
* See {@link #c1_e1NDive1}
|
||||
*/
|
||||
ECPoint c1_e1NDive2;
|
||||
private Mix2Statement(ElGamalCiphertext a, ElGamalCiphertext b,
|
||||
ElGamalCiphertext c, ElGamalCiphertext d){
|
||||
|
||||
/**
|
||||
* See {@link #c1_e1NDive1}
|
||||
*/
|
||||
ECPoint c1_e2NDive2;
|
||||
ECPoint a1 = encryptor.decodeElement(a.getC1());
|
||||
ECPoint a2 = encryptor.decodeElement(a.getC2());
|
||||
ECPoint b1 = encryptor.decodeElement(b.getC1());
|
||||
ECPoint b2 = encryptor.decodeElement(b.getC2());
|
||||
ECPoint c1 = encryptor.decodeElement(c.getC1());
|
||||
ECPoint c2 = encryptor.decodeElement(c.getC2());
|
||||
ECPoint d1 = encryptor.decodeElement(d.getC1());
|
||||
ECPoint d2 = encryptor.decodeElement(d.getC2());
|
||||
|
||||
/**
|
||||
* See {@link #c1_e1NDive1}
|
||||
*/
|
||||
ECPoint c2_e1NDive1;
|
||||
ECPoint c1_div_a1 = group.add(c1, group.negate(a1));
|
||||
ECPoint d1_div_a1 = group.add(d1, group.negate(a1));
|
||||
ECPoint c1_div_b1 = group.add(c1, group.negate(b1));
|
||||
ECPoint d1_div_b1 = group.add(d1, group.negate(b1));
|
||||
ECPoint c2_div_a2 = group.add(c2, group.negate(a2));
|
||||
ECPoint d2_div_a2 = group.add(d2, group.negate(a2));
|
||||
ECPoint c2_div_b2 = group.add(c2, group.negate(b2));
|
||||
ECPoint d2_div_b2 = group.add(d2, group.negate(b2));
|
||||
|
||||
/**
|
||||
* See {@link #c1_e1NDive1}
|
||||
*/
|
||||
ECPoint c2_e2NDive1;
|
||||
// "Straight assignment" (a ~ c, b ~ d)
|
||||
DlogStatement s0_0 = new DlogStatement(c1_div_a1, c2_div_a2);
|
||||
DlogStatement s0_1 = new DlogStatement(d1_div_b1, d2_div_b2);
|
||||
clauses[0] = new AndStatement(s0_0, s0_1);
|
||||
|
||||
/**
|
||||
* See {@link #c1_e1NDive1}
|
||||
*/
|
||||
ECPoint c2_e1NDive2;
|
||||
|
||||
/**
|
||||
* See {@link #c1_e1NDive1}
|
||||
*/
|
||||
ECPoint c2_e2NDive2;
|
||||
|
||||
|
||||
private final OrStatement orStatements[] = new OrStatement[4];
|
||||
|
||||
|
||||
public OrStatement getOrStatement(int num) {
|
||||
if (orStatements[0] == null)
|
||||
generateOrStatements();
|
||||
|
||||
return orStatements[num];
|
||||
}
|
||||
|
||||
public void setOrStatement(int num, OrStatement orStatement) {
|
||||
orStatements[num] = orStatement;
|
||||
// "Switched assignment" (a ~ d, b ~ c)
|
||||
DlogStatement s1_0 = new DlogStatement(d1_div_a1, d2_div_a2);
|
||||
DlogStatement s1_1 = new DlogStatement(c1_div_b1, c2_div_b2);
|
||||
clauses[1] = new AndStatement(s1_0, s1_1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Witness information that enables us to generate a ZK proof for the 2-ciphertext mix
|
||||
*/
|
||||
public class Mix2StatementWitness {
|
||||
/**
|
||||
* Generate and set the four substatements.
|
||||
* Which of the two clauses is the true one
|
||||
*/
|
||||
protected void generateOrStatements() {
|
||||
setOrStatement(0, new OrStatement(c1_e1NDive1,c2_e1NDive1,c1_e1NDive2,c2_e1NDive2));
|
||||
setOrStatement(1, new OrStatement(c1_e1NDive1,c2_e1NDive1,c1_e2NDive1,c2_e2NDive1));
|
||||
setOrStatement(2, new OrStatement(c1_e1NDive2,c2_e1NDive2,c1_e2NDive2,c2_e2NDive2));
|
||||
setOrStatement(3, new OrStatement(c1_e2NDive1,c2_e2NDive1,c1_e2NDive2,c2_e2NDive2));
|
||||
public final int trueClauseIndex;
|
||||
|
||||
public final AndStatementWitness witness;
|
||||
|
||||
private Mix2StatementWitness(int trueClauseIndex, AndStatementWitness witness) {
|
||||
|
||||
this.trueClauseIndex = trueClauseIndex;
|
||||
assert (trueClauseIndex >= 0 && trueClauseIndex < 2);
|
||||
this.witness = witness;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Statement(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2,
|
||||
ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){
|
||||
/**
|
||||
* Statement consisting of a conjunction of two {@link DlogStatement}s
|
||||
*/
|
||||
public class AndStatement {
|
||||
public final DlogStatement[] clauses = new DlogStatement[2];
|
||||
|
||||
ECPoint e1c1 = encryptor.decodeElement(e1.getC1());
|
||||
ECPoint e1c2 = encryptor.decodeElement(e1.getC2());
|
||||
ECPoint e2c1 = encryptor.decodeElement(e2.getC1());
|
||||
ECPoint e2c2 = encryptor.decodeElement(e2.getC2());
|
||||
ECPoint e1Nc1 = encryptor.decodeElement(e1New.getC1());
|
||||
ECPoint e1Nc2 = encryptor.decodeElement(e1New.getC2());
|
||||
ECPoint e2Nc1 = encryptor.decodeElement(e2New.getC1());
|
||||
ECPoint e2Nc2 = encryptor.decodeElement(e2New.getC2());
|
||||
private AndStatement(DlogStatement clause0, DlogStatement clause1) {
|
||||
this.clauses[0] = clause0;
|
||||
this.clauses[1] = clause1;
|
||||
}
|
||||
}
|
||||
|
||||
c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1));
|
||||
c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1));
|
||||
c1_e1NDive2 = group.add(e1Nc1, group.negate(e2c1));
|
||||
c1_e2NDive2 = group.add(e2Nc1, group.negate(e2c1));
|
||||
c2_e1NDive1 = group.add(e1Nc2, group.negate(e1c2));
|
||||
c2_e2NDive1 = group.add(e2Nc2, group.negate(e1c2));
|
||||
c2_e1NDive2 = group.add(e1Nc2, group.negate(e2c2));
|
||||
c2_e2NDive2 = group.add(e2Nc2, group.negate(e2c2));
|
||||
public class AndStatementWitness {
|
||||
public final DlogStatementWitness[] witnesses = new DlogStatementWitness[2];
|
||||
|
||||
private AndStatementWitness(DlogStatementWitness witness0, DlogStatementWitness witness1) {
|
||||
this.witnesses[0] = witness0;
|
||||
this.witnesses[1] = witness1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A statement with additional witness information that enables us to generate a ZK proof.
|
||||
* The parameters for a statement of discrete-log equality
|
||||
*
|
||||
* log_{g}(a)==log_{h}(b)
|
||||
*/
|
||||
public class ProverStatement extends Statement {
|
||||
/**
|
||||
* True iff the ciphertexts were switched (i.e., decrypt(e1N) == decrypt(e2) and decrypt(e2N) == decrypt(e1)
|
||||
*/
|
||||
boolean switched;
|
||||
|
||||
/**
|
||||
* Encryption randomness for e1 rerandomization
|
||||
*/
|
||||
Crypto.EncryptionRandomness r1;
|
||||
|
||||
/**
|
||||
* Encryption randomnesss for e2 rerandomization
|
||||
*/
|
||||
Crypto.EncryptionRandomness r2;
|
||||
|
||||
@Override
|
||||
protected void generateOrStatements() {
|
||||
ConcreteCrypto.GroupElement c1_e1NDive1Encoded = encryptor.encodeElement(c1_e1NDive1);
|
||||
ConcreteCrypto.GroupElement c1_e2NDive1Encoded = encryptor.encodeElement(c1_e2NDive1);
|
||||
ConcreteCrypto.GroupElement c1_e1NDive2Encoded = encryptor.encodeElement(c1_e1NDive2);
|
||||
ConcreteCrypto.GroupElement c1_e2NDive2Encoded = encryptor.encodeElement(c1_e2NDive2);
|
||||
ConcreteCrypto.GroupElement c2_e1NDive1Encoded = encryptor.encodeElement(c2_e1NDive1);
|
||||
ConcreteCrypto.GroupElement c2_e2NDive1Encoded = encryptor.encodeElement(c2_e2NDive1);
|
||||
ConcreteCrypto.GroupElement c2_e1NDive2Encoded = encryptor.encodeElement(c2_e1NDive2);
|
||||
ConcreteCrypto.GroupElement c2_e2NDive2Encoded = encryptor.encodeElement(c2_e2NDive2);
|
||||
|
||||
|
||||
if (!switched) {
|
||||
setOrStatement(0, new OrProverStatement(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2
|
||||
, c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded
|
||||
, r1, TrueCouple.left));
|
||||
setOrStatement(1, new OrProverStatement(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1
|
||||
, c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded
|
||||
, r1, TrueCouple.left));
|
||||
setOrStatement(2, new OrProverStatement(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2
|
||||
, c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded
|
||||
, r2, TrueCouple.right));
|
||||
setOrStatement(3, new OrProverStatement(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2
|
||||
, c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded
|
||||
, r2, TrueCouple.right));
|
||||
} else {
|
||||
setOrStatement(0, new OrProverStatement(c1_e1NDive1, c2_e1NDive1, c1_e1NDive2, c2_e1NDive2
|
||||
, c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e1NDive2Encoded, c2_e1NDive2Encoded
|
||||
, r2, TrueCouple.right));
|
||||
setOrStatement(1, new OrProverStatement(c1_e1NDive1, c2_e1NDive1, c1_e2NDive1, c2_e2NDive1
|
||||
, c1_e1NDive1Encoded, c2_e1NDive1Encoded, c1_e2NDive1Encoded, c2_e2NDive1Encoded
|
||||
, r1, TrueCouple.right));
|
||||
setOrStatement(2, new OrProverStatement(c1_e1NDive2, c2_e1NDive2, c1_e2NDive2, c2_e2NDive2
|
||||
, c1_e1NDive2Encoded, c2_e1NDive2Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded
|
||||
, r2, TrueCouple.left));
|
||||
setOrStatement(3, new OrProverStatement(c1_e2NDive1, c2_e2NDive1, c1_e2NDive2, c2_e2NDive2
|
||||
, c1_e2NDive1Encoded, c2_e2NDive1Encoded, c1_e2NDive2Encoded, c2_e2NDive2Encoded
|
||||
, r1, TrueCouple.left));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public OrProverStatement getOrStatement(int num) {
|
||||
OrStatement orStatement = super.getOrStatement(num);
|
||||
if (!(orStatement instanceof OrProverStatement))
|
||||
throw new RuntimeException("ProverStatement should always have OrProverStatement substatements!!");
|
||||
|
||||
return (OrProverStatement) orStatement;
|
||||
}
|
||||
|
||||
private ProverStatement(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2,
|
||||
ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New,
|
||||
Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r2, boolean switched) {
|
||||
super(e1, e2, e1New, e2New);
|
||||
this.r1 = r1;
|
||||
this.r2 = r2;
|
||||
this.switched = switched;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The statement of a single disjunction to be proved:
|
||||
* Either there exists x s.t (g1 ^ x == h1 and g2 ^ x == h2) or there exists x s.t. (g1' ^ x == h1 and g2' ^ x == h2)
|
||||
*
|
||||
* The statement can't be constructed externally (all constructors are private)
|
||||
*
|
||||
* 4 instances will be constructed for each new {@link ECElGamalMixParams.Statement}
|
||||
*
|
||||
*/
|
||||
public class OrStatement {
|
||||
public final ECPoint g1;
|
||||
public final ECPoint h1;
|
||||
public final ECPoint g2;
|
||||
public final ECPoint h2;
|
||||
public final ECPoint g1Tag;
|
||||
public final ECPoint h1Tag;
|
||||
public final ECPoint g2Tag;
|
||||
public final ECPoint h2Tag;
|
||||
|
||||
|
||||
/**
|
||||
* used by meerkat.mixer.proofs only
|
||||
*/
|
||||
private OrStatement(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag) {
|
||||
this.g1 = g;
|
||||
this.h1 = h1;
|
||||
this.g2 = h;
|
||||
this.h2 = h2;
|
||||
this.g1Tag = g;
|
||||
this.h1Tag = h1Tag;
|
||||
this.g2Tag = h;
|
||||
this.h2Tag = h2Tag;
|
||||
|
||||
public class DlogStatement {
|
||||
public final ECPoint g;
|
||||
public final ECPoint a;
|
||||
public final ECPoint h;
|
||||
public final ECPoint b;
|
||||
|
||||
|
||||
private DlogStatement(ECPoint a, ECPoint b) {
|
||||
this.g = ECElGamalMixParams.this.g;
|
||||
this.a = a;
|
||||
this.h = ECElGamalMixParams.this.h;
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link OrStatement} with additional info needed to generate a ZK proof.
|
||||
* Witness for correctness of a {@link DlogStatement}
|
||||
*/
|
||||
public class OrProverStatement extends OrStatement {
|
||||
|
||||
protected final Crypto.EncryptionRandomness x;
|
||||
protected final TrueCouple flag;
|
||||
|
||||
// We cache the encoded versions since we need them as input to the random oracle
|
||||
// when using the Fiat-Shamir heuristic.
|
||||
|
||||
protected final ConcreteCrypto.GroupElement g1Encoded;
|
||||
protected final ConcreteCrypto.GroupElement h1Encoded;
|
||||
protected final ConcreteCrypto.GroupElement g2Encoded;
|
||||
protected final ConcreteCrypto.GroupElement h2Encoded;
|
||||
|
||||
protected final ConcreteCrypto.GroupElement g1TagEncoded;
|
||||
protected final ConcreteCrypto.GroupElement h1TagEncoded;
|
||||
protected final ConcreteCrypto.GroupElement g2TagEncoded;
|
||||
protected final ConcreteCrypto.GroupElement h2TagEncoded;
|
||||
|
||||
private OrProverStatement(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag,
|
||||
ConcreteCrypto.GroupElement h1Encoded, ConcreteCrypto.GroupElement h2Encoded, ConcreteCrypto.GroupElement h1TagEncoded, ConcreteCrypto.GroupElement h2TagEncoded,
|
||||
Crypto.EncryptionRandomness x, TrueCouple flag) {
|
||||
super(h1, h2, h1Tag, h2Tag);
|
||||
this.g1Encoded = gEncoded;
|
||||
this.h1Encoded = h1Encoded;
|
||||
this.g2Encoded = hEncoded;
|
||||
this.h2Encoded = h2Encoded;
|
||||
this.g1TagEncoded = gEncoded;
|
||||
this.h1TagEncoded = h1TagEncoded;
|
||||
this.g2TagEncoded = hEncoded;
|
||||
this.h2TagEncoded = h2TagEncoded;
|
||||
public class DlogStatementWitness {
|
||||
/**
|
||||
* The actual discrete logarithm (i.e., a=g^x, b=h^x)
|
||||
*/
|
||||
BigInteger x;
|
||||
|
||||
public DlogStatementWitness(BigInteger x) {
|
||||
this.x = x;
|
||||
this.flag = flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.concrete.ECElGamalEncryption;
|
||||
import meerkat.crypto.concrete.Util;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Prover, Simulator and Verifier
|
||||
*/
|
||||
public class ECElGamalMixProtocols {
|
||||
final ECElGamalMixParams params;
|
||||
final ECGroup group;
|
||||
final ECElGamalEncryption encryptor;
|
||||
final ECPoint g;
|
||||
final ECPoint h;
|
||||
final Random rand;
|
||||
|
||||
|
||||
public ECElGamalMixProtocols(ECElGamalMixParams params, Random rand) {
|
||||
this.params = params;
|
||||
this.rand = rand;
|
||||
group = params.group;
|
||||
encryptor = params.encryptor;
|
||||
g = params.g;
|
||||
h = params.h;
|
||||
}
|
||||
|
||||
public class DlogStatementSchnorrProver implements SigmaProtocol.Prover {
|
||||
ECElGamalMixParams.DlogStatement statement;
|
||||
ECElGamalMixParams.DlogStatementWitness witness;
|
||||
|
||||
BigInteger r = null;
|
||||
|
||||
public DlogStatementSchnorrProver(ECElGamalMixParams.DlogStatement statement, ECElGamalMixParams.DlogStatementWitness witness) {
|
||||
this.statement = statement;
|
||||
this.witness = witness;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mixing.Mix2Proof.DlogProof.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()
|
||||
.setGr(encryptor.encodeElement(gr))
|
||||
.setHr(encryptor.encodeElement(hr))
|
||||
.build();
|
||||
|
||||
return firstMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto.BigInteger getFinalMessage(BigInteger challenge) {
|
||||
return Util.encodeBigInteger(challenge.multiply(witness.x).add(r).mod(group.orderUpperBound()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -46,34 +46,34 @@ public class Prover implements Mix2ZeroKnowledgeProver {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param in1
|
||||
* @param in2
|
||||
* @param out1 - if switched then out1 = rerandomize(in2,r2) else out1 = rerandomize(in1,r1)
|
||||
* @param out2 - if switched then out2 = rerandomize(in1,r1) else out1 = rerandomize(in2,r2)
|
||||
* @param switched - flag
|
||||
* @param i - column of in1 and out1 in encryption table
|
||||
* @param j - column of in2 and out2 in encryption table
|
||||
* @param layer - row of in1,in2 in encryption table
|
||||
* @param a
|
||||
* @param b
|
||||
* @param c - if switched then c = rerandomize(b,r2) else c = rerandomize(a,r1)
|
||||
* @param d - if switched then d = rerandomize(a,r1) else d = rerandomize(b,r2)
|
||||
* @param switched - trueClauseIndex
|
||||
* @param i - column of a and c in encryption table
|
||||
* @param j - column of b and d in encryption table
|
||||
* @param layer - row of a,b in encryption table
|
||||
* @param r1
|
||||
* @param r2
|
||||
* @return - a valid ZKP that indeed out1,out2 calculated as required
|
||||
* @return - a valid ZKP that indeed c,d calculated as required
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
public Mixing.Mix2Proof prove(Crypto.RerandomizableEncryptedMessage a,
|
||||
Crypto.RerandomizableEncryptedMessage b,
|
||||
Crypto.RerandomizableEncryptedMessage c,
|
||||
Crypto.RerandomizableEncryptedMessage d,
|
||||
boolean switched,int i,int j, int layer,
|
||||
Crypto.EncryptionRandomness r1,
|
||||
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
|
||||
Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth;
|
||||
Mixing.Mix2Proof first,second,third,fourth;
|
||||
|
||||
ECElGamalMixParams.ProverStatement statement = mixParams.createProverStatement(in1,in2,out1,out2,r1,r2,switched);
|
||||
ECElGamalMixParams.MixStatementWitness statement = mixParams.createProverStatement(a,b,c,d,r1,r2,switched);
|
||||
|
||||
first = createOrProof(statement.getOrStatement(0));
|
||||
second = createOrProof(statement.getOrStatement(1));
|
||||
third = createOrProof(statement.getOrStatement(2));
|
||||
fourth = createOrProof(statement.getOrStatement(3));
|
||||
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)
|
||||
|
@ -98,18 +98,36 @@ public class Prover implements Mix2ZeroKnowledgeProver {
|
|||
* @param randomOracle
|
||||
* @return randomOracle.hash(input)
|
||||
*/
|
||||
public static BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.FirstMessage input, RandomOracle randomOracle) {
|
||||
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 (g1 ^ x == h1 and g2 ^ x == h2) or (g1' ^ x == h1 and g2' ^ x == h2).
|
||||
* 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_{g1}(h1)==log_{g1}(h2)):
|
||||
* 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 g1^r, g2^r </li>
|
||||
* <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>
|
||||
|
@ -140,7 +158,7 @@ public class Prover implements Mix2ZeroKnowledgeProver {
|
|||
Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage;
|
||||
|
||||
|
||||
switch (orStatement.flag) {
|
||||
switch (orStatement.trueClauseIndex) {
|
||||
case left:
|
||||
c2 = encryptor.generateRandomExponent(rand);
|
||||
zTag = encryptor.generateRandomExponent(rand);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Generic Sigma Protocol.
|
||||
* 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 Simulator {
|
||||
public Message getFirstMessage();
|
||||
public BigInteger getChallenge();
|
||||
public Message getFinalMessage();
|
||||
}
|
||||
|
||||
public interface Verifier {
|
||||
public boolean verify(Message firstMessage, BigInteger challenge, Message finalMessage);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Generic conjuction of sigma protocols
|
||||
*/
|
||||
public class SigmaProtocolAnd {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package meerkat.mixer.proofs;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Disjunction of 2 Sigma protocol statements
|
||||
*/
|
||||
public class SigmaProtocolOr2 {
|
||||
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);
|
||||
|
||||
/**
|
||||
* Subtract two challenges in an appropriate way (e.g., mod group order)
|
||||
* @param c1
|
||||
* @param c2
|
||||
* @return
|
||||
*/
|
||||
abstract protected BigInteger subtractChallenge(BigInteger c1, BigInteger c2);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param prover
|
||||
* @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) {
|
||||
this.prover = prover;
|
||||
this.simulator = simulator;
|
||||
this.proverIdx = proverIdx;
|
||||
assert (proverIdx >= 0 && proverIdx < 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getFirstMessage() {
|
||||
if (proverIdx == 0) {
|
||||
return buildConcatenatedFirstMessage(prover.getFirstMessage(), simulator.getFirstMessage());
|
||||
} else {
|
||||
return buildConcatenatedFirstMessage(simulator.getFirstMessage(), prover.getFirstMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Message getFinalMessage(BigInteger challenge) {
|
||||
BigInteger realchallenge = subtractChallenge(challenge, simulator.getChallenge());
|
||||
if (proverIdx == 0) {
|
||||
return buildConcatenatedFinalMessage(realchallenge, prover.getFinalMessage(realchallenge), simulator.getFinalMessage());
|
||||
} else {
|
||||
return buildConcatenatedFinalMessage(simulator.getChallenge(), simulator.getFinalMessage(), prover.getFinalMessage(realchallenge));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract public class Verifier implements SigmaProtocol.Verifier {
|
||||
final SigmaProtocol.Verifier[] verifiers;
|
||||
|
||||
abstract protected Message getFirstMessage(Message concatenated, int verifier);
|
||||
abstract protected BigInteger getFirstChallenge(Message concatenated);
|
||||
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) {
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,13 +2,17 @@ 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;
|
||||
|
||||
/**
|
||||
* implements Mix2ZeroKnowledgeVerifier
|
||||
*/
|
||||
|
@ -52,42 +56,76 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
|
|||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException {
|
||||
ECElGamalMixParams.Statement statement = mixParams.createStatement(in1,in2,out1,out2);
|
||||
return verifyElGamaOrProof(statement.getOrStatement(0), proof.getFirst())&&
|
||||
verifyElGamaOrProof(statement.getOrStatement(1), proof.getSecond())&&
|
||||
verifyElGamaOrProof(statement.getOrStatement(2), proof.getThird())&&
|
||||
verifyElGamaOrProof(statement.getOrStatement(3), proof.getFourth());
|
||||
ECElGamalMixParams.Mix2Statement statement = mixParams.createStatement(in1,in2,out1,out2);
|
||||
return verifyFiatShamirOrProof(statement, proof.getFirst(), proof.getSecond());
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param orStatement
|
||||
* @param orProof
|
||||
* @return verify single or proof
|
||||
* Verify a Schnorr proof of discrete log equality, given the entire transcript of the ZKP.
|
||||
* @param statement
|
||||
* @param firstMessage
|
||||
* @param challenge
|
||||
* @param finalMessage
|
||||
* @return
|
||||
*/
|
||||
private boolean verifyElGamaOrProof(ECElGamalMixParams.OrStatement orStatement,
|
||||
Mixing.ZeroKnowledgeProof.OrProof orProof) {
|
||||
ZeroKnowledgeOrProofParser.ZeroKnowledgeOrProofContainer container = parser.parseOrProof(orProof);
|
||||
return container.g1.equals(orStatement.g1) &&
|
||||
container.h1.equals(orStatement.h1) &&
|
||||
container.g2.equals(orStatement.g2) &&
|
||||
container.h2.equals(orStatement.h2) &&
|
||||
container.g1Tag.equals(orStatement.g1Tag) &&
|
||||
container.h1Tag.equals(orStatement.h1Tag) &&
|
||||
container.g2Tag.equals(orStatement.g2Tag) &&
|
||||
container.h2Tag.equals(orStatement.h2Tag) &&
|
||||
container.c1.add(container.c2).mod(group.orderUpperBound())
|
||||
.equals(Prover.hash(container.firstMessage,randomOracle).mod(group.orderUpperBound())) &&
|
||||
group.multiply(container.g1, container.z)
|
||||
.equals(group.add(container.u, group.multiply(container.h1,container.c1))) &&
|
||||
group.multiply(container.g2, container.z)
|
||||
.equals(group.add(container.v, group.multiply(container.h2,container.c1))) &&
|
||||
group.multiply(container.g1Tag, container.zTag)
|
||||
.equals(group.add(container.uTag, group.multiply(container.h1Tag,container.c2))) &&
|
||||
group.multiply(container.g2Tag, container.zTag)
|
||||
.equals(group.add(container.vTag, group.multiply(container.h2Tag,container.c2)));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue