Yet more mixer refactoring

mixer
Tal Moran 2016-11-02 11:59:20 +02:00
parent 5b268cd779
commit aac7a50a94
12 changed files with 307 additions and 204 deletions

View File

@ -80,6 +80,45 @@ public class ECElGamalEncryption implements Encryption {
elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ()); elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ());
} }
/**
* Encode a group element into a protobuf.
* @param p
* @return
*/
public ConcreteCrypto.GroupElement encodeElement(ECPoint p) {
return encodeElement(group, p);
}
/**
* Encode a group element into a protobuf.
*
* @param group group to use for encoding
* @param p element to encode.
* @return
*/
public static ConcreteCrypto.GroupElement encodeElement(ECGroup group, ECPoint p) {
return ConcreteCrypto.GroupElement.newBuilder().setData(ByteString.copyFrom(p.getEncoded(true))).build();
}
/**
* Decode from the serialized representation to an {@link ECPoint} object.
* @param bs
* @return
*/
public ECPoint decodeElement(ConcreteCrypto.GroupElement bs) {
return decodeElement(group, bs);
}
/**
* Decode from the serialized representation to an {@link ECPoint} object.
* @param group group to use for decoding.
* @param bs
* @return
*/
public static ECPoint decodeElement(ECGroup group, ConcreteCrypto.GroupElement bs) {
return group.decode(bs.getData().toByteArray());
}
@Override @Override
public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) { public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) {
@ -95,11 +134,11 @@ public class ECElGamalEncryption implements Encryption {
byte[] msg = out.toByteArray(); byte[] msg = out.toByteArray();
ECPoint encodedMsg = group.injectiveEncode(msg, new PRGRandom(msg)); ECPoint encodedMsg = group.injectiveEncode(msg, new PRGRandom(msg));
BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); BigInteger rndInt = extractRandomness(rnd);
Pair<ECPoint,ECPoint> cipherText = elGamalPK.encrypt(encodedMsg, rndInt); Pair<ECPoint,ECPoint> cipherText = elGamalPK.encrypt(encodedMsg, rndInt);
ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder() ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder()
.setC1(ByteString.copyFrom(cipherText.a.getEncoded(true))) .setC1(encodeElement(cipherText.a))
.setC2(ByteString.copyFrom(cipherText.b.getEncoded(true))) .setC2(encodeElement(cipherText.b))
.build(); .build();
return Crypto.RerandomizableEncryptedMessage.newBuilder() return Crypto.RerandomizableEncryptedMessage.newBuilder()
@ -118,34 +157,49 @@ public class ECElGamalEncryption implements Encryption {
@Override @Override
public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException { public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException {
BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray()); BigInteger rndInt = extractRandomness(rnd);
Pair<ECPoint,ECPoint> randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); Pair<ECPoint,ECPoint> randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt);
ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData());
Pair<ECPoint,ECPoint> originalCipher = new Pair<ECPoint, ECPoint>( Pair<ECPoint,ECPoint> originalCipher = new Pair<ECPoint, ECPoint>(
curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), decodeElement(originalEncodedCipher.getC1()),
curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); decodeElement(originalEncodedCipher.getC2()));
Pair<ECPoint,ECPoint> newCipher = elGamalPK.add(originalCipher, randomizer); Pair<ECPoint,ECPoint> newCipher = elGamalPK.add(originalCipher, randomizer);
return Crypto.RerandomizableEncryptedMessage.newBuilder() return Crypto.RerandomizableEncryptedMessage.newBuilder()
.setData( .setData(
ConcreteCrypto.ElGamalCiphertext.newBuilder() ConcreteCrypto.ElGamalCiphertext.newBuilder()
.setC1(ByteString.copyFrom(newCipher.a.getEncoded(true))) .setC1(encodeElement(newCipher.a))
.setC2(ByteString.copyFrom(newCipher.b.getEncoded(true))) .setC2(encodeElement(newCipher.b))
.build().toByteString() .build().toByteString()
).build(); ).build();
} }
@Override @Override
public Crypto.EncryptionRandomness generateRandomness(Random rand) { public Crypto.EncryptionRandomness generateRandomness(Random rand) {
BigInteger randomInt = new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand); BigInteger randomInt = generateRandomExponent(rand);
Crypto.EncryptionRandomness retval = Crypto.EncryptionRandomness.newBuilder() Crypto.EncryptionRandomness retval = Crypto.EncryptionRandomness.newBuilder()
.setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build(); .setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build();
return retval; return retval;
} }
/**
* Return the discrete log of a random element in the group (i.e., a random value in Z_{groupOrder})
* @param rand
* @return
*/
public BigInteger generateRandomExponent(Random rand) {
return new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand);
}
/**
* Extract (deserialize) the random exponent from a {@link Crypto.EncryptionRandomness} protobuf.
*
* @param encryptionRandomness
* @return
*/
public BigInteger extractRandomness(Crypto.EncryptionRandomness encryptionRandomness){ public BigInteger extractRandomness(Crypto.EncryptionRandomness encryptionRandomness){
return new BigInteger(1,encryptionRandomness.getData().toByteArray()); return BigIntegers.fromUnsignedByteArray(encryptionRandomness.getData().toByteArray());
} }
} }

View File

@ -0,0 +1,29 @@
package meerkat.crypto.concrete;
import com.google.protobuf.ByteString;
import meerkat.protobuf.Crypto;
import java.math.BigInteger;
/**
* Created by talm on 02/11/16.
*/
public class Util {
/**
* Decode a BigInteger from a protobuf
* @param i
* @return
*/
public static BigInteger decodeBigInteger(Crypto.BigInteger i) {
return new BigInteger(i.getData().toByteArray());
}
/**
* Encode a BigInteger in a protobuf.
* @param i
* @return
*/
public static Crypto.BigInteger encodeBigInteger(BigInteger i) {
return Crypto.BigInteger.newBuilder().setData(ByteString.copyFrom(i.toByteArray())).build();
}
}

View File

@ -14,9 +14,13 @@ message ElGamalPublicKey {
bytes subject_public_key_info = 1; bytes subject_public_key_info = 1;
} }
// An El-Gamal ciphertext
// Each group element should be an ASN.1 encoded curve point with compression. // Each group element should be an ASN.1 encoded curve point with compression.
message ElGamalCiphertext { message GroupElement {
bytes c1 = 1; // First group element bytes data = 1;
bytes c2 = 2; // Second group element }
// An El-Gamal ciphertext
message ElGamalCiphertext {
GroupElement c1 = 1; // First group element
GroupElement c2 = 2; // Second group element
} }

View File

@ -5,49 +5,51 @@ package meerkat;
option java_package = "meerkat.protobuf"; option java_package = "meerkat.protobuf";
import 'meerkat/crypto.proto'; import 'meerkat/crypto.proto';
import 'meerkat/concrete_crypto.proto';
message Plaintext{ message Plaintext {
bytes data = 1; bytes data = 1;
} }
message ZeroKnowledgeProof { message ZeroKnowledgeProof {
message OrProof { message OrProof {
message ForRandomOracle{ message FirstMessage {
bytes g1 = 1; GroupElement g1 = 1;
bytes h1 = 2; GroupElement h1 = 2;
bytes g2 = 3; GroupElement g2 = 3;
bytes h2 = 4; GroupElement h2 = 4;
bytes g1Tag = 5; GroupElement g1Tag = 5;
bytes h1Tag = 6; GroupElement h1Tag = 6;
bytes g2Tag = 7; GroupElement g2Tag = 7;
bytes h2Tag = 8; GroupElement h2Tag = 8;
bytes u = 9; GroupElement u = 9;
bytes v = 10; GroupElement v = 10;
bytes uTag = 11; GroupElement uTag = 11;
bytes vTag = 12; GroupElement vTag = 12;
} }
//input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag; //statement parameters : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag;
bytes g1 = 1; GroupElement g1 = 1;
bytes h1 = 2; GroupElement h1 = 2;
bytes g2 = 3; GroupElement g2 = 3;
bytes h2 = 4; GroupElement h2 = 4;
bytes g1Tag = 5; GroupElement g1Tag = 5;
bytes h1Tag = 6; GroupElement h1Tag = 6;
bytes g2Tag = 7; GroupElement g2Tag = 7;
bytes h2Tag = 8; GroupElement h2Tag = 8;
//calc: u, v, uTag, vTag; //calc: u, v, uTag, vTag;
bytes u = 9; GroupElement u = 9;
bytes v = 10; GroupElement v = 10;
bytes uTag = 11; GroupElement uTag = 11;
bytes vTag = 12; GroupElement vTag = 12;
//generated: c1,c2,z,zTag //generated: c1,c2,z,zTag
bytes c1 = 13; BigInteger c1 = 13;
bytes c2 = 14; BigInteger c2 = 14;
bytes z = 15; BigInteger z = 15;
bytes zTag = 16; BigInteger zTag = 16;
} }
message Location{ message Location{
int32 i = 1; int32 i = 1;
int32 j = 2; int32 j = 2;

View File

@ -15,33 +15,26 @@ import org.factcenter.qilin.primitives.concrete.ECGroup;
*/ */
public class ECElGamalMixParams { public class ECElGamalMixParams {
private final ECElGamalEncryption encryptor;
private final ECGroup group; private final ECGroup group;
private final ECPoint g; private final ECPoint g;
private final ECPoint h; private final ECPoint h;
private final byte[] gEncoded;
private final byte[] hEncoded;
// Cache encoded formats to save multiple re-encodings
private final ConcreteCrypto.GroupElement gEncoded;
private final ConcreteCrypto.GroupElement hEncoded;
/** /**
* Decode from the serialized representation to an {@link ECPoint} object. * @param encryptor encryptor used for encoding/decoding serialized ciphertexts. The group, default generator and
* @param bs * second base (h) are taken from the encryptor (second base is the public key)
* @return
*/ */
private ECPoint decodeECPoint(ByteString bs){ public ECElGamalMixParams(ECElGamalEncryption encryptor){
return group.decode(bs.toByteArray()); this.encryptor = encryptor;
} this.group = encryptor.getGroup();
this.g = group.getGenerator();
/** this.h = encryptor.getElGamalPK().getPK();
* @param group this.gEncoded = encryptor.encodeElement(g);
* @param g - generator of group this.hEncoded = encryptor.encodeElement(h);
* @param h - h = g ^ SecretKey
*/
public ECElGamalMixParams(ECGroup group, ECPoint g, ECPoint h){
this.group = group;
this.g = g;
this.h = h;
this.gEncoded = group.encode(g);
this.hEncoded = group.encode(h);
} }
public enum TrueCouple { public enum TrueCouple {
@ -165,17 +158,17 @@ public class ECElGamalMixParams {
} }
private Statement(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2 private Statement(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2,
, ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){ ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){
ECPoint e1c1 = decodeECPoint(e1.getC1()); ECPoint e1c1 = encryptor.decodeElement(e1.getC1());
ECPoint e1c2 = decodeECPoint(e1.getC2()); ECPoint e1c2 = encryptor.decodeElement(e1.getC2());
ECPoint e2c1 = decodeECPoint(e2.getC1()); ECPoint e2c1 = encryptor.decodeElement(e2.getC1());
ECPoint e2c2 = decodeECPoint(e2.getC2()); ECPoint e2c2 = encryptor.decodeElement(e2.getC2());
ECPoint e1Nc1 = decodeECPoint(e1New.getC1()); ECPoint e1Nc1 = encryptor.decodeElement(e1New.getC1());
ECPoint e1Nc2 = decodeECPoint(e1New.getC2()); ECPoint e1Nc2 = encryptor.decodeElement(e1New.getC2());
ECPoint e2Nc1 = decodeECPoint(e2New.getC1()); ECPoint e2Nc1 = encryptor.decodeElement(e2New.getC1());
ECPoint e2Nc2 = decodeECPoint(e2New.getC2()); ECPoint e2Nc2 = encryptor.decodeElement(e2New.getC2());
c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1)); c1_e1NDive1 = group.add(e1Nc1, group.negate(e1c1));
c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1)); c1_e2NDive1 = group.add(e2Nc1, group.negate(e1c1));
@ -188,6 +181,9 @@ public class ECElGamalMixParams {
} }
} }
/**
* A statement with additional witness information that enables us to generate a ZK proof.
*/
public class ProverStatement extends Statement { public class ProverStatement extends Statement {
/** /**
* True iff the ciphertexts were switched (i.e., decrypt(e1N) == decrypt(e2) and decrypt(e2N) == decrypt(e1) * True iff the ciphertexts were switched (i.e., decrypt(e1N) == decrypt(e2) and decrypt(e2N) == decrypt(e1)
@ -206,14 +202,14 @@ public class ECElGamalMixParams {
@Override @Override
protected void generateOrStatements() { protected void generateOrStatements() {
byte[] c1_e1NDive1Encoded = group.encode(c1_e1NDive1); ConcreteCrypto.GroupElement c1_e1NDive1Encoded = encryptor.encodeElement(c1_e1NDive1);
byte[] c1_e2NDive1Encoded = group.encode(c1_e2NDive1); ConcreteCrypto.GroupElement c1_e2NDive1Encoded = encryptor.encodeElement(c1_e2NDive1);
byte[] c1_e1NDive2Encoded = group.encode(c1_e1NDive2); ConcreteCrypto.GroupElement c1_e1NDive2Encoded = encryptor.encodeElement(c1_e1NDive2);
byte[] c1_e2NDive2Encoded = group.encode(c1_e2NDive2); ConcreteCrypto.GroupElement c1_e2NDive2Encoded = encryptor.encodeElement(c1_e2NDive2);
byte[] c2_e1NDive1Encoded = group.encode(c2_e1NDive1); ConcreteCrypto.GroupElement c2_e1NDive1Encoded = encryptor.encodeElement(c2_e1NDive1);
byte[] c2_e2NDive1Encoded = group.encode(c2_e2NDive1); ConcreteCrypto.GroupElement c2_e2NDive1Encoded = encryptor.encodeElement(c2_e2NDive1);
byte[] c2_e1NDive2Encoded = group.encode(c2_e1NDive2); ConcreteCrypto.GroupElement c2_e1NDive2Encoded = encryptor.encodeElement(c2_e1NDive2);
byte[] c2_e2NDive2Encoded = group.encode(c2_e2NDive2); ConcreteCrypto.GroupElement c2_e2NDive2Encoded = encryptor.encodeElement(c2_e2NDive2);
if (!switched) { if (!switched) {
@ -304,20 +300,29 @@ public class ECElGamalMixParams {
} }
} }
/**
* An {@link OrStatement} with additional info needed to generate a ZK proof.
*/
public class OrProverStatement extends OrStatement { public class OrProverStatement extends OrStatement {
protected final byte[] g1Encoded;
protected final byte[] h1Encoded;
protected final byte[] g2Encoded;
protected final byte[] h2Encoded;
protected final byte[] g1TagEncoded;
protected final byte[] h1TagEncoded;
protected final byte[] g2TagEncoded;
protected final byte[] h2TagEncoded;
protected final Crypto.EncryptionRandomness x; protected final Crypto.EncryptionRandomness x;
protected final TrueCouple flag; 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, private OrProverStatement(ECPoint h1, ECPoint h2, ECPoint h1Tag, ECPoint h2Tag,
byte[] h1Encoded, byte[] h2Encoded, byte[] h1TagEncoded, byte[] h2TagEncoded, ConcreteCrypto.GroupElement h1Encoded, ConcreteCrypto.GroupElement h2Encoded, ConcreteCrypto.GroupElement h1TagEncoded, ConcreteCrypto.GroupElement h2TagEncoded,
Crypto.EncryptionRandomness x, TrueCouple flag) { Crypto.EncryptionRandomness x, TrueCouple flag) {
super(h1, h2, h1Tag, h2Tag); super(h1, h2, h1Tag, h2Tag);
this.g1Encoded = gEncoded; this.g1Encoded = gEncoded;

View File

@ -1,8 +1,8 @@
package meerkat.mixer.proofs; package meerkat.mixer.proofs;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing; import meerkat.protobuf.Mixing;
@ -26,14 +26,14 @@ public class Prover implements Mix2ZeroKnowledgeProver {
private final ECElGamalEncryption encryptor; private final ECElGamalEncryption encryptor;
private final ECPoint g,h; private final ECPoint g,h;
private final BigInteger groupOrderUpperBound; private final BigInteger groupOrderUpperBound;
private final ECElGamalMixParams organizer; private final ECElGamalMixParams mixParams;
/** /**
* @param rand * @param rand
* @param encryptor * @param encryptor
* @param randomOracle - use for FiatShamir heuristic * @param randomOracle - use for FiatShamir heuristic
*/ */
public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) { public Prover(Random rand, ECElGamalEncryption encryptor, RandomOracle randomOracle) {
this.rand = rand; this.rand = rand;
this.encryptor = encryptor; this.encryptor = encryptor;
@ -41,16 +41,16 @@ public class Prover implements Mix2ZeroKnowledgeProver {
this.group = this.encryptor.getGroup(); this.group = this.encryptor.getGroup();
this.g = group.getGenerator(); this.g = group.getGenerator();
this.h = this.encryptor.getElGamalPK().getPK(); this.h = this.encryptor.getElGamalPK().getPK();
this.organizer = new ECElGamalMixParams(group,g,h); this.mixParams = new ECElGamalMixParams(encryptor);
this.groupOrderUpperBound = group.orderUpperBound(); this.groupOrderUpperBound = group.orderUpperBound();
} }
/** /**
* @param in1 * @param in1
* @param in2 * @param in2
* @param out1 - if sw then out1 = rerandomize(in2,r2) else out1 = rerandomize(in1,r1) * @param out1 - if switched then out1 = rerandomize(in2,r2) else out1 = rerandomize(in1,r1)
* @param out2 - if sw then out2 = rerandomize(in1,r1) else out1 = rerandomize(in2,r2) * @param out2 - if switched then out2 = rerandomize(in1,r1) else out1 = rerandomize(in2,r2)
* @param sw - flag * @param switched - flag
* @param i - column of in1 and out1 in encryption table * @param i - column of in1 and out1 in encryption table
* @param j - column of in2 and out2 in encryption table * @param j - column of in2 and out2 in encryption table
* @param layer - row of in1,in2 in encryption table * @param layer - row of in1,in2 in encryption table
@ -63,17 +63,17 @@ public class Prover implements Mix2ZeroKnowledgeProver {
Crypto.RerandomizableEncryptedMessage in2, Crypto.RerandomizableEncryptedMessage in2,
Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out1,
Crypto.RerandomizableEncryptedMessage out2, Crypto.RerandomizableEncryptedMessage out2,
boolean sw,int i,int j, int layer, boolean switched,int i,int j, int layer,
Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r1,
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth; Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth;
ECElGamalMixParams.ProverStatement statement = organizer.createProverStatement(in1,in2,out1,out2,r1,r2,sw); ECElGamalMixParams.ProverStatement statement = mixParams.createProverStatement(in1,in2,out1,out2,r1,r2,switched);
first = createOrProofElGamal(statement.getOrStatement(0)); first = createOrProof(statement.getOrStatement(0));
second = createOrProofElGamal(statement.getOrStatement(1)); second = createOrProof(statement.getOrStatement(1));
third = createOrProofElGamal(statement.getOrStatement(2)); third = createOrProof(statement.getOrStatement(2));
fourth = createOrProofElGamal(statement.getOrStatement(3)); fourth = createOrProof(statement.getOrStatement(3));
Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder() Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder()
.setI(i) .setI(i)
@ -98,18 +98,28 @@ public class Prover implements Mix2ZeroKnowledgeProver {
* @param randomOracle * @param randomOracle
* @return randomOracle.hash(input) * @return randomOracle.hash(input)
*/ */
public static BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input, RandomOracle randomOracle) { public static BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.FirstMessage input, RandomOracle randomOracle) {
byte[] arr = input.toByteArray(); byte[] arr = input.toByteArray();
return new BigInteger(1,randomOracle.hash(arr,arr.length)); return new BigInteger(1,randomOracle.hash(arr,arr.length));
} }
/** /**
* 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).
*
* For each clause of the disjunction, we use the following sigma-protocol for DLOG equality (i.e. log_{g1}(h1)==log_{g1}(h2)):
* <ol>
* <li>Prover chooses a random r, and sends g1^r, g2^r </li>
* <li>Verifier chooses a random c and sends c</li>
* <li>Prover computes </li>
* </ol>
*
*
* @param orStatement * @param orStatement
* @return ZKP OrProof: there exists x s.t (g1 ^ x == h1 and g2 ^ x == h2) or (g1' ^ x == h1 and g2' ^ x == h2) * @return ZKP OrProof:
* assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.proofs * assuming DLog is hard in this.group then that proves x is known for the meerkat.mixer.proofs
*/ */
private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ECElGamalMixParams.OrProverStatement orStatement) { private Mixing.ZeroKnowledgeProof.OrProof createOrProof(ECElGamalMixParams.OrProverStatement orStatement) {
ECPoint g1 = orStatement.g1; ECPoint g1 = orStatement.g1;
ECPoint h1 = orStatement.h1; ECPoint h1 = orStatement.h1;
@ -121,16 +131,19 @@ public class Prover implements Mix2ZeroKnowledgeProver {
ECPoint g2Tag = orStatement.g2Tag; ECPoint g2Tag = orStatement.g2Tag;
ECPoint h2Tag = orStatement.h2Tag; ECPoint h2Tag = orStatement.h2Tag;
BigInteger r = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); // Randomness for the ZK proof
BigInteger r = encryptor.generateRandomExponent(rand);
BigInteger c1,c2,z,zTag; BigInteger c1,c2,z,zTag;
ECPoint u,v,uTag,vTag; ECPoint u,v,uTag,vTag;
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage;
switch (orStatement.flag) { switch (orStatement.flag) {
case left: case left:
c2 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); c2 = encryptor.generateRandomExponent(rand);
zTag = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); zTag = encryptor.generateRandomExponent(rand);
//step 1 //step 1
u = group.multiply(g1, r); u = group.multiply(g1, r);
v = group.multiply(g2, r); v = group.multiply(g2, r);
@ -138,29 +151,29 @@ public class Prover implements Mix2ZeroKnowledgeProver {
vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2))); vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2)));
//step 2 //step 2
// c1 = (hash(input + step1) + group size - c2)% group size // c1 = (hash(input + step1) + group size - c2)% group size
forRandomOracle = firstMessage =
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder()
.setG1(ByteString.copyFrom(orStatement.g1Encoded)) .setG1(orStatement.g1Encoded)
.setH1(ByteString.copyFrom(orStatement.h1Encoded)) .setH1(orStatement.h1Encoded)
.setG2(ByteString.copyFrom(orStatement.g2Encoded)) .setG2(orStatement.g2Encoded)
.setH2(ByteString.copyFrom(orStatement.h2Encoded)) .setH2(orStatement.h2Encoded)
.setG1Tag(ByteString.copyFrom(orStatement.g1TagEncoded)) .setG1Tag(orStatement.g1TagEncoded)
.setH1Tag(ByteString.copyFrom(orStatement.h1TagEncoded)) .setH1Tag(orStatement.h1TagEncoded)
.setG2Tag(ByteString.copyFrom(orStatement.g2TagEncoded)) .setG2Tag(orStatement.g2TagEncoded)
.setH2Tag(ByteString.copyFrom(orStatement.h2TagEncoded)) .setH2Tag(orStatement.h2TagEncoded)
.setU(ByteString.copyFrom(group.encode(u))) .setU(encryptor.encodeElement(u))
.setV(ByteString.copyFrom(group.encode(v))) .setV(encryptor.encodeElement(v))
.setUTag(ByteString.copyFrom(group.encode(uTag))) .setUTag(encryptor.encodeElement(uTag))
.setVTag(ByteString.copyFrom(group.encode(vTag))) .setVTag(encryptor.encodeElement(vTag))
.build(); .build();
c1 = hash(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound); c1 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound);
//step 3 //step 3
//z = (r + c1 * x) % group size; //z = (r + c1 * x) % group size;
z = r.add(c1.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound); z = r.add(c1.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound);
break; break;
case right: case right:
c1 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); c1 = encryptor.generateRandomExponent(rand);
z = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound); z = encryptor.generateRandomExponent(rand);
//step 1 //step 1
uTag = group.multiply(g1Tag, r); uTag = group.multiply(g1Tag, r);
vTag = group.multiply(g2Tag, r); vTag = group.multiply(g2Tag, r);
@ -168,22 +181,22 @@ public class Prover implements Mix2ZeroKnowledgeProver {
v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1))); v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1)));
//step 2 //step 2
// c1 = (hash(input + step1) + group size - c1)% group size // c1 = (hash(input + step1) + group size - c1)% group size
forRandomOracle = firstMessage =
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder()
.setG1(ByteString.copyFrom(orStatement.g1Encoded)) .setG1(orStatement.g1Encoded)
.setH1(ByteString.copyFrom(orStatement.h1Encoded)) .setH1(orStatement.h1Encoded)
.setG2(ByteString.copyFrom(orStatement.g2Encoded)) .setG2(orStatement.g2Encoded)
.setH2(ByteString.copyFrom(orStatement.h2Encoded)) .setH2(orStatement.h2Encoded)
.setG1Tag(ByteString.copyFrom(orStatement.g1TagEncoded)) .setG1Tag(orStatement.g1TagEncoded)
.setH1Tag(ByteString.copyFrom(orStatement.h1TagEncoded)) .setH1Tag(orStatement.h1TagEncoded)
.setG2Tag(ByteString.copyFrom(orStatement.g2TagEncoded)) .setG2Tag(orStatement.g2TagEncoded)
.setH2Tag(ByteString.copyFrom(orStatement.h2TagEncoded)) .setH2Tag(orStatement.h2TagEncoded)
.setU(ByteString.copyFrom(group.encode(u))) .setU(encryptor.encodeElement(u))
.setV(ByteString.copyFrom(group.encode(v))) .setV(encryptor.encodeElement(v))
.setUTag(ByteString.copyFrom(group.encode(uTag))) .setUTag(encryptor.encodeElement(uTag))
.setVTag(ByteString.copyFrom(group.encode(vTag))) .setVTag(encryptor.encodeElement(vTag))
.build(); .build();
c2 = hash(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound); c2 = hash(firstMessage,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound);
//step 3 //step 3
//zTag = (r + c2 * x) % group size; //zTag = (r + c2 * x) % group size;
zTag = r.add(c2.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound); zTag = r.add(c2.multiply(encryptor.extractRandomness(orStatement.x))).mod(groupOrderUpperBound);
@ -194,22 +207,22 @@ public class Prover implements Mix2ZeroKnowledgeProver {
return Mixing.ZeroKnowledgeProof.OrProof.newBuilder() return Mixing.ZeroKnowledgeProof.OrProof.newBuilder()
.setG1(forRandomOracle.getG1()) .setG1(firstMessage.getG1())
.setH1(forRandomOracle.getH1()) .setH1(firstMessage.getH1())
.setG2(forRandomOracle.getG2()) .setG2(firstMessage.getG2())
.setH2(forRandomOracle.getH2()) .setH2(firstMessage.getH2())
.setG1Tag(forRandomOracle.getG1()) .setG1Tag(firstMessage.getG1())
.setH1Tag(forRandomOracle.getH1Tag()) .setH1Tag(firstMessage.getH1Tag())
.setG2Tag(forRandomOracle.getG2Tag()) .setG2Tag(firstMessage.getG2Tag())
.setH2Tag(forRandomOracle.getH2Tag()) .setH2Tag(firstMessage.getH2Tag())
.setU(forRandomOracle.getU()) .setU(firstMessage.getU())
.setV(forRandomOracle.getV()) .setV(firstMessage.getV())
.setUTag(forRandomOracle.getUTag()) .setUTag(firstMessage.getUTag())
.setVTag(forRandomOracle.getVTag()) .setVTag(firstMessage.getVTag())
.setC1(ByteString.copyFrom(c1.toByteArray())) .setC1(Util.encodeBigInteger(c1))
.setC2(ByteString.copyFrom(c2.toByteArray())) .setC2(Util.encodeBigInteger(c2))
.setZ(ByteString.copyFrom(z.toByteArray())) .setZ(Util.encodeBigInteger(z))
.setZTag(ByteString.copyFrom(zTag.toByteArray())) .setZTag(Util.encodeBigInteger(zTag))
.build(); .build();
} }
} }

View File

@ -18,7 +18,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
private final ECGroup group; private final ECGroup group;
private final RandomOracle randomOracle; private final RandomOracle randomOracle;
private final ECPoint g,h; private final ECPoint g,h;
private final ECElGamalMixParams organizer; private final ECElGamalMixParams mixParams;
private final ZeroKnowledgeOrProofParser parser; private final ZeroKnowledgeOrProofParser parser;
/** /**
@ -31,7 +31,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
this.g = group.getGenerator(); this.g = group.getGenerator();
this.h = encryptor.getElGamalPK().getPK(); this.h = encryptor.getElGamalPK().getPK();
this.randomOracle = randomOracle; this.randomOracle = randomOracle;
this.organizer = new ECElGamalMixParams(group,g,h); this.mixParams = new ECElGamalMixParams(encryptor);
this.parser = new ZeroKnowledgeOrProofParser(group); this.parser = new ZeroKnowledgeOrProofParser(group);
} }
@ -52,7 +52,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
Crypto.RerandomizableEncryptedMessage out1, Crypto.RerandomizableEncryptedMessage out1,
Crypto.RerandomizableEncryptedMessage out2, Crypto.RerandomizableEncryptedMessage out2,
Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException { Mixing.ZeroKnowledgeProof proof) throws InvalidProtocolBufferException {
ECElGamalMixParams.Statement statement = organizer.createStatement(in1,in2,out1,out2); ECElGamalMixParams.Statement statement = mixParams.createStatement(in1,in2,out1,out2);
return verifyElGamaOrProof(statement.getOrStatement(0), proof.getFirst())&& return verifyElGamaOrProof(statement.getOrStatement(0), proof.getFirst())&&
verifyElGamaOrProof(statement.getOrStatement(1), proof.getSecond())&& verifyElGamaOrProof(statement.getOrStatement(1), proof.getSecond())&&
verifyElGamaOrProof(statement.getOrStatement(2), proof.getThird())&& verifyElGamaOrProof(statement.getOrStatement(2), proof.getThird())&&
@ -79,7 +79,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
container.g2Tag.equals(orStatement.g2Tag) && container.g2Tag.equals(orStatement.g2Tag) &&
container.h2Tag.equals(orStatement.h2Tag) && container.h2Tag.equals(orStatement.h2Tag) &&
container.c1.add(container.c2).mod(group.orderUpperBound()) container.c1.add(container.c2).mod(group.orderUpperBound())
.equals(Prover.hash(container.forRandomOracle,randomOracle).mod(group.orderUpperBound())) && .equals(Prover.hash(container.firstMessage,randomOracle).mod(group.orderUpperBound())) &&
group.multiply(container.g1, container.z) group.multiply(container.g1, container.z)
.equals(group.add(container.u, group.multiply(container.h1,container.c1))) && .equals(group.add(container.u, group.multiply(container.h1,container.c1))) &&
group.multiply(container.g2, container.z) group.multiply(container.g2, container.z)

View File

@ -1,6 +1,7 @@
package meerkat.mixer.proofs; package meerkat.mixer.proofs;
import com.google.protobuf.ByteString; import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.protobuf.Mixing; import meerkat.protobuf.Mixing;
import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECGroup; import org.factcenter.qilin.primitives.concrete.ECGroup;
@ -32,15 +33,6 @@ public class ZeroKnowledgeOrProofParser {
this.group = group; this.group = group;
} }
/**
* convert ByteString to ECPoint
* @param bs
* @return
*/
public ECPoint convert2ECPoint(ByteString bs){
return group.decode(bs.toByteArray());
}
/** /**
* inner class * inner class
@ -52,15 +44,15 @@ public class ZeroKnowledgeOrProofParser {
public final ECPoint g1Tag,g2Tag,h1Tag,h2Tag; public final ECPoint g1Tag,g2Tag,h1Tag,h2Tag;
public final ECPoint u,v,uTag,vTag; public final ECPoint u,v,uTag,vTag;
public final BigInteger c1,c2,z,zTag; public final BigInteger c1,c2,z,zTag;
public final Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle; public final Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage;
/** /**
* constructor * constructor
* @param orProof * @param orProof
*/ */
private ZeroKnowledgeOrProofContainer(Mixing.ZeroKnowledgeProof.OrProof orProof){ private ZeroKnowledgeOrProofContainer(Mixing.ZeroKnowledgeProof.OrProof orProof){
this.forRandomOracle = this.firstMessage =
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder() Mixing.ZeroKnowledgeProof.OrProof.FirstMessage.newBuilder()
.setG1(orProof.getG1()) .setG1(orProof.getG1())
.setH1(orProof.getH1()) .setH1(orProof.getH1())
.setG2(orProof.getG2()) .setG2(orProof.getG2())
@ -74,22 +66,22 @@ public class ZeroKnowledgeOrProofParser {
.setUTag(orProof.getUTag()) .setUTag(orProof.getUTag())
.setVTag(orProof.getVTag()) .setVTag(orProof.getVTag())
.build(); .build();
this.g1 = convert2ECPoint(orProof.getG1()); this.g1 = ECElGamalEncryption.decodeElement(group, orProof.getG1());
this.g2 = convert2ECPoint(orProof.getG2()); this.g2 = ECElGamalEncryption.decodeElement(group, orProof.getG2());
this.h1 = convert2ECPoint(orProof.getH1()); this.h1 = ECElGamalEncryption.decodeElement(group, orProof.getH1());
this.h2 = convert2ECPoint(orProof.getH2()); this.h2 = ECElGamalEncryption.decodeElement(group, orProof.getH2());
this.g1Tag = convert2ECPoint(orProof.getG1Tag()); this.g1Tag = ECElGamalEncryption.decodeElement(group, orProof.getG1Tag());
this.g2Tag = convert2ECPoint(orProof.getG2Tag()); this.g2Tag = ECElGamalEncryption.decodeElement(group, orProof.getG2Tag());
this.h1Tag = convert2ECPoint(orProof.getH1Tag()); this.h1Tag = ECElGamalEncryption.decodeElement(group, orProof.getH1Tag());
this.h2Tag = convert2ECPoint(orProof.getH2Tag()); this.h2Tag = ECElGamalEncryption.decodeElement(group, orProof.getH2Tag());
this.u = convert2ECPoint(orProof.getU()); this.u = ECElGamalEncryption.decodeElement(group, orProof.getU());
this.v = convert2ECPoint(orProof.getV()); this.v = ECElGamalEncryption.decodeElement(group, orProof.getV());
this.uTag = convert2ECPoint(orProof.getUTag()); this.uTag = ECElGamalEncryption.decodeElement(group, orProof.getUTag());
this.vTag = convert2ECPoint(orProof.getVTag()); this.vTag = ECElGamalEncryption.decodeElement(group, orProof.getVTag());
this.c1 = new BigInteger(orProof.getC1().toByteArray()); this.c1 = Util.decodeBigInteger(orProof.getC1());
this.c2 = new BigInteger(orProof.getC2().toByteArray()); this.c2 = Util.decodeBigInteger(orProof.getC2());
this.z = new BigInteger(orProof.getZ().toByteArray()); this.z = Util.decodeBigInteger(orProof.getZ());
this.zTag = new BigInteger(orProof.getZTag().toByteArray()); this.zTag = Util.decodeBigInteger(orProof.getZTag());
} }
} }
} }

View File

@ -43,8 +43,8 @@ public class RerandomizeTest {
h = enc.getElGamalPK().getPK(); h = enc.getElGamalPK().getPK();
} }
private ECPoint convert2ECPoint(ByteString bs){ private ECPoint convert2ECPoint(ConcreteCrypto.GroupElement bs){
return group.decode(bs.toByteArray()); return enc.decodeElement(bs);
} }
public void oneRerandomizeTest() throws InvalidProtocolBufferException { public void oneRerandomizeTest() throws InvalidProtocolBufferException {

View File

@ -62,11 +62,11 @@ public class Utils {
public static <T extends Message> T decrypt(Class<T> plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher) public static <T extends Message> T decrypt(Class<T> plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher)
throws InvalidProtocolBufferException { throws InvalidProtocolBufferException {
ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData()); ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData());
ByteString c1encoded = cipherText.getC1(); ConcreteCrypto.GroupElement c1encoded = cipherText.getC1();
ByteString c2encoded = cipherText.getC2(); ConcreteCrypto.GroupElement c2encoded = cipherText.getC2();
ECPoint c1 = group.decode(c1encoded.toByteArray()); ECPoint c1 = ECElGamalEncryption.decodeElement(group, c1encoded);
ECPoint c2 = group.decode(c2encoded.toByteArray()); ECPoint c2 = ECElGamalEncryption.decodeElement(group, c2encoded);
assert (group.contains(c1)); assert (group.contains(c1));
assert (group.contains(c2)); assert (group.contains(c2));
@ -87,7 +87,7 @@ public class Utils {
} }
} }
static Random random = new Random(); static Random random = new Random(0);
public static Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) { public static Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) {
Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder(); Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder();

View File

@ -9,6 +9,7 @@ import meerkat.mixer.proofs.Prover;
import meerkat.mixer.proofs.Verifier; import meerkat.mixer.proofs.Verifier;
import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing;
import meerkat.protobuf.Voting; import meerkat.protobuf.Voting;
//import meerkat.protobuf.Voting.PlaintextBallot; //import meerkat.protobuf.Voting.PlaintextBallot;
import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.ECPoint;
@ -51,8 +52,8 @@ public class ZeroKnowledgeProofTest {
prover = new Prover(new Random(),enc,randomOracle); prover = new Prover(new Random(),enc,randomOracle);
} }
private ECPoint convert2ECPoint(ByteString bs){ private ECPoint convert2ECPoint(ConcreteCrypto.GroupElement bs){
return group.decode(bs.toByteArray()); return enc.decodeElement(bs);
} }
public void oneZKPTest() throws InvalidProtocolBufferException { public void oneZKPTest() throws InvalidProtocolBufferException {
@ -89,7 +90,10 @@ public class ZeroKnowledgeProofTest {
assertEquals (h.multiply(enc.extractRandomness(r2)), assertEquals (h.multiply(enc.extractRandomness(r2)),
group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2())))); group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2()))));
assertTrue (verifier.verify(e1,e2,e1New,e2New,prover.prove(e1,e2,e1New,e2New,false,0,0,0,r1,r2)));
Mixing.ZeroKnowledgeProof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0,r1,r2);
assertTrue (verifier.verify(e1,e2,e1New,e2New, proof));
} }
@Test @Test

View File

@ -45,8 +45,8 @@ public class ByteString2ECPoint {
(enc.encrypt(msg, enc.generateRandomness(rand))); (enc.encrypt(msg, enc.generateRandomness(rand)));
} }
} }
private ECPoint convert2ECPoint(ByteString bs){ private ECPoint convert2ECPoint(ConcreteCrypto.GroupElement bs){
return group.decode(bs.toByteArray()); return enc.decodeElement(bs);
} }
public void ByteString2ECPointProfiling() throws InvalidProtocolBufferException { public void ByteString2ECPointProfiling() throws InvalidProtocolBufferException {