diff --git a/distributed-key-generation/build.gradle b/distributed-key-generation/build.gradle index 074667f..8f0a397 100644 --- a/distributed-key-generation/build.gradle +++ b/distributed-key-generation/build.gradle @@ -49,6 +49,9 @@ dependencies { // Google protobufs compile 'com.google.protobuf:protobuf-java:3.+' + // Depend on test resources from meerkat-common + testCompile project(path: ':meerkat-common', configuration: 'testOutput') + testCompile 'junit:junit:4.+' runtime 'org.codehaus.groovy:groovy:2.4.+' diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java deleted file mode 100644 index 5cd1be0..0000000 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MailHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -package meerkat.crypto.dkg.comm; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.crypto.utils.Channel; -import meerkat.protobuf.DKG; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Created by Tzlil on 2/14/2016. - * - * an implementation of ReceiverCallback - */ -public abstract class MailHandler implements Channel.ReceiverCallback{ - final Logger logger = LoggerFactory.getLogger(getClass()); - - /** - * fixed value for broadcasting - */ - public static final int BROADCAST = 0; - - /** - * message handler - */ - private MessageHandler messageHandler; - - /** - * constructor - * @param messageHandler - */ - public MailHandler(MessageHandler messageHandler){ - this.messageHandler = messageHandler; - } - - /** - * Was this broadcastMessage was received by broadcast channel - * @param broadcastMessage - * @return broadcastMessage user destination == BROADCAST - */ - public boolean isBroadcast(DKG.BroadcastMessage broadcastMessage){ - return broadcastMessage.getDestination() == BROADCAST; - } - - @Override - public void receiveMail(DKG.BroadcastMessage envelope) { - try { - messageHandler.handleMessage(envelope); - } catch (InvalidProtocolBufferException e) { - logger.warn("Received invalid protocol buffer from channel", e); - } - } -} diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java index 4927e94..02c751b 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/comm/MessageHandler.java @@ -1,50 +1,47 @@ package meerkat.crypto.dkg.comm; import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.protobuf.DKG; +import meerkat.comm.Channel; +import meerkat.protobuf.Comm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Created by Tzlil on 2/14/2016. - * an interface for handling received messages + * + * an implementation of ReceiverCallback */ -public interface MessageHandler { +public abstract class MessageHandler implements Channel.ReceiverCallback { + final Logger logger = LoggerFactory.getLogger(getClass()); /** + * fixed value for broadcasting + */ + public static final int BROADCAST = 0; + + /** * Handle a broadcast (or unicast) message. * If the message is invalid, the handler can throw an {@link InvalidProtocolBufferException}, in which * case the message will simply be ignored. * @param envelope */ - void handleMessage(DKG.BroadcastMessage envelope) throws InvalidProtocolBufferException; -// -// /** -// * handle share message -// */ -// void handleShareMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle commitment message -// */ -// void handleCommitmentMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle complaint message -// */ -// void handleComplaintMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle done message -// */ -// void handleDoneMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle answer message -// */ -// void handleAnswerMessage(int sender, boolean isBroadcast, Message message); -// -// /** -// * handle abort message -// */ -// void handleAbortMessage(int sender, boolean isBroadcast, Message message); + public abstract void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException; + + /** + * Was this broadcastMessage was received by broadcast channel + * @param broadcastMessage + * @return broadcastMessage user destination == BROADCAST + */ + public boolean isBroadcast(Comm.BroadcastMessage broadcastMessage){ + return broadcastMessage.getDestination() == BROADCAST; + } + + @Override + public void receiveMessage(Comm.BroadcastMessage envelope) { + try { + handleMessage(envelope); + } catch (InvalidProtocolBufferException e) { + logger.warn("Received invalid protocol buffer from channel", e); + } + } } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java deleted file mode 100644 index dabfa17..0000000 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/MailHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package meerkat.crypto.dkg.feldman; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.crypto.dkg.comm.MessageHandler; -import meerkat.protobuf.DKG; - -/** - * Created by Tzlil on 2/29/2016. - * an extension of MailHandler matching joint feldman protocol - */ -public class MailHandler extends meerkat.crypto.dkg.comm.MailHandler { - - /** - * constructor - * @param messageHandler - */ - public MailHandler(MessageHandler messageHandler) { - super(messageHandler); - } -} diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java index 74d35d4..d81c75a 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/Protocol.java @@ -1,6 +1,6 @@ package meerkat.crypto.dkg.feldman; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing; import meerkat.crypto.secretsharing.shamir.Polynomial; import com.google.protobuf.ByteString; @@ -171,7 +171,9 @@ public class Protocol extends VerifiableSecretSharing { */ public boolean isValidShare(int i){ Party party = parties[i - 1]; - return isValidShare(party.share,party.commitments,id); + synchronized (parties[i - 1]) { + return isValidShare(party.share, party.commitments, id); + } } /** @@ -232,7 +234,7 @@ public class Protocol extends VerifiableSecretSharing { */ public void answerAllComplainingPlayers(){ ComplaintState[] complaints = parties[id - 1].complaints; - for (int i = 1; i <= n ; i++) { + for (int i = 1; i <= n; i++) { switch (complaints[i - 1]) { case Waiting: broadcastComplaintAnswer(i); @@ -241,6 +243,7 @@ public class Protocol extends VerifiableSecretSharing { break; } } + } /** @@ -252,26 +255,28 @@ public class Protocol extends VerifiableSecretSharing { Set QUAL = new HashSet(); boolean nonDisqualified; int counter; - for (int i = 1; i <= n; i++){ - ComplaintState[] complaints = parties[i - 1].complaints; - nonDisqualified = true; - counter = 0; - for (int j = 1; j <= n; j++){ - switch (complaints[j - 1]) { - case OK: - break; - case NonDisqualified: - counter++; - break; - default: - nonDisqualified = false; + for (int i = 1; i <= n; i++) { + synchronized (parties[i - 1]) { + ComplaintState[] complaints = parties[i - 1].complaints; + nonDisqualified = true; + counter = 0; + for (int j = 1; j <= n; j++) { + switch (complaints[j - 1]) { + case OK: + break; + case NonDisqualified: + counter++; + break; + default: + nonDisqualified = false; + break; + } + if (!nonDisqualified) break; } - if(!nonDisqualified) - break; - } - if(nonDisqualified && counter <= t){ - QUAL.add(i); + if (nonDisqualified && counter <= t) { + QUAL.add(i); + } } } return QUAL; @@ -285,7 +290,9 @@ public class Protocol extends VerifiableSecretSharing { public T calcY(Set QUAL){ T y = group.zero(); for (int i : QUAL) { - y = group.add(y , parties[i - 1].commitments.get(0)); + synchronized (parties[i - 1]) { + y = group.add(y, parties[i - 1].commitments.get(0)); + } } return y; } @@ -301,7 +308,9 @@ public class Protocol extends VerifiableSecretSharing { for (int k = 0; k <= t; k++){ value = group.zero(); for (int i : QUAL) { - value = group.add(value, parties[i - 1].commitments.get(k)); + synchronized (parties[i - 1]) { + value = group.add(value, parties[i - 1].commitments.get(k)); + } } commitments.add(k,value); } @@ -315,7 +324,9 @@ public class Protocol extends VerifiableSecretSharing { public Polynomial.Point calcShare(Set QUAL){ BigInteger xj = BigInteger.ZERO; for (int i : QUAL) { - xj = xj.add(parties[i - 1].share.y); + synchronized (parties[i - 1]) { + xj = xj.add(parties[i - 1].share.y); + } } return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java index 4e4f155..6563dfd 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/feldman/User.java @@ -1,16 +1,23 @@ package meerkat.crypto.dkg.feldman; import com.google.protobuf.InvalidProtocolBufferException; -import meerkat.crypto.utils.Channel; +import com.google.protobuf.TextFormat; +import meerkat.comm.Channel; +import meerkat.crypto.dkg.comm.MessageHandler; import meerkat.crypto.secretsharing.shamir.Polynomial; import com.google.protobuf.ByteString; -import com.google.protobuf.Message; +import meerkat.protobuf.Comm; import meerkat.protobuf.DKG; import org.factcenter.qilin.primitives.Group; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.math.BigInteger; import java.util.ArrayList; import java.util.Set; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; import static meerkat.crypto.dkg.comm.MessageUtils.createMessage; @@ -25,7 +32,8 @@ import static meerkat.crypto.dkg.comm.MessageUtils.createMessage; * by the end of run(), each party in QUAL has his own share of the generated random key. * this key can be recover by any subset of QUAL of size at least t + 1. */ -public class User implements Runnable{ +public class User implements Runnable { + final Logger logger = LoggerFactory.getLogger(getClass()); /** * joint feldman protocol object @@ -59,10 +67,6 @@ public class User implements Runnable{ */ protected final int n; - /** - * mail handler registered to channel as ReceiverCallback - */ - protected meerkat.crypto.dkg.comm.MailHandler mailHandler; /** * channel object @@ -96,6 +100,8 @@ public class User implements Runnable{ */ protected T y; + protected BlockingQueue receiveQueue; + /** * constructor * @param dkg joint feldman protocol object @@ -120,14 +126,45 @@ public class User implements Runnable{ this.share = null; this.y = null; + this.receiveQueue = new LinkedBlockingDeque<>(); + } /** - * create MailHandler and register it as ReceiverCallback + * create MessageHandler and register it as ReceiverCallback */ - protected void registerReceiverCallback(){ - this.mailHandler = new MailHandler(new MessageHandler()); - channel.registerReceiverCallback(mailHandler); + protected void registerReceiverCallback() { + channel.registerReceiverCallback(new meerkat.crypto.dkg.comm.MessageHandler() { + @Override + public void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException { + receiveQueue.add(envelope); + } + }); + +// this.messageHandler = new MessageHandler(); +// channel.registerReceiverCallback(messageHandler); + } + + /** + * Wait for at least one message to arrive, then handle any messages currently in the queue + */ + protected void waitAndHandleReceivedMessages() { + Comm.BroadcastMessage msg = null; + while (!stop && msg == null) { + try { + msg = receiveQueue.take(); + } catch (InterruptedException e) { + // Possibly stop + } + } + while (!stop && msg != null) { + try { + handleMessage(msg); + } catch (InvalidProtocolBufferException e) { + logger.warn("Received invalid message: {}", TextFormat.printToString(msg)); + } + msg = receiveQueue.poll(); + } } /** @@ -140,37 +177,34 @@ public class User implements Runnable{ dkg.sendSecrets(); } - /** - * wait for all shares and commitments will arrive from other parties + * Check if all shares and commitments have arrived from other parties */ - protected void waitUntilStageOneCompleted(){ - // wait for parties' share - for (int i = 0 ; i < n ; i++){ - synchronized (parties[i]) { - while (parties[i].share == null && !parties[i].aborted) { - try { - parties[i].wait(); - } catch (InterruptedException e) { - if (stop) return; - } + protected boolean isStageOneCompleted() { + for (int i = 0 ; i < n ; i++) { + if (!parties[i].aborted) { + if (parties[i].share == null) + return false; + for (int k = 0 ; k <= t ; k++) { + if (parties[i].commitments.get(k) == null) + return false; } } } - // wait for parties' commitments - for (int i = 0 ; i < n ; i++){ - for (int k = 0 ; k <= t ; k++) { - synchronized (parties[i]) { - while (parties[i].commitments.get(k) == null && !parties[i].aborted) { - try { - parties[i].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } + return true; + } + + protected void waitUntilStageOneCompleted() { + while (!stop && !isStageOneCompleted()) + waitAndHandleReceivedMessages(); + } + + protected boolean isStageTwoCompleted() { + for (int i = 0 ; i < n ; i++) { + if (!parties[i].aborted && !parties[i].doneFlag) + return false; } + return true; } /** @@ -185,25 +219,28 @@ public class User implements Runnable{ channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE)); } - /** * wait until all other parties done complaining by receiving done message */ protected void waitUntilStageTwoCompleted(){ - for (int i = 0 ; i < n ; i++){ - synchronized (parties[i]) { - while (!parties[i].doneFlag && !parties[i].aborted) { - try { - parties[i].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } + while (!stop && !isStageTwoCompleted()) + waitAndHandleReceivedMessages(); } + protected boolean haveReceivedAllStage3ComplaintAnswers() { + for (int i = 0; i < n; i++) { + if (parties[i].aborted) + continue; + for (int j = 0; j < n; j++) { + if (parties[i].complaints[j].equals(Protocol.ComplaintState.Waiting)) + return false; + + } + } + return true; + } + /** * stage3 according to the protocol * 1. if more than t players complain against a player Pi he is disqualified. @@ -213,20 +250,11 @@ public class User implements Runnable{ */ protected void stage3(){ dkg.answerAllComplainingPlayers(); + // wait until there is no complaint waiting for answer - for (int i = 0; i < n; i++){ - for (int j = 0; j < n; j++){ - synchronized (parties[i]) { - while (parties[i].complaints[j].equals(Protocol.ComplaintState.Waiting) && !parties[i].aborted) { - try { - parties[i].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } - } + while (!stop && !haveReceivedAllStage3ComplaintAnswers()) + waitAndHandleReceivedMessages(); + this.QUAL = dkg.calcQUAL(); } @@ -245,15 +273,23 @@ public class User implements Runnable{ @Override public void run() { this.runThread = Thread.currentThread(); - stage1(); - waitUntilStageOneCompleted(); - if (stop) return; - stage2(); - waitUntilStageTwoCompleted(); - if (stop) return; - stage3(); - if (stop) return; - stage4(); + // For debugging + String previousName = runThread.getName(); + runThread.setName(getClass().getName() +":" + getID()); + + try { + stage1(); + waitUntilStageOneCompleted(); + if (stop) return; + stage2(); + waitUntilStageTwoCompleted(); + if (stop) return; + stage3(); + if (stop) return; + stage4(); + } finally { + runThread.setName(previousName); + } } /** @@ -360,199 +396,193 @@ public class User implements Runnable{ } /** - * an implementation of MessageHandler + * commitment message is valid if: + * 1. it was received in broadcast chanel + * 2. the sender didn't sent this commitment before */ - public class MessageHandler implements meerkat.crypto.dkg.comm.MessageHandler { + protected boolean isValidCommitmentMessage(int sender, boolean isBroadcast, DKG.CommitmentMessage commitmentMessage){ + int i = sender - 1; + int k = commitmentMessage.getK(); + return isBroadcast && parties[i].commitments.get(k) == null; + } - /** - * commitment message is valid if: - * 1. it was received in broadcast chanel - * 2. the sender didn't sent this commitment before - */ - protected boolean isValidCommitmentMessage(int sender, boolean isBroadcast, DKG.CommitmentMessage commitmentMessage){ - int i = sender - 1; - int k = commitmentMessage.getK(); - return isBroadcast && parties[i].commitments.get(k) == null; - } + /** + * secret message is valid if: + * 1. it was received in private chanel + * 2. the sender didn't sent secret message before + * 3. secret.i == i + * 4. secret.j == id + */ + protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKG.ShareMessage secretMessage){ + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + if(sender != i || isBroadcast) + return false; + else + return parties[i - 1].share == null && j == id; - /** - * secret message is valid if: - * 1. it was received in private chanel - * 2. the sender didn't sent secret message before - * 3. secret.i == i - * 4. secret.j == id - */ - protected boolean isValidSecretMessage(int sender, boolean isBroadcast, DKG.ShareMessage secretMessage){ - int i = secretMessage.getI(); - int j = secretMessage.getJ(); - if(sender != i || isBroadcast) - return false; - else - return parties[i - 1].share == null && j == id; + } - } - - /** - * done message is valid if: - * 1. it was received in broadcast chanel - * 2. the sender didn't sent done message before - */ - protected boolean isValidDoneMessage(int sender, boolean isBroadcast){ - return isBroadcast && !parties[sender - 1].doneFlag; - } + /** + * done message is valid if: + * 1. it was received in broadcast chanel + * 2. the sender didn't sent done message before + */ + protected boolean isValidDoneMessage(int sender, boolean isBroadcast){ + return isBroadcast && !parties[sender - 1].doneFlag; + } - /** - * complaint message is valid if: - * 1. it was received in broadcast chanel - * 2. the sender didn't complained against id before - */ - protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKG.IDMessage complaintMessage){ - int i = sender; - int j = complaintMessage.getId(); - return isBroadcast && parties[i - 1].complaints[j - 1].equals( Protocol.ComplaintState.OK); - } + /** + * complaint message is valid if: + * 1. it was received in broadcast chanel + * 2. the sender didn't complained against id before + */ + protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKG.IDMessage complaintMessage){ + int i = sender; + int j = complaintMessage.getId(); - /** - * answer message is valid if: - * 1. it was received in broadcast chanel - * 2. secret.i == i - * 3. 1 <= secret.j <= n - * 4. it is marked that j complained against i and i didn't received - */ - protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKG.ShareMessage secretMessage){ - int i = secretMessage.getI(); - int j = secretMessage.getJ(); - if(sender != i || !isBroadcast) - return false; - else - return j >= 1 && j <= n && parties[i - 1].complaints[j - 1].equals(Protocol.ComplaintState.Waiting); - } + assert(i > 0); + assert(j > 0); + assert(i <= parties.length); + assert(j <= parties[i-1].complaints.length); + + return isBroadcast && parties[i - 1].complaints[j - 1].equals( Protocol.ComplaintState.OK); + } + + /** + * answer message is valid if: + * 1. it was received in broadcast chanel + * 2. secret.i == i + * 3. 1 <= secret.j <= n + * 4. it is marked that j complained against i and i didn't received + */ + protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKG.ShareMessage secretMessage){ + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + if(sender != i || !isBroadcast) + return false; + else + return j >= 1 && j <= n && parties[i - 1].complaints[j - 1].equals(Protocol.ComplaintState.Waiting); + } - @Override - public void handleMessage(DKG.BroadcastMessage envelope) throws InvalidProtocolBufferException { - int sender = envelope.getSender(); - boolean isBroadcast = !envelope.getIsPrivate(); - DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload()); + public void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException { + int sender = envelope.getSender(); + boolean isBroadcast = !envelope.getIsPrivate(); + DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload()); - switch (msg.getType()) { - case COMMITMENT: - /** - * saves the commitment - */ - DKG.CommitmentMessage commitmentMessage = msg.getCommitment(); - if (isValidCommitmentMessage(sender, isBroadcast, commitmentMessage)) { - int i = sender - 1; - int k = commitmentMessage.getK(); - synchronized (parties[i]) { - parties[i].commitments.set(k, extractCommitment(commitmentMessage)); - parties[i].notify(); - } + logger.debug("handling Message: Dst={}, Src={}, [{}]", + envelope.getDestination(), envelope.getSender(), TextFormat.printToString(msg)); + + switch (msg.getType()) { + case COMMITMENT: + /** + * saves the commitment + */ + assert msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.COMMITMENT; + DKG.CommitmentMessage commitmentMessage = msg.getCommitment(); + if (isValidCommitmentMessage(sender, isBroadcast, commitmentMessage)) { + int i = sender - 1; + int k = commitmentMessage.getK(); + + parties[i].commitments.set(k, extractCommitment(commitmentMessage)); + } + break; + + + case SHARE: + /** + * saves the secret + */ + assert msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.SHARE; + DKG.ShareMessage secretMessage = msg.getShare(); + if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + Polynomial.Point secret = extractShare(id,secretMessage.getShare()); + parties[i - 1].share = secret; + } + break; + + case DONE: + + /** + * marks that the sender was finished sending all his complaints + */ + if(isValidDoneMessage(sender,isBroadcast)) { + parties[sender - 1].doneFlag = true; + } + break; + + case COMPLAINT: + /** + * marks that the sender was complained against id + */ + if (msg.getPayloadDataCase() != DKG.Payload.PayloadDataCase.ID) { + logger.error("User {} Expecting ID message, got from SRC={} msg {}", getID(), envelope.getSender(), TextFormat.printToString(msg)); + assert (msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.ID); + } + + DKG.IDMessage complaintMessage = msg.getId(); + if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ + int i = sender; + int j = complaintMessage.getId(); + parties[j - 1].complaints[i - 1] = Protocol.ComplaintState.Waiting; + } + break; + case ANSWER: + /** + * if the secret is valid, marks the complaint as NonDisqualified + * else marks it as Disqualified + * in case that the complainer is id ( j == id ), saves the secret + */ + assert msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.SHARE; + secretMessage = msg.getShare(); + if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { + int i = secretMessage.getI(); + int j = secretMessage.getJ(); + Polynomial.Point secret = extractShare(j,secretMessage.getShare()); + if (dkg.isValidShare(secret, parties[i - 1].commitments, j)) { + parties[i - 1].complaints[j - 1] = Protocol.ComplaintState.NonDisqualified; + } else { + parties[i - 1].complaints[j - 1] = Protocol.ComplaintState.Disqualified; } - break; - - - case SHARE: - /** - * saves the secret - */ - DKG.ShareMessage secretMessage = msg.getShare(); - if(isValidSecretMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - Polynomial.Point secret = extractShare(id,secretMessage.getShare()); - synchronized (parties[i -1]) { - parties[i - 1].share = secret; - parties[i - 1].notify(); - } + if (j == id) { + parties[i - 1].share = secret; } - break; + } + break; + case ABORT: + /** + * marks that the sender was aborted + */ + parties[sender - 1].aborted = true; + break; + default: + logger.error("Bad message: SRC={}, DST={}, Payload={}", envelope.getSender(), envelope.getDestination(), TextFormat.printToString(msg)); + break; - case DONE: - - /** - * marks that the sender was finished sending all his complaints - */ - if(isValidDoneMessage(sender,isBroadcast)) { - synchronized (parties[sender - 1]) { - parties[sender - 1].doneFlag = true; - parties[sender - 1].notify(); - } - } - break; - - case COMPLAINT: - /** - * marks that the sender was complained against id - */ - DKG.IDMessage complaintMessage = msg.getId(); - if(isValidComplaintMessage(sender,isBroadcast,complaintMessage)){ - int i = sender; - int j = complaintMessage.getId(); - synchronized (parties[j - 1]) { - parties[j - 1].complaints[i - 1] = Protocol.ComplaintState.Waiting; - parties[j - 1].notify(); - } - } - break; - case ANSWER: - /** - * if the secret is valid, marks the complaint as NonDisqualified - * else marks it as Disqualified - * in case that the complainer is id ( j == id ), saves the secret - */ - secretMessage = msg.getShare(); - if(isValidAnswerMessage(sender,isBroadcast,secretMessage)) { - int i = secretMessage.getI(); - int j = secretMessage.getJ(); - Polynomial.Point secret = extractShare(j,secretMessage.getShare()); - synchronized (parties[i - 1]) { - if (dkg.isValidShare(secret, parties[i - 1].commitments, j)) { - parties[i - 1].complaints[j - 1] = Protocol.ComplaintState.NonDisqualified; - } else { - parties[i - 1].complaints[j - 1] = Protocol.ComplaintState.Disqualified; - } - if (j == id) { - parties[i - 1].share = secret; - } - parties[i - 1].notify(); - } - } - break; - case ABORT: - /** - * marks that the sender was aborted - */ - synchronized (parties[sender - 1]) { - parties[sender - 1].aborted = true; - parties[sender - 1].notify(); - } - break; - - - - } - } - - /** - * extract share value from ByteString - * @param i - * @param share - * @return new Point (i,share) - */ - public Polynomial.Point extractShare(int i, ByteString share){ - BigInteger x = BigInteger.valueOf(i); - BigInteger y = new BigInteger(share.toByteArray()); - return new Polynomial.Point(x,y); - } - - /** - * - * @param commitmentMessage - * @return - */ - public T extractCommitment(DKG.CommitmentMessage commitmentMessage){ - return dkg.decodeCommitment(commitmentMessage.getCommitment().toByteArray()); } } + + /** + * extract share value from ByteString + * @param i + * @param share + * @return new Point (i,share) + */ + public Polynomial.Point extractShare(int i, ByteString share){ + BigInteger x = BigInteger.valueOf(i); + BigInteger y = new BigInteger(share.toByteArray()); + return new Polynomial.Point(x,y); + } + + /** + * + * @param commitmentMessage + * @return + */ + public T extractCommitment(DKG.CommitmentMessage commitmentMessage){ + return dkg.decodeCommitment(commitmentMessage.getCommitment().toByteArray()); + } } diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java deleted file mode 100644 index 36f970e..0000000 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/MailHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -package meerkat.crypto.dkg.gjkr; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import meerkat.crypto.dkg.comm.MessageHandler; -import meerkat.protobuf.DKG; - -/** - * Created by Tzlil on 2/29/2016. - * an extension of MailHandler matching gjkr protocl - */ -public class MailHandler extends meerkat.crypto.dkg.comm.MailHandler { - - /** - * flag that indicants whether the - * current run achieved stage 4 of the protocol or not - */ - private boolean isStage4; - - /** - * constructor - * @param messageHandler - */ - public MailHandler(MessageHandler messageHandler) { - super(messageHandler); - this.isStage4 = false; - } - - /** - * setter - * @param stage4 - */ - public void setStage4(boolean stage4) { - isStage4 = stage4; - } -} diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java index 6a3e0a4..5c1b418 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java +++ b/distributed-key-generation/src/main/java/meerkat/crypto/dkg/gjkr/User.java @@ -3,10 +3,10 @@ package meerkat.crypto.dkg.gjkr; import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.utils.Arithmetic; import meerkat.crypto.utils.concrete.Fp; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.crypto.secretsharing.shamir.Polynomial; import meerkat.crypto.secretsharing.shamir.SecretSharing; -import com.google.protobuf.Message; +import meerkat.protobuf.Comm; import meerkat.protobuf.DKG; import java.math.BigInteger; @@ -38,10 +38,7 @@ public class User extends meerkat.crypto.dkg.feldman.User { */ protected final Protocol sdkg; - /** - * message handler - */ - private MessageHandler messageHandler; + boolean isStage4; /** * constructor @@ -55,13 +52,6 @@ public class User extends meerkat.crypto.dkg.feldman.User { this.parties = sdkg.getParties(); } - @Override - protected void registerReceiverCallback() { - this.messageHandler = new MessageHandler(); - this.mailHandler = new MailHandler(messageHandler); - this.channel.registerReceiverCallback(mailHandler); - } - /** * stage1 according to the protocol * 1. Pi broadcasts Cik=Aik*Bik for k = 0,...,t. @@ -73,6 +63,8 @@ public class User extends meerkat.crypto.dkg.feldman.User { sdkg.sendSecrets(); } + + @Override protected void waitUntilStageOneCompleted() { super.waitUntilStageOneCompleted(); @@ -98,40 +90,74 @@ public class User extends meerkat.crypto.dkg.feldman.User { channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE)); } + /** + * Check if all non-aborting qualified parties have sent commitments. + * @return + */ + protected boolean haveAllQualPartiesCommitted() { + for (int i : QUAL) { + if (parties[i - 1].aborted) + continue; + for (int k = 0; k <= t; k++) { + if (parties[i - 1].commitments.get(k) == null) + return false; + } + } + return true; + } + + + /** + * Check if all non-aborting qualified parties sent a done message + * @return + */ + protected boolean areAllQualPartiesDone() { + for (int i : QUAL) { + if (parties[i - 1].aborted) + continue; + for (int k = 0; k <= t; k++) { + if (!parties[i - 1].ysDoneFlag) + return false; + } + } + return true; + } + + /** + * Check if at least t + 1 secrets were received foreach i in QUAL that aborted + * @return + */ + protected boolean haveReceivedEnoughSecretShares() { + for (int i : QUAL) { + if (parties[i - 1].aborted && parties[i - 1].recoverSharesSet.size() <= t) + return false; + } + return true; + } + /** * broadcast commitments and recover parties information if necessary */ private void resolveQualifyingPublicKey() { sdkg.broadcastCommitments(); // wait until all parties in QUAL broadcast their commitments or aborted - for (int i : QUAL) { - for (int k = 0; k <= t; k++) { - synchronized (parties[i - 1]) { - while (parties[i - 1].commitments.get(k) == null && !parties[i - 1].aborted) { - try { - parties[i - 1].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } - } + while (!stop && !haveAllQualPartiesCommitted()) + waitAndHandleReceivedMessages(); + + if (stop) + return; + sdkg.computeAndBroadcastComplaints(QUAL); + //broadcast done message after all complaints channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE)); + // wait until all parties in QUAL done or aborted - for (int i : QUAL) { - synchronized ((parties[i - 1])) { - while (!parties[i - 1].ysDoneFlag && !parties[i - 1].aborted) { - try { - parties[i - 1].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } + while (!stop && !areAllQualPartiesDone()) + waitAndHandleReceivedMessages(); + + if (stop) + return; // broadcast i private secret foreach i in QUAL that aborted for (int i : QUAL) { @@ -140,19 +166,12 @@ public class User extends meerkat.crypto.dkg.feldman.User { } } // wait until at least t + 1 secrets will received foreach i in QUAL that aborted - for (int i : QUAL) { - synchronized ((parties[i - 1])) { - if (parties[i - 1].aborted) { - while (parties[i - 1].recoverSharesSet.size() <= t) { - try { - parties[i - 1].wait(); - } catch (InterruptedException e) { - if (stop) return; - } - } - } - } - } + while (!stop && !haveReceivedEnoughSecretShares()) + waitAndHandleReceivedMessages(); + + if (stop) + return; + Arithmetic arithmetic = new Fp(sdkg.getQ()); // restore necessary information for (int i = 0; i < n; i++) { @@ -177,11 +196,10 @@ public class User extends meerkat.crypto.dkg.feldman.User { } /** - * notifies mail handler and message handler that stage 4 was started + * notifies message handler and message handler that stage 4 was started */ protected void setStage4() { - this.messageHandler.isStage4 = true; - ((MailHandler) this.mailHandler).setStage4(true); + isStage4 = true; } @Override @@ -192,151 +210,150 @@ public class User extends meerkat.crypto.dkg.feldman.User { super.stage4(); } - private class MessageHandler extends meerkat.crypto.dkg.feldman.User.MessageHandler { - boolean isStage4; - - /** - * if !isStage4 as super, with extension to double secret message - * else answer message is valid if: - * 1. it was received in broadcast chanel - * 2. secret.j == sender - * 3. QUAL contains i and j - */ - protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKG.ShareMessage doubleSecretMessage) { - if (!isStage4) { - return super.isValidAnswerMessage(sender, isBroadcast, doubleSecretMessage); - } else { - int i = doubleSecretMessage.getI(); - int j = doubleSecretMessage.getJ(); - return isBroadcast && j == sender && parties[i - 1].aborted && !parties[j - 1].aborted - && QUAL.contains(i) && QUAL.contains(j); - } - } - - - /** - * as in super with respect to protocol stage - */ - @Override - protected boolean isValidDoneMessage(int sender, boolean isBroadcast) { - if (!isStage4) { - return super.isValidDoneMessage(sender, isBroadcast); - } else { - return isBroadcast && !parties[sender - 1].ysDoneFlag; - } - } - - /** - * use only in stage4 - * complaint message is valid if: - * 1. it was received in broadcast chanel - * 2. secret.j == sender - * 3. QUAL contains i and j - */ - protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, - DKG.ShareMessage complaintMessage) { - int i = complaintMessage.getI(); - int j = complaintMessage.getJ(); - return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); - } - - - @Override - public void handleMessage(DKG.BroadcastMessage envelope) throws InvalidProtocolBufferException { - int sender = envelope.getSender(); - boolean isBroadcast = !envelope.getIsPrivate(); - DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload()); - switch (msg.getType()) { - case SHARE: - /** - * as in super, with extension to double secret message - */ - DKG.ShareMessage doubleSecretMessage = msg.getShare(); - if (isValidSecretMessage(sender, isBroadcast, doubleSecretMessage)) { - int i = doubleSecretMessage.getI(); - synchronized (parties[i - 1]) { - parties[i - 1].share = extractShare(id, doubleSecretMessage.getShare()); - parties[i - 1].shareT = extractShare(id, doubleSecretMessage.getShareT()); - parties[i - 1].notify(); - } - } - break; - case ANSWER: - /** - * if !isStage4 as super, with extension to double secret message - * else saves secret - */ - doubleSecretMessage = msg.getShare(); - if (isValidAnswerMessage(sender, isBroadcast, doubleSecretMessage)) { - int i = doubleSecretMessage.getI(); - int j = doubleSecretMessage.getJ(); - Polynomial.Point secret = extractShare(j, doubleSecretMessage.getShare()); - Polynomial.Point secretT = extractShare(j, doubleSecretMessage.getShareT()); - synchronized (parties[i - 1]) { - if (!isStage4) { - if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) { - parties[i - 1].complaints[j - 1] = meerkat.crypto.dkg.feldman.Protocol.ComplaintState.NonDisqualified; - - } else { - parties[i - 1].complaints[j - 1] = meerkat.crypto.dkg.feldman.Protocol.ComplaintState.Disqualified; - } - if (j == id) { - parties[i - 1].share = secret; - parties[i - 1].shareT = secretT; - } - } else if (sdkg.isValidShare(secret, secretT, parties[i - 1].verifiableValues, j)) { - parties[i - 1].recoverSharesSet.add(secret); - } - parties[i - 1].notify(); - } - } - break; - case DONE: - /** - * as in super with respect to protocol state - */ - if (!isStage4) - super.handleMessage(envelope); - else { - if (isValidDoneMessage(sender, isBroadcast)) { - synchronized (parties[sender - 1]) { - parties[sender - 1].ysDoneFlag = true; - parties[sender - 1].notify(); - } - } - } - break; - case COMPLAINT: - /** - * if !isStage4 as in super - * else if secret,secretT are valid with respect to verifiableValues but - * secret is not valid with respect to commitments then - * marks i as aborted - */ - if (!isStage4) { - super.handleMessage(envelope); - } else { - DKG.ShareMessage ysComplaintMessage = msg.getShare(); - if (isValidComplaintMessage(sender, isBroadcast, ysComplaintMessage)) { - int i = ysComplaintMessage.getI(); - int j = ysComplaintMessage.getJ(); - Polynomial.Point secret = extractShare(i, ysComplaintMessage.getShare()); - Polynomial.Point secretT = extractShare(i, ysComplaintMessage.getShareT()); - if (sdkg.isValidShare(secret, secretT, parties[i - 1].verifiableValues, j) - && !dkg.isValidShare(secret, parties[i - 1].commitments, j)) { - synchronized (parties[i - 1]) { - parties[i - 1].aborted = true; - parties[i - 1].notify(); - } - } - } - } - break; - default: - super.handleMessage(envelope); - break; - } + /** + * if !isStage4 as super, with extension to double secret message + * else answer message is valid if: + * 1. it was received in broadcast chanel + * 2. secret.j == sender + * 3. QUAL contains i and j + */ + protected boolean isValidAnswerMessage(int sender, boolean isBroadcast, DKG.ShareMessage doubleSecretMessage) { + if (!isStage4) { + return super.isValidAnswerMessage(sender, isBroadcast, doubleSecretMessage); + } else { + int i = doubleSecretMessage.getI(); + int j = doubleSecretMessage.getJ(); + return isBroadcast && j == sender && parties[i - 1].aborted && !parties[j - 1].aborted + && QUAL.contains(i) && QUAL.contains(j); } } + + + /** + * as in super with respect to protocol stage + */ + @Override + protected boolean isValidDoneMessage(int sender, boolean isBroadcast) { + if (!isStage4) { + return super.isValidDoneMessage(sender, isBroadcast); + } else { + return isBroadcast && !parties[sender - 1].ysDoneFlag; + } + } + + /** + * use only in stage4 + * complaint message is valid if: + * 1. it was received in broadcast chanel + * 2. secret.j == sender + * 3. QUAL contains i and j + */ + protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, + DKG.ShareMessage complaintMessage) { + int i = complaintMessage.getI(); + int j = complaintMessage.getJ(); + return isBroadcast && j == sender && QUAL.contains(i) && QUAL.contains(j); + } + + + @Override + public void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException { + int sender = envelope.getSender(); + boolean isBroadcast = !envelope.getIsPrivate(); + DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload()); + switch (msg.getType()) { + case SHARE: + /** + * as in super, with extension to double secret message + */ + DKG.ShareMessage doubleSecretMessage = msg.getShare(); + if (isValidSecretMessage(sender, isBroadcast, doubleSecretMessage)) { + int i = doubleSecretMessage.getI(); + synchronized (parties[i - 1]) { + parties[i - 1].share = extractShare(id, doubleSecretMessage.getShare()); + parties[i - 1].shareT = extractShare(id, doubleSecretMessage.getShareT()); + parties[i - 1].notify(); + } + } + break; + case ANSWER: + /** + * if !isStage4 as super, with extension to double secret message + * else saves secret + */ + assert msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.SHARE; + doubleSecretMessage = msg.getShare(); + if (isValidAnswerMessage(sender, isBroadcast, doubleSecretMessage)) { + int i = doubleSecretMessage.getI(); + int j = doubleSecretMessage.getJ(); + Polynomial.Point secret = extractShare(j, doubleSecretMessage.getShare()); + Polynomial.Point secretT = extractShare(j, doubleSecretMessage.getShareT()); + synchronized (parties[i - 1]) { + if (!isStage4) { + if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) { + parties[i - 1].complaints[j - 1] = meerkat.crypto.dkg.feldman.Protocol.ComplaintState.NonDisqualified; + + } else { + parties[i - 1].complaints[j - 1] = meerkat.crypto.dkg.feldman.Protocol.ComplaintState.Disqualified; + } + if (j == id) { + parties[i - 1].share = secret; + parties[i - 1].shareT = secretT; + } + } else if (sdkg.isValidShare(secret, secretT, parties[i - 1].verifiableValues, j)) { + parties[i - 1].recoverSharesSet.add(secret); + } + parties[i - 1].notify(); + } + } + break; + case DONE: + /** + * as in super with respect to protocol state + */ + if (!isStage4) + super.handleMessage(envelope); + else { + if (isValidDoneMessage(sender, isBroadcast)) { + synchronized (parties[sender - 1]) { + parties[sender - 1].ysDoneFlag = true; + parties[sender - 1].notify(); + } + } + } + break; + case COMPLAINT: + /** + * if !isStage4 as in super + * else if secret,secretT are valid with respect to verifiableValues but + * secret is not valid with respect to commitments then + * marks i as aborted + */ + if (!isStage4) { + super.handleMessage(envelope); + } else { + assert (msg.getPayloadDataCase() == DKG.Payload.PayloadDataCase.SHARE); + DKG.ShareMessage ysComplaintMessage = msg.getShare(); + if (isValidComplaintMessage(sender, isBroadcast, ysComplaintMessage)) { + int i = ysComplaintMessage.getI(); + int j = ysComplaintMessage.getJ(); + Polynomial.Point secret = extractShare(i, ysComplaintMessage.getShare()); + Polynomial.Point secretT = extractShare(i, ysComplaintMessage.getShareT()); + if (sdkg.isValidShare(secret, secretT, parties[i - 1].verifiableValues, j) + && !dkg.isValidShare(secret, parties[i - 1].commitments, j)) { + synchronized (parties[i - 1]) { + parties[i - 1].aborted = true; + parties[i - 1].notify(); + } + } + } + } + break; + default: + super.handleMessage(envelope); + break; + } + } + } \ No newline at end of file diff --git a/distributed-key-generation/src/main/proto/meerkat/DKG.proto b/distributed-key-generation/src/main/proto/meerkat/DKG.proto index 235f062..7d43a67 100644 --- a/distributed-key-generation/src/main/proto/meerkat/DKG.proto +++ b/distributed-key-generation/src/main/proto/meerkat/DKG.proto @@ -4,14 +4,6 @@ package meerkat; option java_package = "meerkat.protobuf"; -message BroadcastMessage { - int32 sender = 1; - int32 destination = 2; - bool is_private = 3; - - bytes payload = 5; -} - message Payload { enum Type { SHARE = 0; @@ -25,9 +17,11 @@ message Payload { ABORT = 8; } + + // Type of message in protocol Type type = 1; - oneof specific { + oneof payload_data { IDMessage id = 5; ShareMessage share = 6; CommitmentMessage commitment = 7; diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java index ebd2ff6..78b70d4 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGMaliciousUser.java @@ -1,6 +1,6 @@ package meerkat.crypto.dkg.feldman; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import java.math.BigInteger; import java.util.*; diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java index 18b3674..f522a42 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGTest.java @@ -1,9 +1,9 @@ package meerkat.crypto.dkg.feldman; -import meerkat.crypto.utils.ChannelImpl; +import meerkat.comm.ChannelImpl; import meerkat.crypto.utils.Arithmetic; import meerkat.crypto.utils.concrete.Fp; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing; import meerkat.crypto.secretsharing.shamir.Polynomial; import meerkat.crypto.secretsharing.shamir.SecretSharing; @@ -71,13 +71,6 @@ public class DKGTest { assert (calculatedSecret.equals(testable.secret)); } - public void stopReceivers(Testable testable){ - ChannelImpl channel; - for (int i = 0 ; i < testable.dkgs.length ; i++){ - channel = (ChannelImpl)testable.dkgs[i].getChannel(); - channel.stop(); - } - } @Test public void test() throws Exception { @@ -85,7 +78,6 @@ public class DKGTest { for (int i = 0; i < tests; i++){ testable = new Testable(new Random()); oneTest(testable); - stopReceivers(testable); } } @@ -115,11 +107,11 @@ public class DKGTest { BigInteger s; Protocol dkg; this.secret = BigInteger.ZERO; - ChannelImpl channel; + ChannelImpl channels = new ChannelImpl(); ByteEncoder byteEncoder = new BigIntegerByteEncoder(); while (!ids.isEmpty()) { id = ids.remove(random.nextInt(ids.size())); - channel = new ChannelImpl(id,n); + Channel channel = channels.getChannel(id); s = randomIntModQ(random); dkg = new meerkat.crypto.dkg.feldman.Protocol(t, n, s, random, q, g, group, id,byteEncoder); dkgs[id - 1] = randomDKGUser(id,channel,dkg,random); diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java index 902d103..528ea9f 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/feldman/DKGUserImplAbort.java @@ -1,6 +1,6 @@ package meerkat.crypto.dkg.feldman; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.protobuf.DKG; import static meerkat.crypto.dkg.comm.MessageUtils.createMessage; diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java index f72b00a..baf1a81 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGMaliciousUserImpl.java @@ -1,6 +1,6 @@ package meerkat.crypto.dkg.gjkr; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import java.math.BigInteger; import java.util.Random; diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java index b5c4c9f..e4550f0 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGTest.java @@ -1,9 +1,9 @@ package meerkat.crypto.dkg.gjkr; -import meerkat.crypto.utils.ChannelImpl; +import meerkat.comm.ChannelImpl; import meerkat.crypto.utils.Arithmetic; import meerkat.crypto.utils.concrete.Fp; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing; import meerkat.crypto.dkg.feldman.DKGMaliciousUser; import meerkat.crypto.secretsharing.shamir.Polynomial; @@ -13,34 +13,45 @@ import meerkat.crypto.utils.GenerateRandomPrime; import org.factcenter.qilin.primitives.Group; import org.factcenter.qilin.primitives.concrete.Zpstar; import org.factcenter.qilin.util.ByteEncoder; +import org.junit.Assert; import org.junit.Test; +import org.junit.internal.runners.statements.Fail; + +import static org.junit.Assert.*; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashSet; import java.util.Random; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; /** * Created by Tzlil on 3/29/2016. + * TODO: Separate into multiple tests, + * TODO: Make tests deterministic (using constant seed for random generator) */ public class SDKGTest { - int tests = 10; + private ExecutorService executorService = Executors.newCachedThreadPool(); + + final static int NUM_TESTS = 10; BigInteger p = GenerateRandomPrime.SafePrime100Bits; BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); Group group = new Zpstar(p); Arithmetic arithmetic = new Fp(q); - int t = 9; + int t = 1; int n = 20; - + Random rand = new Random(1); public void oneTest(Testable testable) throws Exception { - for (int i = 0; i < testable.threads.length ; i++){ - testable.threads[i].start(); + for (int i = 0; i < testable.sdkgs.length ; i++){ + testable.futures[i] = executorService.submit(testable.sdkgs[i]); } - for (int i = 0; i < testable.threads.length ; i++){ - testable.threads[i].join(); + for (int i = 0; i < testable.futures.length ; i++){ + testable.futures[i].get(); } // got the right public value @@ -73,41 +84,45 @@ public class SDKGTest { assert (calculatedSecret.equals(testable.secret)); } - public void stopReceivers(Testable testable){ - ChannelImpl channel; - for (int i = 0 ; i < testable.sdkgs.length ; i++){ - channel = (ChannelImpl)testable.sdkgs[i].getChannel(); - channel.stop(); - } - } @Test public void test() throws Exception { Testable testable; - for (int i = 0; i < tests; i++) { - testable = new Testable(new Random()); + for (int i = 0; i < NUM_TESTS; i++) { + testable = new Testable(n, t, group, q, rand); oneTest(testable); - stopReceivers(testable); } } - class Testable{ + + static class Testable { Set valids; Set QUAL; Set aborted; Set malicious; User[] sdkgs; - Thread[] threads; + Future[] futures; BigInteger g; BigInteger h; BigInteger secret; + Group group; + int n; + int t; + BigInteger q; + Random random; + ChannelImpl channels = new ChannelImpl(); - public Testable(Random random) { + public Testable(int n, int t, Group group, BigInteger q, Random random) { + this.n = n; + this.t = t; + this.group = group; + this.q = q; + this.random = random; this.sdkgs = new User[n]; this.valids = new HashSet(); this.QUAL = new HashSet(); this.aborted = new HashSet(); this.malicious = new HashSet(); - this.threads = new Thread[n]; + this.futures = new Future[n]; this.g = sampleGenerator(random); this.h = group.multiply(g,randomIntModQ(random)); ArrayList ids = new ArrayList(); @@ -123,10 +138,9 @@ public class SDKGTest { while (!ids.isEmpty()) { id = ids.remove(random.nextInt(ids.size())); s = randomIntModQ(random); - channel = new ChannelImpl(id,n); + channel = channels.getChannel(id); sdkg = new Protocol(t, n, s, random, q, g , h, group, id,encoder); - sdkgs[id - 1] = randomSDKGUser(id,channel,sdkg,random); - threads[id - 1] = new Thread(sdkgs[id - 1]); + sdkgs[id - 1] = randomSDKGUser(id,channel,sdkg); if(QUAL.contains(id)){ this.secret = this.secret.add(s).mod(q); } @@ -134,33 +148,44 @@ public class SDKGTest { } - public User randomSDKGUser(int id, Channel channel, Protocol sdkg, Random random){ - if (QUAL.size() <= t) { - valids.add(id); - QUAL.add(id); - return new User(sdkg,channel); - }else{ - int type = random.nextInt(3); - switch (type){ - case 0:// regular - valids.add(id); + enum UserType { + HONEST, + FAILSTOP, + MALICIOUS, + } + + public User newSDKGUser(int id, Channel channel, Protocol sdkg, UserType userType) { + switch(userType) { + case HONEST: + valids.add(id); + QUAL.add(id); + return new User(sdkg,channel); + + case FAILSTOP: + int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3 + aborted.add(id); + if (abortStage > 1){ QUAL.add(id); - return new User(sdkg,channel); - case 1:// abort - int abortStage = random.nextInt(3) + 1; // 1 or 2 or 3 - aborted.add(id); - if (abortStage > 1){ - QUAL.add(id); - } - return new SDKGUserImplAbort(sdkg,channel,abortStage); - case 2:// malicious - malicious.add(id); - Set falls = DKGMaliciousUser.selectFallsRandomly(valids,random); - Protocol maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random); - return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls); - default: - return null; - } + } + return new SDKGUserImplAbort(sdkg,channel,abortStage); + + case MALICIOUS: + malicious.add(id); + Set falls = DKGMaliciousUser.selectFallsRandomly(valids,random); + Protocol maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random); + return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls); + + } + fail("Unknown user type"); + return null; + } + + public User randomSDKGUser(int id, Channel channel, Protocol sdkg){ + if (QUAL.size() <= t) { + return newSDKGUser(id, channel, sdkg, UserType.HONEST); + } else { + UserType type = UserType.values()[random.nextInt(UserType.values().length)]; + return newSDKGUser(id, channel, sdkg, type); } } diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java index b067c1a..5b0e11b 100644 --- a/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java +++ b/distributed-key-generation/src/test/java/meerkat/crypto/dkg/gjkr/SDKGUserImplAbort.java @@ -1,7 +1,9 @@ package meerkat.crypto.dkg.gjkr; +import com.google.protobuf.InvalidProtocolBufferException; import meerkat.crypto.dkg.comm.MessageUtils; -import meerkat.crypto.utils.Channel; +import meerkat.comm.Channel; +import meerkat.protobuf.Comm; import meerkat.protobuf.DKG; /** @@ -9,6 +11,10 @@ import meerkat.protobuf.DKG; */ public class SDKGUserImplAbort extends User { + public static class AbortException extends RuntimeException { + + } + final int abortStage; int stage; public SDKGUserImplAbort(Protocol sdkg, Channel channel, int abortStage) { @@ -20,6 +26,7 @@ public class SDKGUserImplAbort extends User { private void abort(){ //stopReceiver(); channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ABORT)); + throw new AbortException(); } @Override @@ -61,4 +68,13 @@ public class SDKGUserImplAbort extends User { } stage++; } + + @Override + public void run() { + try { + super.run(); + } catch (AbortException e) { + // Expected + } + } } diff --git a/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java b/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java deleted file mode 100644 index dfb1bfb..0000000 --- a/distributed-key-generation/src/test/java/meerkat/crypto/utils/ChannelImpl.java +++ /dev/null @@ -1,111 +0,0 @@ -package meerkat.crypto.utils; - -import com.google.protobuf.Message; -import meerkat.protobuf.DKG; - -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; - -/** - * Created by Tzlil on 2/14/2016. - */ -// TODO: Change nane to network - -public class ChannelImpl implements Channel { - - public static int BROADCAST = 0; - private static ChannelImpl[] channels = null; - - protected final Queue mailbox; - protected final int id; - protected final int n; - protected Thread receiverThread; - - - public ChannelImpl(int id, int n) { - if (channels == null){ - channels = new ChannelImpl[n]; - } - this.mailbox = new ArrayBlockingQueue( n * n * n); - this.id = id; - this.n = n; - channels[id - 1] = this; - } - - @Override - public int getSourceId() { - return id; - } - - - @Override - public void sendMessage(int destUser, Message msg) { - if(destUser < 1 || destUser > n) - return; - ChannelImpl channel = channels[destUser - 1]; - if (channel == null) - return; - DKG.BroadcastMessage broadcastMessage = DKG.BroadcastMessage.newBuilder() - .setSender(id) - .setDestination(destUser) - .setIsPrivate(true) - .setPayload(msg.toByteString()) - .build(); - synchronized (channel.mailbox) { - channel.mailbox.add(broadcastMessage); - channel.mailbox.notify(); - } - } - - @Override - public void broadcastMessage(Message msg) { - ChannelImpl channel; - DKG.BroadcastMessage broadcastMessage = DKG.BroadcastMessage.newBuilder() - .setSender(id) - .setDestination(BROADCAST) - .setIsPrivate(false) - .setPayload(msg.toByteString()) - .build(); - for (int i = 0 ; i < n ; i++){ - channel = channels[i]; - synchronized (channel.mailbox) { - channel.mailbox.add(broadcastMessage); - channel.mailbox.notify(); - } - } - } - - public void stop(){ - try{ - receiverThread.interrupt(); - }catch (Exception e){ - //do nothing - } - } - - @Override - public void registerReceiverCallback(final ReceiverCallback callback) { - stop(); - receiverThread = new Thread(new Runnable() { - @Override - public void run() { - while (true){ - try { - synchronized (mailbox) { - while (!mailbox.isEmpty()) { - callback.receiveMail(mailbox.remove()); - } - mailbox.wait(); - } - } catch (InterruptedException e) { - //do nothing - } - } - } - }); - receiverThread.start(); - } - - - -} diff --git a/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java b/meerkat-common/src/main/java/meerkat/comm/Channel.java similarity index 89% rename from distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java rename to meerkat-common/src/main/java/meerkat/comm/Channel.java index 97a6060..7dd74c1 100644 --- a/distributed-key-generation/src/main/java/meerkat/crypto/utils/Channel.java +++ b/meerkat-common/src/main/java/meerkat/comm/Channel.java @@ -1,7 +1,7 @@ -package meerkat.crypto.utils; +package meerkat.comm; import com.google.protobuf.Message; -import meerkat.protobuf.DKG; +import meerkat.protobuf.Comm; /** * A generic communication channel that supports point-to-point and broadcast operation @@ -15,7 +15,7 @@ public interface Channel { public int getSourceId(); public interface ReceiverCallback { - public void receiveMail(DKG.BroadcastMessage envelope); + public void receiveMessage(Comm.BroadcastMessage envelope); } /** diff --git a/meerkat-common/src/main/proto/meerkat/comm.proto b/meerkat-common/src/main/proto/meerkat/comm.proto new file mode 100644 index 0000000..c509165 --- /dev/null +++ b/meerkat-common/src/main/proto/meerkat/comm.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package meerkat; + +option java_package = "meerkat.protobuf"; + +message BroadcastMessage { + int32 sender = 1; + int32 destination = 2; + bool is_private = 3; + + bytes payload = 5; +} diff --git a/meerkat-common/src/test/java/meerkat/comm/ChannelImpl.java b/meerkat-common/src/test/java/meerkat/comm/ChannelImpl.java new file mode 100644 index 0000000..cfe32c2 --- /dev/null +++ b/meerkat-common/src/test/java/meerkat/comm/ChannelImpl.java @@ -0,0 +1,96 @@ +package meerkat.comm; + +import com.google.protobuf.Message; +import com.google.protobuf.TextFormat; +import meerkat.protobuf.Comm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.Queue; +import java.util.TreeMap; +import java.util.concurrent.*; + +/** + * Created by Tzlil on 2/14/2016. + */ +// TODO: Change nane to network + +public class ChannelImpl { + final Logger logger = LoggerFactory.getLogger(getClass()); + + //private ExecutorService executorService = Executors.newCachedThreadPool(); + public static int BROADCAST = 0; + Map channels = new TreeMap<>(); + + + public ChannelImpl() { + } + + public Channel getChannel(int id) { + return new SingleChannel(id); + } + + public class SingleChannel implements Channel { + protected final int id; + + ReceiverCallback callback; + + SingleChannel(int id) { + this.id = id; + channels.put(id, this); + } + + @Override + public int getSourceId() { + return id; + } + + + @Override + public void sendMessage(int destUser, Message msg) { + if (destUser < 1) + return; + SingleChannel channel = channels.get(destUser); + if (channel == null) { + logger.warn("Party {} attempting to send message to non-existing party {}", getSourceId(), destUser); + return; + } + Comm.BroadcastMessage broadcastMessage = Comm.BroadcastMessage.newBuilder() + .setSender(id) + .setDestination(destUser) + .setIsPrivate(true) + .setPayload(msg.toByteString()) + .build(); + + logger.debug("sending Message: Dst={},Src={} [{}]", broadcastMessage.getDestination(), + broadcastMessage.getSender(), TextFormat.printToString(msg)); + + channel.callback.receiveMessage(broadcastMessage); + } + + @Override + public void broadcastMessage(Message msg) { + Comm.BroadcastMessage broadcastMessage = Comm.BroadcastMessage.newBuilder() + .setSender(id) + .setDestination(BROADCAST) + .setIsPrivate(false) + .setPayload(msg.toByteString()) + .build(); + + logger.debug("broadcasting Message: Src={} [{}]", + broadcastMessage.getSender(), TextFormat.printToString(msg)); + + for (SingleChannel channel : channels.values()) { + channel.callback.receiveMessage(broadcastMessage); + } + } + + @Override + public void registerReceiverCallback(final ReceiverCallback callback) { + this.callback = callback; + } + } + +}