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());
}
/**
* 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
public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) {
@ -95,11 +134,11 @@ public class ECElGamalEncryption implements Encryption {
byte[] msg = out.toByteArray();
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);
ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder()
.setC1(ByteString.copyFrom(cipherText.a.getEncoded(true)))
.setC2(ByteString.copyFrom(cipherText.b.getEncoded(true)))
.setC1(encodeElement(cipherText.a))
.setC2(encodeElement(cipherText.b))
.build();
return Crypto.RerandomizableEncryptedMessage.newBuilder()
@ -118,34 +157,49 @@ public class ECElGamalEncryption implements Encryption {
@Override
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);
ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData());
Pair<ECPoint,ECPoint> originalCipher = new Pair<ECPoint, ECPoint>(
curve.decodePoint(originalEncodedCipher.getC1().toByteArray()),
curve.decodePoint(originalEncodedCipher.getC2().toByteArray()));
decodeElement(originalEncodedCipher.getC1()),
decodeElement(originalEncodedCipher.getC2()));
Pair<ECPoint,ECPoint> newCipher = elGamalPK.add(originalCipher, randomizer);
return Crypto.RerandomizableEncryptedMessage.newBuilder()
.setData(
ConcreteCrypto.ElGamalCiphertext.newBuilder()
.setC1(ByteString.copyFrom(newCipher.a.getEncoded(true)))
.setC2(ByteString.copyFrom(newCipher.b.getEncoded(true)))
.setC1(encodeElement(newCipher.a))
.setC2(encodeElement(newCipher.b))
.build().toByteString()
).build();
}
@Override
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()
.setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build();
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){
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;
}
// An El-Gamal ciphertext
// Each group element should be an ASN.1 encoded curve point with compression.
message GroupElement {
bytes data = 1;
}
// An El-Gamal ciphertext
message ElGamalCiphertext {
bytes c1 = 1; // First group element
bytes c2 = 2; // Second group element
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";
import 'meerkat/crypto.proto';
import 'meerkat/concrete_crypto.proto';
message Plaintext{
message Plaintext {
bytes data = 1;
}
message ZeroKnowledgeProof {
message OrProof {
message ForRandomOracle{
bytes g1 = 1;
bytes h1 = 2;
bytes g2 = 3;
bytes h2 = 4;
bytes g1Tag = 5;
bytes h1Tag = 6;
bytes g2Tag = 7;
bytes h2Tag = 8;
bytes u = 9;
bytes v = 10;
bytes uTag = 11;
bytes vTag = 12;
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;
}
//input : g1,h1, g2, h2, g1Tag, h1Tag, g2Tag, h2Tag;
bytes g1 = 1;
bytes h1 = 2;
bytes g2 = 3;
bytes h2 = 4;
bytes g1Tag = 5;
bytes h1Tag = 6;
bytes g2Tag = 7;
bytes h2Tag = 8;
//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;
//calc: u, v, uTag, vTag;
bytes u = 9;
bytes v = 10;
bytes uTag = 11;
bytes vTag = 12;
GroupElement u = 9;
GroupElement v = 10;
GroupElement uTag = 11;
GroupElement vTag = 12;
//generated: c1,c2,z,zTag
bytes c1 = 13;
bytes c2 = 14;
bytes z = 15;
bytes zTag = 16;
BigInteger c1 = 13;
BigInteger c2 = 14;
BigInteger z = 15;
BigInteger zTag = 16;
}
message Location{
int32 i = 1;
int32 j = 2;

View File

@ -15,33 +15,26 @@ import org.factcenter.qilin.primitives.concrete.ECGroup;
*/
public class ECElGamalMixParams {
private final ECElGamalEncryption encryptor;
private final ECGroup group;
private final ECPoint g;
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 bs
* @return
* @param encryptor encryptor used for encoding/decoding serialized ciphertexts. The group, default generator and
* second base (h) are taken from the encryptor (second base is the public key)
*/
private ECPoint decodeECPoint(ByteString bs){
return group.decode(bs.toByteArray());
}
/**
* @param group
* @param g - generator of group
* @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 ECElGamalMixParams(ECElGamalEncryption encryptor){
this.encryptor = encryptor;
this.group = encryptor.getGroup();
this.g = group.getGenerator();
this.h = encryptor.getElGamalPK().getPK();
this.gEncoded = encryptor.encodeElement(g);
this.hEncoded = encryptor.encodeElement(h);
}
public enum TrueCouple {
@ -165,17 +158,17 @@ public class ECElGamalMixParams {
}
private Statement(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2
, ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){
private Statement(ConcreteCrypto.ElGamalCiphertext e1, ConcreteCrypto.ElGamalCiphertext e2,
ConcreteCrypto.ElGamalCiphertext e1New, ConcreteCrypto.ElGamalCiphertext e2New){
ECPoint e1c1 = decodeECPoint(e1.getC1());
ECPoint e1c2 = decodeECPoint(e1.getC2());
ECPoint e2c1 = decodeECPoint(e2.getC1());
ECPoint e2c2 = decodeECPoint(e2.getC2());
ECPoint e1Nc1 = decodeECPoint(e1New.getC1());
ECPoint e1Nc2 = decodeECPoint(e1New.getC2());
ECPoint e2Nc1 = decodeECPoint(e2New.getC1());
ECPoint e2Nc2 = decodeECPoint(e2New.getC2());
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());
c1_e1NDive1 = group.add(e1Nc1, 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 {
/**
* 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
protected void generateOrStatements() {
byte[] c1_e1NDive1Encoded = group.encode(c1_e1NDive1);
byte[] c1_e2NDive1Encoded = group.encode(c1_e2NDive1);
byte[] c1_e1NDive2Encoded = group.encode(c1_e1NDive2);
byte[] c1_e2NDive2Encoded = group.encode(c1_e2NDive2);
byte[] c2_e1NDive1Encoded = group.encode(c2_e1NDive1);
byte[] c2_e2NDive1Encoded = group.encode(c2_e2NDive1);
byte[] c2_e1NDive2Encoded = group.encode(c2_e1NDive2);
byte[] c2_e2NDive2Encoded = group.encode(c2_e2NDive2);
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) {
@ -304,20 +300,29 @@ public class ECElGamalMixParams {
}
}
/**
* An {@link OrStatement} with additional info needed to generate a ZK proof.
*/
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 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,
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) {
super(h1, h2, h1Tag, h2Tag);
this.g1Encoded = gEncoded;

View File

@ -1,8 +1,8 @@
package meerkat.mixer.proofs;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing;
@ -26,14 +26,14 @@ public class Prover implements Mix2ZeroKnowledgeProver {
private final ECElGamalEncryption encryptor;
private final ECPoint g,h;
private final BigInteger groupOrderUpperBound;
private final ECElGamalMixParams organizer;
private final ECElGamalMixParams mixParams;
/**
* @param rand
* @param encryptor
* @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.encryptor = encryptor;
@ -41,16 +41,16 @@ public class Prover implements Mix2ZeroKnowledgeProver {
this.group = this.encryptor.getGroup();
this.g = group.getGenerator();
this.h = this.encryptor.getElGamalPK().getPK();
this.organizer = new ECElGamalMixParams(group,g,h);
this.mixParams = new ECElGamalMixParams(encryptor);
this.groupOrderUpperBound = group.orderUpperBound();
}
/**
* @param in1
* @param in2
* @param out1 - if sw 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 sw - flag
* @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
@ -63,17 +63,17 @@ public class Prover implements Mix2ZeroKnowledgeProver {
Crypto.RerandomizableEncryptedMessage in2,
Crypto.RerandomizableEncryptedMessage out1,
Crypto.RerandomizableEncryptedMessage out2,
boolean sw,int i,int j, int layer,
boolean switched,int i,int j, int layer,
Crypto.EncryptionRandomness r1,
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
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));
second = createOrProofElGamal(statement.getOrStatement(1));
third = createOrProofElGamal(statement.getOrStatement(2));
fourth = createOrProofElGamal(statement.getOrStatement(3));
first = createOrProof(statement.getOrStatement(0));
second = createOrProof(statement.getOrStatement(1));
third = createOrProof(statement.getOrStatement(2));
fourth = createOrProof(statement.getOrStatement(3));
Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder()
.setI(i)
@ -98,18 +98,28 @@ public class Prover implements Mix2ZeroKnowledgeProver {
* @param randomOracle
* @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();
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
* @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
*/
private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ECElGamalMixParams.OrProverStatement orStatement) {
private Mixing.ZeroKnowledgeProof.OrProof createOrProof(ECElGamalMixParams.OrProverStatement orStatement) {
ECPoint g1 = orStatement.g1;
ECPoint h1 = orStatement.h1;
@ -121,16 +131,19 @@ public class Prover implements Mix2ZeroKnowledgeProver {
ECPoint g2Tag = orStatement.g2Tag;
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;
ECPoint u,v,uTag,vTag;
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle;
Mixing.ZeroKnowledgeProof.OrProof.FirstMessage firstMessage;
switch (orStatement.flag) {
case left:
c2 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
zTag = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
c2 = encryptor.generateRandomExponent(rand);
zTag = encryptor.generateRandomExponent(rand);
//step 1
u = group.multiply(g1, 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)));
//step 2
// c1 = (hash(input + step1) + group size - c2)% group size
forRandomOracle =
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder()
.setG1(ByteString.copyFrom(orStatement.g1Encoded))
.setH1(ByteString.copyFrom(orStatement.h1Encoded))
.setG2(ByteString.copyFrom(orStatement.g2Encoded))
.setH2(ByteString.copyFrom(orStatement.h2Encoded))
.setG1Tag(ByteString.copyFrom(orStatement.g1TagEncoded))
.setH1Tag(ByteString.copyFrom(orStatement.h1TagEncoded))
.setG2Tag(ByteString.copyFrom(orStatement.g2TagEncoded))
.setH2Tag(ByteString.copyFrom(orStatement.h2TagEncoded))
.setU(ByteString.copyFrom(group.encode(u)))
.setV(ByteString.copyFrom(group.encode(v)))
.setUTag(ByteString.copyFrom(group.encode(uTag)))
.setVTag(ByteString.copyFrom(group.encode(vTag)))
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(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound);
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.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
z = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
c1 = encryptor.generateRandomExponent(rand);
z = encryptor.generateRandomExponent(rand);
//step 1
uTag = group.multiply(g1Tag, 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)));
//step 2
// c1 = (hash(input + step1) + group size - c1)% group size
forRandomOracle =
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder()
.setG1(ByteString.copyFrom(orStatement.g1Encoded))
.setH1(ByteString.copyFrom(orStatement.h1Encoded))
.setG2(ByteString.copyFrom(orStatement.g2Encoded))
.setH2(ByteString.copyFrom(orStatement.h2Encoded))
.setG1Tag(ByteString.copyFrom(orStatement.g1TagEncoded))
.setH1Tag(ByteString.copyFrom(orStatement.h1TagEncoded))
.setG2Tag(ByteString.copyFrom(orStatement.g2TagEncoded))
.setH2Tag(ByteString.copyFrom(orStatement.h2TagEncoded))
.setU(ByteString.copyFrom(group.encode(u)))
.setV(ByteString.copyFrom(group.encode(v)))
.setUTag(ByteString.copyFrom(group.encode(uTag)))
.setVTag(ByteString.copyFrom(group.encode(vTag)))
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(forRandomOracle,randomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound);
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);
@ -194,22 +207,22 @@ public class Prover implements Mix2ZeroKnowledgeProver {
return Mixing.ZeroKnowledgeProof.OrProof.newBuilder()
.setG1(forRandomOracle.getG1())
.setH1(forRandomOracle.getH1())
.setG2(forRandomOracle.getG2())
.setH2(forRandomOracle.getH2())
.setG1Tag(forRandomOracle.getG1())
.setH1Tag(forRandomOracle.getH1Tag())
.setG2Tag(forRandomOracle.getG2Tag())
.setH2Tag(forRandomOracle.getH2Tag())
.setU(forRandomOracle.getU())
.setV(forRandomOracle.getV())
.setUTag(forRandomOracle.getUTag())
.setVTag(forRandomOracle.getVTag())
.setC1(ByteString.copyFrom(c1.toByteArray()))
.setC2(ByteString.copyFrom(c2.toByteArray()))
.setZ(ByteString.copyFrom(z.toByteArray()))
.setZTag(ByteString.copyFrom(zTag.toByteArray()))
.setG1(firstMessage.getG1())
.setH1(firstMessage.getH1())
.setG2(firstMessage.getG2())
.setH2(firstMessage.getH2())
.setG1Tag(firstMessage.getG1())
.setH1Tag(firstMessage.getH1Tag())
.setG2Tag(firstMessage.getG2Tag())
.setH2Tag(firstMessage.getH2Tag())
.setU(firstMessage.getU())
.setV(firstMessage.getV())
.setUTag(firstMessage.getUTag())
.setVTag(firstMessage.getVTag())
.setC1(Util.encodeBigInteger(c1))
.setC2(Util.encodeBigInteger(c2))
.setZ(Util.encodeBigInteger(z))
.setZTag(Util.encodeBigInteger(zTag))
.build();
}
}

View File

@ -18,7 +18,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
private final ECGroup group;
private final RandomOracle randomOracle;
private final ECPoint g,h;
private final ECElGamalMixParams organizer;
private final ECElGamalMixParams mixParams;
private final ZeroKnowledgeOrProofParser parser;
/**
@ -31,7 +31,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
this.g = group.getGenerator();
this.h = encryptor.getElGamalPK().getPK();
this.randomOracle = randomOracle;
this.organizer = new ECElGamalMixParams(group,g,h);
this.mixParams = new ECElGamalMixParams(encryptor);
this.parser = new ZeroKnowledgeOrProofParser(group);
}
@ -52,7 +52,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
Crypto.RerandomizableEncryptedMessage out1,
Crypto.RerandomizableEncryptedMessage out2,
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())&&
verifyElGamaOrProof(statement.getOrStatement(1), proof.getSecond())&&
verifyElGamaOrProof(statement.getOrStatement(2), proof.getThird())&&
@ -79,7 +79,7 @@ public class Verifier implements Mix2ZeroKnowledgeVerifier {
container.g2Tag.equals(orStatement.g2Tag) &&
container.h2Tag.equals(orStatement.h2Tag) &&
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)
.equals(group.add(container.u, group.multiply(container.h1,container.c1))) &&
group.multiply(container.g2, container.z)

View File

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

View File

@ -43,8 +43,8 @@ public class RerandomizeTest {
h = enc.getElGamalPK().getPK();
}
private ECPoint convert2ECPoint(ByteString bs){
return group.decode(bs.toByteArray());
private ECPoint convert2ECPoint(ConcreteCrypto.GroupElement bs){
return enc.decodeElement(bs);
}
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)
throws InvalidProtocolBufferException {
ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData());
ByteString c1encoded = cipherText.getC1();
ByteString c2encoded = cipherText.getC2();
ConcreteCrypto.GroupElement c1encoded = cipherText.getC1();
ConcreteCrypto.GroupElement c2encoded = cipherText.getC2();
ECPoint c1 = group.decode(c1encoded.toByteArray());
ECPoint c2 = group.decode(c2encoded.toByteArray());
ECPoint c1 = ECElGamalEncryption.decodeElement(group, c1encoded);
ECPoint c2 = ECElGamalEncryption.decodeElement(group, c2encoded);
assert (group.contains(c1));
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) {
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.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing;
import meerkat.protobuf.Voting;
//import meerkat.protobuf.Voting.PlaintextBallot;
import org.bouncycastle.math.ec.ECPoint;
@ -51,8 +52,8 @@ public class ZeroKnowledgeProofTest {
prover = new Prover(new Random(),enc,randomOracle);
}
private ECPoint convert2ECPoint(ByteString bs){
return group.decode(bs.toByteArray());
private ECPoint convert2ECPoint(ConcreteCrypto.GroupElement bs){
return enc.decodeElement(bs);
}
public void oneZKPTest() throws InvalidProtocolBufferException {
@ -89,7 +90,10 @@ public class ZeroKnowledgeProofTest {
assertEquals (h.multiply(enc.extractRandomness(r2)),
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

View File

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