client/protocols/booleans/boolean.js

// Generic version of operations
module.exports = function (SecretShare) {
  /**
   * bitwise-XOR with a constant (BOTH BITS).
   * @method cxor_bit
   * @param {number} cst - the constant bit to XOR with (0 or 1).
   * @return {SecretShare} this party's share of the result.
   * @memberof SecretShare
   * @instance
   */
  SecretShare.prototype.cxor_bit = function (cst) {
    if (!(this.isConstant(cst))) {
      throw new Error('parameter should be a number (^)');
    }
    if (!this.jiff.share_helpers['binary'](cst)) {
      throw new Error('parameter should be binary (^)');
    }

    return this.icadd(cst).issub(this.icmult(cst).icmult(2));
  };

  /**
   * bitwise-OR with a constant (BOTH BITS).
   * @method cor_bit
   * @param {number} cst - the constant bit to OR with (0 or 1).
   * @return {SecretShare} this party's share of the result.
   * @memberof SecretShare
   * @instance
   */
  SecretShare.prototype.cor_bit = function (cst) {
    if (!(this.isConstant(cst))) {
      throw new Error('parameter should be a number (|)');
    }
    if (!this.jiff.share_helpers['binary'](cst)) {
      throw new Error('parameter should be binary (|)');
    }

    return this.icadd(cst).issub(this.icmult(cst));
  };

  /**
   * bitwise-XOR of two secret shares OF BITS.
   * @method sxor_bit
   * @param {SecretShare} o - the share to XOR with.
   * @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.
   * @return {SecretShare} this party's share of the result, the final result is 1 if this < o, and 0 otherwise.
   * @return {SecretShare} this party's share of the result.
   * @memberof SecretShare
   * @instance
   */
  SecretShare.prototype.sxor_bit = function (o, op_id) {
    if (!(o.jiff === this.jiff)) {
      throw new Error('shares do not belong to the same instance (^)');
    }
    if (!this.jiff.helpers.Zp_equals(this, o)) {
      throw new Error('shares must belong to the same field (^)');
    }
    if (!this.jiff.helpers.array_equals(this.holders, o.holders)) {
      throw new Error('shares must be held by the same parties (^)');
    }
    if (op_id == null) {
      op_id = this.jiff.counters.gen_op_id('sxor_bit', this.holders);
    }

    return this.isadd(o).issub(this.ismult(o, op_id + ':smult1').icmult(2));
  };

  /**
   * OR of two secret shares OF BITS.
   * @method sor_bit
   * @param {SecretShare} o - the share to OR with.
   * @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.
   * @return {SecretShare} this party's share of the result, the final result is 1 if this < o, and 0 otherwise.
   * @return {SecretShare} this party's share of the result.
   * @memberof SecretShare
   * @instance
   */
  SecretShare.prototype.sor_bit = function (o, op_id) {
    if (!(o.jiff === this.jiff)) {
      throw new Error('shares do not belong to the same instance (|)');
    }
    if (!this.jiff.helpers.Zp_equals(this, o)) {
      throw new Error('shares must belong to the same field (|)');
    }
    if (!this.jiff.helpers.array_equals(this.holders, o.holders)) {
      throw new Error('shares must be held by the same parties (|)');
    }
    if (op_id == null) {
      op_id = this.jiff.counters.gen_op_id('sor_bit', this.holders);
    }

    return this.isadd(o).issub(this.ismult(o, op_id + ':smult1'));
  };

  /**
   * Negation of a bit.
   * This has to be a share of a BIT in order for this to work properly.
   * @method not
   * @return {SecretShare} this party's share of the result (negated bit).
   * @memberof SecretShare
   * @instance
   */
  SecretShare.prototype.not = function () {
    return this.icmult(-1).icadd(1);
  };

  /**
   * Simulate an oblivious If-else statement with a single return value.
   * Should be called on a secret share of a bit: 0 representing false, and 1 representing true
   * If this is a share of 1, a new sharing of the element represented by the first parameter is returned,
   * otherwise, a new sharing of the second is returned.
   * @method if_else
   * @memberof SecretShare
   * @instance
   * @param {SecretShare | number} trueVal - the value/share to return if this is a sharing of 1.
   * @param {SecretShare | number} falseVal - the value/share to return if this is a sharing of 0.
   * @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.
   * @return {SecretShare} a new sharing of the result of the if.
   *
   * @example
   * // a and b are secret shares
   * // cmp will be a secret share of either 1 or 0, depending on whether a or b is greater
   * var cmp = a.gt(b);
   *
   * // max is set to the greater value, without revealing the value or the result of the inequality
   * var max = cmp.if_else(a, b);
   */
  SecretShare.prototype.if_else = function (trueVal, falseVal, op_id) {
    if (op_id == null) {
      op_id = this.jiff.counters.gen_op_id('if_else', this.holders);
    }

    var const1 = this.isConstant(trueVal);
    var const2 = this.isConstant(falseVal);
    if (const1 && const2) {
      return this.icmult(trueVal).isadd(this.inot().icmult(falseVal));
    } else if (const1) {
      return this.inot().ismult(falseVal.icsub(trueVal), op_id + ':smult').icadd(trueVal);
    } else if (const2) {
      return this.ismult(trueVal.icsub(falseVal), op_id + ':smult').icadd(falseVal);
    } else {
      return this.ismult(trueVal.issub(falseVal), op_id + ':smult').isadd(falseVal);
    }
  };
};