def send_result(socket, circuit, g_tables, pbits_out, b_inputs): """Evaluate circuit and send the result to Alice. Keyword arguments: socket -- socket for exchanges between A and B circuit -- dict containing circuit spec g_tables -- garbled tables of yao circuit pbits_out -- p-bits of outputs b_inputs -- dict mapping Bob's wires to (clear) input bits """ # dict mapping Alice's wires to (key, encr_bit) inputs a_inputs = socket.receive() # dict mapping Bob's wires to (key, encr_bit) inputs b_inputs_encr = {} for w, b_input in b_inputs.items(): # Send the gate ID on which to perform OT socket.send(w) # Perform oblivious transfer util.log('OT Request sent') b_inputs_encr[w] = pickle.loads(ot_bob(socket, b_input)) # Evaluate circuit using Alice and Bob's inputs result = yao.evaluate(circuit, g_tables, pbits_out, \ a_inputs, b_inputs_encr) socket.send(result)
def send_result(self, circuit, g_tables, pbits_out, b_inputs): """Evaluate circuit and send the result to Alice. Args: circuit: A dict containing circuit spec. g_tables: Garbled tables of yao circuit. pbits_out: p-bits of outputs. b_inputs: A dict mapping Bob's wires to (clear) input bits. """ # map from Alice's wires to (key, encr_bit) inputs a_inputs = self.socket.receive() # map from Bob's wires to (key, encr_bit) inputs b_inputs_encr = {} logging.debug("Received Alice's inputs") for w, b_input in b_inputs.items(): logging.debug(f"Sending gate ID {w}") self.socket.send(w) if self.enabled: b_inputs_encr[w] = pickle.loads(self.ot_evaluator(b_input)) else: pair = self.socket.receive() logging.debug(f"Received key pair, key {b_input} selected") b_inputs_encr[w] = pair[b_input] result = yao.evaluate(circuit, g_tables, pbits_out, a_inputs, b_inputs_encr) logging.debug("Sending circuit evaluation") self.socket.send(result)
def send_result(socket, circuit, g_tables, pbits_out, b_inputs): a_inputs = socket.receive() b_inputs_encr = {} for w, b_input in b_inputs.items(): socket.send(w) pair = socket.receive() # Bob receives the pair of keys and choose one of them b_inputs_encr[w] = pair[b_input] result = yao.evaluate(circuit, g_tables, pbits_out, \ a_inputs, b_inputs_encr) socket.send(result)
def print_evaluation_local(circuit, g_tables, keys, pbits): """Print circuit evaluation for all Bob and Alice inputs. Keyword arguments: circuit -- dict containing circuit spec g_tables -- garbled tables of the yao circuit keys -- dict mapping each wire to a pair of key pbits -- dict mapping each wire to a p-bit """ outputs = circuit["out"] # ID of outputs a_wires = circuit.get("alice", []) # list of Alice's wires b_wires = circuit.get("bob", []) # list of Bob's wires # dict mapping Alice's wires to (key, encr_bit) inputs a_inputs = {} # dict mapping Bob's wires to (key, encr_bit) inputs b_inputs = {} # p-bits of outputs pbits_out = {w: pbits[w] for w in outputs} print("\n======= {0} =======".format(circuit["name"])) len_a_wires, len_b_wires = len(a_wires), len(b_wires) N = len_a_wires + len_b_wires # Generate all possible inputs for both Alice and Bob for bits in [format(n, 'b').zfill(N) for n in range(2**N)]: bits_a = [int(b) for b in bits[:len_a_wires]] # Alice's inputs bits_b = [int(b) for b in bits[N - len_b_wires:]] # Bob's inputs # Map Alice's wires to (key, encr_bit) for i in range(len_a_wires): a_inputs[a_wires[i]] = \ (keys[a_wires[i]][bits_a[i]], pbits[a_wires[i]] ^ bits_a[i]) # Map Bob's wires to (key, encr_bit) for i in range(len_b_wires): b_inputs[b_wires[i]] = \ (keys[b_wires[i]][bits_b[i]], pbits[b_wires[i]] ^ bits_b[i]) # Send Alice's encrypted inputs and keys to Bob and wait for results result = yao.evaluate(circuit, g_tables, pbits_out, a_inputs, b_inputs) # Last term is a little hack to respect the given output format str_bits_a = ' '.join(bits[:len_a_wires]) + ' ' * bool(len_a_wires) str_bits_b = ' '.join(bits[len_a_wires:]) + ' ' * bool(len_b_wires) str_result = ' '.join([str(result[w]) for w in outputs]) + ' ' # Print one evaluation of the circuit line = " Alice{0} = {1} Bob{2} = {3} Outputs{4} = {5}".\ format(a_wires, str_bits_a, b_wires, str_bits_b, \ outputs, str_result) print(line)
def _print_evaluation(self, entry): """Print circuit evaluation.""" circuit, pbits, keys = entry["circuit"], entry["pbits"], entry["keys"] garbled_tables = entry["garbled_tables"] outputs = circuit["out"] a_wires = circuit.get("alice", []) # Alice's wires a_inputs = {} # map from Alice's wires to (key, encr_bit) inputs b_wires = circuit.get("bob", []) # Bob's wires b_inputs = {} # map from Bob's wires to (key, encr_bit) inputs pbits_out = {w: pbits[w] for w in outputs} # p-bits of outputs N = len(a_wires) + len(b_wires) print(f"======== {circuit['id']} ========") # Generate all possible inputs for both Alice and Bob for bits in [format(n, 'b').zfill(N) for n in range(2**N)]: bits_a = [int(b) for b in bits[:len(a_wires)]] # Alice's inputs bits_b = [int(b) for b in bits[N - len(b_wires):]] # Bob's inputs # Map Alice's wires to (key, encr_bit) for i in range(len(a_wires)): a_inputs[a_wires[i]] = (keys[a_wires[i]][bits_a[i]], pbits[a_wires[i]] ^ bits_a[i]) # Map Bob's wires to (key, encr_bit) for i in range(len(b_wires)): b_inputs[b_wires[i]] = (keys[b_wires[i]][bits_b[i]], pbits[b_wires[i]] ^ bits_b[i]) result = yao.evaluate(circuit, garbled_tables, pbits_out, a_inputs, b_inputs) # Format output str_bits_a = ' '.join(bits[:len(a_wires)]) str_bits_b = ' '.join(bits[len(a_wires):]) str_result = ' '.join([str(result[w]) for w in outputs]) print(f" Alice{a_wires} = {str_bits_a} " f"Bob{b_wires} = {str_bits_b} " f"Outputs{outputs} = {str_result}") print()
def _print_evaluation(self, entry): """ Print circuit evaluation and perform equality check of the result. """ circuit, pbits, keys = entry["circuit"], entry["pbits"], entry["keys"] garbled_tables = entry["garbled_tables"] outputs = circuit["out"] # Alice a_wires = circuit.get("alice", []) # Alice's wires a_inputs = {} # map from Alice's wires to (key, encr_bit) inputs print(f'Alice\'s wires {a_wires[::-1]}') # Bob b_wires = circuit.get("bob", []) # Bob's wires b_inputs = {} # map from Bob's wires to (key, encr_bit) inputs print(f'Bob\'s wires {b_wires[::-1]}\n') pbits_out = {w: pbits[w] for w in outputs} # p-bits of outputs total_wires = len(a_wires) + len(b_wires) print(f'Total wires: {total_wires}') possible_bit_combinations = [ format(n, 'b').zfill(total_wires) for n in range(2**total_wires) ] print(f"======== {circuit['id']} ========") # Generate all possible inputs for both Alice and Bob for bits in possible_bit_combinations: bits_a = [int(b) for b in bits[:len(a_wires)]] # Alice's inputs bits_b = [int(b) for b in bits[total_wires - len(b_wires):] ] # Bob's inputs # Excluding carry bits_per_party = len(bits_b) # Map Alice's wires to (key, encr_bit) for i in range(len(a_wires)): a_inputs[a_wires[i]] = (keys[a_wires[i]][bits_a[i]], pbits[a_wires[i]] ^ bits_a[i]) # Map Bob's wires to (key, encr_bit) for i in range(len(b_wires)): b_inputs[b_wires[i]] = (keys[b_wires[i]][bits_b[i]], pbits[b_wires[i]] ^ bits_b[i]) result = yao.evaluate(circuit, garbled_tables, pbits_out, a_inputs, b_inputs) # Format output str_bits_a = ''.join(bits[:len(a_wires)]) str_bits_b = ''.join(bits[len(a_wires):]) mpc_result = ''.join([str(result[w]) for w in outputs]) # === Performing the non-MPC function evaluation === non_mpc_result = add_n_bits(bits_a, bits_b, bits_per_party=bits_per_party) # This operation is necessary because the result of # add_n_bits will have the following shape: # R_3, R_2, R_1, R_0, C_3 # # While the outputs variable has the following shape: # R_0, R_1, R_2, R_3, C_3 # # Therefore the displayed wires order needs to be modified accordingly. output_wires = outputs[::-1][1:] output_wires.append(outputs[-1]) print(outputs) print( f"Alice{a_wires[::-1]} = {str_bits_a} - " f"Bob{b_wires[::-1]} = {str_bits_b} -> " f"Outputs{output_wires} = {mpc_result} - " f"Correct result = {non_mpc_result} - " f"Are they equal? {'Yes' if verifyResults(mpc_result, non_mpc_result) else 'No'}" )