From aac7a50a94a9ddfa32a0db8d566e075e249e5943 Mon Sep 17 00:00:00 2001 From: Tal Moran Date: Wed, 2 Nov 2016 11:59:20 +0200 Subject: [PATCH] Yet more mixer refactoring --- .../crypto/concrete/ECElGamalEncryption.java | 74 +++++++-- .../java/meerkat/crypto/concrete/Util.java | 29 ++++ .../main/proto/meerkat/concrete_crypto.proto | 10 +- .../src/main/proto/meerkat/mixing.proto | 64 ++++---- .../mixer/proofs/ECElGamalMixParams.java | 99 ++++++------ .../java/meerkat/mixer/proofs/Prover.java | 149 ++++++++++-------- .../java/meerkat/mixer/proofs/Verifier.java | 8 +- .../proofs/ZeroKnowledgeOrProofParser.java | 50 +++--- .../java/meerkat/mixer/RerandomizeTest.java | 4 +- mixer/src/test/java/meerkat/mixer/Utils.java | 10 +- .../meerkat/mixer/ZeroKnowledgeProofTest.java | 10 +- .../profiling/Convert/ByteString2ECPoint.java | 4 +- 12 files changed, 307 insertions(+), 204 deletions(-) create mode 100644 meerkat-common/src/main/java/meerkat/crypto/concrete/Util.java diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index 31ad4c1..7264cd0 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -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 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 randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); Pair originalCipher = new Pair( - curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), - curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); + decodeElement(originalEncodedCipher.getC1()), + decodeElement(originalEncodedCipher.getC2())); Pair 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()); } } diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/Util.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/Util.java new file mode 100644 index 0000000..4508d0c --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/Util.java @@ -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(); + } +} diff --git a/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto b/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto index d8c40d3..4fa6857 100644 --- a/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto +++ b/meerkat-common/src/main/proto/meerkat/concrete_crypto.proto @@ -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 } \ No newline at end of file diff --git a/meerkat-common/src/main/proto/meerkat/mixing.proto b/meerkat-common/src/main/proto/meerkat/mixing.proto index 83c87d6..abbd0a1 100644 --- a/meerkat-common/src/main/proto/meerkat/mixing.proto +++ b/meerkat-common/src/main/proto/meerkat/mixing.proto @@ -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; diff --git a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java b/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java index d601d1a..895253c 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/ECElGamalMixParams.java @@ -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; diff --git a/mixer/src/main/java/meerkat/mixer/proofs/Prover.java b/mixer/src/main/java/meerkat/mixer/proofs/Prover.java index cc8e46b..cfa4407 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/Prover.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/Prover.java @@ -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 Fiat–Shamir 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)): + *
    + *
  1. Prover chooses a random r, and sends g1^r, g2^r
  2. + *
  3. Verifier chooses a random c and sends c
  4. + *
  5. Prover computes
  6. + *
+ * + * * @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(); } } diff --git a/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java b/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java index 2dc9254..92ca859 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/Verifier.java @@ -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) diff --git a/mixer/src/main/java/meerkat/mixer/proofs/ZeroKnowledgeOrProofParser.java b/mixer/src/main/java/meerkat/mixer/proofs/ZeroKnowledgeOrProofParser.java index bdd2b4c..a2ab318 100644 --- a/mixer/src/main/java/meerkat/mixer/proofs/ZeroKnowledgeOrProofParser.java +++ b/mixer/src/main/java/meerkat/mixer/proofs/ZeroKnowledgeOrProofParser.java @@ -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()); } } } diff --git a/mixer/src/test/java/meerkat/mixer/RerandomizeTest.java b/mixer/src/test/java/meerkat/mixer/RerandomizeTest.java index dea0069..860dafd 100644 --- a/mixer/src/test/java/meerkat/mixer/RerandomizeTest.java +++ b/mixer/src/test/java/meerkat/mixer/RerandomizeTest.java @@ -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 { diff --git a/mixer/src/test/java/meerkat/mixer/Utils.java b/mixer/src/test/java/meerkat/mixer/Utils.java index 06329ef..c402876 100644 --- a/mixer/src/test/java/meerkat/mixer/Utils.java +++ b/mixer/src/test/java/meerkat/mixer/Utils.java @@ -62,11 +62,11 @@ public class Utils { public static T decrypt(Class 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(); diff --git a/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java index cb4d86b..0f7e729 100644 --- a/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java +++ b/mixer/src/test/java/meerkat/mixer/ZeroKnowledgeProofTest.java @@ -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 diff --git a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java index f9b5b2e..5e885f8 100644 --- a/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java +++ b/mixer/src/test/java/profiling/Convert/ByteString2ECPoint.java @@ -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 {