var shareProtocol = require('../protocols/shamir/share.js');
var openProtocol = require('../protocols/shamir/open.js');
var reshareProtocol = require('../protocols/shamir/reshare.js');
var arraysSharing = require('../protocols/arrays/api.js');
module.exports = function (jiffClient) {
/**
* Share a secret input
*
* Can be overriden by extensions to customize behavior
*
* @method share
* @memberof module:jiff-client~JIFFClient
* @instance
* @param {number} secret - the number to share (this party's input)
* @param {number} [threshold=receivers_list.length] - the minimum number of parties needed to reconstruct the secret, defaults to all the receivers
* @param {Array} [receivers_list=all_parties] - array of party ids to share with, by default, this includes all parties
* @param {Array} [senders_list=all_parties] - array of party ids to receive from, by default, this includes all parties
* @param {number} [Zp=jiff_instance.Zp] - the mod (if null then the default Zp for the instance is used)
* @param {string|number} [share_id=auto_gen()] - the tag used to tag the messages sent by this share operation, this tag is used
* so that parties distinguish messages belonging to this share operation from other
* share operations between the same parties (when the order of execution is not
* deterministic). An automatic id is generated by increasing a local counter, default
* ids suffice when all parties execute all sharing operations with the same senders
* and receivers in the same order
* @returns {object} a map (of size equal to the number of sending parties)
* where the key is the party id (between 1 and n), or 's1' if 's1' is specified in the senders_list,
* and the value is the share object that wraps the value received from that party (the internal value maybe
* deferred).
*
* @example
* // share an input value with all parties, and receive all other parties' inputs
* var shares = jiffClient.share(input);
* // my party id is '1', so the first share is mine (technically my share of my input value)
* var my_share = shares[1];
* // my share of party 2's input
* var p2_share = shares[2];
*/
jiffClient.share = function (secret, threshold, receivers_list, senders_list, Zp, share_id) {
// 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)) {
throw new Error('secret \'' + secret + '\' must be a non-negative whole number');
}
if (secret != null && (secret >= (Zp == null ? jiffClient.Zp : Zp))) {
throw new Error('secret \'' + secret + '\' must fit inside Zp');
}
return jiffClient.internal_share(secret, threshold, receivers_list, senders_list, Zp, share_id);
};
/**
* Same as share, but used by internal JIFF primitives/protocols, do not override this!
* @see {@link share}
* @method internal_share
* @instance
* @memberof module:jiff-client~JIFFClient
*/
jiffClient.internal_share = shareProtocol.jiff_share.bind(null, jiffClient);
/**
* re-share an existing share (value) under a new threshold or to a new set of parties or both.
* Do not use this to refresh a share (use {@link SecretShare#refresh} instead)
* @method reshare
* @instance
* @memberof module:jiff-client~JIFFClient
* @param {SecretShare} [share=null] - the share you would like to reshare (null if you are a receiver but not a sender)
* @param {number} [threshold=receivers_list.length] - the new threshold, defaults to the length of receivers_list param
* @param {Array} [receivers_list=all_parties] - array of party ids to receive from, by default, this includes all parties
* @param {Array} [senders_list=all_parties] - array of party ids that posses the share and will reshare it with the receivers, by default, this includes all parties
* @param {number} [Zp=jiff.Zp] - the Zp of the existing share
* @param {string} [op_id=auto_gen()] - the operation id which is used to identify this multiplication (and internally, the corresponding beaver triplet).
* This id must be unique, and must be passed by all parties to the same instruction.
* this ensures that every party gets a share from the same triplet for every matching instruction. An automatic id
* is generated by increasing a local counter, default ids suffice when all parties execute the
* instructions in the same order
* @return {SecretShare} this party's share of the result under the new threshold, or null if this party is not a receiver
*/
jiffClient.reshare = reshareProtocol.bind(null, jiffClient);
/**
* Open a secret share to reconstruct secret.
* @method open
* @memberof module:jiff-client~JIFFClient
* @instance
* @param {SecretShare} share - this party's share of the secret to reconstruct.
* @param {Array} [parties=all_parties] - an array with party ids (1 to n) of receiving parties.
* @param {string|number} [op_id=auto_gen()] - the operation id to be used to tag outgoing messages.
* @returns {?promise} a (JQuery) promise to the open value of the secret, null if the party is not specified in the parties array as a receiver.
* @example
* var shares = jiff_instance.share(input);
* //multiply the inputs of party 1 and 2 together
* var result = shares[1].mult(shares[2]);
* // reveal the result of the multiplication to all parties
* return jiff_instance.open(result);
*/
jiffClient.open = openProtocol.jiff_open.bind(null, jiffClient);
/**
* Same as open, but used by internal JIFF primitives/protocols, do not override this!
* @see {@link open}
* @method internal_open
* @instance
* @memberof module:jiff-client~JIFFClient
*/
jiffClient.internal_open = jiffClient.open;
/**
* Receive shares from the specified parties and reconstruct their secret.
* Use this function in a party that will receive some answer/value but does not have a share of it.
* @method receive_open
* @memberof module:jiff-client~JIFFClient
* @instance
* @param {Array} senders - an array with party ids (1 to n) specifying the parties sending the shares, this must be provided!
* @param {Array} [receivers=all_parties] - an array with party ids (1 to n) specifying the parties receiving the result
* @param {number} [threshold=senders.length] - the min number of parties needed to reconstruct the secret, defaults to all the senders
* @param {number} [Zp=jiff_instance.Zp] - the mod (if null then the default Zp for the instance is used)
* @param {string|number} [op_id=auto_Gen()] - same as jiff-instance.open
* @returns {!promise} a (JQuery) promise to the open value of the secret.
*/
jiffClient.receive_open = function (senders, receivers, threshold, Zp, op_id) {
if (senders == null) {
throw new Error('Must provide "senders" parameter in receive_open');
}
jiffClient.helpers.sort_ids(senders);
if (receivers == null) {
receivers = [];
for (var i = 1; i <= jiffClient.party_count; i++) {
receivers.push(i);
}
} else {
jiffClient.helpers.sort_ids(receivers);
}
if (Zp == null) {
Zp = jiffClient.Zp;
}
if (threshold == null) {
threshold = senders.length;
}
var imitationSecretShare = new jiffClient.SecretShare({}, senders, threshold, Zp);
return jiffClient.open(imitationSecretShare, receivers, op_id);
};
/**
* Receive arrays of shares from the specified parties and reconstruct their secrets.
* Use this function in a party that will receive some answer/value but does not have a share of it.
* @method receive_open
* @memberof module:jiff-client~JIFFClient
* @instance
* @param {Array} senders - an array with party ids (1 to n) specifying the parties sending the shares, this must be provided!
* @param {number} [threshold=senders.length] - the min number of parties needed to reconstruct the secret, defaults to all the senders
* @param {number} [Zp=jiff_instance.Zp] - the mod (if null then the default Zp for the instance is used)
* @param {string|number} [op_id=auto_Gen()] - same as jiff-instance.open
* @returns {!promise} a (JQuery) promise to the open value of the secret.
*/
jiffClient.receive_open_array = arraysSharing.jiff_receive_open_ND_array.bind(null, jiffClient);
/**
* Share an array of values. Each sender may have an array of different length. This is handled by the lengths parameter.
* This function will reveal the lengths of the shared array.
*
* If parties would like to keep the lengths of their arrays secret, they should agree on some public "max" length apriori (either under MPC
* or as part of the logistics of the computation), all their arrays should be padded to that length by using appropriate default/identity
* values
* @method share_array
* @memberof module:jiff-client~JIFFClient
* @instance
* @param {Array} array - the array to be shared.
* @param {null|number|object} [lengths] - the lengths of the arrays to be shared, has the following options: <br>
* 1. null: lengths are unknown, each sender will publicly reveal the lengths of its own array. <br>
* 2. number: all arrays are of this length <br>
* 3. object: { <sender_party_id>: length }: must specify the length of the array for each sender. <br>
* @param {number} [threshold=receivers_list.length] - the min number of parties needed to reconstruct the secret, defaults to all the receivers.
* @param {Array} [receivers_list=all_parties] - array of party ids to share with, by default, this includes all parties.
* @param {Array} [senders_list=all_parties] - array of party ids to receive from, by default, this includes all parties.
* @param {number} [Zp=jiff_instance.Zp] - the mod (if null then the default Zp for the instance is used).
* @param {string|number} [share_id=auto_gen()] - the base tag used to tag the messages sent by this share operation, every element of the array
* will get a unique id based on the concatenation of base_share_id and the index of the element.
* This tag is used so that parties distinguish messages belonging to this share operation from
* other share operations between the same parties (when the order of execution is not
* deterministic). An automatic id is generated by increasing a local counter, default
* ids suffice when all parties execute all sharing operations with the same senders
* and receivers in the same order.
* @returns {?promise} if the calling party is a receiver then a promise to the shared arrays is returned, the promise will provide an object
* formatted as follows: { <party_id>: [ <1st_share>, <2nd_share>, ..., <(lengths[party_id])th_share> ] }
* where the party_ids are those of the senders.
* if the calling party is not a receiver, then null is returned.
*/
jiffClient.share_array = arraysSharing.jiff_share_array.bind(null, jiffClient);
/**
* Share an array of values. Each sender may have an array of different length. This is handled by the lengths parameter.
* This function will reveal the lengths of the shared array.
*
* If parties would like to keep the lengths of their arrays secret, they should agree on some "max" length apriori (either under MPC
* or as part of the logistics of the computation), all their arrays should be padded to that length by using appropriate default/identity
* values.
* @method share_2D_array
* @memberof module:jiff-client~JIFFClient
* @instance
* @param {Array} array - the array to be shared.
* @param {null|number|object} lengths - the lengths of the arrays to be shared. For this to work successfully, the
* same exact value must be used in the calling code for each party. Any missing
* lengths for a row will be automatically publicly revealed by this function.
* Must have the following format:
* 1. null: lengths are unknown, each sender will publicly reveal the lengths of its own array.
* 2. { rows: <number>, cols: <number>, 0: <number>, 1: <number>, ...}: all parties have arrays
* with the given number of rows and cols. In case of jagged 2D arrays, different rows
* can have a different number of cols specified by using <row_index>: <col_size>.
* rows is mandatory, cols and any other number matching a specific row are optional.
* 3. { <sender_party_id>: <length_object> }: must specify the lengths for each party by using
* an object with the same format as 2. Must include every party.
* @param {number} [threshold=receivers_list.length] - the min number of parties needed to reconstruct the secret, defaults to all the receivers.
* @param {Array} [receivers_list=all_parties] - array of party ids to share with, by default, this includes all parties.
* @param {Array} [senders_list=all_parties] - array of party ids to receive from, by default, this includes all parties.
* @param {number} [Zp=jiff_instance.Zp] - the mod (if null then the default Zp for the instance is used).
* @param {string|number} [share_id=auto_gen()] - the base tag used to tag the messages sent by this share operation, every element of the array
* will get a unique id based on the concatenation of base_share_id and the index of the element.
* This tag is used so that parties distinguish messages belonging to this share operation from
* other share operations between the same parties (when the order of execution is not
* deterministic). An automatic id is generated by increasing a local counter, default
* ids suffice when all parties execute all sharing operations with the same senders
* and receivers in the same order.
* @returns {promise} if the calling party is a receiver then a promise to the shared arrays is returned, the promise will provide an object
* formatted as follows: { <party_id>: [ [ <1st_row_shares> ], [<2nd_row_share> ], ..., [ <(lengths[party_id])th_row_shares> ] ] }
* where the party_ids are those of the senders.
* if the calling party is not a receiver, then null is returned.
*/
jiffClient.share_2D_array = arraysSharing.jiff_share_2D_array.bind(null, jiffClient);
/**
* Share an n-dimensional array of secrets
* The arrays can be of different lengths and dimensions.
* @method share_ND_array
* @memberof module:jiff-client~JIFFClient
* @instance
* @returns {object|promise}
*/
jiffClient.share_ND_array = arraysSharing.jiff_share_ND_array.bind(null, jiffClient);
/**
* Helper function of share_ND_array
* This method gets called if share_ND_array does not have enough information
* to output an array of shares immediately. Instead it
* returns a promise to an object holding the unknown-size
* arrays from each sender.
* @method share_ND_array_deferred
* @memberof module:jiff-client~JIFFClient
* @instance
* @returns {promise}
*/
//jiffClient.share_ND_array_deferred = arraysSharing.jiff_share_ND_array_deferred.bind(null, jiffClient);
/**
* Helper function of share_ND_array
* This method gets called if share_ND_array when share_ND_array was given
* sufficients information (in the form of array skeletons) to
* infer the size and shape of each of the senders' arrays.
* This allows it to immediately return an object containing
* the secret-shared arrays from each sender.
* @method share_ND_array_static
* @memberof module:jiff-client~JIFFClient
* @instance
* @returns {object}
*/
//jiffClient.share_ND_array_static = arraysSharing.jiff_share_ND_array_static.bind(null, jiffClient);
/*
* Wipe a secret array of all secrets but preserve the shape
*/
jiffClient.skeleton_of = arraysSharing.jiff_skeleton_of.bind(null, jiffClient);
/**
* Opens an array of secret shares.
* @method open_array
* @memberof module:jiff-client~JIFFClient
* @instance
* @param {SecretShare[]} shares - an array containing this party's shares of the secrets to reconstruct.
* @param {Array<number|string|Array>} [parties=all_parties] - an array with party ids of receiving parties.
* This must be one of 3 cases:
* 1. null: open all shares to all parties.
* 2. array of numbers: open all shares to all the parties specified in the array.
* 3. array of array of numbers: open share with index i to the parties specified
* in the nested array at parties[i]. if parties[i] was null,
* then shares[i] will be opened to all parties.
* @param {string|number|object} [op_ids=auto_gen()] - an optional mapping that specifies the ID/Tag associated with each
* open message sent. Since open_array involves sending many messages per party,
* this parameter only specifies the BASE OPERATION ID. Each message sent will
* have this base id attached to it concatenated to a counter.
* If this is an object, then it should map an id of a receiving parties
* to the base op_id that should be used to tag the messages sent to that party.
* Parties left unmapped by this object will get an automatically generated id.
* If this is a number/string, then it will be used as the base id tagging all messages
* sent by this open to all parties.
* You can safely ignore this unless you have multiple opens each containing other opens.
* In that case, the order by which these opens are executed is not fully deterministic
* and depends on the order of arriving messages. In this case, use this parameter
* with every nested_open, to ensure ids are unique and define a total ordering on
* the execution of the opens (check implementation of slt for an example).
* @returns {promise} a (JQuery) promise to ALL the open values of the secret, the promise will yield
* a 2D array of values, each corresponding to the given share in the shares parameter
* at the same index. In the case where different values are opened to different parties, the order
* of the values will be preserved, but not the indices, there will be no blanks in the resulting arrays,
* the first share that is opened to this party will appear at index [0], even if it was not initially
* at [0].
* @throws error if some shares does not belong to the passed jiff instance.
*/
jiffClient.open_array = arraysSharing.jiff_open_array.bind(null, jiffClient);
/**
* Opens an n-dimensional array of secret shares.
* @method open_ND_array
* @memberof module:jiff-client~JIFFClient
* @instance
* @param {SecretShare|SecretShare[]|SecretShare[][]} shares - an n-dimensional array containing this party's shares of the secrets to reconstruct.
* @param {Array[]} [parties=all_parties] - an array with party ids (1 to n) of receiving parties.
* @param {string|number|object} [op_ids=auto_gen()] - an optional ID/Tag associated with these open operations
* @returns {promise} a (JQuery) promise to ALL the open values of the secret, the promise will yield
* an n-dimensional array of values, each corresponding to the given share in the shares parameter
* at the same index. In the case where different values are opened to different parties, the order
* of the values will be preserved, but not the indices, there will be no blanks in the resulting arrays,
* the first share that is opened to this party will appear at indices [0][0], even if it was not initially
* at [0][0].
* @throws error if some shares does not belong to the passed jiff instance.
*/
jiffClient.open_ND_array = arraysSharing.jiff_open_ND_array.bind(null, jiffClient);
};