diff --git a/lib/jiff-client.js b/lib/jiff-client.js index a63ee352c..a6f0f4e6d 100644 --- a/lib/jiff-client.js +++ b/lib/jiff-client.js @@ -186,7 +186,7 @@ * if the party that calls this function is not a receiver then the map * will be empty. */ - function jiff_share(jiff, secret, threshold, receivers_list, senders_list, Zp, share_id) { + function jiff_share(jiff, secret, threshold, receivers_list, senders_list, Zp, share_id, receivers_ratios) { var i, p_id; // defaults @@ -214,6 +214,12 @@ if (threshold > receivers_list.length) { threshold = receivers_list.length; } + if (receivers_ratios == null) { + receivers_ratios = {}; + for (var i = 1; i <= jiff.party_count; i++){ + receivers_ratios[i] = 2; + } + } // if party is uninvolved in the share, do nothing if (receivers_list.indexOf(jiff.id) === -1 && senders_list.indexOf(jiff.id) === -1) { @@ -233,7 +239,7 @@ secret = jiff.execute_array_hooks('beforeShare', [jiff, secret, threshold, receivers_list, senders_list, Zp], 1); // compute shares - var shares = jiff.hooks.computeShares(jiff, secret, receivers_list, threshold, Zp); + var shares = jiff.hooks.computeShares(jiff, secret, receivers_list, threshold, Zp, receivers_ratios); // Call hook shares = jiff.execute_array_hooks('afterComputeShare', [jiff, shares, threshold, receivers_list, senders_list, Zp], 1); @@ -246,10 +252,13 @@ } // send encrypted and signed shares_id[p_id] to party p_id - var msg = { party_id: p_id, share: shares[p_id], op_id: share_id }; + var p_ratio = (p_id in receivers_ratios) ? receivers_ratios[p_id] : 1; + var msg = {party_id: p_id, share: shares[p_id].slice(), op_id: share_id}; msg = jiff.execute_array_hooks('beforeOperation', [jiff, 'share', msg], 2); - msg['share'] = jiff.hooks.encryptSign(jiff, msg['share'].toString(10), jiff.keymap[msg['party_id']], jiff.secret_key); + for (var j = 0; j < p_ratio; j++) { + msg['share'][j] = jiff.hooks.encryptSign(jiff, msg['share'][j].toString(10), jiff.keymap[msg['party_id']], jiff.secret_key); + } jiff.socket.safe_emit('share', JSON.stringify(msg)); } } @@ -285,11 +294,10 @@ }); })(promise, p_id); - // receive share_i[id] from party p_id + //receive share_i[id] from party p_id result[p_id] = jiff.secret_share(jiff, false, promise, undefined, receivers_list, threshold, Zp, share_id + ':' + p_id); } } - return result; } @@ -308,7 +316,7 @@ * point from the polynomial. * */ - function jiff_compute_shares(jiff, secret, parties_list, threshold, Zp) { + function jiff_compute_shares(jiff, secret, parties_list, threshold, Zp, parties_ratios) { var shares = {}; // Keeps the shares var i; @@ -330,16 +338,19 @@ // Compute each players share such that share[i] = f(i) for (i = 0; i < parties_list.length; i++) { var p_id = parties_list[i]; - shares[p_id] = polynomial[0]; - var power = jiff.helpers.get_party_number(p_id); - - for (var j = 1; j < polynomial.length; j++) { - var tmp = jiff.helpers.mod((polynomial[j] * power), Zp); - shares[p_id] = jiff.helpers.mod((shares[p_id] + tmp), Zp); - power = jiff.helpers.mod(power * jiff.helpers.get_party_number(p_id), Zp); + var p_ratio = p_id in parties_ratios ? parties_ratios[p_id] : 1; + shares[p_id] = []; + for (var share_num = 0; share_num < p_ratio; share_num++) { + shares[p_id][share_num] = polynomial[0]; + var power = jiff.helpers.get_party_number(p_id, share_num); + + for (var j = 1; j < polynomial.length; j++) { + var tmp = jiff.helpers.mod((polynomial[j] * power), Zp); + shares[p_id][share_num] = jiff.helpers.mod((shares[p_id][share_num] + tmp), Zp); + power = jiff.helpers.mod(power * jiff.helpers.get_party_number(p_id, share_num), Zp); + } } } - return shares; } @@ -352,7 +363,10 @@ */ function receive_share(jiff, json_msg) { // Decrypt share - json_msg['share'] = jiff.hooks.decryptSign(jiff, json_msg['share'], jiff.secret_key, jiff.keymap[json_msg['party_id']]); + var num_shares = json_msg['share'].length; + for (var i = 0; i < num_shares; i++) { + json_msg['share'][i] = jiff.hooks.decryptSign(jiff, json_msg['share'][i], jiff.secret_key, jiff.keymap[json_msg['party_id']]); + } json_msg = jiff.execute_array_hooks('afterOperation', [jiff, 'share', json_msg], 2); var sender_id = json_msg['party_id']; @@ -452,6 +466,7 @@ // Party is a receiver if (parties.indexOf(jiff.id) > -1) { var shares = []; // this will store received shares + var numberofshares = 0; var final_deferred = new Deferred(); // will be resolved when the final value is reconstructed var final_promise = final_deferred.promise; for (i = 0; i < share.holders.length; i++) { @@ -473,9 +488,10 @@ promise.then(function (received_share) { jiff.deferreds[op_ids[jiff.id]][p_id] = null; shares.push(received_share); + numberofshares = numberofshares + received_share.value.length; // Too few shares, nothing to do. - if (shares.length < share.threshold) { + if (numberofshares < share.threshold) { return; } @@ -484,7 +500,6 @@ if (final_deferred != null) { var recons_secret = jiff.hooks.reconstructShare(jiff, shares); recons_secret = jiff.execute_array_hooks('afterReconstructShare', [jiff, recons_secret], 1); - final_deferred.resolve(recons_secret); final_deferred = null; } @@ -518,15 +533,17 @@ for (var index = 0; index < parties.length; index++) { var i = parties[index]; // Party id if (i === jiff.id) { - receive_open(jiff, { party_id: i, share: share.value, op_id: op_ids[i], Zp: share.Zp }); + receive_open(jiff, {party_id: i, share: share.value, op_id: op_ids[i], Zp: share.Zp}); continue; } // encrypt, sign and send - var msg = {party_id: i, share: share.value, op_id: op_ids[i], Zp: share.Zp}; + var msg = {party_id: i, share: share.value.slice(), op_id: op_ids[i], Zp: share.Zp}; msg = jiff.execute_array_hooks('beforeOperation', [jiff, 'open', msg], 2); - msg['share'] = jiff.hooks.encryptSign(jiff, msg['share'].toString(), jiff.keymap[msg['party_id']], jiff.secret_key); + for (var j = 0; j < msg['share'].length; j++) { + msg['share'][j] = jiff.hooks.encryptSign(jiff, msg['share'][j].toString(), jiff.keymap[msg['party_id']], jiff.secret_key); + } jiff.socket.safe_emit('open', JSON.stringify(msg)); } } @@ -540,7 +557,9 @@ function receive_open(jiff, json_msg) { // Decrypt share if (json_msg['party_id'] !== jiff.id) { - json_msg['share'] = jiff.hooks.decryptSign(jiff, json_msg['share'], jiff.secret_key, jiff.keymap[json_msg['party_id']]); + for (var i = 0; i < json_msg['share'].length; i++) { + json_msg['share'][i] = jiff.hooks.decryptSign(jiff, json_msg['share'][i], jiff.secret_key, jiff.keymap[json_msg['party_id']]); + } json_msg = jiff.execute_array_hooks('afterOperation', [jiff, 'open', json_msg], 2); } @@ -576,17 +595,21 @@ function jiff_lagrange(jiff, shares) { var lagrange_coeff = []; // will contain shares.length many elements. - // Compute the Langrange coefficients at 0. + // Compute the Lagrange coefficients at 0. for (var i = 0; i < shares.length; i++) { - var pi = jiff.helpers.get_party_number(shares[i].sender_id); - lagrange_coeff[pi] = 1; - - for (var j = 0; j < shares.length; j++) { - var pj = jiff.helpers.get_party_number(shares[j].sender_id); - if (pj !== pi) { - var inv = jiff.helpers.extended_gcd(pi - pj, shares[i].Zp)[0]; - lagrange_coeff[pi] = jiff.helpers.mod(lagrange_coeff[pi] * (0 - pj), shares[i].Zp) * inv; - lagrange_coeff[pi] = jiff.helpers.mod(lagrange_coeff[pi], shares[i].Zp); + for (var share_num = 0; share_num < shares[i].value.length; share_num++) { + var pi = jiff.helpers.get_party_number(shares[i].sender_id, share_num); + lagrange_coeff[pi] = 1; + + for (var j = 0; j < shares.length; j++) { + for (var n = 0; n < shares[j].value.length; n++) { + var pj = jiff.helpers.get_party_number(shares[j].sender_id, n); + if (pj !== pi) { + var inv = jiff.helpers.extended_gcd(pi - pj, shares[i].Zp)[0]; + lagrange_coeff[pi] = jiff.helpers.mod(lagrange_coeff[pi] * (0 - pj), shares[i].Zp) * inv; + lagrange_coeff[pi] = jiff.helpers.mod(lagrange_coeff[pi], shares[i].Zp); + } + } } } } @@ -594,11 +617,12 @@ // Reconstruct the secret via Lagrange interpolation var recons_secret = 0; for (var p = 0; p < shares.length; p++) { - var party = jiff.helpers.get_party_number(shares[p].sender_id); - var tmp = jiff.helpers.mod((shares[p].value * lagrange_coeff[party]), shares[p].Zp); - recons_secret = jiff.helpers.mod((recons_secret + tmp), shares[p].Zp); + for (share_num = 0; share_num < shares[p].value.length; share_num++) { + var party = jiff.helpers.get_party_number(shares[p].sender_id, share_num); + var tmp = jiff.helpers.mod((shares[p].value[share_num] * lagrange_coeff[party]), shares[p].Zp); + recons_secret = jiff.helpers.mod((recons_secret + tmp), shares[p].Zp); + } } - return recons_secret; } @@ -1298,7 +1322,7 @@ * @param {jiff-instance} jiff - the jiff instance. * @param {boolean} ready - whether the value of the share is ready or deferred. * @param {promise} promise - a promise to the value of the share. - * @param {number} value - the value of the share (null if not ready). + * @param {Array} value - the value of the share (null if not ready). * @param {Array} holders - the parties that hold all the corresponding shares (must be sorted). * @param {number} threshold - the min number of parties needed to reconstruct the secret. * @param {number} Zp - the mod under which this share was created. @@ -1377,7 +1401,7 @@ */ self.promise = promise; /** - * @member {number} value + * @member {Array} value * @memberof SecretShare * @instance */ @@ -1532,7 +1556,8 @@ * @instance */ self.refresh = function (op_id) { - return self.isadd(self.jiff.server_generate_and_share({number: 0}, self.holders, self.threshold, self.Zp, op_id)[0]); + return self + //return self.isadd(self.jiff.server_generate_and_share({number: 0}, self.holders, self.threshold, self.Zp, op_id)[0]); }; /** @@ -3374,7 +3399,9 @@ // parse content of share/open messages to be integers (instead of strings due to encryption/decryption) jiff.hooks.afterOperation.unshift(function (jiff, label, msg) { if (label === 'share' || label === 'open') { - msg['share'] = parseInt(msg['share'], 10); + for (var i = 0; i < msg['share'].length; i++) { + msg['share'][i] = parseInt(msg['share'][i], 10); + } } return msg; }); @@ -3851,14 +3878,17 @@ * @param {number/string} party_id - the party id from which to compute the number. * @return {number} the party number (> 0). */ - jiff.helpers.get_party_number = function (party_id) { + jiff.helpers.get_party_number = function (party_id, share_num) { + if (share_num == null){ + share_num = 0; + } if (typeof(party_id) === 'number') { - return party_id; + return party_id + (share_num * (jiff.party_count+1)); } if (party_id.startsWith('s')) { - return -1 * parseInt(party_id.substring(1), 10); + return parseInt(party_id.substring(1), 10) * (jiff.party_count+1); // n+1 reserved for server } - return parseInt(party_id, 10); + return parseInt(party_id, 10) + (share_num * (jiff.party_count+1)); }; /** @@ -3903,7 +3933,7 @@ * and the value is the share object that wraps * the value sent from that party (the internal value maybe deferred). */ - jiff.share = function (secret, threshold, receivers_list, senders_list, Zp, share_id) { + jiff.share = function (secret, threshold, receivers_list, senders_list, Zp, share_id, receivers_ratios) { // type check to confirm the secret to be shared is a number // for fixed-point extension it should allow non-ints if (secret != null && (typeof(secret) !== 'number' || Math.floor(secret) !== secret || secret < 0)) { @@ -3912,14 +3942,14 @@ if (secret != null && (secret >= (Zp == null ? jiff.Zp : Zp))) { throw new Error('secret must fit inside Zp'); } - return jiff.internal_share(secret, threshold, receivers_list, senders_list, Zp, share_id); + return jiff.internal_share(secret, threshold, receivers_list, senders_list, Zp, share_id, receivers_ratios); }; /** * Same as jiff-instance.share, but used by internal JIFF primitives/protocols (bgw). */ - jiff.internal_share = function (secret, threshold, receivers_list, senders_list, Zp, share_id) { - return jiff_share(jiff, secret, threshold, receivers_list, senders_list, Zp, share_id); + jiff.internal_share = function (secret, threshold, receivers_list, senders_list, Zp, share_id, receivers_ratios) { + return jiff_share(jiff, secret, threshold, receivers_list, senders_list, Zp, share_id, receivers_ratios); }; /** @@ -4728,7 +4758,7 @@ // Setup receiving matching shares jiff.socket.on('share', function (msg, callback) { - callback(true); // send ack to server + callback(true); // send back to server // parse message var json_msg = JSON.parse(msg);