diff --git a/mixer/src/test/java/mixer/MixingText.java b/mixer/src/test/java/mixer/MixingText.java index 5081850..c5f8f33 100644 --- a/mixer/src/test/java/mixer/MixingText.java +++ b/mixer/src/test/java/mixer/MixingText.java @@ -69,7 +69,6 @@ public class MixingText { } } - @Test public void mixingTest() throws InvalidProtocolBufferException, InvalidKeySpecException { // initialization random = new Random(); diff --git a/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java new file mode 100644 index 0000000..e75ce19 --- /dev/null +++ b/mixer/src/test/java/mixer/ZeroKnowledgeProofTest.java @@ -0,0 +1,171 @@ +package mixer; + +import com.google.protobuf.ByteString; +import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Message; +import meerkat.crypto.concrete.ECElGamalEncryption; +import meerkat.crypto.concrete.GlobalCryptoSetup; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver; +import meerkat.crypto.mixnet.Mix2ZeroKnowledgeVerifier; +import meerkat.protobuf.ConcreteCrypto; +import meerkat.protobuf.Crypto; +import meerkat.protobuf.Mixing; +import meerkat.protobuf.Voting; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECPoint; +import org.junit.Before; +import org.junit.Test; +import prover.Prover; +import qilin.primitives.RandomOracle; +import qilin.primitives.concrete.DigestOracle; +import qilin.primitives.concrete.ECElGamal; +import qilin.primitives.concrete.ECGroup; +import qilin.primitives.generic.ElGamal; +import qilin.util.Pair; +import verifier.Verifier; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; +import java.util.Random; + +import static org.junit.Assert.assertEquals; + +/** + * Created by Tzlil on 12/31/2015. + */ +public class ZeroKnowledgeProofTest { + + + public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; + /** + * Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption} + * @param pk + * @return + */ + public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK pk) { + ECPoint pkPoint = pk.getPK(); + ECParameterSpec params = group.getCurveParams(); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params); + + try { + KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, + GlobalCryptoSetup.getBouncyCastleProvider()); + PublicKey javaPk = fact.generatePublic(pubKeySpec); + ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() + .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); + + return serializedPk; + } catch (Exception e) { + throw new RuntimeException("Error converting public key!", e); + } + } + + /** + * Standard (non-threshold) decryption for testing purposes. + * @param secretKey + * @return + */ + 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(); + + ECPoint c1 = group.decode(c1encoded.toByteArray()); + ECPoint c2 = group.decode(c2encoded.toByteArray()); + + assert (group.contains(c1)); + assert (group.contains(c2)); + + ECPoint plaintextEncoded = secretKey.decrypt(new Pair(c1, c2)); + + byte[] plaintext = group.injectiveDecode(plaintextEncoded); + + ByteArrayInputStream in = new ByteArrayInputStream(plaintext); + + try { + java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder"); + GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(plaintextMessageType); + builder.mergeDelimitedFrom(in); + return plaintextMessageType.cast(builder.build()); + } catch (Exception e) { + throw new InvalidProtocolBufferException("Plaintext protobuf error"); + } + } + + + Random rand = new Random(0); // Insecure deterministic random for testing. + + ECElGamal.SK key; + ECGroup group; + ECElGamalEncryption enc; + ConcreteCrypto.ElGamalPublicKey serializedPk; + Mix2ZeroKnowledgeVerifier verifier ; + Mix2ZeroKnowledgeProver prover ; + + @Before + public void setup() throws Exception { + group = new ECGroup("secp256k1"); + BigInteger sk = ECElGamal.generateSecretKey(group, rand); + key = new ECElGamal.SK(group, sk); + serializedPk = serializePk(group, key); + + + enc = new ECElGamalEncryption(); + + enc.init(serializedPk); + RandomOracle randomOracle = new DigestOracle(); + verifier = new Verifier(enc,randomOracle); + prover = new Prover(new Random(),enc,randomOracle); + } + + + Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) { + Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder(); + ballot.setSerialNumber(rand.nextInt(1000000)); + for (int i = 0; i < numQuestions; ++i) { + Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder(); + for (int j = 0; j < numAnswers; ++j) { + answers.addAnswer(rand.nextInt(maxAnswer)); + } + } + return ballot.build(); + } + + + public void oneZKPTest() throws InvalidProtocolBufferException { + + Voting.PlaintextBallot msg1 = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15. + Voting.PlaintextBallot msg2 = genRandomBallot(2,3,16); + Crypto.EncryptionRandomness r1 = enc.generateRandomness(rand); + Crypto.EncryptionRandomness r2 = enc.generateRandomness(rand); + + Crypto.RerandomizableEncryptedMessage e1 = enc.encrypt(msg1, enc.generateRandomness(rand)); + Crypto.RerandomizableEncryptedMessage e2 = enc.encrypt(msg2, enc.generateRandomness(rand)); + Crypto.RerandomizableEncryptedMessage e1Tag = enc.rerandomize(e1, r1); + Crypto.RerandomizableEncryptedMessage e2Tag = enc.rerandomize(e2, r2); + assert (decrypt(Voting.PlaintextBallot.class, key, group, e1).equals(msg1)); + assert (decrypt(Voting.PlaintextBallot.class, key, group, e1Tag).equals(msg1)); + assert (decrypt(Voting.PlaintextBallot.class, key, group, e2).equals(msg2)); + assert (decrypt(Voting.PlaintextBallot.class, key, group, e2Tag).equals(msg2)); + assert (verifier.verify(e1,e2,e1Tag,e2Tag,prover.prove(e1,e2,e1Tag,e2Tag,false,0,0,0,r1,r2))); + } + + @Test + public void zeroKnowledgeProofTest() throws InvalidProtocolBufferException { + + int tests = 1000; + + for (int i = 0; i < tests; i ++){ + System.out.println("test " + i); + oneZKPTest(); + } + } +}