client/protocols/numbers/protocols.js

// general arithmetic protocols
module.exports = function (SecretShare) {
  /**
   * Reshares/refreshes the sharing of this number, used before opening to keep the share secret.
   * @method refresh
   * @param {string} [op_id=auto_gen()] - the operation id with which to tag the messages sent by this refresh, by default
   *                         an automatic operation id is generated by increasing a local counter, default operation ids
   *                         suffice when all parties execute the instructions in the same order.
   * @returns {SecretShare} a new share of the same number.
   * @memberof SecretShare
   * @instance
   */
  SecretShare.prototype.refresh = function (op_id) {
    if (op_id == null) {
      op_id = this.jiff.counters.gen_op_id('refresh', this.holders);
    }

    // final result
    var final_deferred = new this.jiff.helpers.Deferred();
    var final_promise = final_deferred.promise;
    var result = new this.jiff.SecretShare(final_promise, this.holders, this.threshold, this.Zp);

    // refresh
    var self = this;
    var ready_number = function (zero) {
      self.isadd(zero).wThen(final_deferred.resolve);
    };

    // get shares of zero
    var zero = this.jiff.get_preprocessing(op_id);
    if (zero == null) {
      var promise = this.jiff.from_crypto_provider('numbers', this.holders, this.threshold, this.Zp, op_id, {
        number: 0,
        count: 1
      });
      promise.then(function (msg) {
        ready_number(msg['shares'][0]);
      });
    } else {
      ready_number(zero);
    }

    return result;
  };

  /**
   * Bit Decomposition: Transform existing share to an array of bit shares.
   * @method bit_decomposition
   * @memberof SecretShare
   * @instance
   * @param {string} [op_id=auto_gen()] - the operation id which is used to identify this operation.
   *                         This id must be unique, and must be passed by all parties to the same instruction, to
   *                         ensure that corresponding instructions across different parties are matched correctly.
   * @returns {SecretShare[]} an array of secret shares of bits of length [ceil(log_2(this.Zp))], where
   *   index 0 represents the least significant bit.
   */
  SecretShare.prototype.bit_decomposition = function (op_id) {
    if (op_id == null) {
      op_id = this.jiff.counters.gen_op_id('bit_decomposition', this.holders);
    }

    // bit length of this secret
    var bitLength = this.jiff.share_helpers['ceil'](this.jiff.helpers.bLog(this.Zp, 2));

    // Create deferred shares to resolve to later when the computation completes
    var many_shares = this.jiff.utils.many_secret_shares(bitLength, this.holders, this.threshold, this.Zp);
    var deferreds = many_shares.deferreds;
    var result = many_shares.shares;

    // Execute protocol when randomly sampled bit-wise random number is ready
    var self = this;
    var ready_sampling = function (bits) {
      var r = self.jiff.protocols.bits.bit_composition(bits);
      // add and reveal random number to this
      self.jiff.internal_open(r.isadd(self), self.holders, op_id + ':open').then(function (result) {
        // compute bits assuming r+this < Zp
        var noWrap = self.jiff.protocols.bits.csubr(result, bits, op_id + ':bits.csubr:1');
        var didWrap = noWrap.pop();

        // compute bits assuming r+this >= Zp
        var withWrap = self.jiff.protocols.bits.csubr(self.jiff.share_helpers['+'](result, self.Zp), bits, op_id + ':bits.csubr:2');
        withWrap.pop(); // withWrap cannot underflow!

        // choose noWrap if first subtraction does not overflow (sign bit is zero), otherwise choose withWrap.
        for (var i = 0; i < bitLength; i++) {
          withWrap[i] = didWrap.iif_else(withWrap[i], noWrap[i], op_id + ':if_else:' + i);
        }
        self.jiff.utils.resolve_many_secrets(deferreds, withWrap);
      });
    };

    // generate the bits of a random number less than our prime
    var bits = this.jiff.get_preprocessing(op_id + ':sampling');
    if (bits == null) {
      var promise = this.jiff.from_crypto_provider('numbers', this.holders, this.threshold, this.Zp, op_id + ':sampling', {
        bitLength: bitLength,
        count: 1,
        max: this.Zp
      });
      promise.then(function (msg) {
        ready_sampling(msg['shares']);
      });
    } else {
      ready_sampling(bits);
    }

    return result;
  };
};