diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java index 30a56ed..2bdf2ad 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/Polynomial.java @@ -208,6 +208,16 @@ public class Polynomial implements Comparable { this.y = new BigInteger(pointMessage.getY().toByteArray()); } + /** + * constructor + * @param x + * @param y + */ + public Point(BigInteger x,BigInteger y) { + this.x = x; + this.y = y; + } + public DKGMessages.SecretMessage.Point asMessage(){ return DKGMessages.SecretMessage.Point.newBuilder() .setX(ByteString.copyFrom(x.toByteArray())) diff --git a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java index ebed7a2..9e3319d 100644 --- a/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java +++ b/destributed-key-generation/src/main/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/SecretSharing.java @@ -53,7 +53,7 @@ public class SecretSharing { * * @return polynomial.image(i)%q */ - protected Polynomial.Point getShare(int i){ + protected final Polynomial.Point getShare(int i){ assert (i > 0 && i <= n); return new Polynomial.Point(BigInteger.valueOf(i), polynomial, q); } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java index dcd12fa..2cbef48 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/DKG.java @@ -11,6 +11,7 @@ import java.math.BigInteger; import java.util.HashSet; import java.util.Random; import java.util.Set; +import java.util.concurrent.Callable; /** * Created by Tzlil on 2/5/2016. @@ -19,28 +20,31 @@ import java.util.Set; */ public class DKG extends VerifiableSecretSharing implements Runnable{ - private Network.User user; - private Network.MailHandler handler; - private Polynomial.Point[] shares; - private Polynomial.Point[] myshares; - private BigInteger[][] commitmentsArray; - private BigInteger[] ys; - final ComplainState[][] complainStates; - private Set QUAL; + private final int id; + private final Network.User user; // send and receive messages throw network + + private final BigInteger[] ys; // container for y values that + private final Polynomial.Point[] shares; // shares[i] equivalent to Si,id in terms of the protocol + private final BigInteger[][] commitmentsArray; // commitmentsArray[i] equivalent to Ai in terms of the protocol + private final ComplainState[][] complainStates; // complainStates[i][j] == state of Pj's complaint against Pi + + private final Set QUAL; // set of all non-disqualified parties + private final BigInteger[] commitments; // public verification values + private Polynomial.Point share; // final share of the secrete + private BigInteger y; // final public value - private BigInteger x; - private BigInteger y; - private BigInteger[] commitments; public DKG(int t, int n, BigInteger x, Random random, BigInteger p, BigInteger q, BigInteger g,Network network) { super(t, n, x, random, p, q, g); this.commitmentsArray = new BigInteger[n][t + 1]; this.shares = new Polynomial.Point[n]; - this.myshares = new Polynomial.Point[n]; - this.handler = new Handler(); - this.user = network.connect(handler); + this.user = network.connect(new Handler()); + this.id = user.getID(); this.complainStates = new ComplainState[n][n]; + this.QUAL = new HashSet(); + this.ys = new BigInteger[n]; + this.commitments = new BigInteger[t + 1]; for (int i = 0; i < n; i ++){ for (int j = 0 ; j < n ; j ++) @@ -49,44 +53,67 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ } + /** + * use for simulate real distributed protocol + */ + @Override + public void run() { + user.getReceiverThread().start(); + stage1(); + stage2(); + stage3(); + stage4(); + user.getReceiverThread().interrupt(); + } + /** + * stage1 according to the protocol + * 1. Pi broadcasts Aik for k = 0,...,t. + * 2. Pi computes the shares Sij for j = 1,...,n and sends Sij secretly to Pj. + */ private void stage1(){ - int i = user.getID(); + // for avoiding edge cases, sets commitmentsArray[id - 1] BigInteger[] commitments = super.getCommitments(); - System.arraycopy(commitments, 0, commitmentsArray[i - 1], 0, commitmentsArray[i - 1].length); + System.arraycopy(commitments, 0, commitmentsArray[id - 1], 0, commitmentsArray[id - 1].length); + // broadcasts commitments CommitmentMessage commitment; - for (int k = 1; k <= commitmentsArray[i - 1].length; k ++){ + for (int k = 0; k <= t ; k ++){ commitment = CommitmentMessage.newBuilder() .setK(k) - .setCommitment(ByteString.copyFrom(commitmentsArray[i - 1][k - 1].toByteArray())) + .setCommitment(ByteString.copyFrom(commitmentsArray[id - 1][k].toByteArray())) .build(); user.broadcast(Mail.Type.COMMITMENT,commitment); } + // computes and sends shares SecretMessage secret; for (int j = 1; j <= n ; j++ ){ - if(j != i){ - myshares[j - 1] = super.getShare(j); + if(j != id){ secret = SecretMessage.newBuilder() - .setSecret(myshares[j - 1].asMessage()) + .setSecret(getShare(j).asMessage()) .build(); user.send(j, Mail.Type.SECRET,secret); } + else{ + shares[id - 1] = super.getShare(id); + } } while (!isStage1Complete()){ try { - Thread.sleep(30); + Thread.sleep(300); } catch (InterruptedException e) { // do nothing } } } + /** + * @return true iff all shares and commitments were received + */ private boolean isStage1Complete(){ - int id = user.getID(); - for (int j = 1 ; j <= n ; j++){ - if(id != j && shares[j - 1] == null) + for (int i = 1 ; i <= n ; i++){ + if(shares[i - 1] == null) return false; } @@ -99,28 +126,36 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ return true; } + /** + * @param secret + * @param i + * @return g ^ Sij == verify(j,Ai,zpstar) (mod p) + */ private boolean isValidSecret(Polynomial.Point secret, int i){ int j = secret.x.intValue(); - return zpstar.multiply(g,secret.y).equals(verify(j,commitmentsArray[i],zpstar)); + return zpstar.multiply(g,secret.y).equals(verify(j,commitmentsArray[i - 1],zpstar)); } + /** + * stage2 according to the protocol + * Pj verifies all the shares he received (using isValidSecret) + * if check fails for an index i, Pj broadcasts a complaint against Pi. + * Pj broadcasts yj value at the end of this stage + */ private void stage2(){ - int j = user.getID(); - QUAL = new HashSet(); + ys[id - 1] = super.getY(); ComplaintMessage complaint; for (int i = 1; i <= n ; i++ ){ - if(isValidSecret(shares[i - 1],j)) { - QUAL.add(i); - }else{ + if(id != i && !isValidSecret(shares[i - 1],i)) { //message = new Message(Type.Complaint, j) complaint = ComplaintMessage.newBuilder() .setId(i) .build(); user.broadcast(Mail.Type.COMPLAINT,complaint); - complainStates[j - 1][i - 1] = ComplainState.Waiting; + complainStates[i - 1][id - 1] = ComplainState.Waiting; } } - //sending y after Complaints + //broadcast y after all complaints YMessage yMessage = YMessage.newBuilder() .setY(ByteString.copyFrom(super.getY().toByteArray())) .build(); @@ -128,87 +163,99 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ while (!isStage2Complete()){ try { - Thread.sleep(30); + Thread.sleep(300); } catch (InterruptedException e) { // do nothing } } } + /** + * @return true iff all yi received for i = 1,...,n . + */ private boolean isStage2Complete() { - int id = user.getID(); for (int j = 1; j <= n ; j++) { - if (id != j && ys[j - 1] == null) + if (j != id && ys[j - 1] == null) return false; } - for (int i = 0; i < complainStates.length;i++){ - for (int j =0 ; j < complainStates[i].length;j++){ - switch (complainStates[i][j]){ - case Waiting: - return false; - default: - break; - } - } - } return true; } + + /** + * stage3 according to the protocol + * 1. if more than t players complain against a player Pi he is disqualified. + * 2. Pi broadcasts the share Sij for each complaining player Pj. + * 3. if any of the revealed shares fails the verification test, player Pi is disqualified. + * 4. set QUAL to be the set of non-disqualified players. + */ private void stage3(){ - for (int i = 0; i < complainStates.length;i++){ - ComplainState state = ComplainState.Non; - for (int j = 0 ; j < complainStates[i].length;j++){ - switch (complainStates[i][j]){ - case Disqualified: - state = ComplainState.Disqualified; - break; - case NonDisqualified: - if(state == ComplainState.Non){ - state = ComplainState.NonDisqualified; - } - break; - default: - break; - } - } - switch (state){ - case Disqualified: - if(QUAL.contains(i + 1)){ - QUAL.remove(i + 1); - } - break; - case NonDisqualified: - if (!QUAL.contains(i + 1)){ - QUAL.add(i + 1); - } + + // broadcasts Sij for each complaint against Pid + for (int j = 1 ; j <= complainStates[id - 1].length;j++) { + switch (complainStates[id - 1][j - 1]) { + case Waiting: + user.broadcast(Mail.Type.SECRET, SecretMessage.newBuilder() + .setSecret(getShare(j).asMessage()) + .build()); + complainStates[id - 1][j - 1] = ComplainState.NonDisqualified; break; default: break; } } + + // wait until there is no complaint waiting for answer + for (int i = 0; i < complainStates.length;i++){ + for (int j = 0 ; j < complainStates[i].length;j++){ + while (complainStates[i][j].equals(ComplainState.Waiting)){ + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // do nothing + } + } + } + } + + // add each non-disqualified player to QUAL + boolean nonDisqualified; + for (int i = 1; i <= complainStates.length;i++){ + nonDisqualified = true; + for (int j = 1 ; j <= complainStates[i - 1].length;j++){ + nonDisqualified &= complainStates[i - 1][j - 1].equals(ComplainState.Disqualified); + } + if(nonDisqualified){ + QUAL.add(i); + } + } } + /** + * stage4 according to the protocol + * 1. public value y is computed as y = multiplication of yi mod p for i in QUAL + * 2. public verification values are computed as Ak = multiplication of Aik mod p for i in QUAL for k = 0,...,t + * 3. Pj sets is share of the secret as xj = sum of Sij mod q for i in QUAL + */ private void stage4(){ - BigInteger y = zpstar.zero(); + this.y = zpstar.zero(); for (int i : QUAL) { - y = zpstar.add(y , ys[i - 1]); + this.y = zpstar.add(this.y , ys[i - 1]); } - this.commitments = new BigInteger[t]; BigInteger commitment; - for (int k = 1; k <= t ; k++){ + for (int k = 0; k <= t ; k++){ commitment = zpstar.zero(); for (int i : QUAL) { - commitment = zpstar.add(commitment,commitmentsArray[i - 1][k - 1]); + commitment = zpstar.add(commitment,commitmentsArray[i - 1][k]); } - commitments[k - 1] = commitment; + commitments[k] = commitment; } - int j = user.getID(); - BigInteger x = BigInteger.ZERO; + BigInteger xj = BigInteger.ZERO; for (int i : QUAL) { - x = x.add(shares[i - 1].y); + xj = xj.add(shares[i - 1].y); } - this.x = x.mod(q); + this.share = new Polynomial.Point(BigInteger.valueOf(id) , xj.mod(q)); } @Override @@ -221,18 +268,8 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ return Arrays.clone(commitments); } - @Override - protected Polynomial.Point getShare(int i) { - return null; - } - @Override - public void run() { - stage1(); - stage2(); - stage3(); - stage4(); - } + private enum ComplainState{ Non, Waiting,Disqualified,NonDisqualified @@ -240,11 +277,7 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ private class Handler implements Network.MailHandler { - final int id; - - private Handler() { - this.id = user.getID(); - } + private Handler() {} void handelSecretMessage(Mail mail) throws InvalidProtocolBufferException { if(shares[mail.getSender() - 1] == null) { @@ -255,12 +288,12 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ }else{ int i = mail.getSender(); int j = secret.x.intValue(); - switch (complainStates[i][j]){ + switch (complainStates[i - 1][j - 1]){ case Waiting: if(isValidSecret(secret,i)){ - complainStates[i][j] = ComplainState.NonDisqualified; + complainStates[i - 1][j - 1] = ComplainState.NonDisqualified; }else{ - complainStates[i][j] = ComplainState.Disqualified; + complainStates[i - 1][j - 1] = ComplainState.Disqualified; } break; default: @@ -291,22 +324,17 @@ public class DKG extends VerifiableSecretSharing implements Runnable{ } void handelComplaintMessage(Mail mail) throws InvalidProtocolBufferException { + int id = user.getID(); if(!mail.getIsPrivate()) { //broadcast only ComplaintMessage complaintMessage = ComplaintMessage.parseFrom(mail.getMessage()); int i = complaintMessage.getId(); int j = mail.getSender(); - if(i == id){ - user.broadcast(Mail.Type.SECRET,SecretMessage.newBuilder() - .setSecret(myshares[j].asMessage()) - .build()); - }else{ - switch (complainStates[i - 1][j - 1]){ - case Non: - complainStates[i - 1][j - 1] = ComplainState.Waiting; - break; - default: - break; - } + switch (complainStates[i - 1][j - 1]){ + case Non: + complainStates[i - 1][j - 1] = ComplainState.Waiting; + break; + default: + break; } } } diff --git a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java index 3cc3c85..70ab678 100644 --- a/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java +++ b/destributed-key-generation/src/main/java/JointFeldmanProtocol/Network.java @@ -7,6 +7,9 @@ import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; /** * Created by Tzlil on 2/7/2016. + * JointFeldamn protocol assumes all parties can communicate throw broadcast chanel + * and private chanel (for each pair) + * this class simulates it */ public class Network { @@ -28,7 +31,8 @@ public class Network { Integer id = availableIDs.poll(); if (id == null) return null; - return new User(id,messageHandler); + users[id - 1] = new User(id,messageHandler); + return users[id - 1]; } private boolean sendMessage(User sender,int destination,Mail.Type type,Message message){ @@ -70,13 +74,12 @@ public class Network { private final MailHandler messageHandler; private final Queue mailbox; private final int ID; - + private final Thread receiverThread; public User(int ID, MailHandler messageHandler) { - this.mailbox = new ArrayBlockingQueue(n*n); + this.mailbox = new ArrayBlockingQueue(1 << n); this.ID = ID; this.messageHandler = messageHandler; - Thread thread = new Thread(new Receiver()); - thread.run(); + this.receiverThread = new Thread(new Receiver()); } public boolean send(int id, Mail.Type type,Message message){ @@ -88,7 +91,9 @@ public class Network { public int getID() { return ID; } - + public Thread getReceiverThread(){ + return receiverThread; + } private class Receiver implements Runnable{ @Override public void run() { diff --git a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java index 71c93fa..53a50af 100644 --- a/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java +++ b/destributed-key-generation/src/test/java/FeldmanVerifiableSecretSharing/ShamirSecretSharing/PolynomialTests/InterpolationTest.java @@ -33,7 +33,6 @@ public class InterpolationTest { public Polynomial.Point[] randomPoints(Polynomial p){ Polynomial.Point[] points = new Polynomial.Point[p.getDegree() + 1]; BigInteger x; - Boolean b; Set set = new HashSet(); for (int i = 0; i < points.length; i++){ x = new BigInteger(bits,random); diff --git a/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java new file mode 100644 index 0000000..98e58ed --- /dev/null +++ b/destributed-key-generation/src/test/java/JointFeldmanProtocol/DKGTest.java @@ -0,0 +1,57 @@ +package JointFeldmanProtocol; + +import org.factcenter.qilin.primitives.concrete.Zpstar; +import org.junit.Before; +import org.junit.Test; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Created by Tzlil on 2/9/2016. + */ +public class DKGTest { + + + DKG[] dkgs; + Thread[] threads; + int tests = 1 << 10; + Random random; + + @Before + public void settings(){ + BigInteger p = BigInteger.valueOf(2903); + BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + Zpstar zpstar = new Zpstar(p); + random = new Random(); + BigInteger g; + BigInteger ZERO = zpstar.zero(); + do{ + g = zpstar.sample(random); + }while (!g.equals(ZERO) && !zpstar.multiply(g,q).equals(ZERO));// sample from QRZp* + int t = 8; + int n = 20 + ; + Network network = new Network(n); + dkgs = new DKG[n]; + threads = new Thread[n]; + for (int i = 0 ; i < n ; i++) { + dkgs[i] = new DKG(t, n, new BigInteger(q.bitLength(), random).mod(q), random, p, q, g, network); + threads[i] = new Thread(dkgs[i]); + } + } + + @Test + public void DKGTest() throws Exception { + for (int i = 0 ; i < threads.length ; i++){ + threads[i].start(); + } + for (int i = 0 ; i < threads.length ; i++){ + threads[i].join(); + } + + for (int i = 0; i < dkgs.length - 1 ; i++){ + assert (dkgs[i].getY().equals(dkgs[i+1].getY())); + } + } +}