Merge branch 'master' of http://cs.idc.ac.il/rhodecode/meerkat/meerkat-java into Voter-Registry

Voter-Registry
Vladimir Eliezer Tokarev 2016-04-15 02:45:35 -07:00
commit 53fc701444
132 changed files with 10476 additions and 6638 deletions

3
.gitignore vendored
View File

@ -13,5 +13,4 @@ out
*.prefs *.prefs
*.project *.project
*.classpath *.classpath
*.db bulletin-board-server/local-instances/meerkat.db
Wombat Code And Documentation Conventions

View File

@ -0,0 +1,59 @@
package meerkat.bulletinboard.workers.singleserver;
import meerkat.bulletinboard.SingleServerWorker;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI.SyncQuery;
import meerkat.protobuf.BulletinBoardAPI.SyncQueryResponse;
import meerkat.rest.Constants;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import static meerkat.bulletinboard.BulletinBoardConstants.BULLETIN_BOARD_SERVER_PATH;
import static meerkat.bulletinboard.BulletinBoardConstants.SYNC_QUERY_PATH;
/**
* Created by Arbel Deutsch Peled on 27-Dec-15.
* Tries to contact server once and perform a post operation
*/
public class SingleServerQuerySyncWorker extends SingleServerWorker<SyncQuery, SyncQueryResponse> {
public SingleServerQuerySyncWorker(String serverAddress, SyncQuery payload, int maxRetry) {
super(serverAddress, payload, maxRetry);
}
@Override
public SyncQueryResponse call() throws Exception {
Client client = clientLocal.get();
WebTarget webTarget;
Response response;
// Send request to Server
webTarget = client.target(serverAddress).path(BULLETIN_BOARD_SERVER_PATH).path(SYNC_QUERY_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(payload, Constants.MEDIATYPE_PROTOBUF));
// Retrieve answer
try {
// If a BulletinBoardMessageList is returned: the read was successful
return response.readEntity(SyncQueryResponse.class);
} catch (ProcessingException | IllegalStateException e) {
// Read failed
throw new CommunicationException("Server access failed");
}
finally {
response.close();
}
}
}

View File

@ -51,6 +51,7 @@ dependencies {
compile 'org.xerial:sqlite-jdbc:3.8.+' compile 'org.xerial:sqlite-jdbc:3.8.+'
compile 'mysql:mysql-connector-java:5.1.+' compile 'mysql:mysql-connector-java:5.1.+'
compile 'com.h2database:h2:1.0.+' compile 'com.h2database:h2:1.0.+'
compile 'org.apache.commons:commons-dbcp2:2.0.+'
// Servlets // Servlets
compile 'javax.servlet:javax.servlet-api:3.0.+' compile 'javax.servlet:javax.servlet-api:3.0.+'

View File

@ -1,6 +1,7 @@
package meerkat.bulletinboard.sqlserver; package meerkat.bulletinboard.sqlserver;
import meerkat.protobuf.BulletinBoardAPI.FilterType; import meerkat.protobuf.BulletinBoardAPI.FilterType;
import org.apache.commons.dbcp2.BasicDataSource;
import org.h2.jdbcx.JdbcDataSource; import org.h2.jdbcx.JdbcDataSource;
import javax.naming.Context; import javax.naming.Context;
import javax.naming.InitialContext; import javax.naming.InitialContext;
@ -61,7 +62,7 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider
return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum"; return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum";
case INSERT_MSG: case INSERT_MSG:
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId,:Msg)"; return "INSERT INTO MsgTable (MsgId, Msg, ExactTime) VALUES(:MsgId,:Msg,:TimeStamp)";
case INSERT_NEW_TAG: case INSERT_NEW_TAG:
return "INSERT INTO TagTable(Tag) SELECT DISTINCT :Tag AS NewTag FROM UtilityTable WHERE" return "INSERT INTO TagTable(Tag) SELECT DISTINCT :Tag AS NewTag FROM UtilityTable WHERE"
@ -200,10 +201,13 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider
@Override @Override
public DataSource getDataSource() { public DataSource getDataSource() {
JdbcDataSource dataSource = new JdbcDataSource(); BasicDataSource dataSource = new BasicDataSource();
dataSource.setURL("jdbc:h2:~/" + dbName);
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:~/" + dbName);
return dataSource; return dataSource;
} }

View File

@ -4,6 +4,7 @@ import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import meerkat.bulletinboard.BulletinBoardConstants; import meerkat.bulletinboard.BulletinBoardConstants;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider; import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.protobuf.BulletinBoardAPI.FilterType; import meerkat.protobuf.BulletinBoardAPI.FilterType;
import org.apache.commons.dbcp2.BasicDataSource;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.text.MessageFormat; import java.text.MessageFormat;
@ -216,16 +217,17 @@ public class MySQLQueryProvider implements SQLQueryProvider {
@Override @Override
public DataSource getDataSource() { public DataSource getDataSource() {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setServerName(dbAddress); BasicDataSource dataSource = new BasicDataSource();
dataSource.setPort(dbPort);
dataSource.setDatabaseName(dbName); dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUser(username); dataSource.setUrl("jdbc:mysql://" + dbAddress + ":" + dbPort + "/" + dbName);
dataSource.setUsername(username);
dataSource.setPassword(password); dataSource.setPassword(password);
dataSource.setAllowMultiQueries(true);
return dataSource; return dataSource;
} }
@Override @Override

View File

@ -140,6 +140,16 @@ public class H2BulletinBoardServerTest {
} }
@Test
public void testSyncQuery() {
try {
serverTest.testSyncQuery();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@After @After
public void close() { public void close() {
System.err.println("Starting to close H2BulletinBoardServerTest"); System.err.println("Starting to close H2BulletinBoardServerTest");

View File

@ -0,0 +1,223 @@
plugins {
id "us.kirchmeier.capsule" version "1.0.1"
id 'com.google.protobuf' version '0.7.0'
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'maven-publish'
// Uncomment the lines below to define an application
// (this will also allow you to build a "fatCapsule" which includes
// the entire application, including all dependencies in a single jar)
//apply plugin: 'application'
//mainClassName='your.main.ApplicationClass'
// Is this a snapshot version?
ext { isSnapshot = false }
ext {
groupId = 'org.factcenter.meerkat'
nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/"
// Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing)
// Should be set in ${HOME}/.gradle/gradle.properties
nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : ""
nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : ""
}
description = "TODO: Add a description"
// Your project version
version = "0.0"
version += "${isSnapshot ? '-SNAPSHOT' : ''}"
dependencies {
// Meerkat common
compile project(':meerkat-common')
// Logging
compile 'org.slf4j:slf4j-api:1.7.7'
runtime 'ch.qos.logback:logback-classic:1.1.2'
runtime 'ch.qos.logback:logback-core:1.1.2'
// 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.+'
}
/*==== You probably don't have to edit below this line =======*/
// Setup test configuration that can appear as a dependency in
// other subprojects
configurations {
testOutput.extendsFrom (testCompile)
}
task testJar(type: Jar, dependsOn: testClasses) {
classifier = 'tests'
from sourceSets.test.output
}
artifacts {
testOutput testJar
}
// The run task added by the application plugin
// is also of type JavaExec.
tasks.withType(JavaExec) {
// Assign all Java system properties from
// the command line to the JavaExec task.
systemProperties System.properties
}
protobuf {
// Configure the protoc executable
protoc {
// Download from repositories
artifact = 'com.google.protobuf:protoc:3.+'
}
}
idea {
module {
project.sourceSets.each { sourceSet ->
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
println "Adding $srcDir"
// add protobuf generated sources to generated source dir.
if ("test".equals(sourceSet.name)) {
testSourceDirs += file(srcDir)
} else {
sourceDirs += file(srcDir)
}
generatedSourceDirs += file(srcDir)
}
// Don't exclude build directory
excludeDirs -= file(buildDir)
}
}
/*===================================
* "Fat" Build targets
*===================================*/
if (project.hasProperty('mainClassName') && (mainClassName != null)) {
task mavenCapsule(type: MavenCapsule) {
description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
applicationClass mainClassName
destinationDir = buildDir
}
task fatCapsule(type: FatCapsule) {
description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class"
destinationDir = buildDir
def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
applicationClass fatMain
def testJar = hasProperty('test')
if (hasProperty('fatmain')) {
appendix = "fat-${fatMain}"
} else {
appendix = "fat"
}
if (testJar) {
from sourceSets.test.output
}
}
}
/*===================================
* Repositories
*===================================*/
repositories {
// Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral)
maven {
url nexusRepository
if (isSnapshot) {
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
// Use local maven repository
mavenLocal()
// Use 'maven central' for other dependencies.
mavenCentral()
}
task "info" << {
println "Project: ${project.name}"
println "Description: ${project.description}"
println "--------------------------"
println "GroupId: $groupId"
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
println ""
}
info.description 'Print some information about project parameters'
/*===================================
* Publishing
*===================================*/
publishing {
publications {
mavenJava(MavenPublication) {
groupId project.groupId
pom.withXml {
asNode().appendNode('description', project.description)
}
from project.components.java
}
}
repositories {
maven {
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
credentials { username
password
username nexusUser
password nexusPassword
}
}
}
}

View File

@ -0,0 +1,47 @@
package meerkat.crypto.dkg.comm;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.comm.Channel;
import meerkat.protobuf.Comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by Tzlil on 2/14/2016.
*
* an implementation of ReceiverCallback
*/
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
*/
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

@ -0,0 +1,36 @@
package meerkat.crypto.dkg.comm;
import meerkat.protobuf.DKG;
/**
* Created by talm on 12/04/16.
*/
public class MessageUtils {
public static DKG.Payload createMessage(DKG.Payload.Type type) {
return DKG.Payload.newBuilder().setType(type).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.ShareMessage share) {
return DKG.Payload.newBuilder().setType(type).setShare(share).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.ShareMessage.Builder share) {
return DKG.Payload.newBuilder().setType(type).setShare(share).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.IDMessage id) {
return DKG.Payload.newBuilder().setType(type).setId(id).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.IDMessage.Builder id) {
return DKG.Payload.newBuilder().setType(type).setId(id).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.CommitmentMessage commitment) {
return DKG.Payload.newBuilder().setType(type).setCommitment(commitment).build();
}
public static DKG.Payload createMessage(DKG.Payload.Type type, DKG.CommitmentMessage.Builder commitment) {
return DKG.Payload.newBuilder().setType(type).setCommitment(commitment).build();
}
}

View File

@ -0,0 +1,40 @@
package meerkat.crypto.dkg.feldman;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Created by Tzlil on 3/14/2016.
*
* contains all relevant information on specific party during
* the run of Joint Feldamn protocol
*/
public class Party<T> {
public final int id;
public Polynomial.Point share;
public ArrayList<T> commitments;
public boolean doneFlag;
public Protocol.ComplaintState[] complaints;
public boolean aborted;
/**
*
* @param id party identifier - 1 <= id <= n
* @param n number of parties in current run protocol
* @param t protocol's threshold
*/
public Party(int id, int n, int t) {
this.id = id;
this.share = null;
this.doneFlag = false;
this.complaints = new Protocol.ComplaintState[n];
Arrays.fill(this.complaints, Protocol.ComplaintState.OK);
this.commitments = new ArrayList<T>(t + 1);
for (int i = 0; i <= t ; i++){
commitments.add(null);
}
this.aborted = false;
}
}

View File

@ -0,0 +1,368 @@
package meerkat.crypto.dkg.feldman;
import meerkat.comm.Channel;
import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import com.google.protobuf.ByteString;
import meerkat.protobuf.DKG;
import org.factcenter.qilin.primitives.Group;
import org.factcenter.qilin.util.ByteEncoder;
import java.math.BigInteger;
import java.util.*;
import static meerkat.crypto.dkg.comm.MessageUtils.*;
/**
* Created by Tzlil on 3/14/2016.
*
* an implementation of JointFeldman distributed key generation protocol.
*
* allows set of n parties to generate random key with threshold t.
*/
public class Protocol<T> extends VerifiableSecretSharing<T> {
public enum ComplaintState {
/**
* No complaints, no response required at this point.
*/
OK,
/**
* Party received complaint, waiting for response from party
*/
Waiting,
/**
* Party gave invalid answer to conplaint.
*/
Disqualified,
/**
* Party received complaint, gave valid answer.
*/
NonDisqualified
}
/**
* My share id.
*/
protected final int id;
/**
* All parties participating in key generation.
* parties[id-1] has my info.
*/
private Party<T>[] parties;
/**
* communication object
*/
protected Channel channel;
/**
* Encode/Decode group elements
*/
protected final ByteEncoder<T> encoder;
/**
* constructor
* @param q a large prime.
* @param t threshold. Any t+1 share holders can recover the secret,
* but any set of at most t share holders cannot
* @param n number of share holders
* @param zi secret, chosen from Zq
* @param random use for generate random polynomial
* @param group
* @param q a large prime dividing group order.
* @param g a generator of cyclic group of order q.
* the generated group is a subgroup of the given group.
* it must be chosen such that computing discrete logarithms is hard in this group.
* @param encoder Encode/Decode group elements (of type T) to/from byte array
*/
public Protocol(int t, int n, BigInteger zi, Random random, BigInteger q, T g
, Group<T> group, int id, ByteEncoder<T> encoder) {
super(t, n, zi, random, q, g,group);
this.id = id;
this.parties = new Party[n];
for (int i = 1; i <= n ; i++){
this.parties[i - 1] = new Party(i,n,t);
}
this.parties[id - 1].share = getShare(id);
this.encoder = encoder;
}
/**
* setter
* @param channel
*/
public void setChannel(Channel channel){
this.channel = channel;
}
/**
* setter
* @param parties
*/
protected void setParties(Party[] parties){
this.parties = parties;
}
/**
* getter
* @return
*/
protected Party[] getParties(){
return parties;
}
/**
* stage1.1 according to the protocol
* Pi broadcasts Aik for k = 0,...,t.
*/
public void broadcastCommitments(){
broadcastCommitments(commitmentsArrayList);
}
/**
* pack commitments as messages and broadcast them
* @param commitments
*/
public void broadcastCommitments(ArrayList<T> commitments){
DKG.CommitmentMessage commitmentMessage;
for (int k = 0; k <= t ; k++){
commitmentMessage = DKG.CommitmentMessage.newBuilder()
.setCommitment(ByteString.copyFrom(encoder.encode(commitments.get(k))))
.setK(k)
.build();
channel.broadcastMessage(createMessage(DKG.Payload.Type.COMMITMENT, commitmentMessage));
}
}
/**
* Send channel j her secret share (of my polynomial)
* @param j
*/
public void sendSecret(int j){
ByteString secret = ByteString.copyFrom(getShare(j).y.toByteArray());
channel.sendMessage(j, createMessage(DKG.Payload.Type.SHARE,
DKG.ShareMessage.newBuilder()
.setI(id)
.setJ(j)
.setShare(secret)
));
}
/**
* stage1.2 according to the protocol
* Pi computes the shares Sij for j = 1,...,n and sends Sij secretly to Pj.
*/
public void sendSecrets(){
for (int j = 1; j <= n ; j++){
if(j != id){
sendSecret(j);
}
}
}
/**
*
* @param i
* @return computeVerificationValue(j,parties[i - 1].commitments,group) == g ^ parties[i - 1].share mod q
*/
public boolean isValidShare(int i){
Party<T> party = parties[i - 1];
synchronized (parties[i - 1]) {
return isValidShare(party.share, party.commitments, id);
}
}
/**
* @param share
* @param commitments
* @param j
* @return computeVerificationValue(j,commitments,group) == g ^ secret.y mod q
*/
public boolean isValidShare(Polynomial.Point share, ArrayList<T> commitments, int j){
try{
T v = computeVerificationValue(j,commitments,group);
return group.multiply(g,share.y).equals(v);
}
catch (NullPointerException e){
return false;
}
}
/**
* stage2 according to the protocol
* Pj verifies all the shares he received (using isValidShare)
* if check fails for an index i, Pj broadcasts a complaint against Pi.
*/
public void broadcastComplaints(){
for (int i = 1; i <= n ; i++ ){
if(i != id && !isValidShare(i)) {
broadcastComplaint(i);
}
}
}
/**
* create a complaint message against i and broadcast it
* @param i
*/
private void broadcastComplaint(int i){
//message = new Message(Type.Complaint, j)
DKG.IDMessage complaint = DKG.IDMessage.newBuilder()
.setId(i)
.build();
channel.broadcastMessage(createMessage(DKG.Payload.Type.COMPLAINT, complaint));
}
/**
* create an answer message for j and broadcast it
* @param j
*/
public void broadcastComplaintAnswer(int j){
channel.broadcastMessage(createMessage(DKG.Payload.Type.ANSWER, DKG.ShareMessage.newBuilder()
.setI(id)
.setJ(j)
.setShare(ByteString.copyFrom(getShare(j).y.toByteArray()))));
}
/**
* stage3.1 according to the protocol
* if more than t players complain against a player Pi he is disqualified.
*/
public void answerAllComplainingPlayers(){
ComplaintState[] complaints = parties[id - 1].complaints;
for (int i = 1; i <= n; i++) {
switch (complaints[i - 1]) {
case Waiting:
broadcastComplaintAnswer(i);
break;
default:
break;
}
}
}
/**
* stage3.2 according to the protocol
* if any of the revealed shares fails the verification test, player Pi is disqualified.
* set QUAL to be the set of non-disqualified players.
*/
public Set<Integer> calcQUAL(){
Set<Integer> QUAL = new HashSet<Integer>();
boolean nonDisqualified;
int counter;
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 && counter <= t) {
QUAL.add(i);
}
}
}
return QUAL;
}
/**
* compute Y, the commitment to the final public key (includes only qualifying set)
* stage4.1 according to the protocol
* public value y is computed as y = multiplication of yi mod p for i in QUAL
*/
public T calcY(Set<Integer> QUAL){
T y = group.zero();
for (int i : QUAL) {
synchronized (parties[i - 1]) {
y = group.add(y, parties[i - 1].commitments.get(0));
}
}
return y;
}
/**
* stage4.2 according to the protocol
* public verification values are computed as Ak = multiplication
* of Aik mod p for i in QUAL for k = 0,...,t
*/
public ArrayList<T> calcCommitments(Set<Integer> QUAL){
ArrayList<T> commitments = new ArrayList<T>(t+1);
T value;
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;
}
/**
* stage4.3 according to the protocol
* Pj sets is share of the share as xj = sum of Sij mod q for i in QUAL
*/
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));
}
/**
* decode commitment from arr
* @param arr
* @return
*/
public T decodeCommitment(byte[] arr){
return encoder.decode(arr);
}
/**
* getter
* @return id
*/
public int getId() {
return id;
}
/**
* getter
* @return channel
*/
public Channel getChannel() {
return channel;
}
/**
* getter
* @return encoder
*/
public ByteEncoder<T> getEncoder() {
return encoder;
}
}

View File

@ -0,0 +1,588 @@
package meerkat.crypto.dkg.feldman;
import com.google.protobuf.InvalidProtocolBufferException;
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 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;
/**
* Created by Tzlil on 3/14/2016.
*
* implementation of joint feldman protocol user.
*
* according to the protocol, each user run feldman verifiable secret sharing
* as a dealer.
*
* 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 {
final Logger logger = LoggerFactory.getLogger(getClass());
/**
* joint feldman protocol object
*/
protected final Protocol<T> dkg;
/**
* a generator of cyclic group of order q.
* the generated group is a subgroup of the given group.
* it must be chosen such that computing discrete logarithms is hard in this group.
*/
protected final T g;
/**
* cyclic group contains g.
*/
protected final Group<T> group;
/**
* user id
*/
protected final int id;
/**
* threshold
*/
protected final int t;
/**
* number of shares
*/
protected final int n;
/**
* channel object
*/
protected final Channel channel; //
/**
* All parties participating in key generation.
* parties[id-1] has my info.
*/
protected final Party[] parties;
/**
* set of all non-disqualified parties
*/
protected Set<Integer> QUAL;
/**
* my own share of the generated random key.
*/
protected Polynomial.Point share;
/**
* public verification values
*/
protected ArrayList<T> commitments;
/**
* public value,
* y = g ^ key
*/
protected T y;
protected BlockingQueue<Comm.BroadcastMessage> receiveQueue;
/**
* constructor
* @param dkg joint feldman protocol object
* @param channel channel object
*/
public User(Protocol<T> dkg, Channel channel) {
this.dkg = dkg;
this.g = dkg.getGenerator();
this.group = dkg.getGroup();
this.n = dkg.getN();
this.t = dkg.getT();
this.id = dkg.getId();
this.channel = channel;
dkg.setChannel(channel);
registerReceiverCallback();
this.parties = dkg.getParties();
this.QUAL = null;
this.commitments = null;
this.share = null;
this.y = null;
this.receiveQueue = new LinkedBlockingDeque<>();
}
/**
* create MessageHandler and register it as ReceiverCallback
*/
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();
}
}
/**
* 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.
*/
protected void stage1() {
dkg.broadcastCommitments();
dkg.sendSecrets();
}
/**
* Check if all shares and commitments have arrived from other parties
*/
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;
}
}
}
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;
}
/**
* stage2 according to the protocol
* Pj verifies all the shares he received
* if check fails for an index i, Pj broadcasts a complaint against Pi.
* Pj broadcasts done message at the end of this stage
*/
protected void stage2() {
dkg.broadcastComplaints();
//broadcast done message after all complaints
channel.broadcastMessage(createMessage(DKG.Payload.Type.DONE));
}
/**
* wait until all other parties done complaining by receiving done message
*/
protected void waitUntilStageTwoCompleted(){
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.
* otherwise Pi broadcasts the share Sij for each complaining player Pj.
* 2. if any of the revealed shares fails the verification test, player Pi is disqualified.
* set QUAL to be the set of non-disqualified players.
*/
protected void stage3(){
dkg.answerAllComplainingPlayers();
// wait until there is no complaint waiting for answer
while (!stop && !haveReceivedAllStage3ComplaintAnswers())
waitAndHandleReceivedMessages();
this.QUAL = dkg.calcQUAL();
}
/**
* 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
*/
protected void stage4(){
this.y = dkg.calcY(QUAL);
this.commitments = dkg.calcCommitments(QUAL);
this.share = dkg.calcShare(QUAL);
}
@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;
stage2();
waitUntilStageTwoCompleted();
if (stop) return;
stage3();
if (stop) return;
stage4();
} finally {
runThread.setName(previousName);
}
}
/**
* current thread in the main loop
*/
protected Thread runThread;
/**
* flag indicates if there was request to stop the current run of the protocol
*/
protected boolean stop = false;
/**
* Request the current run loop to exit gracefully
*/
public void stop() {
try {
stop = true;
runThread.interrupt();
}catch (Exception e){
//do nothing
}
}
/**
* getter
* @return commitments
*/
public ArrayList<T> getCommitments() {
return commitments;
}
/**
* getter
* @return g
*/
public T getGenerator() {
return g;
}
/**
* getter
* @return group
*/
public Group<T> getGroup() {
return group;
}
/**
* getter
* @return share
*/
public Polynomial.Point getShare() {
return share;
}
/**
* getter
* @return id
*/
public int getID() {
return id;
}
/**
* getter
* @return n
*/
public int getN() {
return n;
}
/**
* getter
* @return t
*/
public int getT() {
return t;
}
/**
* getter
* @return y
*/
public T getPublicValue() {
return y;
}
/**
* getter
* @return QUAL
*/
public Set<Integer> getQUAL() {
return QUAL;
}
/**
* getter
* @return channel
*/
public Channel getChannel() {
return channel;
}
/**
* 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;
}
/**
* 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();
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);
}
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();
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;
}
if (j == id) {
parties[i - 1].share = secret;
}
}
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;
}
}
/**
* 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

@ -0,0 +1,28 @@
package meerkat.crypto.dkg.gjkr;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/**
* Created by Tzlil on 3/16/2016.
*
* an extension of DistributedKeyGenerationParty
* contains all relevant information on specific party during
* the run of the safe protocol
*/
public class Party<T> extends meerkat.crypto.dkg.feldman.Party<T> {
public Polynomial.Point shareT;
public boolean ysDoneFlag;
public ArrayList<T> verifiableValues;
public Set<Polynomial.Point> recoverSharesSet;
public Party(int id, int n, int t) {
super(id, n, t);
this.shareT = null;
this.ysDoneFlag = false;
this.verifiableValues = new ArrayList<T>(this.commitments);
this.recoverSharesSet = new HashSet<Polynomial.Point>();
}
}

View File

@ -0,0 +1,165 @@
package meerkat.crypto.dkg.gjkr;
import meerkat.crypto.dkg.comm.MessageUtils;
import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import com.google.protobuf.ByteString;
import meerkat.protobuf.DKG;
import org.factcenter.qilin.primitives.Group;
import org.factcenter.qilin.util.ByteEncoder;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Random;
import java.util.Set;
/**
* Created by Tzlil on 3/16/2016.
* TODO: comments
* TODO: put Channel (ChannelImpl) in constructor
*/
public class Protocol<T> extends meerkat.crypto.dkg.feldman.Protocol<T> {
private VerifiableSecretSharing<T> maskingShares;
private final T h;
private Party<T>[] parties;
public Protocol(int t, int n, BigInteger zi, Random random, BigInteger q, T g
, T h, Group<T> group, int id, ByteEncoder<T> byteEncoder) {
super(t, n, zi, random, q, g, group, id,byteEncoder);
this.h = h;
BigInteger r = new BigInteger(q.bitLength(),random).mod(q);
this.maskingShares = new VerifiableSecretSharing(t,n,r,random,q,h,group);
this.parties = new Party[n];
for (int i = 1; i <= n ; i++){
this.parties[i - 1] = new Party(i,n,t);
}
this.parties[id - 1].share = getShare(id);
this.parties[id - 1].shareT = maskingShares.getShare(id);
super.setParties(parties);
}
protected Party[] getParties(){
return parties;
}
protected void setParties(Party[] parties) {
super.setParties(parties);
this.parties = parties;
}
@Override
public void sendSecret(int j) {
Polynomial.Point secret = getShare(j);
Polynomial.Point secretT = maskingShares.getShare(j);
DKG.ShareMessage doubleSecretMessage = createShareMessage(id,j,secret,secretT);
// TODO: Change SHARE to SHARE
channel.sendMessage(j, MessageUtils.createMessage(DKG.Payload.Type.SHARE, doubleSecretMessage));
}
@Override
public boolean isValidShare(int i){
Party party = parties[i - 1];
return isValidShare(party.share, party.shareT, party.verifiableValues, id);
}
/**
* test if share, shareT are valid with respect to verificationValues
* @param share
* @param shareT
* @param verificationValues
* @param j
* @return computeVerificationValue(j,verificationValues,group) == (g ^ share.y) * (h ^ shareT.y) mod q
*/
public boolean isValidShare(Polynomial.Point share, Polynomial.Point shareT, ArrayList<T> verificationValues, int j){
try {
T v = computeVerificationValue(j, verificationValues, group);
T exp = group.add(group.multiply(g, share.y), group.multiply(h, shareT.y));
return exp.equals(v);
}
catch (NullPointerException e){
return false;
}
}
/**
* create complaint message against i and broadcast it
* @param share
* @param shareT
* @param i
*/
private void broadcastComplaint(Polynomial.Point share, Polynomial.Point shareT, int i){
DKG.ShareMessage complaint = createShareMessage(i,id,share,shareT);
channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.COMPLAINT, complaint));
}
/**
* stage4.3 according to the protocol
* if check fails for index i, Pj
*/
public void computeAndBroadcastComplaints(Set<Integer> QUAL){
Party party;
for (int i : QUAL) {
party = parties[i - 1];
if (i != id) {
if (!super.isValidShare(party.share, party.commitments, id)) {
broadcastComplaint(party.share, party.shareT, i);
}
}
}
}
/**
* compute verification values and broadcast them
* verificationValues[k] = g ^ commitments [k] * h ^ maskingShares.commitments [k]
*/
public void computeAndBroadcastVerificationValues(){
ArrayList<T> verificationValues = new ArrayList<T>(t+1);
ArrayList<T> hBaseCommitments = maskingShares.getCommitmentsArrayList();
for (int k = 0 ; k <= t ; k++){
verificationValues.add(k,group.add(commitmentsArrayList.get(k),hBaseCommitments.get(k)));
}
broadcastCommitments(verificationValues);
}
/**
* pack share, shareT i,j to createShareMessage
* @param i
* @param j
* @param share
* @param shareT
* @return
*/
private DKG.ShareMessage createShareMessage(int i, int j, Polynomial.Point share, Polynomial.Point shareT){
DKG.ShareMessage ShareMessage = DKG.ShareMessage.newBuilder()
.setI(i)
.setJ(j)
.setShare(ByteString.copyFrom(share.y.toByteArray()))
.setShareT(ByteString.copyFrom(shareT.y.toByteArray()))
.build();
return ShareMessage;
}
@Override
public void broadcastComplaintAnswer(int j) {
DKG.ShareMessage answer = createShareMessage(id,j,getShare(j)
, maskingShares.getShare(j));
channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ANSWER, answer));
}
public void broadcastAnswer(Polynomial.Point secret, Polynomial.Point secretT, int i){
DKG.ShareMessage complaint = createShareMessage(i,id,secret,secretT);
channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ANSWER,complaint));
}
/**
* getter
* @return h
*/
public T getH() {
return h;
}
}

View File

@ -0,0 +1,359 @@
package meerkat.crypto.dkg.gjkr;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.comm.Channel;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.secretsharing.shamir.SecretSharing;
import meerkat.protobuf.Comm;
import meerkat.protobuf.DKG;
import java.math.BigInteger;
import java.util.ArrayList;
import static meerkat.crypto.dkg.comm.MessageUtils.*;
/**
* Created by Tzlil on 3/16/2016.
* <p/>
* implementation of gjkr protocol user.
* <p/>
* this protocol extends joint Feldman protocol by splitting the protocol to commitment stage (stages 1,2,3)
* and revealing stage (stage 4).
* <p/>
* as in joint Feldman, 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> extends meerkat.crypto.dkg.feldman.User<T> {
/**
* All parties participating in key generation.
* parties[id-1] has my info.
*/
protected Party<T>[] parties;
/**
* gjkr secure protocol object
*/
protected final Protocol<T> sdkg;
boolean isStage4;
/**
* constructor
*
* @param sdkg gjkr protocol object
* @param channel channel object
*/
public User(Protocol<T> sdkg, Channel channel) {
super(sdkg, channel);
this.sdkg = sdkg;
this.parties = sdkg.getParties();
}
/**
* stage1 according to the protocol
* 1. Pi broadcasts Cik=Aik*Bik for k = 0,...,t.
* 2. Pi computes the shares Sij,Sij' for j = 1,...,n and sends Sij,Sij' secretly to Pj.
*/
@Override
protected void stage1() {
sdkg.computeAndBroadcastVerificationValues();
sdkg.sendSecrets();
}
@Override
protected void waitUntilStageOneCompleted() {
super.waitUntilStageOneCompleted();
// save the received commitments as verification values
ArrayList<T> temp;
for (int i = 0; i < n; i++) {
temp = parties[i].verifiableValues;
parties[i].verifiableValues = parties[i].commitments;
parties[i].commitments = temp;
}
}
/**
* stage2 according to the protocol
* Pj verifies all the shares,sharesT he received
* if check fails for an index i, Pj broadcasts a complaint against Pi.
* Pj broadcasts done message at the end of this stage
*/
@Override
protected void stage2() {
sdkg.broadcastComplaints();
//broadcast done message after all complaints
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
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
while (!stop && !areAllQualPartiesDone())
waitAndHandleReceivedMessages();
if (stop)
return;
// broadcast i private secret foreach i in QUAL that aborted
for (int i : QUAL) {
if (parties[i - 1].aborted) {
sdkg.broadcastAnswer(parties[i - 1].share, parties[i - 1].shareT, i);
}
}
// wait until at least t + 1 secrets will received foreach i in QUAL that aborted
while (!stop && !haveReceivedEnoughSecretShares())
waitAndHandleReceivedMessages();
if (stop)
return;
Arithmetic<BigInteger> arithmetic = new Fp(sdkg.getQ());
// restore necessary information
for (int i = 0; i < n; i++) {
if (parties[i].recoverSharesSet.isEmpty()) {
continue;
}
Polynomial.Point[] shares = new Polynomial.Point[t + 1];
int j = 0;
for (Polynomial.Point share : parties[i].recoverSharesSet) {
shares[j++] = share;
if (j >= shares.length) {
break;
}
}
Polynomial polynomial = SecretSharing.recoverPolynomial(shares, arithmetic);
BigInteger[] coefficients = polynomial.getCoefficients();
for (int k = 0; k <= t; k++) {
parties[i].commitments.add(k, group.multiply(g, coefficients[k]));
}
parties[i].share = new Polynomial.Point(BigInteger.valueOf(id), polynomial);
}
}
/**
* notifies message handler and message handler that stage 4 was started
*/
protected void setStage4() {
isStage4 = true;
}
@Override
protected void stage4() {
setStage4();
resolveQualifyingPublicKey();
if (stop) return;
super.stage4();
}
/**
* 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

@ -0,0 +1,117 @@
package meerkat.crypto.secretsharing.feldman;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.secretsharing.shamir.SecretSharing;
import org.factcenter.qilin.primitives.Group;
import java.util.ArrayList;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*
* an implementation of Feldman's verifiable secret sharing scheme.
*
* allows trusted dealer to share a key x among n parties.
*
*/
public class VerifiableSecretSharing<T> extends SecretSharing {
/**
* cyclic group contains g.
*/
protected final Group<T> group;
/**
* a generator of cyclic group of order q.
* the generated group is a subgroup of the given group.
* it must be chosen such that computing discrete logarithms is hard in this group.
*/
protected final T g;
/**
* commitments to polynomial coefficients.
* commitments[k] = g ^ coefficients[k] (group operation)
*/
protected final ArrayList<T> commitmentsArrayList;
/**
* constructor
* @param q a large prime.
* @param t threshold. Any t+1 share holders can recover the secret,
* but any set of at most t share holders cannot
* @param n number of share holders
* @param zi secret, chosen from Zq
* @param random use for generate random polynomial
* @param group
* @param q a large prime dividing group order.
* @param g a generator of cyclic group of order q.
* the generated group is a subgroup of the given group.
* it must be chosen such that computing discrete logarithms is hard in this group.
*/
public VerifiableSecretSharing(int t, int n, BigInteger zi, Random random, BigInteger q, T g
, Group<T> group) {
super(t, n, zi, random,q);
this.g = g;
this.group = group;
assert (this.group.contains(g));
this.commitmentsArrayList = generateCommitments();
}
/**
* commitments[i] = g ^ polynomial.coefficients[i]
* @return commitments
*/
private ArrayList<T> generateCommitments() {
Polynomial polynomial = getPolynomial();
BigInteger[] coefficients = polynomial.getCoefficients();
ArrayList<T> commitments = new ArrayList<T>(t + 1);
for (int i = 0 ; i <= t;i++){
commitments.add(i,group.multiply(g,coefficients[i]));
}
return commitments;
}
/**
* Compute verification value (g^{share value}) using coefficient commitments sent by dealer and my share id.
* @param j my share holder id
* @param commitments commitments to polynomial coefficients of share (received from dealer)
* @param group
*
* @return product of Aik ^ (j ^ k) == g ^ polynomial(i)
*/
public static <T> T computeVerificationValue(int j, ArrayList<T> commitments, Group<T> group) {
T v = group.zero();
BigInteger power = BigInteger.ONE;
BigInteger J = BigInteger.valueOf(j);
for (int k = 0 ; k < commitments.size() ; k ++){
v = group.add(v,group.multiply(commitments.get(k),power));
power = power.multiply(J);
}
return v;
}
/**
* getter
* @return generator of group
*/
public T getGenerator() {
return g;
}
/**
* getter
* @return group
*/
public Group<T> getGroup(){
return group;
}
/**
* getter
* @return commitmentsArrayList
*/
public ArrayList<T> getCommitmentsArrayList() {
return commitmentsArrayList;
}
}

View File

@ -0,0 +1,66 @@
package meerkat.crypto.secretsharing.shamir;
import meerkat.crypto.utils.Arithmetic;
import java.math.BigInteger;
/**
* Created by Tzlil on 1/28/2016.
*
* container of lagrange polynomial
*
* Constructor is private (use {@link #lagrangePolynomials(Polynomial.Point[], Arithmetic)} to construct)
*
* l = (evaluate/divisor)* polynomial
*
* Note : image and divisor stored separately for avoiding lose of information by division
*/
class LagrangePolynomial{
public final Polynomial polynomial;
public final BigInteger image;
public final BigInteger divisor;
/**
* inner constructor, stores all given parameters
* @param polynomial
* @param image
* @param divisor
*/
private LagrangePolynomial(Polynomial polynomial, BigInteger image, BigInteger divisor) {
this.polynomial = polynomial;
this.image = image;
this.divisor = divisor;
}
/**
* static method
* @param points array points s.t there are no couple of points that shares the same x value
*
* @return the lagrange polynomials that mach to given points.
* in case there exists i != j s.t points[i].x == points[j].x returns null.
*/
public static LagrangePolynomial[] lagrangePolynomials(Polynomial.Point[] points,Arithmetic<BigInteger> arithmetic) {
Polynomial one = new Polynomial(new BigInteger[]{BigInteger.ONE},arithmetic);
LagrangePolynomial[] lagrangePolynomials = new LagrangePolynomial[points.length];
Polynomial[] factors = new Polynomial[points.length];
for (int i = 0 ; i < factors.length ; i++){
factors[i] = new Polynomial(new BigInteger[]{points[i].x.negate(),BigInteger.ONE},arithmetic); // X - Xi
}
Polynomial product;
BigInteger divisor;
for(int i = 0; i < points.length; i ++) {
product = one;
divisor = BigInteger.ONE;
for (int j = 0; j < points.length; j++) {
if (i != j) {
divisor = arithmetic.mul(divisor,arithmetic.sub(points[i].x,points[j].x));
product = product.mul(factors[j]);
}
}
if(divisor.equals(BigInteger.ZERO))
return null;
lagrangePolynomials[i] = new LagrangePolynomial(product,points[i].y,divisor);
}
return lagrangePolynomials;
}
}

View File

@ -0,0 +1,208 @@
package meerkat.crypto.secretsharing.shamir;
import meerkat.crypto.utils.Arithmetic;
import java.math.BigInteger;
import java.util.Arrays;
/**
* Created by Tzlil on 1/27/2016.
*/
public class Polynomial implements Comparable<Polynomial> {
private final int degree;
private final BigInteger[] coefficients;
private final Arithmetic<BigInteger> arithmetic;
/**
* constructor
* @param coefficients
* @param arithmetic
* degree set as max index such that coefficients[degree] not equals zero
*/
public Polynomial(BigInteger[] coefficients,Arithmetic<BigInteger> arithmetic) {
int d = coefficients.length - 1;
while (d > 0 && coefficients[d].equals(BigInteger.ZERO)){
d--;
}
this.degree = d;
this.coefficients = coefficients;
this.arithmetic = arithmetic;
}
/**
* Compare to another polynomial (order by degree, then coefficients).
*/
@Override
public int compareTo(Polynomial other) {
if (this.degree != other.degree)
return this.degree - other.degree;
int compare;
for (int i = degree; i >= degree ; i--){
compare = this.coefficients[i].compareTo(other.coefficients[i]);
if (compare != 0){
return compare;
}
}
return 0;
}
/**
* @param x
* @return sum of coefficients[i] * (x ^ i)
*/
public BigInteger evaluate(BigInteger x){
BigInteger result = BigInteger.ZERO;
BigInteger power = BigInteger.ONE;
for(int i = 0 ; i <= degree ; i++){
result = arithmetic.add(result,arithmetic.mul(coefficients[i],power));
power = power.multiply(x);
}
return result;
}
/**
* @param points
* @return polynomial of minimal degree which goes through all points.
* If there exists i != j s.t points[i].x == points[j].x, method returns null.
*/
public static Polynomial interpolation(Point[] points, Arithmetic<BigInteger> arithmetic) {
LagrangePolynomial[] l = LagrangePolynomial.lagrangePolynomials(points,arithmetic);
if (l == null){
return null;
}
// product = product of l[i].divisor
BigInteger product = BigInteger.ONE;
for (int i = 0; i < l.length;i++){
product = arithmetic.mul(product,l[i].divisor);
}
// factor[i] = product divided by l[i].divisor = product of l[j].divisor s.t j!=i
BigInteger[] factors = new BigInteger[l.length];
for (int i = 0; i < l.length;i++){
factors[i] = arithmetic.div(product,l[i].divisor);
}
int degree = l[0].polynomial.degree;
// coefficients[j] = (sum of l[i].evaluate * factor[i] * l[i].coefficients[j] s.t i!=j) divide by product =
// = sum of l[i].evaluate * l[i].coefficients[j] / l[i].divisor s.t i!=j
BigInteger[] coefficients = new BigInteger[degree + 1];
for (int j = 0; j < coefficients.length;j++){
coefficients[j] = BigInteger.ZERO;
for (int i = 0; i < l.length; i++){
BigInteger current = arithmetic.mul(l[i].image,factors[i]);
current = arithmetic.mul(current,l[i].polynomial.coefficients[j]);
coefficients[j] = arithmetic.add(coefficients[j],current);
}
coefficients[j] = arithmetic.div(coefficients[j],product);
}
return new Polynomial(coefficients,arithmetic);
}
/**
* @param other
* @return new Polynomial of degree max(this degree,other degree) s.t for all x
* new.evaluate(x) = this.evaluate(x) + other.evaluate(x)
*/
public Polynomial add(Polynomial other){
Polynomial bigger,smaller;
if(this.degree < other.degree){
bigger = other;
smaller = this;
}else{
bigger = this;
smaller = other;
}
BigInteger[] coefficients = bigger.getCoefficients();
for (int i = 0; i <= smaller.degree ; i++){
coefficients[i] = arithmetic.add(smaller.coefficients[i],bigger.coefficients[i]);
}
return new Polynomial(coefficients,other.arithmetic);
}
/**
* @param constant
* @return new Polynomial of degree this.degree s.t for all x
* new.evaluate(x) = constant * this.evaluate(x)
*/
public Polynomial mul(BigInteger constant){
BigInteger[] coefficients = this.getCoefficients();
for (int i = 0; i <= this.degree ; i++){
coefficients[i] = arithmetic.mul(constant,coefficients[i]);
}
return new Polynomial(coefficients,arithmetic);
}
/**
* @param other
* @return new Polynomial of degree this degree + other degree + 1 s.t for all x
* new.evaluate(x) = this.evaluate(x) * other.evaluate(x)
*/
public Polynomial mul(Polynomial other){
BigInteger[] coefficients = new BigInteger[this.degree + other.degree + 1];
Arrays.fill(coefficients,BigInteger.ZERO);
for (int i = 0; i <= this.degree ; i++){
for (int j = 0; j <= other.degree; j++){
coefficients[i+j] = arithmetic.add(coefficients[i+j],arithmetic.mul(this.coefficients[i],other.coefficients[j]));
}
}
return new Polynomial(coefficients,arithmetic);
}
/** getter
* @return copy of coefficients
*/
public BigInteger[] getCoefficients() {
return Arrays.copyOf(coefficients,coefficients.length);
}
/** getter
* @return degree
*/
public int getDegree() {
return degree;
}
/**
* inner class
* container for (x,y) x from range and y from evaluate of polynomial
*/
public static class Point implements java.io.Serializable {
public final BigInteger x;
public final BigInteger y;
/**
* constructor
* @param x
* @param polynomial y = polynomial.evaluate(x)
*/
public Point(BigInteger x, Polynomial polynomial) {
this.x = x;
this.y = polynomial.evaluate(x);
}
/**
* constructor
* @param x
* @param y
*/
public Point(BigInteger x,BigInteger y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if(!super.equals(obj))
return false;
Point other = (Point)obj;
return this.x.equals(other.x) && this.y.equals(other.y);
}
}
}

View File

@ -0,0 +1,123 @@
package meerkat.crypto.secretsharing.shamir;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
* an implementation of Shamire's secret sharing scheme
*/
public class SecretSharing{
/**
* threshold
*/
protected final int t;
/**
* number of shares
*/
protected final int n;
/**
* a large prime
*/
protected final BigInteger q;
/**
* random polynomial of degree s.t polynomial.evaluate(0) = secret
*/
protected final Polynomial polynomial;
/**
* constructor
* @param q a large prime.
* @param t threshold. Any t+1 share holders can recover the secret,
* but any set of at most t share holders cannot
* @param n number of share holders
* @param zi secret, chosen from Zq
* @param random use for generate random polynomial
*/
public SecretSharing(int t, int n, BigInteger zi, Random random, BigInteger q) {
this.q = q;
this.t = t;
this.n = n;
this.polynomial = generateRandomPolynomial(zi,random);
}
/**
* @param x
* @param random
* @return new Polynomial polynomial of degree t ,such that
* 1. polynomial(0) = x
* 2. polynomial coefficients randomly chosen from Zq (except of coefficients[0] = x)
*/
private Polynomial generateRandomPolynomial(BigInteger x, Random random) {
BigInteger[] coefficients = new BigInteger[t + 1];
coefficients[0] = x.mod(q);
int bits = q.bitLength();
for (int i = 1 ; i <= t; i++ ){
coefficients[i] = new BigInteger(bits,random).mod(q);
}
return new Polynomial(coefficients,new Fp(q));
}
/**
* @param i in range of [1,...n]
*
* @return polynomial.evaluate(i)
*/
public Polynomial.Point getShare(int i){
assert (i > 0 && i <= n);
return new Polynomial.Point(BigInteger.valueOf(i), polynomial);
}
/**
* @param shares - subset of the original shares
*
* @return evaluate of interpolation(shares) at x = 0
*/
public static BigInteger recoverSecret(Polynomial.Point[] shares, Arithmetic<BigInteger> arithmetic) {
return recoverPolynomial(shares,arithmetic).evaluate(BigInteger.ZERO);
}
/**
* @param shares - subset of the original shares
*
* @return interpolation(shares)
*/
public static Polynomial recoverPolynomial(Polynomial.Point[] shares, Arithmetic<BigInteger> arithmetic) {
return Polynomial.interpolation(shares,arithmetic);
}
/**
* getter
* @return threshold
*/
public int getT() {
return t;
}
/**
* getter
* @return number of share holders
*/
public int getN() {
return n;
}
/**
* getter
* @return the prime was given in the constructor
*/
public BigInteger getQ() {
return q;
}
/**
* getter
* @return the polynomial was generated in constructor
*/
public Polynomial getPolynomial() {
return polynomial;
}
}

View File

@ -0,0 +1,38 @@
package meerkat.crypto.utils;
/**
* Created by Tzlil on 3/17/2016.
* defines the properties of the traditional operations : add,sub,mul,div
* between two objects of type T
*/
public interface Arithmetic<T> {
/**
* addition
* @param a
* @param b
* @return a + b
*/
T add(T a, T b);
/**
* subtraction
* @param a
* @param b
* @return a - b
*/
T sub(T a, T b);
/**
* multiplication
* @param a
* @param b
* @return a * b
*/
T mul(T a, T b);
/**
* division
* @param a
* @param b
* @return a / b
*/
T div(T a, T b);
}

View File

@ -0,0 +1,44 @@
package meerkat.crypto.utils.concrete;
import meerkat.crypto.utils.Arithmetic;
import org.factcenter.qilin.primitives.concrete.Zpstar;
import java.math.BigInteger;
/**
* Created by Tzlil on 3/17/2016.
* an implementation of Arithmetic<BigInteger> over prime fields: integers modulo p
*/
public class Fp implements Arithmetic<BigInteger> {
public final BigInteger p;
private final Zpstar zp;
/**
* constructor
* @param p prime
*/
public Fp(BigInteger p) {
this.p = p;
this.zp = new Zpstar(p);
}
@Override
public BigInteger add(BigInteger a, BigInteger b){
return a.add(b).mod(p);
}
@Override
public BigInteger sub(BigInteger a, BigInteger b){
return a.add(p).subtract(b).mod(p);
}
@Override
public BigInteger mul(BigInteger a, BigInteger b){
return zp.add(a,b);
}
@Override
public BigInteger div(BigInteger a, BigInteger b){
return mul(a,zp.negate(b));
}
}

View File

@ -0,0 +1,46 @@
syntax = "proto3";
package meerkat;
option java_package = "meerkat.protobuf";
message Payload {
enum Type {
SHARE = 0;
COMMITMENT = 1;
COMPLAINT = 2;
DONE = 3;
ANSWER = 4;
YCOMMITMENT = 5;
YCOMPLAINT = 6;
YANSWER = 7;
ABORT = 8;
}
// Type of message in protocol
Type type = 1;
oneof payload_data {
IDMessage id = 5;
ShareMessage share = 6;
CommitmentMessage commitment = 7;
}
}
message IDMessage {
int32 id = 1;
}
message ShareMessage {
int32 i = 1;
int32 j = 2;
bytes share = 3;
// For double shares (used in GJKR protocol)
bytes share_t = 4;
}
message CommitmentMessage {
int32 k = 1;
bytes commitment = 2;
}

View File

@ -0,0 +1,73 @@
package meerkat.crypto.dkg.feldman;
import meerkat.comm.Channel;
import java.math.BigInteger;
import java.util.*;
/**
* Created by Tzlil on 3/21/2016.
*/
public class DKGMaliciousUser<T> extends User<T> {
private final Protocol<T> maliciousDkg;
private final Set<Integer> falls;
public DKGMaliciousUser(Protocol<T> dkg, Protocol<T> maliciousDKG, Channel channel, Set<Integer> falls) {
super(dkg, channel);
this.falls = falls;
this.maliciousDkg = maliciousDKG;
maliciousDKG.setParties(parties);
}
public static Set<Integer> selectFallsRandomly(Set<Integer> ids, Random random){
Set<Integer> falls = new HashSet<Integer>();
ArrayList<Integer> idsList = new ArrayList<Integer>();
for (int id : ids){
idsList.add(id);
}
int fallsSize = random.nextInt(idsList.size()) + 1;// 1 - (n-1)
while (falls.size() < fallsSize){
falls.add(idsList.remove(random.nextInt(idsList.size())));
}
return falls;
}
public static <T> Protocol<T> generateMaliciousDKG(Protocol<T> dkg,Channel channel,Random random){
BigInteger q = dkg.getQ();
BigInteger zi = new BigInteger(q.bitLength(), random).mod(q);
Protocol<T> malicious = new Protocol<T>(dkg.getT(),dkg.getN(),zi,random,dkg.getQ()
,dkg.getGenerator(),dkg.getGroup(),dkg.getId(),dkg.getEncoder());
malicious.setChannel(channel);
return malicious;
}
@Override
public void stage1() {
dkg.broadcastCommitments();
sendSecrets(); //insteadof crypto.sendSecrets(channel);
}
@Override
public void stage3() {
maliciousDkg.answerAllComplainingPlayers();
}
@Override
public void stage4(){
// do nothing
}
private void sendSecrets(){
for (int j = 1; j <= n ; j++){
if(j != id){
if(falls.contains(j)){
maliciousDkg.sendSecret(j);
}else {
dkg.sendSecret(j);
}
}
}
}
}

View File

@ -0,0 +1,170 @@
package meerkat.crypto.dkg.feldman;
import meerkat.comm.ChannelImpl;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.comm.Channel;
import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.secretsharing.shamir.SecretSharing;
import meerkat.crypto.utils.BigIntegerByteEncoder;
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.Test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* Created by Tzlil on 3/21/2016.
*/
public class DKGTest {
int 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 n = 20;
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.threads.length ; i++){
testable.threads[i].join();
}
// got the right public value
BigInteger publicValue = group.multiply(testable.g,testable.secret);
for (int i: testable.valids){
assert (testable.dkgs[i - 1].getPublicValue().equals(publicValue));
}
// assert valid verification values
BigInteger expected,verification;
for (int i: testable.valids){
expected = group.multiply(testable.g, testable.dkgs[i - 1].getShare().y);
verification = VerifiableSecretSharing.computeVerificationValue(i, testable.dkgs[i - 1].getCommitments(), group);
assert (expected.equals(verification));
}
// restore the secret from shares
ArrayList<Polynomial.Point> sharesList = new ArrayList<Polynomial.Point>();
for (int i: testable.valids){
sharesList.add(testable.dkgs[i - 1].getShare());
}
Polynomial.Point[] shares = new Polynomial.Point[sharesList.size()];
for (int i = 0; i < shares.length; i ++){
shares[i] = sharesList.get(i);
}
BigInteger calculatedSecret = SecretSharing.recoverSecret(shares,arithmetic);
assert (calculatedSecret.equals(testable.secret));
}
@Test
public void test() throws Exception {
Testable testable;
for (int i = 0; i < tests; i++){
testable = new Testable(new Random());
oneTest(testable);
}
}
class Testable{
Set<Integer> valids;
Set<Integer> QUAL;
Set<Integer> aborted;
Set<Integer> malicious;
User<BigInteger>[] dkgs;
Thread[] threads;
BigInteger g;
BigInteger secret;
public Testable(Random random) {
this.dkgs = 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.g = sampleGenerator(random);
ArrayList<Integer> ids = new ArrayList<Integer>();
for (int id = 1; id<= n ; id++){
ids.add(id);
}
int id;
BigInteger s;
Protocol<BigInteger> dkg;
this.secret = BigInteger.ZERO;
ChannelImpl channels = new ChannelImpl();
ByteEncoder<BigInteger> byteEncoder = new BigIntegerByteEncoder();
while (!ids.isEmpty()) {
id = ids.remove(random.nextInt(ids.size()));
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);
threads[id - 1] = new Thread(dkgs[id - 1]);
if(QUAL.contains(id)){
this.secret = this.secret.add(s).mod(q);
}
}
}
public User<BigInteger> randomDKGUser(int id, Channel channel, Protocol<BigInteger> dkg, Random random){
if (QUAL.size() <= t) {
valids.add(id);
QUAL.add(id);
return new User<BigInteger>(dkg,channel);
}else{
int type = random.nextInt(3);
switch (type){
case 0:// regular
valids.add(id);
QUAL.add(id);
return new User<BigInteger>(dkg,channel);
case 1:// abort
int abortStage = random.nextInt(2) + 1; // 1 or 2
aborted.add(id);
if (abortStage == 2){
QUAL.add(id);
}
return new DKGUserImplAbort(dkg,channel,abortStage);
case 2:// malicious
malicious.add(id);
Set<Integer> falls = DKGMaliciousUser.selectFallsRandomly(valids,random);
Protocol<BigInteger> maliciousDKG = DKGMaliciousUser.generateMaliciousDKG(dkg,channel,random);
return new DKGMaliciousUser(dkg,maliciousDKG,channel,falls);
default:
return null;
}
}
}
public BigInteger sampleGenerator(Random random){
BigInteger ZERO = group.zero();
BigInteger g;
do {
g = group.sample(random);
} while (!g.equals(ZERO) && !group.multiply(g, q).equals(ZERO));
return g;
}
public BigInteger randomIntModQ(Random random){
return new BigInteger(q.bitLength(), random).mod(q);
}
}
}

View File

@ -0,0 +1,65 @@
package meerkat.crypto.dkg.feldman;
import meerkat.comm.Channel;
import meerkat.protobuf.DKG;
import static meerkat.crypto.dkg.comm.MessageUtils.createMessage;
/**
* Created by Tzlil on 3/14/2016.
*/
public class DKGUserImplAbort<T> extends User<T> {
final int abortStage;
int stage;
public DKGUserImplAbort(Protocol<T> dkg, Channel channel, int abortStage) {
super(dkg, channel);
this.abortStage = abortStage;// 1 - 2
this.stage = 1;
}
private void sendAbort(){
channel.broadcastMessage(createMessage(DKG.Payload.Type.ABORT));
}
@Override
protected void stage1() {
if(stage < abortStage)
super.stage1();
else if(stage == abortStage){
sendAbort();
}
stage++;
}
@Override
protected void stage2() {
if(stage < abortStage)
super.stage2();
else if(stage == abortStage){
sendAbort();
}
stage++;
}
@Override
protected void stage3() {
if(stage < abortStage)
super.stage3();
else if(stage == abortStage){
sendAbort();
}
stage++;
}
@Override
protected void stage4() {
if(stage < abortStage)
super.stage4();
else if(stage == abortStage){
sendAbort();
}
stage++;
}
}

View File

@ -0,0 +1,61 @@
package meerkat.crypto.dkg.gjkr;
import meerkat.comm.Channel;
import java.math.BigInteger;
import java.util.Random;
import java.util.Set;
/**
* Created by Tzlil on 3/29/2016.
*/
public class SDKGMaliciousUserImpl<T> extends User<T> {
private final Protocol<T> maliciousSDKG;
private final Set<Integer> falls;
public SDKGMaliciousUserImpl(Protocol<T> sdkg, Protocol<T> maliciousSDKG
, Channel channel, Set<Integer> falls) {
super(sdkg, channel);
this.falls = falls;
this.maliciousSDKG = maliciousSDKG;
maliciousSDKG.setParties(parties);
}
public static<T> Protocol<T> generateMaliciousSDKG(Protocol<T> sdkg,Channel channel,Random random){
BigInteger q = sdkg.getQ();
BigInteger zi = new BigInteger(q.bitLength(), random).mod(q);
Protocol<T> malicious = new Protocol<T>(sdkg.getT(),sdkg.getN(),zi,random,sdkg.getQ()
,sdkg.getGenerator(),sdkg.getH(),sdkg.getGroup(),sdkg.getId(),sdkg.getEncoder());
malicious.setChannel(channel);
return malicious;
}
@Override
public void stage1() {
sdkg.computeAndBroadcastVerificationValues();
sendSecrets(); //insteadof crypto.sendSecrets(channel);
}
@Override
public void stage3() {
maliciousSDKG.answerAllComplainingPlayers();
}
@Override
public void stage4(){
//do nothing
}
private void sendSecrets(){
for (int j = 1; j <= n ; j++){
if(j != id){
if(falls.contains(j)){
maliciousSDKG.sendSecret(j);
}else {
sdkg.sendSecret(j);
}
}
}
}
}

View File

@ -0,0 +1,206 @@
package meerkat.crypto.dkg.gjkr;
import meerkat.comm.ChannelImpl;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.comm.Channel;
import meerkat.crypto.secretsharing.feldman.VerifiableSecretSharing;
import meerkat.crypto.dkg.feldman.DKGMaliciousUser;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.secretsharing.shamir.SecretSharing;
import meerkat.crypto.utils.BigIntegerByteEncoder;
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 {
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 = 1;
int n = 20;
Random rand = new Random(1);
public void oneTest(Testable testable) throws Exception {
for (int i = 0; i < testable.sdkgs.length ; i++){
testable.futures[i] = executorService.submit(testable.sdkgs[i]);
}
for (int i = 0; i < testable.futures.length ; i++){
testable.futures[i].get();
}
// got the right public value
BigInteger publicValue = group.multiply(testable.g,testable.secret);
for (int i: testable.valids){
assert (testable.sdkgs[i - 1].getPublicValue().equals(publicValue));
}
// assert valid verification values
BigInteger expected,verification;
for (int i: testable.valids){
expected = group.multiply(testable.g, testable.sdkgs[i - 1].getShare().y);
verification = VerifiableSecretSharing.computeVerificationValue(i, testable.sdkgs[i - 1].getCommitments(), group);
assert (expected.equals(verification));
}
// restore the secret from shares
ArrayList<Polynomial.Point> sharesList = new ArrayList<Polynomial.Point>();
for (int i: testable.valids){
sharesList.add(testable.sdkgs[i - 1].getShare());
}
Polynomial.Point[] shares = new Polynomial.Point[sharesList.size()];
for (int i = 0; i < shares.length; i ++){
shares[i] = sharesList.get(i);
}
BigInteger calculatedSecret = SecretSharing.recoverSecret(shares,arithmetic);
assert (calculatedSecret.equals(testable.secret));
}
@Test
public void test() throws Exception {
Testable testable;
for (int i = 0; i < NUM_TESTS; i++) {
testable = new Testable(n, t, group, q, rand);
oneTest(testable);
}
}
static class Testable {
Set<Integer> valids;
Set<Integer> QUAL;
Set<Integer> aborted;
Set<Integer> malicious;
User<BigInteger>[] sdkgs;
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(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.futures = new Future[n];
this.g = sampleGenerator(random);
this.h = group.multiply(g,randomIntModQ(random));
ArrayList<Integer> ids = new ArrayList<Integer>();
for (int id = 1; id<= n ; id++){
ids.add(id);
}
int id;
BigInteger s;
Channel channel;
Protocol<BigInteger> sdkg;
this.secret = BigInteger.ZERO;
ByteEncoder<BigInteger> encoder = new BigIntegerByteEncoder();
while (!ids.isEmpty()) {
id = ids.remove(random.nextInt(ids.size()));
s = randomIntModQ(random);
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);
if(QUAL.contains(id)){
this.secret = this.secret.add(s).mod(q);
}
}
}
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 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);
}
}
public BigInteger sampleGenerator(Random random){
BigInteger ZERO = group.zero();
BigInteger g;
do {
g = group.sample(random);
} while (!g.equals(ZERO) && !group.multiply(g, q).equals(ZERO));
return g;
}
public BigInteger randomIntModQ(Random random){
return new BigInteger(q.bitLength(), random).mod(q);
}
}
}

View File

@ -0,0 +1,80 @@
package meerkat.crypto.dkg.gjkr;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.dkg.comm.MessageUtils;
import meerkat.comm.Channel;
import meerkat.protobuf.Comm;
import meerkat.protobuf.DKG;
/**
* Created by Tzlil on 3/14/2016.
*/
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) {
super(sdkg, channel);
this.abortStage = abortStage;// 1 - 4
this.stage = 1;
}
private void abort(){
//stopReceiver();
channel.broadcastMessage(MessageUtils.createMessage(DKG.Payload.Type.ABORT));
throw new AbortException();
}
@Override
protected void stage1() {
if(stage < abortStage)
super.stage1();
else if(stage == abortStage){
abort();
}
stage++;
}
@Override
protected void stage2() {
if(stage < abortStage)
super.stage2();
else if(stage == abortStage){
abort();
}
stage++;
}
@Override
protected void stage3() {
if(stage < abortStage)
super.stage3();
else if(stage == abortStage){
abort();
}
stage++;
}
@Override
protected void stage4() {
if(stage < abortStage)
super.stage4();
else if(stage == abortStage){
abort();
}
stage++;
}
@Override
public void run() {
try {
super.run();
} catch (AbortException e) {
// Expected
}
}
}

View File

@ -0,0 +1,68 @@
package meerkat.crypto.secretsharing.feldman;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import org.factcenter.qilin.primitives.Group;
import org.factcenter.qilin.primitives.concrete.Zpstar;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Random;
/**
* Created by Tzlil on 1/29/2016.
*/
public class VerifiableSecretSharingTest {
VerifiableSecretSharing[] verifiableSecretSharingArray;
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;
verifiableSecretSharingArray = new VerifiableSecretSharing[tests];
for (int i = 0; i < verifiableSecretSharingArray.length; i++){
verifiableSecretSharingArray[i] = new VerifiableSecretSharing(t,n
,new BigInteger(q.bitLength(),random).mod(q),random,q,g,zpstar);
}
}
public void oneTest(VerifiableSecretSharing<BigInteger> verifiableSecretSharing) throws Exception {
int n = verifiableSecretSharing.getN();
Group<BigInteger> zpstar = verifiableSecretSharing.getGroup();
BigInteger g = verifiableSecretSharing.getGenerator();
Polynomial.Point[] shares = new Polynomial.Point[n];
ArrayList<BigInteger> commitments = verifiableSecretSharing.getCommitmentsArrayList();
BigInteger[] verifications = new BigInteger[n];
for (int i = 1 ; i <= shares.length; i ++){
shares[i - 1] = verifiableSecretSharing.getShare(i);
verifications[i - 1] = VerifiableSecretSharing.computeVerificationValue(i,commitments,zpstar);
}
BigInteger expected;
for (int i = 0 ; i < shares.length ; i++){
expected = zpstar.multiply(g,shares[i].y);
assert (expected.equals(verifications[i]));
}
}
@Test
public void secretSharingTest() throws Exception {
for (int i = 0 ; i < verifiableSecretSharingArray.length; i ++){
oneTest(verifiableSecretSharingArray[i]);
}
}
}

View File

@ -0,0 +1,46 @@
package meerkat.crypto.secretsharing.shamir.PolynomialTests;
import meerkat.crypto.utils.GenerateRandomPolynomial;
import meerkat.crypto.utils.Z;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*/
public class AddTest {
Polynomial[] arr1;
Polynomial[] arr2;
int tests = 1 << 12;
int maxDegree = 15;
int bits = 128;
Random random;
@Before
public void settings(){
random = new Random();
arr1 = new Polynomial[tests];
arr2 = new Polynomial[tests];
for (int i = 0; i < arr1.length; i++){
arr1[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
arr2[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
}
}
public void oneTest(Polynomial p1, Polynomial p2){
Polynomial sum = p1.add(p2);
BigInteger x = new BigInteger(bits,random);
assert(sum.evaluate(x).equals(p1.evaluate(x).add(p2.evaluate(x))));
}
@Test
public void addTest(){
for (int i = 0 ; i < arr1.length; i ++){
oneTest(arr1[i],arr2[i]);
}
}
}

View File

@ -0,0 +1,68 @@
package meerkat.crypto.secretsharing.shamir.PolynomialTests;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.utils.Arithmetic;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.crypto.utils.GenerateRandomPolynomial;
import meerkat.crypto.utils.GenerateRandomPrime;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* Created by Tzlil on 1/27/2016.
*/
public class InterpolationTest {
Polynomial[] polynomials;
int tests = 1 << 10;
int maxDegree = 15;
int bits = 128;
Random random;
Polynomial.Point[][] pointsArrays;
Arithmetic<BigInteger> arithmetic;
BigInteger p = GenerateRandomPrime.SafePrime100Bits;
@Before
public void settings(){
random = new Random();
polynomials = new Polynomial[tests];
pointsArrays = new Polynomial.Point[tests][];
arithmetic = new Fp(p);
for (int i = 0; i < polynomials.length; i++){
polynomials[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,p);
pointsArrays[i] = randomPoints(polynomials[i]);
}
}
public Polynomial.Point[] randomPoints(Polynomial polynomial){
Polynomial.Point[] points = new Polynomial.Point[polynomial.getDegree() + 1];
BigInteger x;
Set<BigInteger> set = new HashSet();
for (int i = 0; i < points.length; i++){
x = new BigInteger(bits,random).mod(p);
if(set.contains(x)){
i--;
continue;
}
set.add(x);
points[i] = new Polynomial.Point(x,polynomial);
}
return points;
}
public void oneTest(Polynomial p, Polynomial.Point[] points) throws Exception {
Polynomial interpolation = Polynomial.interpolation(points,arithmetic);
assert (p.compareTo(interpolation) == 0);
}
@Test
public void interpolationTest() throws Exception {
for (int i = 0; i < polynomials.length; i ++){
oneTest(polynomials[i],pointsArrays[i]);
}
}
}

View File

@ -0,0 +1,48 @@
package meerkat.crypto.secretsharing.shamir.PolynomialTests;
import meerkat.crypto.utils.GenerateRandomPolynomial;
import meerkat.crypto.utils.Z;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*/
public class MulByConstTest {
Polynomial[] arr1;
BigInteger[] arr2;
int tests = 1 << 12;
int maxDegree = 15;
int bits = 128;
Random random;
@Before
public void settings(){
random = new Random();
arr1 = new Polynomial[tests];
arr2 = new BigInteger[tests];
for (int i = 0; i < arr1.length; i++){
arr1[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
arr2[i] = new BigInteger(bits,random);
}
}
public void oneTest(Polynomial p, BigInteger c){
Polynomial product = p.mul(c);
BigInteger x = new BigInteger(bits,random);
assert(product.evaluate(x).equals(p.evaluate(x).multiply(c)));
}
@Test
public void mulByConstTest(){
for (int i = 0 ; i < arr1.length; i ++){
oneTest(arr1[i],arr2[i]);
}
}
}

View File

@ -0,0 +1,48 @@
package meerkat.crypto.secretsharing.shamir.PolynomialTests;
import meerkat.crypto.utils.GenerateRandomPolynomial;
import meerkat.crypto.utils.Z;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*/
public class MulTest {
Polynomial[] arr1;
Polynomial[] arr2;
int tests = 1 << 12;
int maxDegree = 15;
int bits = 128;
Random random;
@Before
public void settings(){
random = new Random();
arr1 = new Polynomial[tests];
arr2 = new Polynomial[tests];
for (int i = 0; i < arr1.length; i++){
arr1[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
arr2[i] = GenerateRandomPolynomial.generateRandomPolynomial(random.nextInt(maxDegree),bits,random,new Z());
}
}
public void oneTest(Polynomial p1, Polynomial p2){
Polynomial product = p1.mul(p2);
BigInteger x = new BigInteger(bits,random);
assert(product.evaluate(x).equals(p1.evaluate(x).multiply(p2.evaluate(x))));
}
@Test
public void mulTest(){
for (int i = 0 ; i < arr1.length; i ++){
oneTest(arr1[i],arr2[i]);
}
}
}

View File

@ -0,0 +1,64 @@
package meerkat.crypto.secretsharing.shamir;
import meerkat.crypto.utils.concrete.Fp;
import meerkat.crypto.utils.GenerateRandomPrime;
import org.factcenter.qilin.primitives.CyclicGroup;
import org.factcenter.qilin.primitives.concrete.Zn;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by Tzlil on 1/29/2016.
*/
public class SecretSharingTest {
SecretSharing[] secretSharingArray;
BigInteger[] secrets;
CyclicGroup<BigInteger> group;
int tests = 1 << 10;
Random random;
BigInteger p = GenerateRandomPrime.SafePrime100Bits;
BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
@Before
public void settings(){
group = new Zn(q);
int t = 9;
int n = 20;
random = new Random();
secretSharingArray = new SecretSharing[tests];
secrets = new BigInteger[tests];
for (int i = 0; i < secretSharingArray.length; i++){
secrets[i] = group.sample(random);
secretSharingArray[i] = new SecretSharing(t,n,secrets[i],random,q);
}
}
public void oneTest(SecretSharing secretSharing, BigInteger secret) throws Exception {
int t = secretSharing.getT();
int n = secretSharing.getN();
Polynomial.Point[] shares = new Polynomial.Point[t + 1];
List<Integer> indexes = new ArrayList<Integer>(n);
for (int i = 1 ; i <= n; i ++){
indexes.add(i);
}
for (int i = 0 ; i < shares.length ; i++){
shares[i] = secretSharing.getShare(indexes.remove(random.nextInt(indexes.size())));
}
BigInteger calculated = SecretSharing.recoverSecret(shares,new Fp(q));
assert (secret.equals(calculated));
}
@Test
public void secretSharingTest() throws Exception {
for (int i = 0 ; i < secretSharingArray.length; i ++){
oneTest(secretSharingArray[i],secrets[i]);
}
}
}

View File

@ -0,0 +1,28 @@
package meerkat.crypto.utils;
import java.math.BigInteger;
/**
* Created by Tzlil on 4/7/2016.
*/
public class BigIntegerByteEncoder implements org.factcenter.qilin.util.ByteEncoder<BigInteger> {
@Override
public byte[] encode(BigInteger input) {
return input.toByteArray();
}
@Override
public BigInteger decode(byte[] input) {
return new BigInteger(1,input);
}
@Override
public int getMinLength() {
return 0;
}
@Override
public BigInteger denseDecode(byte[] input) {
return decode(input);
}
}

View File

@ -0,0 +1,30 @@
package meerkat.crypto.utils;
import meerkat.crypto.secretsharing.shamir.Polynomial;
import meerkat.crypto.utils.concrete.Fp;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 1/27/2016.
*/
public class GenerateRandomPolynomial {
public static Polynomial generateRandomPolynomial(int degree, int bits, Random random, Arithmetic<BigInteger> arithmetic) {
BigInteger[] coefficients = new BigInteger[degree + 1];
for (int i = 0 ; i <= degree; i++ ){
coefficients[i] = new BigInteger(bits,random); // sample from Zp [0,... q-1]
}
return new Polynomial(coefficients,arithmetic);
}
public static Polynomial generateRandomPolynomial(int degree,int bits,Random random,BigInteger p) {
BigInteger[] coefficients = generateRandomPolynomial(degree,bits,random,new Fp(p)).getCoefficients();
for (int i = 0; i<coefficients.length;i++){
coefficients[i] = coefficients[i].mod(p);
}
return new Polynomial(coefficients,new Fp(p));
}
}

View File

@ -0,0 +1,30 @@
package meerkat.crypto.utils;
import java.math.BigInteger;
import java.util.Random;
/**
* Created by Tzlil on 3/28/2016.
*/
public class GenerateRandomPrime {
private final static int Certainty = 10000;
public final static BigInteger SafePrime100Bits = new BigInteger("146407324427772525685319783363");
public static BigInteger generateRandomPrime(int bits, Random random) {
BigInteger p;
do {
p = new BigInteger(bits, random);
} while (!p.isProbablePrime(Certainty));
return p;
}
public static BigInteger generateRandomSafePrime(int bits, Random random) {
BigInteger p;
BigInteger q;
do {
p = generateRandomPrime(bits, random);
q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
} while (!q.isProbablePrime(Certainty));
return q;
}
}

View File

@ -0,0 +1,28 @@
package meerkat.crypto.utils;
import java.math.BigInteger;
/**
* Created by Tzlil on 4/8/2016.
*/
public class Z implements Arithmetic<BigInteger> {
@Override
public BigInteger add(BigInteger a, BigInteger b) {
return a.add(b);
}
@Override
public BigInteger sub(BigInteger a, BigInteger b) {
return a.subtract(b);
}
@Override
public BigInteger mul(BigInteger a, BigInteger b) {
return a.multiply(b);
}
@Override
public BigInteger div(BigInteger a, BigInteger b) {
return a.divide(b);
}
}

Binary file not shown.

View File

@ -1,7 +1,6 @@
#Tue Aug 05 03:26:05 IDT 2014 #Fri Jan 29 21:00:29 IST 2016
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip
distributionSha256Sum=4647967f8de78d6d6d8093cdac50f368f8c2b8038f41a5afe1c3bce4c69219a9

10
gradlew vendored
View File

@ -42,11 +42,6 @@ case "`uname`" in
;; ;;
esac esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" PRG="$0"
@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do
fi fi
done done
SAVED="`pwd`" SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&- cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`" APP_HOME="`pwd -P`"
cd "$SAVED" >&- cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -114,6 +109,7 @@ fi
if $cygwin ; then if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`

View File

@ -0,0 +1,42 @@
package meerkat.comm;
import com.google.protobuf.Message;
import meerkat.protobuf.Comm;
/**
* A generic communication channel that supports point-to-point and broadcast operation
*/
public interface Channel {
/**
* Return the id of the channel's endpoint (this will be used as the source of message sent from the channel).
* @return
*/
public int getSourceId();
public interface ReceiverCallback {
public void receiveMessage(Comm.BroadcastMessage envelope);
}
/**
* sends a private message
* @param destUser destination user's identifier
* @param msg message
*/
public void sendMessage(int destUser, Message msg);
/**
* broadcasts a message to all parties (including the sender)
* @param msg message
*/
public void broadcastMessage(Message msg);
/**
* Register a callback to handle received messages.
* The callback is called in the <b>Channel</b> thread, so no long processing should
* occur in the callback method.
* @param callback
*/
public void registerReceiverCallback(ReceiverCallback callback);
}

View File

@ -113,7 +113,7 @@ public class ECElGamalEncryption implements Encryption {
Pair<ECPoint,ECPoint> randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt); Pair<ECPoint,ECPoint> randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt);
ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData()); ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData());
Pair<ECPoint,ECPoint> originalCipher = new Pair<>( Pair<ECPoint,ECPoint> originalCipher = new Pair<ECPoint, ECPoint>(
curve.decodePoint(originalEncodedCipher.getC1().toByteArray()), curve.decodePoint(originalEncodedCipher.getC1().toByteArray()),
curve.decodePoint(originalEncodedCipher.getC2().toByteArray())); curve.decodePoint(originalEncodedCipher.getC2().toByteArray()));
Pair<ECPoint,ECPoint> newCipher = elGamalPK.add(originalCipher, randomizer); Pair<ECPoint,ECPoint> newCipher = elGamalPK.add(originalCipher, randomizer);

View File

@ -27,4 +27,5 @@ public class TimestampComparator implements Comparator<Timestamp> {
} }
} }
} }

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

View File

@ -3,7 +3,6 @@ package meerkat.crypto.concrete;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.Message; import com.google.protobuf.Message;
import meerkat.crypto.concrete.ECDSASignature;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import org.junit.Test; import org.junit.Test;

View File

@ -3,7 +3,6 @@ package meerkat.crypto.concrete;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.Message; import com.google.protobuf.Message;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;
import meerkat.crypto.concrete.ECDSASignature;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;

View File

@ -0,0 +1,8 @@
-----BEGIN CERTIFICATE-----
MIIBGjCBw6ADAgECAgEBMAkGByqGSM49BAEwEDEOMAwGA1UEAxMFY2VydDEwHhcN
MTUxMTI4MTEwNDAwWhcNMTYxMTI4MTEwNDAwWjAQMQ4wDAYDVQQDEwVjZXJ0MTBZ
MBMGByqGSM49AgEGCCqGSM49AwEHA0IABLiyFMVWQtFi4fCjOGLDwQcdjyr48Y8j
P+eLEIGMYKKv8bqL3Vchs0iOPoyGH6jxYj2/ShnLSIEuIMPfVgV9kxSjDzANMAsG
A1UdDwQEAwIHgDAJBgcqhkjOPQQBA0cAMEQCIH7R0AWO0AYiHOs+QsHEpWiebFc1
cyxCKJGkf8KA1KJrAiArCia7PWl0KzaqA0RQC4J0BKp4rZo1PCqKI8DirKQf/Q==
-----END CERTIFICATE-----

View File

@ -4,4 +4,5 @@ include 'bulletin-board-server'
include 'polling-station' include 'polling-station'
include 'restful-api-common' include 'restful-api-common'
include 'bulletin-board-client' include 'bulletin-board-client'
include 'voter-registry' include 'distributed-key-generation'