Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asyncShare extension #181

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions demos/asyncshare/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Sum Demo

Description and guide for computing sum of inputs with secure MPC.

## Secure summation protocol

The implementation of the following protocol may be found in jiff/demos/sum/mpc.js lines 23 through 36.

Input: arbitrary number of parties P1,...Pn with inputs x1,...xn

Each party Pi does the following:
- secret shares their input xi to all other parties
- iteratively uses secret addition protocol to add all of the shares they received together to get a total sum
- reconstructs output sum in final opening step

## Note on the code

The compute function in mpc.js executes once for every single party. In line 29 of *mpc.js*, the parties' shares are
created. It is important to note that the variable created in that line, *shares*, is not just the secret shares belonging
to a single parties' inputs but rather includes all shares that that party has received. The *for* loop in line 31 of *mpc.js* loops
through a single party's shares of all of those parties' inputs.

Note also that the parties have to iteratively use secret addition instead of doing a single sum of their shares of x1,...,xn
because in JIFF the secret addition protocol is a binary operation. I.e. if you have shares a, b, and c that you want to
add, then you can't do
```
var output = a.sadd(b,c);
```
but instead have to do
```
var d = a.sadd(b);
var output = d.sadd(c);
```

## Legal inputs

This instantiation of summation only supports positive integer inputs. For an implementation that supports fixed-point
numbers, see the fixedpoint-sum demo.

## Running Demo
1. Running a server:
```shell
node demos/sum/server.js
```

2. Either open browser based parties by going to *http://localhost:8080/demos/sum/client.html* in the browser, or a node.js party by running
```shell
node demos/sum/party.js <input> [<party count> [<computation_id> [<party id>]]]]'
```

3. Running tests: run the following. Note that you *do not* need to have the server running when running the tests; they run the server on their own.
```shell
npm run-script test-demo -- demos/sum/test.js
```
## File structure
The demo consists of the following parts:
1. Server script: *server.js*
2. Web Based Party: Made from the following files:
* *client.html*: UI for the browser.
* *client.js*: Handlers for UI buttons and input validations.
3. Node.js-Based Party:
* *party.js*: Main entry point. Parses input from the command line and initializes the computation.
4. The MPC protocol: Implemented in *mpc.js*. This file is used in both the browser and node.js versions of the demo.
5. test.js: mocha unit tests.
6. Documentation:
* This *README.md* file.

33 changes: 33 additions & 0 deletions demos/asyncshare/client.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!-- Basic UI for running the demo in the browser -->

<html>
<head>
<title>Sum integers under Asynchronous Share MPC</title>
<style>
.error {
color: #FF0000;
}
</style>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script src="/lib/sodium.js"></script>
<script src="/lib/jiff-client.js"></script>
<script src="/lib/ext/jiff-client-asynchronousshare.js"></script>

<!-- Contains UI Handlers and Input Checks -->
<script type="text/javascript" src="./client.js"></script>

<!-- Contains the MPC implementation -->
<script type="text/javascript" src="./mpc.js"></script>
</head>
<body>
<h1>Connect JIFF</h1>
<label for="computation_id">Computation ID</label><input id="computation_id" value="test"></input><br/><br/>
<label for="count">Party Count<label> <input id="count" pattern="[0-9]*" value="2"> &nbsp; <button id="connectButton" onclick="connect();">Connect</button>
<br/><br/>
<hr/>
<h1>Sum Numbers under Asynchronous Shares MPC</h1>
<label for="number">Input Number (between 0 and 100)</label> <input id="number" pattern="[0-9]+"> &nbsp; <button onclick="submit();" disabled="disabled" id="button">Sum</button><br/>
<div id="output"></div>
</body>
</html>
66 changes: 66 additions & 0 deletions demos/asyncshare/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Do not modify this file unless you have to.
* This file has UI handlers.
*/

// eslint-disable-next-line no-unused-vars
function connect() {
$('#connectButton').prop('disabled', true);
var computation_id = $('#computation_id').val();
var party_count = parseInt($('#count').val());

Check warning on line 10 in demos/asyncshare/client.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/asyncshare/client.js#L10

Always provide a base when using parseInt() functions
//var receiver_ratios =

if (isNaN(party_count)) {
$('#output').append("<p class='error'>Party count must be a valid number!</p>");
$('#connectButton').prop('disabled', false);
} else {
var options = { party_count: party_count};
options.onError = function (error) {
$('#output').append("<p class='error'>"+error+'</p>');
};
options.onConnect = function () {
$('#button').attr('disabled', false); $('#output').append('<p>All parties Connected!</p>');
};

var hostname = window.location.hostname.trim();
var port = window.location.port;
if (port == null || port === '') {
port = '80';
}
if (!(hostname.startsWith('http://') || hostname.startsWith('https://'))) {
hostname = 'http://' + hostname;
}
if (hostname.endsWith('/')) {
hostname = hostname.substring(0, hostname.length-1);
}
if (hostname.indexOf(':') > -1 && hostname.lastIndexOf(':') > hostname.indexOf(':')) {
hostname = hostname.substring(0, hostname.lastIndexOf(':'));
}

hostname = hostname + ':' + port;
// eslint-disable-next-line no-undef
mpc.connect(hostname, computation_id, options);
}
}

// eslint-disable-next-line no-unused-vars
function submit() {
var input = parseInt($('#number').val());

Check warning on line 48 in demos/asyncshare/client.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/asyncshare/client.js#L48

Always provide a base when using parseInt() functions

if (isNaN(input)) {
$('#output').append("<p class='error'>Input a valid number!</p>");
} else if (100 < input || input < 0 || input !== Math.floor(input)) {
$('#output').append("<p class='error'>Input a WHOLE number between 0 and 100!</p>");
} else {
$('#button').attr('disabled', true);
$('#output').append('<p>Starting...</p>');
// eslint-disable-next-line no-undef
var promise = mpc.compute(input);
promise.then(handleResult);
}
}

function handleResult(result) {
$('#output').append('<p>Result is: ' + result + '</p>');
$('#button').attr('disabled', false);
}
43 changes: 43 additions & 0 deletions demos/asyncshare/mpc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
(function (exports, node) {
var saved_instance;

/**
* Connect to the server and initialize the jiff instance
*/
exports.connect = function (hostname, computation_id, options) {
var opt = Object.assign({}, options);
opt.warn = false;
if (node) {
// eslint-disable-next-line no-undef
jiff = require('../../lib/jiff-client');
jiff_asynchronousshare = require('../../lib/ext/jiff-client-asynchronousshare');
}

opt.autoConnect = false;
// eslint-disable-next-line no-undef
saved_instance = jiff.make_jiff(hostname, computation_id, opt);
saved_instance.apply_extension(jiff_asynchronousshare, opt);
saved_instance.connect();
return saved_instance;
};

/**
* The MPC computation
*/
exports.compute = async function (input, jiff_instance) {
if (jiff_instance == null) {
jiff_instance = saved_instance;
}

// The MPC implementation should go *HERE*
var shares = jiff_instance.share(input, 3, null, null, null, null, {1: 1, 2: 2});

var sum = shares[1];
for (var i = 2; i <= jiff_instance.party_count; i++) {
sum = sum.sadd(shares[i]);
}

// Return a promise to the final output(s)
return jiff_instance.open(sum, [1,2]);
};
}((typeof exports === 'undefined' ? this.mpc = {} : exports), typeof exports !== 'undefined'));
43 changes: 43 additions & 0 deletions demos/asyncshare/party.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Do not change this unless you have to.
* This code parses input command line arguments,
* and calls the appropriate initialization and MPC protocol from ./mpc.js
*/

console.log('Command line arguments: <input> [<party count> [<computation_id> [<party id>]]]]');

var mpc = require('./mpc');

// Read Command line arguments
var input = parseInt(process.argv[2], 10);

var party_count = process.argv[3];
if (party_count == null) {
party_count = 2;
} else {
party_count = parseInt(party_count);

Check warning on line 18 in demos/asyncshare/party.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/asyncshare/party.js#L18

Always provide a base when using parseInt() functions
}

var computation_id = process.argv[4];
if (computation_id == null) {
computation_id = 'test';
}

var party_id = process.argv[5];
if (party_id != null) {
party_id = parseInt(party_id, 10);
}

// JIFF options
var options = {party_count: party_count, party_id: party_id};
options.onConnect = function (jiff_instance) {
var promise = mpc.compute(input);

promise.then(function (v) {
console.log(v);
jiff_instance.disconnect(true);
});
};

// Connect
mpc.connect('http://localhost:8080', computation_id, options);
21 changes: 21 additions & 0 deletions demos/asyncshare/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
var express = require('express');
var app = express();

Check notice on line 2 in demos/asyncshare/server.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/asyncshare/server.js#L2

A CSRF middleware was not detected in your express application.
var http = require('http').Server(app);
var base_instance = require('../../lib/jiff-server').make_jiff(http, { logs:true });
var jiffAsyncShareServer = require('../../lib/ext/jiff-server-asyncshare');
base_instance.apply_extension(jiffAsyncShareServer);

//Serve static files
//Configure App
app.use('/demos', express.static('demos'));
app.use('/lib', express.static('lib'));
app.use('/lib/ext', express.static('lib/ext'));

// Serve static files.
http.listen(8080, function () {
console.log('listening on *:8080');
});

console.log('Direct your browser to *:8080/demos/asyncshare/client.html.');
console.log('To run a node.js based party: node demos/asyncshare/party <input>');
console.log();
Loading