More refactoring, wrote command-line mixer application (no BB access as of yet)

mixer
Tal Moran 2017-01-21 21:42:10 +02:00
parent 273338010d
commit 43d4fb75b2
32 changed files with 733 additions and 164 deletions

View File

@ -1,14 +1,31 @@
package meerkat.crypto.concrete; package meerkat.crypto.concrete;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import org.factcenter.qilin.primitives.generic.ElGamal;
import org.factcenter.qilin.util.Pair;
import java.io.ByteArrayInputStream;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
/** /**
* Created by talm on 02/11/16. * Created by talm on 02/11/16.
*/ */
public class Util { public class Util {
public final static String ENCRYPTION_KEY_ALGORITHM = ECElGamalEncryption.KEY_ALGORITHM;
/** /**
* Decode a BigInteger from a protobuf * Decode a BigInteger from a protobuf
* @param i * @param i
@ -26,4 +43,78 @@ public class Util {
public static Crypto.BigInteger encodeBigInteger(BigInteger i) { public static Crypto.BigInteger encodeBigInteger(BigInteger i) {
return Crypto.BigInteger.newBuilder().setData(ByteString.copyFrom(i.toByteArray())).build(); return Crypto.BigInteger.newBuilder().setData(ByteString.copyFrom(i.toByteArray())).build();
} }
/**
* Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption}
* @param pk
* @return
*/
public static ConcreteCrypto.ElGamalPublicKey encodePK(ECGroup group, ElGamal.PK<ECPoint> pk) {
ECPoint pkPoint = pk.getPK();
ECParameterSpec params = group.getCurveParams();
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params);
try {
KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM,
GlobalCryptoSetup.getInstance().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);
}
}
/**
* Deserialize an ECElGamal secret key.
* @param serializedPk
* @param serializedSk
* @return
* @throws InvalidKeySpecException
*/
public static ECElGamal.SK decodeSK(ConcreteCrypto.ElGamalPublicKey serializedPk, Crypto.BigInteger serializedSk)
throws InvalidKeySpecException {
ECElGamalEncryption enc = new ECElGamalEncryption();
enc.init(serializedPk);
ECElGamal.SK sk = new ECElGamal.SK(enc.getGroup(), decodeBigInteger(serializedSk));
return sk;
}
/**
* Standard (non-threshold) decryption for testing purposes.
* @param secretKey
* @return
*/
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());
ConcreteCrypto.GroupElement c1encoded = cipherText.getC1();
ConcreteCrypto.GroupElement c2encoded = cipherText.getC2();
ECPoint c1 = ECElGamalEncryption.decodeElement(group, c1encoded);
ECPoint c2 = ECElGamalEncryption.decodeElement(group, c2encoded);
assert (group.contains(c1));
assert (group.contains(c2));
ECPoint plaintextEncoded = secretKey.decrypt(new Pair<ECPoint, ECPoint>(c1, c2));
byte[] plaintext = group.injectiveDecode(plaintextEncoded);
ByteArrayInputStream in = new ByteArrayInputStream(plaintext);
try {
java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder");
Message.Builder builder = (Message.Builder) newBuilder.invoke(plaintextMessageType);
builder.mergeDelimitedFrom(in);
return plaintextMessageType.cast(builder.build());
} catch (Exception e) {
throw new InvalidProtocolBufferException("Plaintext protobuf error");
}
}
} }

View File

@ -10,4 +10,4 @@ message BroadcastMessage {
bool is_private = 3; bool is_private = 3;
bytes payload = 5; bytes payload = 5;
} }

View File

@ -13,8 +13,8 @@ apply plugin: 'maven-publish'
// Uncomment the lines below to define an application // Uncomment the lines below to define an application
// (this will also allow you to build a "fatCapsule" which includes // (this will also allow you to build a "fatCapsule" which includes
// the entire application, including all dependencies in a single jar) // the entire application, including all dependencies in a single jar)
//apply plugin: 'application' apply plugin: 'application'
//mainClassName='your.main.ApplicationClass' mainClassName='meerkat.mixer.main.Mix'
// Is this a snapshot version? // Is this a snapshot version?
ext { isSnapshot = false } ext { isSnapshot = false }
@ -29,10 +29,10 @@ ext {
nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : "" nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : ""
} }
description = "TODO: Add a description" description = "Mix network implementation"
// Your project version // Your project version
version = "0.0" version = "0.1"
version += "${isSnapshot ? '-SNAPSHOT' : ''}" version += "${isSnapshot ? '-SNAPSHOT' : ''}"
@ -52,6 +52,9 @@ dependencies {
// Crypto // Crypto
compile 'org.factcenter.qilin:qilin:1.2.+' compile 'org.factcenter.qilin:qilin:1.2.+'
// Command-line parsing.
compile 'net.sf.jopt-simple:jopt-simple:6.+'
testCompile 'junit:junit:4.+' testCompile 'junit:junit:4.+'
runtime 'org.codehaus.groovy:groovy:2.4.+' runtime 'org.codehaus.groovy:groovy:2.4.+'

1
mixer/gradlew vendored Symbolic link
View File

@ -0,0 +1 @@
../gradlew

View File

@ -176,7 +176,7 @@ public class MixGenerator {
* mix given encrypted votes using random * mix given encrypted votes using random
* @param ciphertexts encrypted votes * @param ciphertexts encrypted votes
* @param random * @param random
* @return meerkat.mixer.network result * @return meerkat.mixProverVerifier.network result
* @throws InvalidProtocolBufferException * @throws InvalidProtocolBufferException
*/ */
public MixerOutput mix(List<RerandomizableEncryptedMessage> ciphertexts,Random random) throws InvalidProtocolBufferException { public MixerOutput mix(List<RerandomizableEncryptedMessage> ciphertexts,Random random) throws InvalidProtocolBufferException {
@ -197,5 +197,4 @@ public class MixGenerator {
return new meerkat.mixer.MixerOutput(logN, proofsTable, encryptionTable); return new meerkat.mixer.MixerOutput(logN, proofsTable, encryptionTable);
} }
} }

View File

@ -1,36 +1,54 @@
package meerkat.mixer; package meerkat.mixer;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.mixer.network.BenesNetwork;
import meerkat.mixer.network.PermutationNetwork;
import meerkat.mixer.proofs.Mix2nizk; import meerkat.mixer.proofs.Mix2nizk;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing; import meerkat.protobuf.Mixing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays; import java.util.Arrays;
/** /**
* Created by Tzlil on 12/30/2015. * Created by Tzlil on 12/30/2015.
* provide one operation - verify meerkat.mixer.network output * provide one operation - verify meerkat.mixProverVerifier.network output
*/ */
public final class MixVerifier { public final class MixVerifier {
final static Logger logger = LoggerFactory.getLogger(MixVerifier.class);
/** /**
* constructor * constructor
* @param verifier * @param verifier
* @param mixerOutput * @param mixerOutput
* @return true iff the meerkat.mixer.network output is valid * @param strict if true, check that the network structure matches our implementation of the Benes network exactly.
* if false, only checks that the result is a permutation.
* @return true iff the meerkat.mixProverVerifier.network output is valid
* @throws InvalidProtocolBufferException * @throws InvalidProtocolBufferException
*/ */
public static boolean verifyTable(Mix2nizk.Verifier verifier, MixerOutput mixerOutput) public static boolean verifyTable(Mix2nizk.Verifier verifier, MixerOutput mixerOutput, boolean strict)
throws InvalidProtocolBufferException { throws InvalidProtocolBufferException {
int out0,out1,layer, switchIdx;
PermutationNetwork net = null;
int layers = mixerOutput.getNumLayers(); int layers = mixerOutput.getNumLayers();
int n = 1 << mixerOutput.getLogN(); int n = 1 << mixerOutput.getLogN();
//initialize locationChecksum table
// use for check BeneshNet validity if (strict) {
boolean[][] locationChecksum = new boolean[layers][n]; net = new BenesNetwork(mixerOutput.getLogN());
for (boolean[] locationChecksumLayer: locationChecksum) { }
Arrays.fill(locationChecksumLayer,false);
//initialize outputUsed table
// used to check BeneshNet validity
boolean[][] outputUsed = new boolean[layers][n];
for (boolean[] outputUsedLayer: outputUsed) {
Arrays.fill(outputUsedLayer,false);
}
boolean[][] switchUsed = new boolean[layers][n / 2];
for (boolean[] switchUsedLayer: switchUsed) {
Arrays.fill(switchUsedLayer,false);
} }
Mixing.Mix2Proof[][] Mix2Proofs = mixerOutput.getProofs(); Mixing.Mix2Proof[][] Mix2Proofs = mixerOutput.getProofs();
@ -38,6 +56,8 @@ public final class MixVerifier {
for (int i = 0; i < Mix2Proofs.length ; i++){ for (int i = 0; i < Mix2Proofs.length ; i++){
for (int j = 0; j < Mix2Proofs[i].length ; j ++){ for (int j = 0; j < Mix2Proofs[i].length ; j ++){
int out0,out1,layer, switchIdx;
Mixing.Mix2Proof zkp = Mix2Proofs[i][j]; Mixing.Mix2Proof zkp = Mix2Proofs[i][j];
Mixing.Mix2Proof.Location location = zkp.getLocation(); Mixing.Mix2Proof.Location location = zkp.getLocation();
out0 = location.getOut0(); out0 = location.getOut0();
@ -45,20 +65,38 @@ public final class MixVerifier {
layer = location.getLayer(); layer = location.getLayer();
switchIdx = location.getSwitchIdx(); switchIdx = location.getSwitchIdx();
// check location validity if (strict) {
// TODO: add check // Check that location is correct
// if (layer > layers >> 1) { int expectedOut0 = net.getInputIdxInNextLayer(layer, 2 * switchIdx);
// if (out1 - out0 != n >> (layers - layer)) if (out0 != expectedOut0) {
// return false; logger.error("Input {} in layer {} goes to {} instead of {}", 2 * switchIdx, layer, out0, expectedOut0);
// } return false;
// else{ }
// if (out1 - out0 != n >> (layer + 1)) int expectedOut1 = net.getInputIdxInNextLayer(layer, 2 * switchIdx + 1);
// return false; if (out0 != expectedOut0) {
// } logger.error("Input {} in layer {} goes to {} instead of {}", 2 * switchIdx + 1, layer, out1, expectedOut1);
return false;
}
}
// mark location in table // mark location in table
locationChecksum[layer][2 * switchIdx] = true; if (switchUsed[layer][switchIdx]) {
locationChecksum[layer][2 * switchIdx + 1] = true; logger.error("Switch {} in layer {} used twice!", switchIdx, layer);
return false;
}
switchUsed[layer][switchIdx] = true;
if (outputUsed[layer][out0]) {
logger.error("Output {} in layer {} used twice!", out0, layer);
return false;
}
outputUsed[layer][out0] = true;
if (outputUsed[layer][out1]) {
logger.error("Output {} in layer {} used twice!", out1, layer);
return false;
}
outputUsed[layer][out1] = true;
// verify proof // verify proof
if(!verifier.verify(rerandomizableEncryptedMessages[layer][2 * switchIdx], if(!verifier.verify(rerandomizableEncryptedMessages[layer][2 * switchIdx],
@ -71,11 +109,19 @@ public final class MixVerifier {
} }
} }
// verify all meerkat.mixer.necessary locations for BeneshNet were proved // verify all meerkat.mixProverVerifier.necessary locations for BenesNet were proved
for (boolean[] checksumLayer: locationChecksum) { for (int layer = 0; layer < layers; ++layer) {
for (boolean locationBoolean: checksumLayer) { for (int switchIdx = 0; switchIdx < n / 2; ++switchIdx) {
if (!locationBoolean) if (!switchUsed[layer][switchIdx]) {
logger.error("Switch {} in layer {} was not used!", switchIdx, layer);
return false; return false;
}
}
for (int i = 0; i < n / 2; ++i) {
if (!outputUsed[layer][i]) {
logger.error("Output {} in layer {} was not used!", i, layer);
return false;
}
} }
} }
return true; return true;

View File

@ -3,12 +3,14 @@ package meerkat.mixer;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing; import meerkat.protobuf.Mixing;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
* Created by Tzlil on 1/18/2016. * Created by Tzlil on 1/18/2016.
* container for meerkat.mixer.network.mix result. * container for meerkat.mixProverVerifier.network.mix result.
*/ */
public class MixerOutput { public class MixerOutput {
private final Mixing.Mix2Proof[][] proofs; private final Mixing.Mix2Proof[][] proofs;
@ -20,7 +22,9 @@ public class MixerOutput {
* @param logN log (base 2) of the number of votes * @param logN log (base 2) of the number of votes
* @param encryptedMessages at level 0 , contains the original encrypted votes * @param encryptedMessages at level 0 , contains the original encrypted votes
* at each other level contains the re encrypted votes * at each other level contains the re encrypted votes
* @param proofs in each cell (level,switch) contains the match zero knowledge proof * @param proofs in each cell (level,switch) contains the match zero knowledge proof.
* We allow null proofs as a special case -- this is used to store the input to the
* first mixProverVerifier (as a 0-layer mix).
*/ */
public MixerOutput(int logN, Mixing.Mix2Proof[][] proofs, public MixerOutput(int logN, Mixing.Mix2Proof[][] proofs,
Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) { Crypto.RerandomizableEncryptedMessage[][] encryptedMessages) {
@ -42,6 +46,66 @@ public class MixerOutput {
} }
public int getNumLayers() { public int getNumLayers() {
return 2 * logN - 1; return proofs == null ? 0 : proofs.length;
} }
/**
* Read from an InputStream. The data should have been written by {@link #writeDelimitedTo(OutputStream)}
* @param in
* @return
* @throws IOException
*/
public static MixerOutput parseDelimitedFrom(InputStream in) throws IOException {
Mixing.MixBatchHeader header = Mixing.MixBatchHeader.parseDelimitedFrom(in);
int n = 1 << header.getLogN();
int layers = header.getLayers();
Crypto.RerandomizableEncryptedMessage[][] encryptedMessages = new Crypto.RerandomizableEncryptedMessage[layers + 1][n];
Mixing.Mix2Proof[][] proofs = null;
if (layers > 0)
proofs = new Mixing.Mix2Proof[header.getLayers()][n / 2];
for (int i = 0; i < encryptedMessages.length; ++i) {
for (int j = 0; j < encryptedMessages[i].length; ++j) {
encryptedMessages[i][j] = Crypto.RerandomizableEncryptedMessage.parseDelimitedFrom(in);
}
}
if (layers > 0) {
for (int i = 0; i < proofs.length; ++i) {
for (int j = 0; j < proofs[i].length; ++j) {
proofs[i][j] = Mixing.Mix2Proof.parseDelimitedFrom(in);
}
}
}
return new MixerOutput(header.getLogN(), proofs, encryptedMessages);
}
/**
* Write to an outputstream.
* This format can be parsed by {@link #parseDelimitedFrom(InputStream)}
* @param out
* @throws IOException
*/
public void writeDelimitedTo(OutputStream out) throws IOException {
Mixing.MixBatchHeader header = Mixing.MixBatchHeader.newBuilder()
.setLogN(getLogN())
.setLayers(getNumLayers())
.build();
header.writeDelimitedTo(out);
for (int i = 0; i < encryptedMessages.length; ++i) {
for (int j = 0; j < encryptedMessages[i].length; ++j) {
encryptedMessages[i][j].writeDelimitedTo(out);
}
}
if (proofs != null) {
for (int i = 0; i < proofs.length; ++i) {
for (int j = 0; j < proofs[i].length; ++j) {
proofs[i][j].writeDelimitedTo(out);
}
}
}
}
} }

View File

@ -10,13 +10,13 @@ import java.util.List;
/** /**
* Created by Tzlil on 12/17/2015. * Created by Tzlil on 12/17/2015.
* provide convert operation from batch data to meerkat.mixer.network output and backwards * provide convert operation from batch data to meerkat.mixProverVerifier.network output and backwards
*/ */
public class BatchConverter { public class BatchConverter {
/** /**
* convert meerkat.mixer.network output to batch data * convert meerkat.mixProverVerifier.network output to batch data
* @param mixerOutput * @param mixerOutput
* @return meerkat.mixer.network output as list of batch data * @return meerkat.mixProverVerifier.network output as list of batch data
*/ */
public List<BulletinBoardAPI.BatchChunk> MixerOutput2BatchChunk(MixerOutput mixerOutput) { public List<BulletinBoardAPI.BatchChunk> MixerOutput2BatchChunk(MixerOutput mixerOutput) {
@ -49,7 +49,7 @@ public class BatchConverter {
} }
/** /**
* convert batch data list to meerkat.mixer.network output * convert batch data list to meerkat.mixProverVerifier.network output
* @param batchChunkList * @param batchChunkList
* @return batch data list as MixerOutput * @return batch data list as MixerOutput
* @throws Exception * @throws Exception

View File

@ -12,8 +12,8 @@ import java.util.List;
/** /**
* Created by Tzlil on 12/17/2015. * Created by Tzlil on 12/17/2015.
* implements AsyncBulletinBoardClient.ClientCallback<CompleteBatch> * Handles callback for receiving a complete mix proof table from the bulletin board.
*/ */
public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<CompleteBatch> { public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<CompleteBatch> {
private MixerOutput mixerOutput; private MixerOutput mixerOutput;
@ -61,7 +61,7 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
} }
/** /**
* convert batch data to meerkat.mixer.network output * convert batch data to meerkat.mixProverVerifier.network output
* @throws Exception * @throws Exception
*/ */
private void convertMessage() throws Exception { private void convertMessage() throws Exception {
@ -71,29 +71,29 @@ public class BatchHandler implements AsyncBulletinBoardClient.ClientCallback<Com
/** /**
* call convert message, and if succeed verify the table * call convert message, and if succeed verify the table
* @return return true iff the given batch message is valid meerkat.mixer.network output * @return return true iff the given batch message is valid meerkat.mixProverVerifier.network output
* @throws Exception * @throws Exception
*/ */
public boolean verifyTable() throws Exception { public boolean verifyTable(boolean strict) throws Exception {
if (mixerOutput == null) { if (mixerOutput == null) {
convertMessage(); convertMessage();
} }
return MixVerifier.verifyTable(verifier, mixerOutput); return MixVerifier.verifyTable(verifier, mixerOutput, strict);
} }
/** /**
* extract input for meerkat.mixer.network from previous mixers output * extract input for meerkat.mixProverVerifier.network from previous mixers output
* @return last layer of encrypted votes as list * @return last layer of encrypted votes as list
* @throws Throwable in case if failure * @throws Throwable in case if failure
*/ */
public List<Crypto.RerandomizableEncryptedMessage> getInputForMixer() throws Throwable { public List<Crypto.RerandomizableEncryptedMessage> getInputForMixer(boolean strictVerification) throws Throwable {
if (t != null) { if (t != null) {
throw t; throw t;
} }
if(!verifyTable()){ if(!verifyTable(strictVerification)){
throw new Exception("in valid table"); throw new Exception("invalid table");
} }
return Arrays.asList(mixerOutput.getEncryptedMessages()[mixerOutput.getNumLayers()]);//there are layers + 1 return Arrays.asList(mixerOutput.getEncryptedMessages()[mixerOutput.getNumLayers()]); //there are layers + 1
} }
} }

View File

@ -15,11 +15,11 @@ import java.util.Random;
/** /**
* Created by Tzlil on 12/17/2015. * Created by Tzlil on 12/17/2015.
* this class define all the operation meerkat.mixer.network party should do: * this class define all the operation meerkat.mixProverVerifier.network party should do:
* 1. receive previous mixers output (re encrypted votes + proofs) * 1. receive previous mixers output (re encrypted votes + proofs)
* 2. verify its input * 2. verify its input
* 3. mix * 3. mix
* 4. send the meerkat.mixer.network output * 4. send the meerkat.mixProverVerifier.network output
*/ */
public class MainMixing { public class MainMixing {
@ -52,7 +52,7 @@ public class MainMixing {
* @param callback * @param callback
* @throws Throwable * @throws Throwable
*/ */
public void main(List<Integer> prevBatchIds, int batchId, Random random, AsyncBulletinBoardClient.ClientCallback<?> callback) throws Throwable { public void main(List<Integer> prevBatchIds, int batchId, boolean strictVerification, Random random, AsyncBulletinBoardClient.ClientCallback<?> callback) throws Throwable {
List<Crypto.RerandomizableEncryptedMessage> mixerInput; List<Crypto.RerandomizableEncryptedMessage> mixerInput;
@ -72,13 +72,13 @@ public class MainMixing {
} }
// assert all handlers succeeded // assert all handlers succeeded
for (BatchHandler batchHandler : batchHandlers) { for (BatchHandler batchHandler : batchHandlers) {
if(!batchHandler.verifyTable()){ if(!batchHandler.verifyTable(strictVerification)){
throw new Exception("invalid input"); throw new Exception("invalid input");
} }
} }
BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1); BatchHandler lastBatchHandler = batchHandlers.get(batchHandlers.size() - 1);
mixerInput = lastBatchHandler.getInputForMixer(); mixerInput = lastBatchHandler.getInputForMixer(strictVerification);
MixerOutput mixerOutput = mixer.mix(mixerInput,random); MixerOutput mixerOutput = mixer.mix(mixerInput,random);
updateBB(mixerOutput, batchId, callback); updateBB(mixerOutput, batchId, callback);
@ -86,7 +86,7 @@ public class MainMixing {
} }
/** /**
* send meerkat.mixer.network output to BB * send meerkat.mixProverVerifier.network output to BB
* @param mixerOutput * @param mixerOutput
* @param batchId * @param batchId
* @param callback * @param callback

View File

@ -0,0 +1,299 @@
package meerkat.mixer.main;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.StringValue;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.mixer.MixGenerator;
import meerkat.mixer.MixVerifier;
import meerkat.mixer.MixerOutput;
import meerkat.mixer.proofs.concrete.Mix2nizk;
import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto;
import org.factcenter.qilin.primitives.RandomOracle;
import org.factcenter.qilin.primitives.concrete.DigestOracle;
import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import static java.lang.System.exit;
import static java.lang.System.in;
/**
* Command-line mixProverVerifier and verifier.
*/
public class Mix {
final static Logger logger = LoggerFactory.getLogger(Mix.class);
public Random rand;
public ECGroup group;
public ECElGamalEncryption enc;
public RandomOracle randomOracle;
public ConcreteCrypto.ElGamalPublicKey serializedPk;
public ECElGamal.SK secretKey;
public Mix2nizk mixProverVerifier;
public MixerOutput inMix;
public Mix() {
rand = new SecureRandom();
randomOracle = new DigestOracle();
enc = new ECElGamalEncryption();
serializedPk = null;
secretKey = null;
}
public void loadMix(File inFile) throws IOException {
assert(serializedPk != null);
InputStream in = new FileInputStream(inFile);
inMix = MixerOutput.parseDelimitedFrom(in);
in.close();
logger.info("Loaded mixnet with {} layers and logN={}", inMix.getNumLayers(), inMix.getLogN());
}
public boolean verify(boolean strict) {
try {
logger.info("Starting verification of {} ciphertexts", 1 << inMix.getLogN());
long startTime = System.currentTimeMillis();
boolean ok = MixVerifier.verifyTable(mixProverVerifier, inMix, strict);
long endTime = System.currentTimeMillis();
logger.info("Verification took {} seconds", (endTime - startTime) / 1000f);
return ok;
} catch (InvalidProtocolBufferException e) {
logger.error("Badly formatted encryptions", e);
return false;
}
}
public void mix(File outFile) throws IOException {
MixGenerator mixer = new MixGenerator(mixProverVerifier, enc);
List<Crypto.RerandomizableEncryptedMessage> encryptedMessages = Arrays.asList(inMix.getEncryptedMessages()[inMix.getNumLayers()]);
logger.info("Starting mix of {} ciphertexts", encryptedMessages.size());
long startTime = System.currentTimeMillis();
MixerOutput outMix = mixer.mix(encryptedMessages, rand);
long endTime = System.currentTimeMillis();
logger.info("Mix done (took {} seconds)", (endTime - startTime) / 1000f);
OutputStream out = new FileOutputStream(outFile);
outMix.writeDelimitedTo(out);
out.close();
}
// For testing purposes
public void setPK(ConcreteCrypto.ElGamalPublicKey serializedPk) {
this.serializedPk = serializedPk;
try {
enc.init(serializedPk);
group = enc.getGroup();
} catch (InvalidKeySpecException e) {
logger.error("Invalid EC-ElGamal public key", e);
exit(-2);
}
mixProverVerifier = new Mix2nizk(rand, enc, randomOracle);
}
/**
* Create a new ECElGamal key pair and write it serialized to file.
*
* @param outFile
*/
public void createKeypair(File outFile) throws IOException {
group = new ECGroup("secp256k1");
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
secretKey = new ECElGamal.SK(group, sk);
serializedPk = Util.encodePK(group, secretKey);
setPK(serializedPk);
Crypto.BigInteger serializedSk = Util.encodeBigInteger(sk);
OutputStream out = new FileOutputStream(outFile);
serializedPk.writeDelimitedTo(out);
serializedSk.writeDelimitedTo(out);
out.close();
}
/**
* Loads a public key and optionally a secret key from a file.
* @param inFile
* @throws IOException
* @throws InvalidKeySpecException
*/
public void loadKeypair(File inFile) throws IOException, InvalidKeySpecException {
InputStream in = new FileInputStream(inFile);
serializedPk = ConcreteCrypto.ElGamalPublicKey.parseDelimitedFrom(in);
setPK(serializedPk);
try {
Crypto.BigInteger serializedSk = Crypto.BigInteger.parseDelimitedFrom(in);
secretKey = Util.decodeSK(serializedPk, serializedSk);
} catch (EOFException e) {
logger.debug("File {} does not have a secret key", inFile);
} finally {
in.close();
}
}
/**
* Decrypt the output of a mixnet
* Outputs to a file, one line per decoded element.
*
* @throws IOException
*/
public void decrypt(File outFile) throws IOException {
PrintStream out = new PrintStream(outFile);
assert(inMix != null);
assert(inMix.getEncryptedMessages() != null);
logger.info("Decrypting {} ciphertexts", inMix.getEncryptedMessages()[inMix.getNumLayers()].length);
for (Crypto.RerandomizableEncryptedMessage ciphertext : inMix.getEncryptedMessages()[inMix.getNumLayers()]) {
StringValue plaintext = Util.decrypt(StringValue.class, secretKey, group, ciphertext);
out.println(plaintext.getValue());
}
out.close();
}
public void encrypt(File inFile, File outFile) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(inFile)));
ArrayList<String> lines = new ArrayList<>();
String line;
while ((line = in.readLine()) != null) {
lines.add(line);
}
in.close();
int n = lines.size();
int logN = 32 - Integer.numberOfLeadingZeros(n - 1);
n = 1 << logN; // We need the smallest power of 2 greater than the size
Crypto.RerandomizableEncryptedMessage ciphers[][] = new Crypto.RerandomizableEncryptedMessage[1][n];
logger.info("Encrypting {} plaintexts (padded to {})", lines.size(), n);
for (int i = 0; i < lines.size(); ++i) {
ciphers[0][i] = enc.encrypt(StringValue.newBuilder().setValue(lines.get(i)).build(), enc.generateRandomness(rand));
}
// Pad with empty values
StringValue empty = StringValue.newBuilder().setValue("").build();
for (int i = lines.size(); i < n; ++i) {
ciphers[0][i] = enc.encrypt(empty, enc.generateRandomness(rand));
}
inMix = new MixerOutput(logN, null, ciphers);
OutputStream out = new FileOutputStream(outFile);
inMix.writeDelimitedTo(out);
out.close();
logger.info("Wrote mixnet with {} layers and logN={}", inMix.getNumLayers(), inMix.getLogN());
}
static void printHelp(OptionParser parser) {
printHelp(null, parser);
}
static void printHelp(String msg, OptionParser parser) {
if (msg != null)
System.out.println(msg);
try {
parser.printHelpOn(System.out);
} catch (IOException e) {
// should never happen
}
}
public static void main(String[] args) {
OptionParser parser = new OptionParser();
final OptionSpec<Void> OPT_HELP = parser.accepts("help", "Print help");
final OptionSpec<Void> OPT_GENKEY = parser.accepts("genkey", "Generate a key-pair (write into key file)");
final OptionSpec<Void> OPT_DECRYPT = parser.accepts("decrypt", "Decrypt using given keypair");
final OptionSpec<File> OPT_KEYFILE = parser.accepts("keys", "File containing public key (or keypair for decryption)").withRequiredArg().ofType(File.class);
final OptionSpec<Void> OPT_ENCRYPT = parser.accepts("encrypt", "Decrypt using given keypair");
final OptionSpec<Void> OPT_STRICT = parser.accepts("strict", "Use strict verification (verify that network matches our Benes implementation)");
final OptionSpec<File> OPT_INPUTFILE = parser.accepts("infile", "Input file (if mixing, should contain ciphertext or mixProverVerifier output; if verifying, mixProverVerifier output)").withRequiredArg().ofType(File.class);
final OptionSpec<File> OPT_OUTPUTFILE = parser.accepts("outfile", "Output file. If given, operate in Mix mode; otherwise in verify mode.").withRequiredArg().ofType(File.class);
OptionSet options = parser.parse(args);
if (options.has(OPT_HELP)) {
printHelp(parser);
return;
}
File keyFile = options.valueOf(OPT_KEYFILE);
if (keyFile == null) {
printHelp("Must specify key file", parser);
return;
}
File inFile = options.valueOf(OPT_INPUTFILE);
if ((inFile == null || !inFile.canRead()) && !options.has(OPT_GENKEY)) {
printHelp("Must specify input file except for key generation" + (inFile.canRead() ? "" : " (can't read inFile)"), parser);
return;
}
File outFile = options.valueOf(OPT_OUTPUTFILE);
Mix mix = new Mix();
try {
if (options.has(OPT_GENKEY)) {
mix.createKeypair(keyFile);
} else {
mix.loadKeypair(keyFile);
if (options.has(OPT_ENCRYPT)) {
mix.encrypt(inFile, outFile);
} else if (options.has(OPT_DECRYPT)) {
mix.loadMix(inFile);
mix.decrypt(outFile);
} else if (options.has(OPT_OUTPUTFILE)) {
// Mix mode
mix.loadMix(inFile);
mix.mix(outFile);
} else {
mix.loadMix(inFile);
boolean ok = mix.verify(options.has(OPT_STRICT));
if (ok) {
logger.info("Verification successful");
} else {
logger.error("Verification failed!");
exit(-1);
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
}
}

View File

@ -56,7 +56,6 @@ public class Mix2nizk implements Prover, Verifier {
Crypto.RerandomizableEncryptedMessage c, Crypto.RerandomizableEncryptedMessage c,
Crypto.RerandomizableEncryptedMessage d, Crypto.RerandomizableEncryptedMessage d,
boolean switched, int layer, int switchIdx, int out0Idx, int out1Idx, boolean switched, int layer, int switchIdx, int out0Idx, int out1Idx,
Crypto.EncryptionRandomness r1, Crypto.EncryptionRandomness r1,
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException { Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {

View File

@ -13,7 +13,7 @@ import java.math.BigInteger;
/** /**
* used for organizing the input for each ZKP * used for organizing the input for each ZKP
* *
* both meerkat.mixer.proofs and meerkat.mixer.verifier implementation use it * both meerkat.mixProverVerifier.proofs and meerkat.mixProverVerifier.verifier implementation use it
*/ */
public class Statements { public class Statements {

View File

@ -1,13 +1,13 @@
//package meerkat.mixer; //package meerkat.mixer;
// //
//import meerkat.crypto.concrete.ECElGamalEncryption; //import meerkat.crypto.concrete.ECElGamalEncryption;
//import meerkat.mixer.proofs.Mix2nizk.Prover; //import meerkat.mixProverVerifier.proofs.Mix2nizk.Prover;
//import meerkat.mixer.proofs.Mix2nizk.Verifier; //import meerkat.mixProverVerifier.proofs.Mix2nizk.Verifier;
//import meerkat.mixer.Mixer; //import meerkat.mixProverVerifier.Mixer;
//import meerkat.mixer.MixerOutput; //import meerkat.mixProverVerifier.MixerOutput;
//import meerkat.mixer.proofs.Prover; //import meerkat.mixProverVerifier.proofs.Prover;
//import meerkat.mixer.proofs.Verifier; //import meerkat.mixProverVerifier.proofs.Verifier;
//import meerkat.mixer.VerifyTable; //import meerkat.mixProverVerifier.VerifyTable;
//import meerkat.protobuf.Crypto; //import meerkat.protobuf.Crypto;
//import meerkat.protobuf.Voting; //import meerkat.protobuf.Voting;
//import org.factcenter.qilin.primitives.RandomOracle; //import org.factcenter.qilin.primitives.RandomOracle;
@ -34,7 +34,7 @@
// RandomOracle randomOracle; // RandomOracle randomOracle;
// Verifier verifier; // Verifier verifier;
// Prover prover; // Prover prover;
// meerkat.crypto.mixnet.Mixer mixer; // meerkat.crypto.mixnet.Mixer mixProverVerifier;
// private int layers; // private int layers;
// private int n; // private int n;
// //
@ -45,13 +45,13 @@
// random = new Random(); // random = new Random();
// group = new ECGroup("secp256k1"); // group = new ECGroup("secp256k1");
// encryptor = new ECElGamalEncryption(); // encryptor = new ECElGamalEncryption();
// encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); // encryptor.init(Utils.encodePK(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
// randomMixer = new Random(); // randomMixer = new Random();
// randomProver = new Random(); // randomProver = new Random();
// randomOracle = new DigestOracle(); // randomOracle = new DigestOracle();
// verifier = new Verifier(encryptor,randomOracle); // verifier = new Verifier(encryptor,randomOracle);
// prover = new Prover(randomProver,encryptor,randomOracle); // prover = new Prover(randomProver,encryptor,randomOracle);
// mixer = new Mixer(prover,encryptor); // mixProverVerifier = new Mixer(prover,encryptor);
// //
// // generate n // // generate n
// int logN = 10; // + random.nextInt(8) // int logN = 10; // + random.nextInt(8)
@ -73,7 +73,7 @@
// //
// List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput(); // List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
// System.out.println("start network"); // System.out.println("start network");
// MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,randomMixer); // MixerOutput mixerOutput = (MixerOutput)mixProverVerifier.mix(mixerInput,randomMixer);
// System.out.println("network ended, start verification"); // System.out.println("network ended, start verification");
// assert (VerifyTable.verifyTable(verifier,n,mixerOutput)); // assert (VerifyTable.verifyTable(verifier,n,mixerOutput));
// System.out.println("verification ended, start printing"); // System.out.println("verification ended, start printing");
@ -86,11 +86,11 @@
// //
// //Verifier corruptedVerifier = new Verifier(enc,randomOracle,true); // //Verifier corruptedVerifier = new Verifier(enc,randomOracle,true);
// //Prover corruptedProver = new Prover(randomProver,enc,randomOracle,true); // //Prover corruptedProver = new Prover(randomProver,enc,randomOracle,true);
// //mixer = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier); // //mixProverVerifier = new Mixer(randomMixer,corruptedProver,enc,corruptedVerifier);
// //
// List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput(); // List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput();
// System.out.println("start network"); // System.out.println("start network");
// MixerOutput mixerOutput = (MixerOutput)mixer.mix(mixerInput,random); // MixerOutput mixerOutput = (MixerOutput)mixProverVerifier.mix(mixerInput,random);
// System.out.println("network ended, start negative verification"); // System.out.println("network ended, start negative verification");
// assert (!VerifyTable.verifyTable(verifier,n,mixerOutput)); // assert (!VerifyTable.verifyTable(verifier,n,mixerOutput));
// System.out.println("verification ended, start printing"); // System.out.println("verification ended, start printing");

View File

@ -1,6 +1,7 @@
package meerkat.mixer; package meerkat.mixer;
import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import org.factcenter.qilin.primitives.RandomOracle; import org.factcenter.qilin.primitives.RandomOracle;
import org.factcenter.qilin.primitives.concrete.DigestOracle; import org.factcenter.qilin.primitives.concrete.DigestOracle;
@ -28,7 +29,7 @@ public class ECParamTestBase {
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
key = new ECElGamal.SK(group, sk); key = new ECElGamal.SK(group, sk);
serializedPk = Utils.serializePk(group, key); serializedPk = Util.encodePK(group, key);
enc = new ECElGamalEncryption(); enc = new ECElGamalEncryption();
try { try {
enc.init(serializedPk); enc.init(serializedPk);

View File

@ -20,7 +20,6 @@ public class MixingTest extends ECParamTestBase {
Random random,randomMixer,randomProver; Random random,randomMixer,randomProver;
Mix2nizk mix2nizk; Mix2nizk mix2nizk;
MixGenerator mixer; MixGenerator mixer;
private int layers;
private int n; private int n;
@ -35,11 +34,10 @@ public class MixingTest extends ECParamTestBase {
// generate n // generate n
int logN = 5; // + random.nextInt(8) int logN = 5; // + random.nextInt(8)
layers = 2*logN - 1;
n = 1 << logN; n = 1 << logN;
} }
public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(){ public List<Crypto.RerandomizableEncryptedMessage> generateMixerInput(int n){
List<Crypto.RerandomizableEncryptedMessage> result = new ArrayList<Crypto.RerandomizableEncryptedMessage>(); List<Crypto.RerandomizableEncryptedMessage> result = new ArrayList<Crypto.RerandomizableEncryptedMessage>();
Voting.PlaintextBallot msg; Voting.PlaintextBallot msg;
for (int i = 0; i < n ; i++){ for (int i = 0; i < n ; i++){
@ -53,7 +51,7 @@ public class MixingTest extends ECParamTestBase {
public void mixingTest() throws InvalidProtocolBufferException { public void mixingTest() throws InvalidProtocolBufferException {
System.out.println("n is : " + n); System.out.println("n is : " + n);
System.out.println(" generating input"); System.out.println(" generating input");
List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput(); List<Crypto.RerandomizableEncryptedMessage> mixerInput = generateMixerInput(n);
System.out.println(" start network"); System.out.println(" start network");
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
@ -65,7 +63,7 @@ public class MixingTest extends ECParamTestBase {
System.out.println("start verification"); System.out.println("start verification");
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
assert (MixVerifier.verifyTable(mix2nizk, mixerOutput)); assert (MixVerifier.verifyTable(mix2nizk, mixerOutput, true));
finishTime = System.currentTimeMillis(); finishTime = System.currentTimeMillis();
System.out.println(" that took: "+(finishTime-startTime)+ " ms"); System.out.println(" that took: "+(finishTime-startTime)+ " ms");

View File

@ -1,8 +1,8 @@
package meerkat.mixer; package meerkat.mixer;
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.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import meerkat.protobuf.Voting; import meerkat.protobuf.Voting;
@ -35,7 +35,7 @@ public class RerandomizeTest {
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
key = new ECElGamal.SK(group, sk); key = new ECElGamal.SK(group, sk);
serializedPk = Utils.serializePk(group, key); serializedPk = Util.encodePK(group, key);
enc = new ECElGamalEncryption(); enc = new ECElGamalEncryption();
enc.init(serializedPk); enc.init(serializedPk);
RandomOracle randomOracle = new DigestOracle(); RandomOracle randomOracle = new DigestOracle();
@ -56,8 +56,8 @@ public class RerandomizeTest {
Crypto.RerandomizableEncryptedMessage e = enc.encrypt(msg, enc.generateRandomness(rand)); Crypto.RerandomizableEncryptedMessage e = enc.encrypt(msg, enc.generateRandomness(rand));
Crypto.RerandomizableEncryptedMessage eNew = enc.rerandomize(e, r); Crypto.RerandomizableEncryptedMessage eNew = enc.rerandomize(e, r);
assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e).equals(msg)); assert (Util.decrypt(Voting.PlaintextBallot.class, key, group, e).equals(msg));
assert (Utils.decrypt(Voting.PlaintextBallot.class, key, group, eNew).equals(msg)); assert (Util.decrypt(Voting.PlaintextBallot.class, key, group, eNew).equals(msg));
ConcreteCrypto.ElGamalCiphertext eElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e); ConcreteCrypto.ElGamalCiphertext eElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e);
ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(eNew); ConcreteCrypto.ElGamalCiphertext eNewElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(eNew);

View File

@ -27,66 +27,6 @@ import java.util.Random;
* Created by Tzlil on 1/1/2016. * Created by Tzlil on 1/1/2016.
*/ */
public class Utils { public class Utils {
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<ECPoint> pk) {
ECPoint pkPoint = pk.getPK();
ECParameterSpec params = group.getCurveParams();
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params);
try {
KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM,
GlobalCryptoSetup.getInstance().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 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());
ConcreteCrypto.GroupElement c1encoded = cipherText.getC1();
ConcreteCrypto.GroupElement c2encoded = cipherText.getC2();
ECPoint c1 = ECElGamalEncryption.decodeElement(group, c1encoded);
ECPoint c2 = ECElGamalEncryption.decodeElement(group, c2encoded);
assert (group.contains(c1));
assert (group.contains(c2));
ECPoint plaintextEncoded = secretKey.decrypt(new Pair<ECPoint, ECPoint>(c1, c2));
byte[] plaintext = group.injectiveDecode(plaintextEncoded);
ByteArrayInputStream in = new ByteArrayInputStream(plaintext);
try {
java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder");
Message.Builder builder = (Message.Builder) newBuilder.invoke(plaintextMessageType);
builder.mergeDelimitedFrom(in);
return plaintextMessageType.cast(builder.build());
} catch (Exception e) {
throw new InvalidProtocolBufferException("Plaintext protobuf error");
}
}
static Random random = new Random(0); 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) {

View File

@ -0,0 +1,120 @@
package meerkat.mixer.main;
import com.google.protobuf.StringValue;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.protobuf.Crypto;
import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.junit.Before;
import org.junit.Test;
import java.io.*;
import java.util.Random;
import static org.junit.Assert.*;
/**
* Created by talm on 21/01/17.
*/
public class MixTest {
public Mix mix;
Random rand = new Random(1);
@Before
public void setUp() throws Exception {
mix = new Mix();
}
@Test
public void testKeygen() throws Exception {
File tmpKeys = File.createTempFile("elgamal", "key");
mix.createKeypair(tmpKeys);
ECElGamal.SK secretKey = mix.secretKey;
assertNotNull(secretKey);
assertNotNull(mix.serializedPk);
Mix newMix = new Mix();
newMix.loadKeypair(tmpKeys);
assertEquals(mix.serializedPk, newMix.serializedPk);
StringValue tst = StringValue.newBuilder().setValue("test").build();
Crypto.RerandomizableEncryptedMessage cipher = mix.enc.encrypt(tst, mix.enc.generateRandomness(rand));
StringValue newTst = Util.decrypt(StringValue.class, newMix.secretKey, newMix.enc.getGroup(), cipher);
assertEquals(tst, newTst);
}
File createPlaintexts(int n) throws Exception {
File tmpData = File.createTempFile("plaintext", "txt");
PrintStream out = new PrintStream(tmpData);
for (int i = 0; i < n; ++i) {
out.println("Line " + i);
}
out.close();
return tmpData;
}
@Test
public void testEncryptDecrypt() throws Exception {
File tmpKeys = File.createTempFile("elgamal", "key");
mix.createKeypair(tmpKeys);
int n = 35;
File plaintexts = createPlaintexts(n);
File ciphertexts = File.createTempFile("ciphertexts", "bin");
mix.encrypt(plaintexts, ciphertexts);
Mix newMix = new Mix();
newMix.loadKeypair(tmpKeys);
newMix.loadMix(ciphertexts);
File newPlaintexts = File.createTempFile("plaintexts2", "txt");
newMix.decrypt(newPlaintexts);
BufferedReader in1 = new BufferedReader(new FileReader(plaintexts));
BufferedReader in2 = new BufferedReader(new FileReader(newPlaintexts));
int n2 = 1 << newMix.inMix.getLogN();
assert(n2 >= n);
for (int i = 0; i < n; ++i) {
String line1 = in1.readLine();
String line2 = in2.readLine();
assertEquals(line1, line2);
}
for (int i = n; i < n2; ++i) {
String line2 = in2.readLine();
assertEquals("", line2);
}
}
@Test
public void testMixVerify() throws Exception {
File tmpKeys = File.createTempFile("elgamal", "key");
mix.createKeypair(tmpKeys);
int n = 35;
File plaintexts = createPlaintexts(n);
File ciphertexts = File.createTempFile("ciphertexts", "enc");
mix.encrypt(plaintexts, ciphertexts);
File mixedFile = File.createTempFile("mixed", "enc");
Mix newMix1 = new Mix();
newMix1.loadKeypair(tmpKeys);
newMix1.loadMix(ciphertexts);
newMix1.mix(mixedFile);
Mix newMix2 = new Mix();
newMix2.loadKeypair(tmpKeys);
newMix2.loadMix(mixedFile);
boolean ok = newMix2.verify(true);
assertTrue(ok);
}
}

View File

@ -2,6 +2,7 @@ package meerkat.mixer.proofs.concrete;
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.mixer.ECParamTestBase; import meerkat.mixer.ECParamTestBase;
import meerkat.mixer.Utils; import meerkat.mixer.Utils;
import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
@ -45,10 +46,10 @@ public class Mix2ProofTest extends ECParamTestBase {
Crypto.RerandomizableEncryptedMessage e1New = enc.rerandomize(e1, r1); Crypto.RerandomizableEncryptedMessage e1New = enc.rerandomize(e1, r1);
Crypto.RerandomizableEncryptedMessage e2New = enc.rerandomize(e2, r2); Crypto.RerandomizableEncryptedMessage e2New = enc.rerandomize(e2, r2);
assertEquals (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e1), msg1); assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e1), msg1);
assertEquals (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e1New), msg1); assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e1New), msg1);
assertEquals (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e2), msg2); assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e2), msg2);
assertEquals (Utils.decrypt(Voting.PlaintextBallot.class, key, group, e2New), msg2); assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e2New), msg2);
ECPoint g = group.getGenerator(); ECPoint g = group.getGenerator();
ECPoint h = enc.getElGamalPK().getPK(); ECPoint h = enc.getElGamalPK().getPK();

View File

@ -2,6 +2,7 @@ package profiling.BigInteger;
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.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.mixer.Utils; import meerkat.mixer.Utils;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
@ -28,7 +29,7 @@ public class AddSub {
ECGroup group = new ECGroup("secp256k1"); ECGroup group = new ECGroup("secp256k1");
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
ECElGamal.SK key = new ECElGamal.SK(group, sk); ECElGamal.SK key = new ECElGamal.SK(group, sk);
ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key); ConcreteCrypto.ElGamalPublicKey serializedPk = Util.encodePK(group, key);
ECElGamalEncryption enc = new ECElGamalEncryption(); ECElGamalEncryption enc = new ECElGamalEncryption();
enc.init(serializedPk); enc.init(serializedPk);

View File

@ -2,6 +2,7 @@ package profiling.BigInteger;
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.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.mixer.Utils; import meerkat.mixer.Utils;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
@ -25,7 +26,7 @@ public class GenerateRandomness {
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
ECElGamal.SK key = new ECElGamal.SK(group, sk); ECElGamal.SK key = new ECElGamal.SK(group, sk);
ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key); ConcreteCrypto.ElGamalPublicKey serializedPk = Util.encodePK(group, key);
enc = new ECElGamalEncryption(); enc = new ECElGamalEncryption();
enc.init(serializedPk); enc.init(serializedPk);

View File

@ -2,8 +2,8 @@ package profiling.BigInteger;
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.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.mixer.Utils;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup; import org.factcenter.qilin.primitives.concrete.ECGroup;
@ -27,7 +27,7 @@ public class Modulo {
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
ECElGamal.SK key = new ECElGamal.SK(group, sk); ECElGamal.SK key = new ECElGamal.SK(group, sk);
ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key); ConcreteCrypto.ElGamalPublicKey serializedPk = Util.encodePK(group, key);
ECElGamalEncryption enc = new ECElGamalEncryption(); ECElGamalEncryption enc = new ECElGamalEncryption();
enc.init(serializedPk); enc.init(serializedPk);
for (int i =0 ; i < tests ; i++){ for (int i =0 ; i < tests ; i++){

View File

@ -2,6 +2,7 @@ package profiling.BigInteger;
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.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.mixer.Utils; import meerkat.mixer.Utils;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
@ -28,7 +29,7 @@ public class Mul {
ECGroup group = new ECGroup("secp256k1"); ECGroup group = new ECGroup("secp256k1");
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
ECElGamal.SK key = new ECElGamal.SK(group, sk); ECElGamal.SK key = new ECElGamal.SK(group, sk);
ConcreteCrypto.ElGamalPublicKey serializedPk = Utils.serializePk(group, key); ConcreteCrypto.ElGamalPublicKey serializedPk = Util.encodePK(group, key);
ECElGamalEncryption enc = new ECElGamalEncryption(); ECElGamalEncryption enc = new ECElGamalEncryption();
enc.init(serializedPk); enc.init(serializedPk);

View File

@ -1,11 +1,11 @@
package profiling.Convert; package profiling.Convert;
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.mixer.Utils;
import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Voting; import meerkat.protobuf.Voting;
import meerkat.mixer.Utils;
import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup; import org.factcenter.qilin.primitives.concrete.ECGroup;
@ -30,7 +30,7 @@ public class ByteString2ECPoint {
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
key = new ECElGamal.SK(group, sk); key = new ECElGamal.SK(group, sk);
serializedPk = Utils.serializePk(group, key); serializedPk = Util.encodePK(group, key);
enc = new ECElGamalEncryption(); enc = new ECElGamalEncryption();
enc.init(serializedPk); enc.init(serializedPk);
tests = 1024 * 19; tests = 1024 * 19;

View File

@ -2,6 +2,7 @@ package profiling.Convert;
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.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import meerkat.protobuf.Voting; import meerkat.protobuf.Voting;
@ -29,7 +30,7 @@ public class RerandomizableEncryptedMessage2ElGamalCiphertext {
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
key = new ECElGamal.SK(group, sk); key = new ECElGamal.SK(group, sk);
serializedPk = Utils.serializePk(group, key); serializedPk = Util.encodePK(group, key);
enc = new ECElGamalEncryption(); enc = new ECElGamalEncryption();
enc.init(serializedPk); enc.init(serializedPk);
tests = 1024 * 18; tests = 1024 * 18;

View File

@ -2,7 +2,7 @@ package profiling.ECGroup;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.mixer.Utils; import meerkat.crypto.concrete.Util;
import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup; import org.factcenter.qilin.primitives.concrete.ECGroup;
@ -29,7 +29,7 @@ public class Add {
random = new Random(); random = new Random();
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
encryptor = new ECElGamalEncryption(); encryptor = new ECElGamalEncryption();
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); encryptor.init(Util.encodePK(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
// generate n; // generate n;
int sqrtn = 128; int sqrtn = 128;
n = sqrtn*sqrtn; n = sqrtn*sqrtn;

View File

@ -2,6 +2,7 @@ package profiling.ECGroup;
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.mixer.Utils; import meerkat.mixer.Utils;
import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
@ -29,7 +30,7 @@ public class Encode {
random = new Random(); random = new Random();
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
encryptor = new ECElGamalEncryption(); encryptor = new ECElGamalEncryption();
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); encryptor.init(Util.encodePK(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
// generate n; // generate n;
int sqrtn = 128; int sqrtn = 128;
n = sqrtn*sqrtn; n = sqrtn*sqrtn;

View File

@ -2,7 +2,7 @@ package profiling.ECGroup;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.mixer.Utils; import meerkat.crypto.concrete.Util;
import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup; import org.factcenter.qilin.primitives.concrete.ECGroup;
@ -30,7 +30,7 @@ public class Mul {
random = new Random(); random = new Random();
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
encryptor = new ECElGamalEncryption(); encryptor = new ECElGamalEncryption();
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); encryptor.init(Util.encodePK(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
// generate n // generate n
int sqrtn = 128; int sqrtn = 128;
n = sqrtn*sqrtn; n = sqrtn*sqrtn;

View File

@ -2,7 +2,7 @@ package profiling.ECGroup;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.concrete.ECElGamalEncryption; import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.mixer.Utils; import meerkat.crypto.concrete.Util;
import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup; import org.factcenter.qilin.primitives.concrete.ECGroup;
@ -28,7 +28,7 @@ public class Negate {
random = new Random(); random = new Random();
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
encryptor = new ECElGamalEncryption(); encryptor = new ECElGamalEncryption();
encryptor.init(Utils.serializePk(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random)))); encryptor.init(Util.encodePK(group, new ECElGamal.SK(group, ECElGamal.generateSecretKey(group, random))));
// generate n; // generate n;
int sqrtn = 128; int sqrtn = 128;
n = sqrtn*sqrtn; n = sqrtn*sqrtn;

View File

@ -2,10 +2,11 @@ package profiling;
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.mixer.Utils;
import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import meerkat.protobuf.Voting; import meerkat.protobuf.Voting;
import meerkat.mixer.Utils;
import org.factcenter.qilin.primitives.concrete.ECElGamal; import org.factcenter.qilin.primitives.concrete.ECElGamal;
import org.factcenter.qilin.primitives.concrete.ECGroup; import org.factcenter.qilin.primitives.concrete.ECGroup;
@ -31,7 +32,7 @@ public class Rerandomize {
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
key = new ECElGamal.SK(group, sk); key = new ECElGamal.SK(group, sk);
serializedPk = Utils.serializePk(group, key); serializedPk = Util.encodePK(group, key);
enc = new ECElGamalEncryption(); enc = new ECElGamalEncryption();
enc.init(serializedPk); enc.init(serializedPk);
int LogVotes = 10; int LogVotes = 10;

View File

@ -3,6 +3,7 @@ package profiling;
import com.google.protobuf.ByteString; 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.mixer.proofs.concrete.Mix2nizk; import meerkat.mixer.proofs.concrete.Mix2nizk;
import meerkat.protobuf.ConcreteCrypto; import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
@ -38,7 +39,7 @@ public class ZeroKnowledgeProof {
group = new ECGroup("secp256k1"); group = new ECGroup("secp256k1");
BigInteger sk = ECElGamal.generateSecretKey(group, rand); BigInteger sk = ECElGamal.generateSecretKey(group, rand);
key = new ECElGamal.SK(group, sk); key = new ECElGamal.SK(group, sk);
serializedPk = Utils.serializePk(group, key); serializedPk = Util.encodePK(group, key);
enc = new ECElGamalEncryption(); enc = new ECElGamalEncryption();
enc.init(serializedPk); enc.init(serializedPk);
RandomOracle randomOracle = new DigestOracle(); RandomOracle randomOracle = new DigestOracle();