client/util/utils.js

/**
 * Contains utility functions (higher order combinators)
 * @see {@link utils}
 * @name utils
 * @alias utils
 * @namespace
 */

module.exports = function (jiffClient) {
  /**
   * Create an array of secret shares and associated deferred.
   * @method
   * @memberof utils
   * @param {number} count - number of secret shares
   * @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
   * @return {object} the secret share object containing the give value
   *
   */
  jiffClient.utils.many_secret_shares = function (count, holders, threshold, Zp) {
    var deferreds = [];
    var shares = [];
    for (var i = 0; i < count; i++) {
      var deferred = new jiffClient.helpers.Deferred();
      shares.push(new jiffClient.SecretShare(deferred.promise, holders, threshold, Zp));
      deferreds.push(deferred);
    }

    return {shares: shares, deferreds: deferreds};
  };

  /**
   * Resolve the array of deferreds with the values of the given shares when ready, matched by index
   * @method
   * @memberof utils
   * @param {Deferred[]} deferreds - the deferred to resolve
   * @param {SecretShare[]} shares - the shares to resolve with
   */
  jiffClient.utils.resolve_many_secrets = function (deferreds, shares) {
    for (var i = 0; i < deferreds.length; i++) {
      shares[i].wThen(deferreds[i].resolve);
    }
  };

  /**
   * Combines all the promises of the given share into a single promise that is resolved when
   * all shares are resolved
   * @method
   * @methodof utils
   * @param {SecretShare[]} shares - the shares whose promises should be joined
   */
  jiffClient.utils.all_promises = function (shares) {
    var promises = [];
    for (var i = 0; i < shares.length; i++) {
      promises.push(shares[i].value);
    }
    return Promise.all(promises);
  };

  /**
   * A high level combinator for iteration of bit arrays
   * It executes a round of (func) starting from index start to the length (supports backwards if start > length) excluding length
   * Every round is blocked until the previous one finishes and the promise produced by it
   * is resolved
   * The final value is used to resolve deferred
   * @method
   * @memberof utils
   * @param {!Deferred} deferred - the deferred to resolve with the final output
   * @param {!number} start - the index to start from
   * @param {!number} length - the index to stop at (excluding it)
   * @param {?object} initial - an initial aggregator value
   * @param {!function(number, object)} func - the aggregator function to apply to the elements in order, takes the index and the aggregator value so far
   * @param {?function(object)} [promisify] - if initial is not null, this is called prior to starting combinator, to turn initial
   *                                        into a promise of the actually used initial value(in case it has to be resolved),
   *                                        defaults to promisifying a SecretShare with .wThen
   * @param {?function(object)} [valufy] - applied to the final result to turn it into a value, which is then used to resolve deferred,
   *                                       defaults to getting value of a SecretShare
   */
  jiffClient.utils.bit_combinator = function (deferred, start, length, initial, func, promisify, valufy) {
    if (promisify == null) {
      promisify = function (share) {
        return {then: share.wThen.bind(share)};
      }
    }

    if (valufy == null) {
      valufy = function (share) {
        return share.value;
      }
    }

    var next = start <= length ? 1 : -1;
    var __bit_combinator = function (start, val) {
      if (start === length) {
        // done
        deferred.resolve(valufy(val));
        return;
      }

      // execute func once
      val = func(start, val);

      // when done, do next iteration
      promisify(val).then(function () {
        __bit_combinator(start + next, val);
      });
    };

    // start combinator
    if (initial == null) {
      __bit_combinator(start, initial);
    } else {
      promisify(initial).then(function () {
        __bit_combinator(start, initial);
      });
    }
  }
};