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

[WIP] add get / store preprocessing hooks functionality #209

Open
wants to merge 9 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
37 changes: 37 additions & 0 deletions demos/average/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Demos Template

Internal template for use when creating templates.

## File structure
Demos should consist of the following parts:
1. Server script: the defaul server script should be enough unless (1) additional extensions are applied. (2) server side computation is needed.
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*. You should code your protocol in the compute function inside mpc.js, this file is used in both the browser
and node.js versions of the demo.
5. test.js: mocha unit tests.

## File to modify
1. client.html: change the title and different labels, as well as the UI if needed.
2. mpc.js: to encode your protocol and use any needed extensions.
3. test.js: generic test code should work for most demos, you will need to add code to generate appropriate inputs/test cases, and to compute the expected results (not in MPC) for these inputs.
4. server.js: Modify the last two lines in the template file (logs) to show the right command to run the parties.

## Running Demos
1. Running a server:
```shell
node index.js demos/<demo-name>/server.js
```

2. Either open browser based parties by going to *http://localhost:8080/demos/<demo-name>/client.html* in the browser, or a node.js party by running
```shell
node party.js <input>
```

3. Running tests: make sure a server is running and then use:

Check notice on line 34 in demos/average/README.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/README.md#L34

Expected: 1; Actual: 3; Style: 1/1/1
```shell
npm run-script test-demo -- demos/<demo-name>/test.js
```
30 changes: 30 additions & 0 deletions demos/average/client.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!-- Basic UI for running the demo in the browser -->

<html>
<head>
<title>Average Numbers under MPC</title>
<style>
.error {
color: #FF0000;
}
</style>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script src="/dist/jiff-client.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>Average Numbers under 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">Average</button><br/>
<div id="output"></div>
</body>
</html>
67 changes: 67 additions & 0 deletions demos/average/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Do not modify this file unless you have too
* 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());

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>');

Check warning on line 21 in demos/average/client.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/client.js#L21

HTML passed in to function '$('#output').append'
};

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/average/client.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/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>');

Check warning on line 56 in demos/average/client.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/client.js#L56

HTML passed in to function '$('#output').append'

// 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);
}
42 changes: 42 additions & 0 deletions demos/average/mpc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
(function (exports, node) {


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

// Added options goes here
opt.crypto_provider = false;



// eslint-disable-next-line no-undef
saved_instance = new JIFFClient(hostname, computation_id, opt);
// if you need any extensions, put them here
return saved_instance;

Check failure on line 22 in demos/average/mpc.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/mpc.js#L22

'saved_instance' is not defined.
};

/**
* The MPC computation
*/
exports.compute = function (input, jiff_instance) {
if (jiff_instance == null) {
jiff_instance = saved_instance;
}
var shares = jiff_instance.share(input);
var average = shares[1];
for (var i = 2; i <= jiff_instance.party_count; i++) {
average = average.sadd(shares[i]);
}
// var oneOverN = Number.parseFloat((1/jiff_instance.party_count).toFixed(2)); // convert 1/n to fixed point number
var result = average.cdiv(jiff_instance.party_count);
// Return a promise to the final output(s)
return jiff_instance.open(result);
};
}((typeof exports === 'undefined' ? this.mpc = {} : exports), typeof exports !== 'undefined'));

Check notice on line 42 in demos/average/mpc.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/mpc.js#L42

Avoid assignments in operands
48 changes: 48 additions & 0 deletions demos/average/party.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* 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>]]]]');

Check warning on line 7 in demos/average/party.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/party.js#L7

HTML passed in to function 'console.log'

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

Check failure on line 9 in demos/average/party.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/party.js#L9

Require statement not part of import statement.

// 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/average/party.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/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) {
jiff_instance.preprocessing('cdiv', 1);
jiff_instance.preprocessing('open', 1);
jiff_instance.executePreprocessing(function() {
var promise = mpc.compute(input);
promise.then(function (v) {
console.log(v);
// drop mongoose share collections here
jiff_instance.disconnect(false, true);
});
});
};


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

Check failure on line 1 in demos/average/preprocess.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/preprocess.js#L1

Require statement not part of import statement.


var shareSchema = mongoose.Schema({
op_id: String,
ready: Boolean,
value: String,
holders: Array,
threshold: Number,
Zp: Number,
partyID: Number,
onDemand: Boolean
})


module.exports = mongoose.model("Share", shareSchema);
19 changes: 19 additions & 0 deletions demos/average/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
var path = require('path');

Check failure on line 1 in demos/average/server.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/server.js#L1

Require statement not part of import statement.
var express = require('express');

Check failure on line 2 in demos/average/server.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/server.js#L2

Require statement not part of import statement.
var app = express();
var http = require('http').Server(app);

Check failure on line 4 in demos/average/server.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/server.js#L4

Require statement not part of import statement.
var JIFFServer = require('../../lib/jiff-server');
new JIFFServer(http, { logs:true });


// Serve static files.
app.use('/demos', express.static(path.join(__dirname, '..', '..', 'demos')));
app.use('/dist', express.static(path.join(__dirname, '..', '..', 'dist')));
app.use('/lib/ext', express.static(path.join(__dirname, '..', '..', 'lib', 'ext')));
http.listen(8080, function () {
console.log('listening on *:8080');
});

console.log('Direct your browser to http://localhost:8080/demos/average/client.html.');
console.log('To run a server-based party: node demos/average/party <input');

Check warning on line 18 in demos/average/server.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/server.js#L18

HTML passed in to function 'console.log'
console.log();
124 changes: 124 additions & 0 deletions demos/average/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Chai
var assert = require('chai').assert;

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

Check failure on line 4 in demos/average/test.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/test.js#L4

Require statement not part of import statement.
var showProgress = true;

// Generic Testing Parameters
var party_count = 3;
var parallelismDegree = 5; // Max number of test cases running in parallel
var n = 10; // Number of test cases in total
var Zp = null;

// Parameters specific to this demo
/* PUT PARAMETERS HERE */

/**
* CHANGE THIS: Generate inputs for your tests
* Should return an object with this format:
* {
* 'party_id': [ 'test1_input', 'test2_input', ...]
* }
*/
function generateInputs(party_count) {

Check failure on line 23 in demos/average/test.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/test.js#L23

'party_count' is defined but never used.

Check failure on line 23 in demos/average/test.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/test.js#L23

'party_count' is defined but never used.
var inputs = {};

// Generate test cases one at a time
for (var t = 0; t < n; t++) {
/*
* INPUT GENERATION CODE GOES HERE
*/
}

return inputs;
}

/**
* CHANGE THIS: Compute the expected results not in MPC
* @param {object} inputs - same format as generateInputs output.
* Should return a single array with the expected result for every test in order
* [ 'test1_output', 'test2_output', ... ]
*/
function computeResults(inputs) {
var results = [];

for (var j = 0; j < n; j++) {
/*
* COMPUTING THE RESULT IN THE OPEN CODE GOES HERE
*/
}
return results;
}

/**
* Do not change unless you have to.
*/
// eslint-disable-next-line no-undef
describe('Test', function () {
this.timeout(0); // Remove timeout

// eslint-disable-next-line no-undef
it('Exhaustive', function (done) {
var count = 0;

var inputs = generateInputs(party_count);
var realResults = computeResults(inputs);

var onConnect = function (jiff_instance) {
var partyInputs = inputs[jiff_instance.id];

var testResults = [];
(function one_test_case(j) {
if (jiff_instance.id === 1 && showProgress) {
console.log('\tStart ', j > partyInputs.length ? partyInputs.length : j, '/', partyInputs.length);
}

if (j < partyInputs.length) {
var promises = [];
for (var t = 0; t < parallelismDegree && (j + t) < partyInputs.length; t++) {
promises.push(mpc.compute(partyInputs[j + t], jiff_instance));
}

Promise.all(promises).then(function (parallelResults) {
for (var t = 0; t < parallelResults.length; t++) {

Check warning on line 83 in demos/average/test.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/test.js#L83

Expected a `for-of` loop instead of a `for` loop with this simple iteration.
testResults.push(parallelResults[t]);
}

one_test_case(j+parallelismDegree);
});

return;
}

// If we reached here, it means we are done
count++;
for (var i = 0; i < testResults.length; i++) {
// construct debugging message
var ithInputs = inputs[1][i] + '';
for (var p = 2; p <= party_count; p++) {
ithInputs += ',' + inputs[p][i];

Check warning on line 99 in demos/average/test.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/test.js#L99

Generic Object Injection Sink
}
var msg = 'Party: ' + jiff_instance.id + '. inputs: [' + ithInputs + ']';

// assert results are accurate
try {
assert.deepEqual(testResults[i].toString(), realResults[i].toString(), msg);

Check warning on line 105 in demos/average/test.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

demos/average/test.js#L105

Generic Object Injection Sink
} catch (assertionError) {
done(assertionError);
done = function () { };
}
}

jiff_instance.disconnect(true);
if (count === party_count) {
done();
}
})(0);
};

var options = { party_count: party_count, onError: console.log, onConnect: onConnect, Zp: Zp, crypto_provider: true };
for (var i = 0; i < party_count; i++) {
mpc.connect('http://localhost:8080', 'mocha-test', options);
}
});
});
Loading