More refactoring for tests and protocol -- user class now handles all messages synchronously (in the main thread); concurrency is now simpler)

DKG
Tal Moran 2016-04-14 03:34:54 +03:00
parent c798e827dc
commit 1f8df95895
19 changed files with 780 additions and 807 deletions

View File

@ -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.+'

View File

@ -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);
}
}
}

View File

@ -1,14 +1,23 @@
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.
@ -16,35 +25,23 @@ public interface MessageHandler {
* 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);
}
}
}

View File

@ -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);
}
}

View File

@ -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<T> extends VerifiableSecretSharing<T> {
*/
public boolean isValidShare(int i){
Party<T> 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<T> extends VerifiableSecretSharing<T> {
*/
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<T> extends VerifiableSecretSharing<T> {
break;
}
}
}
/**
@ -252,11 +255,12 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
Set<Integer> QUAL = new HashSet<Integer>();
boolean nonDisqualified;
int counter;
for (int i = 1; i <= n; i++){
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++){
for (int j = 1; j <= n; j++) {
switch (complaints[j - 1]) {
case OK:
break;
@ -267,13 +271,14 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
nonDisqualified = false;
break;
}
if(!nonDisqualified)
if (!nonDisqualified)
break;
}
if(nonDisqualified && counter <= t){
if (nonDisqualified && counter <= t) {
QUAL.add(i);
}
}
}
return QUAL;
}
@ -285,7 +290,9 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
public T calcY(Set<Integer> 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,8 +308,10 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
for (int k = 0; k <= t; k++){
value = group.zero();
for (int i : QUAL) {
synchronized (parties[i - 1]) {
value = group.add(value, parties[i - 1].commitments.get(k));
}
}
commitments.add(k,value);
}
return commitments;
@ -315,8 +324,10 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
public Polynomial.Point calcShare(Set<Integer> QUAL){
BigInteger xj = BigInteger.ZERO;
for (int i : QUAL) {
synchronized (parties[i - 1]) {
xj = xj.add(parties[i - 1].share.y);
}
}
return new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q));
}

View File

@ -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<T> implements Runnable{
public class User<T> implements Runnable {
final Logger logger = LoggerFactory.getLogger(getClass());
/**
* joint feldman protocol object
@ -59,10 +67,6 @@ public class User<T> 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<T> implements Runnable{
*/
protected T y;
protected BlockingQueue<Comm.BroadcastMessage> receiveQueue;
/**
* constructor
* @param dkg joint feldman protocol object
@ -120,14 +126,45 @@ public class User<T> 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<T> 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;
}
}
}
}
// wait for parties' commitments
for (int i = 0 ; i < n ; i++){
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++) {
synchronized (parties[i]) {
while (parties[i].commitments.get(k) == null && !parties[i].aborted) {
try {
parties[i].wait();
} catch (InterruptedException e) {
if (stop) return;
if (parties[i].commitments.get(k) == null)
return false;
}
}
}
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<T> 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<T> 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,6 +273,11 @@ public class User<T> implements Runnable{
@Override
public void run() {
this.runThread = Thread.currentThread();
// For debugging
String previousName = runThread.getName();
runThread.setName(getClass().getName() +":" + getID());
try {
stage1();
waitUntilStageOneCompleted();
if (stop) return;
@ -254,6 +287,9 @@ public class User<T> implements Runnable{
stage3();
if (stop) return;
stage4();
} finally {
runThread.setName(previousName);
}
}
/**
@ -359,11 +395,6 @@ public class User<T> implements Runnable{
return channel;
}
/**
* an implementation of MessageHandler
*/
public class MessageHandler implements meerkat.crypto.dkg.comm.MessageHandler {
/**
* commitment message is valid if:
* 1. it was received in broadcast chanel
@ -410,6 +441,12 @@ public class User<T> implements Runnable{
protected boolean isValidComplaintMessage(int sender, boolean isBroadcast, DKG.IDMessage complaintMessage){
int i = sender;
int j = complaintMessage.getId();
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);
}
@ -430,25 +467,26 @@ public class User<T> implements Runnable{
}
@Override
public void handleMessage(DKG.BroadcastMessage envelope) throws InvalidProtocolBufferException {
public void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException {
int sender = envelope.getSender();
boolean isBroadcast = !envelope.getIsPrivate();
DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload());
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();
synchronized (parties[i]) {
parties[i].commitments.set(k, extractCommitment(commitmentMessage));
parties[i].notify();
}
}
break;
@ -457,14 +495,12 @@ public class User<T> implements Runnable{
/**
* 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());
synchronized (parties[i -1]) {
parties[i - 1].share = secret;
parties[i - 1].notify();
}
}
break;
@ -474,10 +510,7 @@ public class User<T> implements Runnable{
* 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;
@ -485,14 +518,16 @@ public class User<T> implements Runnable{
/**
* 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();
synchronized (parties[j - 1]) {
parties[j - 1].complaints[i - 1] = Protocol.ComplaintState.Waiting;
parties[j - 1].notify();
}
}
break;
case ANSWER:
@ -501,12 +536,12 @@ public class User<T> implements Runnable{
* 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());
synchronized (parties[i - 1]) {
if (dkg.isValidShare(secret, parties[i - 1].commitments, j)) {
parties[i - 1].complaints[j - 1] = Protocol.ComplaintState.NonDisqualified;
} else {
@ -515,21 +550,17 @@ public class User<T> implements Runnable{
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;
default:
logger.error("Bad message: SRC={}, DST={}, Payload={}", envelope.getSender(), envelope.getDestination(), TextFormat.printToString(msg));
break;
}
}
@ -554,5 +585,4 @@ public class User<T> implements Runnable{
public T extractCommitment(DKG.CommitmentMessage commitmentMessage){
return dkg.decodeCommitment(commitmentMessage.getCommitment().toByteArray());
}
}
}

View File

@ -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;
}
}

View File

@ -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<T> extends meerkat.crypto.dkg.feldman.User<T> {
*/
protected final Protocol<T> sdkg;
/**
* message handler
*/
private MessageHandler messageHandler;
boolean isStage4;
/**
* constructor
@ -55,13 +52,6 @@ public class User<T> extends meerkat.crypto.dkg.feldman.User<T> {
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<T> extends meerkat.crypto.dkg.feldman.User<T> {
sdkg.sendSecrets();
}
@Override
protected void waitUntilStageOneCompleted() {
super.waitUntilStageOneCompleted();
@ -98,40 +90,74 @@ public class User<T> extends meerkat.crypto.dkg.feldman.User<T> {
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<T> extends meerkat.crypto.dkg.feldman.User<T> {
}
}
// 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<BigInteger> arithmetic = new Fp(sdkg.getQ());
// restore necessary information
for (int i = 0; i < n; i++) {
@ -177,11 +196,10 @@ public class User<T> extends meerkat.crypto.dkg.feldman.User<T> {
}
/**
* 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,9 +210,6 @@ public class User<T> extends meerkat.crypto.dkg.feldman.User<T> {
super.stage4();
}
private class MessageHandler extends meerkat.crypto.dkg.feldman.User.MessageHandler {
boolean isStage4;
/**
* if !isStage4 as super, with extension to double secret message
@ -243,7 +258,7 @@ public class User<T> extends meerkat.crypto.dkg.feldman.User<T> {
@Override
public void handleMessage(DKG.BroadcastMessage envelope) throws InvalidProtocolBufferException {
public void handleMessage(Comm.BroadcastMessage envelope) throws InvalidProtocolBufferException {
int sender = envelope.getSender();
boolean isBroadcast = !envelope.getIsPrivate();
DKG.Payload msg = DKG.Payload.parseFrom(envelope.getPayload());
@ -267,6 +282,7 @@ public class User<T> extends meerkat.crypto.dkg.feldman.User<T> {
* 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();
@ -317,6 +333,7 @@ public class User<T> extends meerkat.crypto.dkg.feldman.User<T> {
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();
@ -338,5 +355,5 @@ public class User<T> extends meerkat.crypto.dkg.feldman.User<T> {
break;
}
}
}
}

View File

@ -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;

View File

@ -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.*;

View File

@ -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<BigInteger> dkg;
this.secret = BigInteger.ZERO;
ChannelImpl channel;
ChannelImpl channels = new ChannelImpl();
ByteEncoder<BigInteger> 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<BigInteger>(t, n, s, random, q, g, group, id,byteEncoder);
dkgs[id - 1] = randomDKGUser(id,channel,dkg,random);

View File

@ -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;

View File

@ -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;

View File

@ -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<BigInteger> group = new Zpstar(p);
Arithmetic<BigInteger> 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<Integer> valids;
Set<Integer> QUAL;
Set<Integer> aborted;
Set<Integer> malicious;
User<BigInteger>[] sdkgs;
Thread[] threads;
Future<?>[] futures;
BigInteger g;
BigInteger h;
BigInteger secret;
Group<BigInteger> group;
int n;
int t;
BigInteger q;
Random random;
ChannelImpl channels = new ChannelImpl();
public Testable(Random random) {
public Testable(int n, int t, Group<BigInteger> 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<Integer>();
this.QUAL = new HashSet<Integer>();
this.aborted = new HashSet<Integer>();
this.malicious = new HashSet<Integer>();
this.threads = new Thread[n];
this.futures = new Future[n];
this.g = sampleGenerator(random);
this.h = group.multiply(g,randomIntModQ(random));
ArrayList<Integer> ids = new ArrayList<Integer>();
@ -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<BigInteger>(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<BigInteger> randomSDKGUser(int id, Channel channel, Protocol<BigInteger> sdkg, Random random){
if (QUAL.size() <= t) {
enum UserType {
HONEST,
FAILSTOP,
MALICIOUS,
}
public User<BigInteger> newSDKGUser(int id, Channel channel, Protocol<BigInteger> sdkg, UserType userType) {
switch(userType) {
case HONEST:
valids.add(id);
QUAL.add(id);
return new User<BigInteger>(sdkg,channel);
}else{
int type = random.nextInt(3);
switch (type){
case 0:// regular
valids.add(id);
QUAL.add(id);
return new User<BigInteger>(sdkg,channel);
case 1:// abort
case FAILSTOP:
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
case MALICIOUS:
malicious.add(id);
Set<Integer> falls = DKGMaliciousUser.selectFallsRandomly(valids,random);
Protocol<BigInteger> maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random);
return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls);
default:
}
fail("Unknown user type");
return null;
}
public User<BigInteger> randomSDKGUser(int id, Channel channel, Protocol<BigInteger> 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);
}
}

View File

@ -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<T> extends User<T> {
public static class AbortException extends RuntimeException {
}
final int abortStage;
int stage;
public SDKGUserImplAbort(Protocol<T> sdkg, Channel channel, int abortStage) {
@ -20,6 +26,7 @@ public class SDKGUserImplAbort<T> extends User<T> {
private void abort(){
//stopReceiver();
channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ABORT));
throw new AbortException();
}
@Override
@ -61,4 +68,13 @@ public class SDKGUserImplAbort<T> extends User<T> {
}
stage++;
}
@Override
public void run() {
try {
super.run();
} catch (AbortException e) {
// Expected
}
}
}

View File

@ -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<DKG.BroadcastMessage> 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<DKG.BroadcastMessage>( 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();
}
}

View File

@ -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);
}
/**

View File

@ -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;
}

View File

@ -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<Integer,SingleChannel> 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;
}
}
}