diff --git a/lib/client/protocols/arrays/api.js b/lib/client/protocols/arrays/api.js index ee15ada33..25b0cb46a 100644 --- a/lib/client/protocols/arrays/api.js +++ b/lib/client/protocols/arrays/api.js @@ -1,17 +1,20 @@ -const share = require('./share.js'); -const open = require('./open.js'); +const _ArrayShare = require('./share.js'); +const _ArrayOpen = require('./open.js'); const util = require('./util.js'); +const ArrayOpen = new _ArrayOpen(); +const ArrayShare = new _ArrayShare(); + module.exports = { - jiff_share_array: share.share_array, - jiff_share_2D_array: share.share_2D_array, - jiff_share_ND_array: share.share_ND_array, - jiff_share_ND_array_static: share.share_ND_array_static, - jiff_share_ND_array_deferred: share.share_ND_array_deferred, + jiff_share_array: ArrayShare.share_array, + jiff_share_2D_array: ArrayShare.share_2D_array, + jiff_share_ND_array: ArrayShare.share_ND_array, + jiff_share_ND_array_static: ArrayShare.share_ND_array_static, + jiff_share_ND_array_deferred: ArrayShare.share_ND_array_deferred, jiff_skeleton_of: util.skeleton_of, - jiff_open_array: open.open_array, - jiff_open_ND_array: open.open_ND_array, - jiff_receive_open_ND_array: open.receive_open_ND_array + jiff_open_array: ArrayOpen.open_array, + jiff_open_ND_array: ArrayOpen.open_ND_array, + jiff_receive_open_ND_array: ArrayOpen.receive_open_ND_array }; diff --git a/lib/client/protocols/arrays/open.js b/lib/client/protocols/arrays/open.js index fd85c5d16..f8646d523 100644 --- a/lib/client/protocols/arrays/open.js +++ b/lib/client/protocols/arrays/open.js @@ -1,76 +1,60 @@ -const open_array = function (jiff, shares, parties, op_ids) { - // A base operation id is provided to use for all opens. - if (typeof op_ids === 'string' || typeof op_ids === 'number') { - const tmp = { s1: op_ids }; - for (let i = 1; i <= jiff.party_count; i++) { - tmp[i] = op_ids; +class ArrayOpen { + open_array = (jiff, shares, parties, op_ids) => { + // A base operation id is provided to use for all opens. + if (typeof op_ids === 'string' || typeof op_ids === 'number') { + const tmp = { s1: op_ids }; + for (let i = 1; i <= jiff.party_count; i++) { + tmp[i] = op_ids; + } + op_ids = tmp; } - op_ids = tmp; - } - return open_ND_array(jiff, shares, parties, null, op_ids); -}; + return this.open_ND_array(jiff, shares, parties, null, op_ids); + }; -const open_ND_array = function (jiff, shares, receivers_list, senders_list, op_ids) { - if (senders_list == null) { - senders_list = []; - for (let i = 1; i <= jiff.party_count; i++) { - senders_list.push(i); - } - if (receivers_list == null) { - receivers_list = Array.from(senders_list); + open_ND_array = (jiff, shares, receivers_list, senders_list, op_ids) => { + if (senders_list == null) { + senders_list = []; + for (let i = 1; i <= jiff.party_count; i++) { + senders_list.push(i); + } + if (receivers_list == null) { + receivers_list = Array.from(senders_list); + } } - } - const is_sending = senders_list.indexOf(jiff.id) > -1; + const is_sending = senders_list.indexOf(jiff.id) > -1; - // Compute operation id - /* - *if (op_ids == null) { - * op_ids = jiff.counters.gen_op_id('open_ND_array', receivers_list.concat(senders_list)); - *} - */ + // Compute operation id + /* + *if (op_ids == null) { + * op_ids = jiff.counters.gen_op_id('open_ND_array', receivers_list.concat(senders_list)); + *} + */ - const final_deferred = jiff.helpers.createDeferred(); - const final_promise = final_deferred.promise; - const resolve_open = function (shares) { - final_deferred.resolve( - (function __open_ND_array(shares, parties, op_ids) { - if (typeof shares.length === 'undefined') { - return jiff.internal_open(shares, parties); - } else if (shares.length === 0) { - return Promise.resolve([]); - } else { - const promised_array = []; - for (let i = 0; i < shares.length; i++) { - promised_array.push(__open_ND_array(shares[i], parties, op_ids + ':' + i)); + const final_deferred = jiff.helpers.createDeferred(); + const final_promise = final_deferred.promise; + function resolve_open(shares) { + final_deferred.resolve( + (function __open_ND_array(shares, parties, op_ids) { + if (typeof shares.length === 'undefined') { + return jiff.internal_open(shares, parties); + } else if (shares.length === 0) { + return Promise.resolve([]); + } else { + const promised_array = []; + for (let i = 0; i < shares.length; i++) { + promised_array.push(__open_ND_array(shares[i], parties, op_ids + ':' + i)); + } + return Promise.all(promised_array); } - return Promise.all(promised_array); - } - })(shares, receivers_list, op_ids) - ); - }; - - if (is_sending) { - // Must emit the skeleton for any parties that are not holders but are receiving the open - const skeleton = (function __unwipe(nd_array, replace) { - if (!(typeof nd_array.length === 'undefined') || nd_array.length === 0) { - const unwiped_array = []; - for (let k = 0; k < nd_array.length; k++) { - unwiped_array.push(__unwipe(nd_array[k], replace)); - } - return unwiped_array; - } - return replace; - })(shares, null); - jiff.emit(op_ids + 'skeleton', receivers_list, JSON.stringify(skeleton)); + })(shares, receivers_list, op_ids) + ); + } - resolve_open(shares); - } else { - // Populate skeleton with imitation shares - const revive_shares = function (skeleton) { - const share = new jiff.SecretShare({}, senders_list, senders_list.length, jiff.Zp); - return (function __unwipe(nd_array, replace) { - if (nd_array != null && !(typeof nd_array.length === 'undefined' && nd_array.length > 0)) { + if (is_sending) { + // Must emit the skeleton for any parties that are not holders but are receiving the open + const skeleton = (function __unwipe(nd_array, replace) { + if (!(typeof nd_array.length === 'undefined') || nd_array.length === 0) { const unwiped_array = []; for (let k = 0; k < nd_array.length; k++) { unwiped_array.push(__unwipe(nd_array[k], replace)); @@ -78,38 +62,52 @@ const open_ND_array = function (jiff, shares, receivers_list, senders_list, op_i return unwiped_array; } return replace; - })(skeleton, share); - }; + })(shares, null); + jiff.emit(op_ids + 'skeleton', receivers_list, JSON.stringify(skeleton)); - // If this party is not a sender, then the variable `shares` may be a skeleton - if (shares != null) { - // Use existing shares as skeleton to revive - shares = revive_shares(shares); resolve_open(shares); } else { - // Receive skeleton from senders - jiff.listen(op_ids + 'skeleton', function (sender, skeleton) { - jiff.remove_listener(op_ids + 'skeleton'); // This doesn't seem to work - - if (typeof skeleton === 'string') { - skeleton = JSON.parse(skeleton); - } + // Populate skeleton with imitation shares + const revive_shares = function (skeleton) { + const share = new jiff.SecretShare({}, senders_list, senders_list.length, jiff.Zp); + return (function __unwipe(nd_array, replace) { + if (nd_array != null && !(typeof nd_array.length === 'undefined' && nd_array.length > 0)) { + const unwiped_array = []; + for (let k = 0; k < nd_array.length; k++) { + unwiped_array.push(__unwipe(nd_array[k], replace)); + } + return unwiped_array; + } + return replace; + })(skeleton, share); + }; - shares = revive_shares(skeleton); + // If this party is not a sender, then the variable `shares` may be a skeleton + if (shares != null) { + // Use existing shares as skeleton to revive + shares = revive_shares(shares); resolve_open(shares); - }); + } else { + // Receive skeleton from senders + jiff.listen(op_ids + 'skeleton', function (sender, skeleton) { + jiff.remove_listener(op_ids + 'skeleton'); // This doesn't seem to work + + if (typeof skeleton === 'string') { + skeleton = JSON.parse(skeleton); + } + + shares = revive_shares(skeleton); + resolve_open(shares); + }); + } } - } - return final_promise; -}; + return final_promise; + }; -const receive_open_ND_array = function (jiff, receivers_list, senders_list, threshold, Zp, op_ids) { - return open_ND_array(jiff, null, receivers_list, senders_list, op_ids); -}; + receive_open_ND_array = (jiff, receivers_list, senders_list, threshold, Zp, op_ids) => { + return this.open_ND_array(jiff, null, receivers_list, senders_list, op_ids); + }; +} -module.exports = { - open_array: open_array, - open_ND_array: open_ND_array, - receive_open_ND_array: receive_open_ND_array -}; +module.exports = ArrayOpen; diff --git a/lib/client/protocols/arrays/share.js b/lib/client/protocols/arrays/share.js index 2b6ec7f85..54f3e90f4 100644 --- a/lib/client/protocols/arrays/share.js +++ b/lib/client/protocols/arrays/share.js @@ -1,14 +1,64 @@ const util = require('./util.js'); -const share_array = function (jiff, array, lengths, threshold, receivers_list, senders_list, Zp, share_id) { - let skeletons = null; - if (lengths != null) { +class ArrayShare { + share_array = (jiff, array, lengths, threshold, receivers_list, senders_list, Zp, share_id) => { + let skeletons = null; + if (lengths != null) { + // Check format of lengths + if (lengths != null && typeof lengths !== 'number' && typeof lengths !== 'object') { + throw new Error('share_array: unrecognized lengths'); + } + + // Get senders list for later checking + if (senders_list == null) { + senders_list = []; + for (let i = 1; i <= jiff.party_count; i++) { + senders_list.push(i); + } + } + + // Generate skeletons from lengths + skeletons = {}; + if (typeof lengths === 'number') { + // All arrays are of the same length + let skeleton = []; + for (let i = 0; i < lengths; i++) { + skeleton.push(null); + } + for (let i = 0; i < senders_list.length; i++) { + skeletons[senders_list[i]] = skeleton; + } + } else { + // Lengths of the different arrays are all provided + for (let i = 0; i < senders_list.length; i++) { + if (lengths[senders_list[i]] == null) { + throw new Error('share_array: missing length'); + } else { + skeletons[senders_list[i]] = []; + for (let j = 0; j < lengths[senders_list[i]]; j++) { + skeletons[senders_list[i]].push(null); + } + } + } + } + } + + return this.share_ND_array(jiff, array, skeletons, threshold, receivers_list, senders_list, Zp, share_id); + }; + + share_2D_array = (jiff, array, lengths, threshold, receivers_list, senders_list, Zp, share_id) => { // Check format of lengths - if (lengths != null && typeof lengths !== 'number' && typeof lengths !== 'object') { + if (lengths != null && typeof lengths !== 'object') { throw new Error('share_array: unrecognized lengths'); } - // Get senders list for later checking + // Default values + if (receivers_list == null) { + receivers_list = []; + for (let i = 1; i <= jiff.party_count; i++) { + receivers_list.push(i); + } + } if (senders_list == null) { senders_list = []; for (let i = 1; i <= jiff.party_count; i++) { @@ -16,337 +66,286 @@ const share_array = function (jiff, array, lengths, threshold, receivers_list, s } } - // Generate skeletons from lengths - skeletons = {}; - if (typeof lengths === 'number') { - // All arrays are of the same length - let skeleton = []; - for (let i = 0; i < lengths; i++) { - skeleton.push(null); + const isReceiving = receivers_list.indexOf(jiff.id) > -1; + if (senders_list.indexOf(jiff.id) === -1 && !isReceiving) { + // This party is neither a sender nor a receiver, do nothing! + return null; + } + + // compute operation id + receivers_list.sort(); // sort to get the same order + senders_list.sort(); + if (share_id == null) { + share_id = jiff.counters.gen_share_id(receivers_list, senders_list) + ':array:'; + } + + // wrap around result of share_array + const lengths_deferred = jiff.helpers.createDeferred(); + const lengths_promise = lengths_deferred.promise; + + // figure out lengths by having each party emit their length publicly + if (lengths == null) { + lengths = {}; + let total = 0; + if (senders_list.indexOf(jiff.id) > -1) { + lengths[jiff.id] = array.length; + + // send the length of this party's array to all receivers + jiff.emit(share_id + 'length', receivers_list, array.length.toString(10)); } + + jiff.listen(share_id + 'length', function (sender, message) { + lengths[sender] = { rows: parseInt(message, 10) }; + total++; + if (total === senders_list.length) { + jiff.remove_listener(share_id + 'length'); + lengths_deferred.resolve(lengths); + } + }); + } else if (typeof lengths.rows === 'number') { + // All arrays are of the same length + const l = lengths; + lengths = {}; for (let i = 0; i < senders_list.length; i++) { - skeletons[senders_list[i]] = skeleton; + lengths[senders_list[i]] = l; } + + lengths_deferred.resolve(lengths); } else { // Lengths of the different arrays are all provided for (let i = 0; i < senders_list.length; i++) { - if (lengths[senders_list[i]] == null) { - throw new Error('share_array: missing length'); - } else { - skeletons[senders_list[i]] = []; - for (let j = 0; j < lengths[senders_list[i]]; j++) { - skeletons[senders_list[i]].push(null); - } + if (lengths[senders_list[i]] == null || lengths[senders_list[i]].rows == null) { + throw new Error('share_2D_array: missing rows length'); } } - } - } - - return share_ND_array(jiff, array, skeletons, threshold, receivers_list, senders_list, Zp, share_id); -}; - -const share_2D_array = function (jiff, array, lengths, threshold, receivers_list, senders_list, Zp, share_id) { - // Check format of lengths - if (lengths != null && typeof lengths !== 'object') { - throw new Error('share_array: unrecognized lengths'); - } - - // Default values - if (receivers_list == null) { - receivers_list = []; - for (let i = 1; i <= jiff.party_count; i++) { - receivers_list.push(i); - } - } - if (senders_list == null) { - senders_list = []; - for (let i = 1; i <= jiff.party_count; i++) { - senders_list.push(i); - } - } - - const isReceiving = receivers_list.indexOf(jiff.id) > -1; - if (senders_list.indexOf(jiff.id) === -1 && !isReceiving) { - // This party is neither a sender nor a receiver, do nothing! - return null; - } - - // compute operation id - receivers_list.sort(); // sort to get the same order - senders_list.sort(); - if (share_id == null) { - share_id = jiff.counters.gen_share_id(receivers_list, senders_list) + ':array:'; - } - - // wrap around result of share_array - const lengths_deferred = jiff.helpers.createDeferred(); - const lengths_promise = lengths_deferred.promise; - - // figure out lengths by having each party emit their length publicly - if (lengths == null) { - lengths = {}; - let total = 0; - if (senders_list.indexOf(jiff.id) > -1) { - lengths[jiff.id] = array.length; - - // send the length of this party's array to all receivers - jiff.emit(share_id + 'length', receivers_list, array.length.toString(10)); - } - jiff.listen(share_id + 'length', function (sender, message) { - lengths[sender] = { rows: parseInt(message, 10) }; - total++; - if (total === senders_list.length) { - jiff.remove_listener(share_id + 'length'); - lengths_deferred.resolve(lengths); - } - }); - } else if (typeof lengths.rows === 'number') { - // All arrays are of the same length - const l = lengths; - lengths = {}; - for (let i = 0; i < senders_list.length; i++) { - lengths[senders_list[i]] = l; - } - - lengths_deferred.resolve(lengths); - } else { - // Lengths of the different arrays are all provided - for (let i = 0; i < senders_list.length; i++) { - if (lengths[senders_list[i]] == null || lengths[senders_list[i]].rows == null) { - throw new Error('share_2D_array: missing rows length'); - } + lengths_deferred.resolve(lengths); } - lengths_deferred.resolve(lengths); - } - - // Final results - const share_array_deferred = jiff.helpers.createDeferred(); - const share_array_promise = share_array_deferred.promise; + // Final results + const share_array_deferred = jiff.helpers.createDeferred(); + const share_array_promise = share_array_deferred.promise; - // lengths are now set, start sharing - lengths_promise.then(function (lengths) { - // compute the number of sharing rounds - let max = 0; - for (let i = 0; i < senders_list.length; i++) { - const l = lengths[senders_list[i]].rows; - max = l > max ? l : max; - } - - // share every round - const promises = []; - for (let r = 0; r < max; r++) { - const round_senders = []; + // lengths are now set, start sharing + lengths_promise.then(function (lengths) { + // compute the number of sharing rounds + let max = 0; for (let i = 0; i < senders_list.length; i++) { - if (lengths[senders_list[i]].rows > r) { - round_senders.push(senders_list[i]); - } + const l = lengths[senders_list[i]].rows; + max = l > max ? l : max; } - let row_lengths = {}; - let empty = false; - for (let p = 0; p < round_senders.length; p++) { - const pid = round_senders[p]; - row_lengths[pid] = lengths[pid].cols; - if (lengths[pid][r] != null) { - row_lengths[pid] = lengths[pid][r]; + // share every round + const promises = []; + for (let r = 0; r < max; r++) { + const round_senders = []; + for (let i = 0; i < senders_list.length; i++) { + if (lengths[senders_list[i]].rows > r) { + round_senders.push(senders_list[i]); + } } - if (row_lengths[pid] == null) { - empty = true; + + let row_lengths = {}; + let empty = false; + for (let p = 0; p < round_senders.length; p++) { + const pid = round_senders[p]; + row_lengths[pid] = lengths[pid].cols; + if (lengths[pid][r] != null) { + row_lengths[pid] = lengths[pid][r]; + } + if (row_lengths[pid] == null) { + empty = true; + } } - } - const row = r < array.length ? array[r] : []; - row_lengths = empty ? null : row_lengths; - let round_results = share_array(jiff, row, row_lengths, threshold, receivers_list, round_senders, Zp, share_id + 'row' + r + ':'); - promises.push(round_results); - } + const row = r < array.length ? array[r] : []; + row_lengths = empty ? null : row_lengths; + let round_results = this.share_array(jiff, row, row_lengths, threshold, receivers_list, round_senders, Zp, share_id + 'row' + r + ':'); + promises.push(round_results); + } - // Wait for every promises corresponding to every row - return Promise.all(promises).then(function (intermediate_results) { - // Store results here - const results = {}; - if (isReceiving) { - for (let i = 0; i < senders_list.length; i++) { - results[senders_list[i]] = []; + // Wait for every promises corresponding to every row + return Promise.all(promises).then(function (intermediate_results) { + // Store results here + const results = {}; + if (isReceiving) { + for (let i = 0; i < senders_list.length; i++) { + results[senders_list[i]] = []; + } } - } - for (let i = 0; i < intermediate_results.length; i++) { - const round = intermediate_results[i]; - for (let sender_id in round) { - if (round.hasOwnProperty(sender_id)) { - results[sender_id].push(round[sender_id]); + for (let i = 0; i < intermediate_results.length; i++) { + const round = intermediate_results[i]; + for (let sender_id in round) { + if (round.hasOwnProperty(sender_id)) { + results[sender_id].push(round[sender_id]); + } } } - } - share_array_deferred.resolve(results); + share_array_deferred.resolve(results); + }); }); - }); - - return isReceiving ? share_array_promise : null; -}; - -const share_from_skeleton_unbound = function (jiff, that, sender, skeleton) { - const shares = typeof skeleton === 'string' ? JSON.parse(skeleton) : skeleton; - - const promise = share_array_single_sender(jiff, shares, that.threshold, that.receivers_list, sender, that.Zp, that.share_id + ':p_id_' + sender); - - promise.then( - function (sender, array) { - that.deferreds[sender].resolve(array); - }.bind(null, sender) - ); -}; - -const share_array_single_sender = function (jiff, secrets, threshold, receivers_list, sender, Zp, share_id) { - if (secrets != null && secrets.length === 0) { - return Promise.resolve([]); - } else if (secrets != null && Array.isArray(secrets)) { - const promised_array = []; - for (let j = 0; j < secrets.length; j++) { - promised_array.push(share_array_single_sender(jiff, secrets[j], threshold, receivers_list, sender, Zp, share_id + ':' + j)); + + return isReceiving ? share_array_promise : null; + }; + + share_from_skeleton_unbound = (jiff, that, sender, skeleton) => { + const shares = typeof skeleton === 'string' ? JSON.parse(skeleton) : skeleton; + + const promise = this.share_array_single_sender(jiff, shares, that.threshold, that.receivers_list, sender, that.Zp, that.share_id + ':p_id_' + sender); + + promise.then( + function (sender, array) { + that.deferreds[sender].resolve(array); + }.bind(null, sender) + ); + }; + + share_array_single_sender = (jiff, secrets, threshold, receivers_list, sender, Zp, share_id) => { + if (secrets != null && secrets.length === 0) { + return Promise.resolve([]); + } else if (secrets != null && Array.isArray(secrets)) { + const promised_array = []; + for (let j = 0; j < secrets.length; j++) { + const curr_sec = secrets[parseInt(j, 10)]; + promised_array.push(this.share_array_single_sender(jiff, curr_sec, threshold, receivers_list, sender, Zp, share_id + ':' + j)); + } + + const isReceiving = receivers_list.indexOf(jiff.id) > -1; + let deferred_array; + if (isReceiving) { + deferred_array = jiff.helpers.createDeferred(); + Promise.all(promised_array).then(function (array) { + deferred_array.resolve(array); + }); + } + + return isReceiving ? deferred_array.promise : Promise.resolve({}); + } else { + // Create and distribute the share - Note: Senders are reorganized in the final array. + // The return value of jiff.share is an array, [sender: share], and we only need to return share by itself. + return Promise.resolve(jiff.share(secrets, threshold, receivers_list, [sender], Zp, 'share:' + share_id)[sender]); } + }; + share_ND_array_deferred = (jiff, secrets, skeletons, threshold, receivers_list, senders_list, Zp, share_id) => { + const parameters = [receivers_list, senders_list, threshold, Zp, share_id]; + [receivers_list, senders_list, threshold, Zp, share_id] = util.sanitize_array_params.bind(null, jiff).apply(null, parameters); + + let skeleton; const isReceiving = receivers_list.indexOf(jiff.id) > -1; - let deferred_array; - if (isReceiving) { - deferred_array = jiff.helpers.createDeferred(); - Promise.all(promised_array).then(function (array) { - deferred_array.resolve(array); - }); + const isSending = senders_list.indexOf(jiff.id) > -1; + if (!isSending && !isReceiving) { + return null; // This party is neither a sender nor a receiver, do nothing! } - return isReceiving ? deferred_array.promise : Promise.resolve({}); - } else { - // Create and distribute the share - Note: Senders are reorganized in the final array. - // The return value of jiff.share is an array, [sender: share], and we only need to return share by itself. - return Promise.resolve(jiff.share(secrets, threshold, receivers_list, [sender], Zp, 'share:' + share_id)[sender]); - } -}; - -const share_ND_array_deferred = function (jiff, secrets, skeletons, threshold, receivers_list, senders_list, Zp, share_id) { - const parameters = [receivers_list, senders_list, threshold, Zp, share_id]; - [receivers_list, senders_list, threshold, Zp, share_id] = util.sanitize_array_params.bind(null, jiff).apply(null, parameters); - - let skeleton; - const isReceiving = receivers_list.indexOf(jiff.id) > -1; - const isSending = senders_list.indexOf(jiff.id) > -1; - if (!isSending && !isReceiving) { - return null; // This party is neither a sender nor a receiver, do nothing! - } - - // Setup deferreds: required because we don't yet know how many shares to account for - const final_deferreds = []; - for (let i = 0; i < senders_list.length; i++) { - const p_id = senders_list[i]; - final_deferreds[p_id] = jiff.helpers.createDeferred(); - } - - const share_from_skeleton = share_from_skeleton_unbound.bind(null, jiff).bind(null, { - deferreds: final_deferreds, - threshold: threshold, - receivers_list: receivers_list, - Zp: Zp, - share_id: share_id - }); - - if (skeletons == null) { - if (isSending) { - // Send the shape and lengths of this party's array to all receivers - skeleton = jiff.skeleton_of(secrets); // All secrets are removed while maintaing the array's orginial structure. - const skeleton_str = JSON.stringify(skeleton); // serialize for emit - jiff.emit(share_id + 'skeleton', receivers_list, skeleton_str); - share_from_skeleton(jiff.id, secrets); // Share the real values matching the emitted skeleton - } - if (isReceiving) { - jiff.listen(share_id + 'skeleton', share_from_skeleton); // Receive shares when dimensions are known - } - } else { - senders_list = Array.from(senders_list); // remove jiff helpers' internal properties - util.match_skeletons(jiff, skeletons, senders_list); // Saftey check array dimention presets - for (let i in senders_list) { - // Share each party's array + // Setup deferreds: required because we don't yet know how many shares to account for + const final_deferreds = []; + for (let i = 0; i < senders_list.length; i++) { const p_id = senders_list[i]; - const myself = p_id === jiff.id; - skeleton = skeletons[p_id]; - share_from_skeleton(p_id, myself ? secrets : skeleton); + final_deferreds[p_id] = jiff.helpers.createDeferred(); + } + + const share_from_skeleton = this.share_from_skeleton_unbound.bind(null, jiff).bind(null, { + deferreds: final_deferreds, + threshold: threshold, + receivers_list: receivers_list, + Zp: Zp, + share_id: share_id + }); + + if (skeletons == null) { + if (isSending) { + // Send the shape and lengths of this party's array to all receivers + skeleton = jiff.skeleton_of(secrets); // All secrets are removed while maintaing the array's orginial structure. + const skeleton_str = JSON.stringify(skeleton); // serialize for emit + jiff.emit(share_id + 'skeleton', receivers_list, skeleton_str); + share_from_skeleton(jiff.id, secrets); // Share the real values matching the emitted skeleton + } + if (isReceiving) { + jiff.listen(share_id + 'skeleton', share_from_skeleton); // Receive shares when dimensions are known + } + } else { + senders_list = Array.from(senders_list); // remove jiff helpers' internal properties + util.match_skeletons(jiff, skeletons, senders_list); // Saftey check array dimention presets + for (let i in senders_list) { + // Share each party's array + const p_id = senders_list[i]; + const myself = p_id === jiff.id; + skeleton = skeletons[p_id]; + share_from_skeleton(p_id, myself ? secrets : skeleton); + } } - } - - // Combine all promises and re-index final array map - const final_deferred = jiff.helpers.createDeferred(); - const final_promise = isReceiving ? final_deferred.promise : Promise.resolve({}); - Promise.all( - (function () { - const all_promises = []; + + // Combine all promises and re-index final array map + const final_deferred = jiff.helpers.createDeferred(); + const final_promise = isReceiving ? final_deferred.promise : Promise.resolve({}); + Promise.all( + (function () { + const all_promises = []; + for (let i = 0; i < senders_list.length; i++) { + const p_id = senders_list[i]; + all_promises.push(final_deferreds[p_id].promise); + } + return all_promises; + })() + ).then(function (array) { + const shares = {}; for (let i = 0; i < senders_list.length; i++) { const p_id = senders_list[i]; - all_promises.push(final_deferreds[p_id].promise); + shares[p_id] = array[i]; } - return all_promises; - })() - ).then(function (array) { + final_deferred.resolve(shares); + jiff.remove_listener(share_id + 'skeleton'); + }); + + return final_promise; // Return promise to map of secret-shared arrays + }; + + share_ND_array_static = (jiff, secrets, skeletons, threshold, receivers_list, senders_list, Zp, share_id) => { + const parameters = [receivers_list, senders_list, threshold, Zp, share_id]; + [receivers_list, senders_list, threshold, Zp, share_id] = util.sanitize_array_params.bind(null, jiff).apply(null, parameters); + const shares = {}; - for (let i = 0; i < senders_list.length; i++) { - const p_id = senders_list[i]; - shares[p_id] = array[i]; - } - final_deferred.resolve(shares); - jiff.remove_listener(share_id + 'skeleton'); - }); - - return final_promise; // Return promise to map of secret-shared arrays -}; - -const share_ND_array_static = function (jiff, secrets, skeletons, threshold, receivers_list, senders_list, Zp, share_id) { - const parameters = [receivers_list, senders_list, threshold, Zp, share_id]; - [receivers_list, senders_list, threshold, Zp, share_id] = util.sanitize_array_params.bind(null, jiff).apply(null, parameters); - - const shares = {}; - - const isReceiving = receivers_list.indexOf(jiff.id) > -1; - const isSending = senders_list.indexOf(jiff.id) > -1; - if (isSending || isReceiving) { - // Static version of share_from_skeleton - const share_from_skeleton = function (sender, skeleton) { - return (function share_recursive(__secrets, share_id) { - if (__secrets != null && __secrets.length === 0) { - return []; - } else if (__secrets != null && Array.isArray(__secrets)) { - const array = []; - for (let j = 0; j < __secrets.length; j++) { - array.push(share_recursive(__secrets[j], share_id + ':' + j)); + + const isReceiving = receivers_list.indexOf(jiff.id) > -1; + const isSending = senders_list.indexOf(jiff.id) > -1; + if (isSending || isReceiving) { + // Static version of share_from_skeleton + const share_from_skeleton = function (sender, skeleton) { + return (function share_recursive(__secrets, share_id) { + if (__secrets != null && __secrets.length === 0) { + return []; + } else if (__secrets != null && Array.isArray(__secrets)) { + const array = []; + for (let j = 0; j < __secrets.length; j++) { + array.push(share_recursive(__secrets[j], share_id + ':' + j)); + } + return isReceiving ? array : {}; + } else { + return jiff.share(__secrets, threshold, receivers_list, [sender], Zp, 'share:' + share_id)[sender]; } - return isReceiving ? array : {}; - } else { - return jiff.share(__secrets, threshold, receivers_list, [sender], Zp, 'share:' + share_id)[sender]; - } - })(skeleton, share_id + ':p_id_' + sender); - }; + })(skeleton, share_id + ':p_id_' + sender); + }; - senders_list = Array.from(senders_list); // remove jiff helpers' internal properties - util.match_skeletons(jiff, skeletons, senders_list); // Saftey check array dimention presets - for (let i in senders_list) { - // Share each party's array - const p_id = senders_list[i]; - const skeleton = skeletons[p_id]; - shares[p_id] = share_from_skeleton(p_id, p_id === jiff.id ? secrets : skeleton); + senders_list = Array.from(senders_list); // remove jiff helpers' internal properties + util.match_skeletons(jiff, skeletons, senders_list); // Saftey check array dimention presets + for (let i in senders_list) { + // Share each party's array + const p_id = senders_list[i]; + const skeleton = skeletons[p_id]; + shares[p_id] = share_from_skeleton(p_id, p_id === jiff.id ? secrets : skeleton); + } } - } - return isReceiving ? shares : {}; // Return promise to map of secret-shared arrays -}; + return isReceiving ? shares : {}; // Return promise to map of secret-shared arrays + }; -const share_ND_array = function (jiff, secrets, skeletons, threshold, receivers_list, senders_list, Zp, share_id) { - const share_ND_array = skeletons != null ? share_ND_array_static : share_ND_array_deferred; - return share_ND_array(jiff, secrets, skeletons, threshold, receivers_list, senders_list, Zp, share_id); -}; + share_ND_array = (jiff, secrets, skeletons, threshold, receivers_list, senders_list, Zp, share_id) => { + const share_ND_array = skeletons != null ? this.share_ND_array_static : this.share_ND_array_deferred; + return share_ND_array(jiff, secrets, skeletons, threshold, receivers_list, senders_list, Zp, share_id); + }; +} -module.exports = { - share_array: share_array, - share_2D_array: share_2D_array, - share_ND_array: share_ND_array -}; +module.exports = ArrayShare;