changed a year ago
Published Linked with GitHub

1/14: Garbled Circuits

First Idea - Lookup Table + Oblivious Transfer

If one wants to compute \(f(x, y)\) where \(x\) is supplied by \(P_1\) and \(y\) is supplied by \(P_2\), we can do this as follows. For each possible input \(x\), \(P_1\) selects a key \(k_x\). This is done similarly for \(y\). Then, \(P_1\) computes, for all \(\lvert X \rvert \cdot \lvert Y \rvert\) possible combinations, the value \(\text{Enc}_{k_x, k_y}(f(x, y))\).

\(P_1\) then sends this encryption table to \(P_2\). Also, \(P_1\) sends the \(k_x\) corresponding to its input \(x\). The hard part arises from \(P_1\) having to send \(k_y\) corresponding to the \(P_2\)'s input \(y\), without knowing \(y\) itself. This can be done via 1-out-of-\(\lvert Y \rvert\) Oblivious Transfer. Once \(P_2\) receives \(k_y\), they can try to decrypt all encryptions, with only success being \(f(x, y)\) if the encryption is authenticated. This is a quite unoptimized protocol, but one that provides MPC.

To allow this lookup table idea to work, we only work with 2-party boolean circuits.

Additional Idea: Point-and-Permute

The main source of wasteful computation is \(P_2\) having to decrypt all encryptions. To prevent this, we could add make the last bit of \(k_x, k_y\) to be a pointer to the encryption table.

This way, it is possible for \(P_2\) to perform a single decryption.

Final Garbled Circuits Protocol

For each wire \(w_i\) of the circuit, \(P_1\) randomly selects wire labels

\[w_i^b = (k_i^b \in \{0, 1\}^\kappa, p_i^b \in \{0, 1\}), \quad p_i^0 + p_i^1 = 1\]

then, if \(G_i\) is a boolean gate implementing \(w_c = g_i(w_a, w_b)\), the garbled table is

\[e_{v_a, v_b} = H(k_a^{v_a} || k_b^{v_b} || i) \oplus w_c^{g_i(v_a, v_b)}\]

with the \(p_a^{v_a}, p_b^{v_b}\) being the according table pointer for \(e_{v_a, v_b}\).

For each output wire \(w_i\), the garbled output table is

\[e_v = H(k_i^v || \text{OUT} || i) \oplus v\]

with the \(p_i^v\) being the according table pointer for \(e_v\).

After this, \(P_1\) sends to \(P_2\) the active wire labels for wires in which \(P_1\) provides the input.

Then, for each wire where \(P_2\) provides the input, an 1-out-of-2 Oblivious Transfer protocol is used so that \(P_1\) sends \(P_2\) the correct wire label without \(P_1\) knowing the actual input value.

With all active wire labels, \(P_2\) begins the evaluation - by computing

\[(k_c, p_c) = w_c = H(k_a || k_b || i) \oplus e_{p_a, p_b}\]

note how \(P_2\) doesn't know or care about \(v_a, v_b\) and so on.

Similarly, for the output, \(P_2\) computes

\[v = H(k_i || \text{OUT} || i) \oplus e_{p_i}\]

and returns \(v\) to be the final output. This is then sent to \(P_1\).

Select a repo