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

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,26 +255,28 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
Set<Integer> QUAL = new HashSet<Integer>();
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<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,7 +308,9 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
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<T> extends VerifiableSecretSharing<T> {
public Polynomial.Point calcShare(Set<Integer> 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));
}

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;
}
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<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,15 +273,23 @@ public class User<T> 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<T> 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());
}
}

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,151 +210,150 @@ 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
* 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;
}
}
}

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) {
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);
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);
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<BigInteger>(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<Integer> falls = DKGMaliciousUser.selectFallsRandomly(valids,random);
Protocol<BigInteger> 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<Integer> falls = DKGMaliciousUser.selectFallsRandomly(valids,random);
Protocol<BigInteger> maliciousSDKG = SDKGMaliciousUserImpl.generateMaliciousSDKG(sdkg,channel,random);
return new SDKGMaliciousUserImpl(sdkg,maliciousSDKG,channel,falls);
}
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;
}
}
}