def half_gates_ungarble(self, garblers_label, evaluators_label): """ Evaluates the gate by decrypting each half gate and XORing the result. :param garblers_label: the chosen label by the garbler :param evaluators_label: the chosen label by the evaluator :return: the correct output label :rtype: :class:`Label` """ if self.gate_type == 'AND': s_a, s_b = garblers_label.pp_bit, evaluators_label.pp_bit entry1, entry2 = self.table gen = hashlib.sha256(garblers_label.label).digest() eva = hashlib.sha256(evaluators_label.label).digest() C_g = xor(gen, entry1) if s_a else gen C_e = xor(eva, xor(entry2, garblers_label.label)) if s_b else eva output_label = Label(0) output_label.represents = None output_label.label = xor(C_g, C_e) output_label.pp_bit = get_last_bit(output_label.label) return output_label else: return self.free_xor_ungarble(garblers_label, evaluators_label)
def free_xor_garble(self): """ In this optimization *XOR* gates are garbled for free, that is, the table corresponding to this gate is empty. The way this optimization accomplishes this is by setting the true label of each wire as an offset *R* of the false label. This offset is global to the whole circuit, so by the properties of *XOR*, everything works out nicely. For more information see `the paper <http://www.cs.toronto.edu/~vlad/papers/XOR_ICALP08.pdf>`_. Note that FreeXOR is not compatible with GRR2. """ if self.gate_type == 'XOR': A0 = self.left_wire.false_label.label B0 = self.right_wire.false_label.label R = settings.R C0, C1 = xor(A0, B0), xor(xor(A0, B0), R) pp_bit = get_last_bit(C0) f_label = self.output_wire.false_label t_label = self.output_wire.true_label f_label.label = C0 f_label.pp_bit = pp_bit t_label.label = C1 t_label.pp_bit = not pp_bit else: if settings.GRR3: self.grr3_garble() else: self.point_and_permute_garble()
def __init__(self, identifier=None): self.identifier = identifier if settings.CLASSICAL: self.false_label = Label(False) self.true_label = Label(True) else: b = random.choice([True, False]) self.false_label = Label(False, pp_bit=b) self.true_label = Label(True, pp_bit=not b) if settings.FREE_XOR or settings.HALF_GATES: self.true_label.label = xor(self.false_label.label, settings.R)
def half_gates_garble(self): """ In this optimization, the most current one to date, the authors propose a method to garble *AND* gates with a table size of two ciphertexts in a way that is compatible with FreeXOR. The way they accomplish this is by breaking up an *AND* gate into two *half gates*. For more information see `the paper <https://eprint.iacr.org/2014/756.pdf>`_. """ if self.gate_type == 'AND': def H(x): return hashlib.sha256(x).digest() self.table = [None] * 2 p_a = self.left_wire.false_label.pp_bit p_b = self.right_wire.false_label.pp_bit # Generator Half Gate entry1 = xor(H(self.left_wire.false_label.label), H(self.left_wire.true_label.label)) if p_b: entry1 = xor(entry1, settings.R) C0 = H(self.left_wire.false_label.label) if p_a: C0 = xor(C0, entry1) # Evaluator Half Gate entry2 = xor(H(self.right_wire.false_label.label), H(self.right_wire.true_label.label)) entry2 = xor(entry2, self.left_wire.false_label.label) C0_ = H(self.right_wire.false_label.label) if p_b: C0_ = xor(C0_, xor(entry2, self.left_wire.false_label.label)) self.table = [entry1, entry2] self.update_output_wire(xor(C0, C0_), xor(xor(C0, C0_), settings.R)) else: self.free_xor_garble()
def flexor_garble(self): """ In this optimization *XOR* are garbled with a table size of 0, 1, or 2 (hence its name flexible XORs). The innovation at the time was that this method is compatible with GRR2. The way it accomplishes this is by changing the input wires' labels to have the same offset as the output wire's labels. For more information see `the paper <https://pdfs.semanticscholar.org/72ba/7c639e3d7b07\ 5fde8eeca3385923551c6a39.pdf>`_. """ if self.gate_type == 'XOR': self.table = [None] * 4 left, right, out = self.wires() adjust_wire_offset(out) A0, A1 = left.false_label.label, left.true_label.label B0, B1 = right.false_label.label, right.true_label.label C0, C1 = out.false_label.label, out.true_label.label R1, R2, R3 = xor(A0, A1), xor(B0, B1), xor(C0, C1) k1, k2 = AESKey(A0), AESKey(B0) A0_ = k1.decrypt(bytes(settings.NUM_BYTES)) B0_ = k2.decrypt(bytes(settings.NUM_BYTES)) C0_, C1_ = xor(A0_, B0_), xor(xor(A0_, B0_), R3) A1_, B1_ = xor(A0_, R3), xor(B0_, R3) self.modify_pp_bits(A0_, B0_, C0_) out.false_label.label = C0_ out.true_label.label = C1_ k1, k2 = AESKey(A1), AESKey(B1) if R1 == R2 == R3: self.free_xor_garble() elif R1 != R2 != R3: self.table[left.true_label.pp_bit] = k1.encrypt(A1_) self.table[right.true_label.pp_bit + 2] = k2.encrypt(B1_) elif R1 == R3: self.table[right.true_label.pp_bit + 2] = k2.encrypt(B1_) elif R2 == R3: self.table[left.true_label.pp_bit] = k1.encrypt(A1_) else: if settings.GRR3: self.grr3_garble() else: self.point_and_permute_garble()
def free_xor_ungarble(self, garblers_label, evaluators_label): """ Evaluates *XOR* gates for free by XORing the two labels he receives. :param garblers_label: the chosen label by the garbler :param evaluators_label: the chosen label by the evaluator :return: the correct output label :rtype: :class:`Label` """ if self.gate_type == 'XOR': output_label = Label(0) output_label.represents = None output_label.label = xor(garblers_label.label, evaluators_label.label) output_label.pp_bit = get_last_bit(output_label.label) else: g, e = garblers_label, evaluators_label if settings.GRR3: output_label = self.grr3_ungarble(g, e) else: output_label = self.point_and_permute_ungarble(g, e) return output_label