Following a previous post of mine I'm posting now an article introducing garbled circuits. If you have any comments or thoughts while reading you want to share, send me a message on Telegram (https://t.me/hamilis) and I'll be happy to chat!
In this article I'd like to give some introduction to Garbled Circuits (Abbr.: GC). If you have reached to this article and are wondering what is a Garbled Circuit, you are probably at least somewhat familiar with Multi-Party-Computation (Abbr.: MPC) and cryptography.
To make things clear, let's say that MPC is a sub-domain of cryptography that deals with methods which allow a set of mistrusting parties, each holding its own input, to compute a function of those inputs such that none of the parties learn anything about the input of the other parties (besides what can be trivially inferred about it from the input).
For example, consider Yao's Millionaires Problem in which a two millionaires would like to know which of them is richer without disclosing their fortune. Each millionaire's input would be the value of its fortune and the function to be evaluated (which returns True
or False
) is whether the first input is bigger than the second input.
Now that the setting is clearer, I can say that Garbled Circuits is a protocol, allowing two parties with inputs respectively, to compute a function of their inputs: such that each party will learn only . How awesome is that?
In this article I'd like to give some sense about how Garbled Circuits are built and how does the magic work. I've found this topic to be cryptic to some friends and colleagues and thought creating this document will give some intuition about the building blocks of GCs. This article does not intend to be rigorous and I'll not be proving the security of GCs. I find learning crypto topics as a multi-tiered-procedure, where first gaining a general sense about the cryptographic entity and only later giving a more explicit rigorous and formal definitions and proofs about this entity makes complex topics easier to grasp. I will also not consider some extensions of GCs for multiple parties (i.e. more than two parties), while such do exist. The interested reader can refer to Oded Goldreich's article to learn more about it. Notice that Oded is using the term "Scrambled Circuit" rather than "Garbled Circuit".
In this article we assume the Semi-Honest model of security. By making this assumption we disregard any scenario in which one of the parties deviates from the protocol to gain extra information. In other words, we assume the parties are honest-but-curious, so they follow the protocol precisely but may be interested in gaining extra information along the process. We will explain why such host-but-curious parties may not gain any information except for the output of the function being computed. We will not approach the more complex problem of building a GC protocol in the Malicious-Adversary model.
The collaborting parties hold inputs respectfully and intent to collaboratively compute a function . The inputs are represented each as a vector of bits. When building a Garbled Circuit for the function the first thing one does is representing as a boolean circuit, composed of boolean gates. For simplicity we will deal with two types of gates:
And Gates, which compute the logical AND of its two input bits:
XOR Gates, which compute the logical exclusive-OR of its two input bits:
It is a well-known result that any boolean function can be represented as a boolean circuit composed only of AND gates and XOR gates. Therefore, if we can show that the XOR and AND functions can be computed by two parties such that the input privacy is preserved, we can infer that composition of these gates into a larger boolean circuit will also preserve the privacy of the inputs of the parties.
We shall not discuss how can a function be represented as a boolean circuit, as this for itself is a whole world of research. Thus at this point we will simply assume that such representation does exist for our given function.
To make the build more concrete and approachable and we shall discuss a specific instance of the problem for a rather simple function . Later, we give a generalized algorithm for any function. The function we will deal with in our construction is the function that takes two numbers of two binary digits each and tells whether they are the binary negation of each other. In other words, if the first input is equal to the number obtained by taking the second input and flipping all the bits representing it. For example, because 's binary representation is and 's binary representation is , and since is obtained by flipping all the bits in then . To be precise, the numbers (inputs) of the parties will be and where are bits and are the input numbers with the binary representation of and respectively. The single bit output of the function is . For example, if the input of party is the number , is will be represented as and the input of party is the number . Then the output of the function will be .
The boolean circuit for the additional function is:
We have annotated each wire with a number which we will use later in our building.
In this subsection we'll try to build a GC for our function taking as input two vectors of two bits each, representing two numbers, and sending as output a vector of a single bit. In the beginning we have two parties who share the boolean circuit for . Now, let's think, if we were trying to solve this problem ourselves what would be the first thing we were trying to tackle? Well, since none of the parties can learn nothing besides the output of the computed function, party can't simply send its input to party . If it did, party could compute and send it to , but by doing so would also learn , the input of which violates our privacy requirements. Therefore, the information should send to shall not disclose its input but would still allow to evaluate the function. So, the approach we shall take is a little bit different, instead, will send a garbled version of the circuit to and some "instructions" for about how to "translate" its input () into the garbled circuit. Next, will evaluate the garbled circuit which would yield a garbled output, and send this output to , who will ungarble the garbled output into the correct output and send it to . Garbling the circuit, done by will require:
In the following subsections we will explain how these can be done.
Let's consider a logical gate with two input wires () and a single output wire (). So when the values that are fed into the input wires are set to specific values, the output wire will hold the correct value obtained from applying the logical function of the gate on the values fed into it from the two input wires. The functionality of the logical gate can be described using a truth table, a table which gives the value of the output wire () to each of the possible four combinations of the input wires . For example, the truth table of a logical-AND gate we have in our boolean circuit is the following:
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
To make things clear, the first line in the table, for example, means that if the input wires and take the values of and , than the output wire will take the value of as well, which is the logical-AND of the two inputs. While it's a common practice, it's important to recall that the value of represents a logical "False" and the value of is representing a logical "True".
The truth table of a logical-XOR gate is the following:
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
We will garble the truth table by assigning two encryption keys to each wire in the circuit. So, for example consider our circuit with seven different wires, thus we will generate for each wire two keys and . Intuitively, we need two keys to represent the two possible states of the wire, where it either carries the value "0" or the value "1". The keys are of a symmetric encryption scheme, so the key is used both for encryption and decryption. Let's zoom-in on a specific gate in the circuit, for instance, our logical XOR gate with input wires and and output wire . Wire will have two keys and . Wire will have two keys and and output wire will have two keys for it and . Next, we can garble the truth table in the following way. For each line in the original (ungarbled) truth table, taking input values on wire and on wire and mapping them into output on wire ( are all a single bit) we can create a line in the garbled truth table mapping and to . For example, the second line in our logical-XOR gate truth table, we had inputs and mapped to output (because 0 XOR 1 = 1), in the garbled table we will have map to . The full garbled table of the logical-XOR will be:
Wire | Wire | Wire |
---|---|---|
The garbling of the input is done so that for each input wire of , then party will send the key representing the garbling of the input. For example, our XOR gate with input wires and and output wire we know the value of wire is part of the input of party . Now if the input of party for this bit is then the garbled value of it will be and if the input is then it will be garbled to where keys and the two keys associated with wire . Notice that in party who receives the garbled input can't tell whether it represents the garbling of or , because both keys are just random numbers and didn't share with the meaning of key.
Now in order to compute, party will send to :
As good as it may sound, things don't end here, since at this point in order to evaluate the gate, receives the garbling of 's input and the problem is that while will be able to evaluate the gate, it will also be able to derive whether 's input to our XOR gate is or , thus inferring the value of the ungarbled input of . This is possible since the ordering of the rows is such that in the first and second rows the 'Wire ' column contains and in the third and forth rows it contains so can just compare the key it got with the values in these rows and ascertain the input of which violates our privacy concerns. So, one thing we have to do is mix the order of the lines randomly. After mixing the rows, the garbled table of our XOR gate looks like this to .
Wire | Wire | Wire |
---|---|---|
For completeness the garbled table of the AND gate (with input wires and output ) is:
Wire | Wire | Wire |
---|---|---|
We use the notation of and to imply that simply doesn't know what is the meaning of the value.
However, even if we mix the rows, can still reveal the whole input of party . One possible attack that can be done on the AND gate by exploiting its asymmetry in its output column of wire . Since this output column (of wire ) has three rows with the same value and one row with another value, by knowing the functionality of AND gate we can tell that this last value represents logical (since only one combination of the inputs to a logical AND gate can yield the output of ). After derives the values of and it can also tell that the two keys of the wires and that yield the output of must be and , and thus can also derive the values of . At this point, going back to the XOR gate (with input wires ) can tell, even without enumerating all the inputs, that if the XOR of the value it provided () with the one provided () yields the then and are different and if it yields the value of and $a and thus it can infer the value of and learn the input of .
The issue stems from the fact that has been able to exploit some asymmetry at the output of the AND gate. Thus, we must have each output of the garbled circuit appear only once so should not be able to exploit such asymmetries.
This time, just like the previous one will assign two encryption keys for each wire in the circuit, so we will use the name notation like in the previous attempt.
However, this time instead of submitting a table for each gate with multiple columns, it will send only the output column of the truth table and each output will be encrypted with the two keys of its corresponding inputs. For example, the table for the XOR gate (with input wires ) will look like this (but don't forget will also shuffle the rows before sending them):
Wire |
---|
We denote with the concatenation of strings . We denote with the encryption of with key . So each output is the double encryption (using the key of the first input wire and the second input wire) or the concatenation of the output with itself. We'll explain shortly why we concatenate the output with itself, but for now take it as given.
And views this table as:
Wire |
---|
So this time, just like previous attempt will send:
Now, for our XOR gate (with input wires and ) will take (just like we did before, we use "" to imply that doesn't know whether its the garbling of the value "" or "") and its own garbled input (let's assume its without loss of generality). Next, it will try to double-decrypt all the entries in the garbled table with the input encryption keys until the decryption successfully results in some value written twice (with or ), in this case it knows that the resulting output is correct. So, we write the output value twice as a way to verify that a decryption is successful so can tell that the output is correct.
For example, if 's garbled input is and 's garbled input is then will try to decrypt each entry in the garbled table:
The only issue we have arises from the fact that receives the garblings of both of its possible inputs for each wire that its input feeds, so it can enumerate all possible combinations of its inputs and evaluate the circuit for each such combination. We know that for all input combinations, except for one, the output will be the same (the value of ) and only for one of the combinations the output will be unique (), this is because only for one possible input of , which is the negation of the input of , the circuit will output the value of . By taking the input that was fed into the circuit to yield the unique value of , ungarbling it and flipping the bits can reveal the whole input of , which violates our privacy requirements.
We understand that can't receive both keys for each wire that it feeds its input, because then it will be able to learn 's input. However, without those keys - it must disclose its input to ! How can we solve it? While it may seem like a dead end - luckily cryptographers have come up with a great solution, known as "Oblivious Transfer".
The problem oblivious transfer (OT) is trying to solve is the following:
While it isn't very complex, in this post the construction of Oblivious-Transfer will not be discussed (please let me know if you find this topic interesting, I may create another post about it later). This post is complex enough :)
This attempt will be exactly like the second attempt, but we will leverage OT to solve our last problem. The only difference from previous attempt will be that now will learn only one of either or and either or , according to what 's input is. This will be done using Oblivious-Transfer. This prevents the attack suggested in the previous attempt since now will hold only one of and and only one of and .
Just to recap over our amazing result, this subsection will give the full details of our garbled circuits.
The evaluation will work in three phases:
Party will garble the circuit and its input. Each wire in the circuit will be assigned with two encryption keys and which will represent the garbling of the values of and going through the wire, respectively. Next, for each gate in the circuit with two input wires and one output wire with the following truth table:
0 | 0 | |
0 | 1 | |
1 | 0 | |
1 | 1 |
Such that is the output of the gate with inputs and . Then the garbling of gate is:
Each garbled gate will be sent to . The input of , which is will be garbled into . The garbled input vector will also be sent to .
After receiving the garbled circuit and the garbled input of , the parties will run iterations of the OT protocol so will learn its garbled input .
At this point will evaluate the circuit by sequentially evaluating each gate in the circuit, starting from gate that depends only on the inputs of the parties up until evaluating the gate which yield the output of the function. For each gate with input wires and output wire we assume that the garbled value of both input wires are already known, either because these are the input wires or because they are wires who come out of a gate which was already evaluated. The value of each wire is one of the encryption keys associated with the wire, either or .
Since the circuit is garbled doesn't know which value of those is he holding so we denote the value he holds in his perspective as and . The party will decrypt, using the keys from the input wires, all entries in the table until the decryption yields some string which is repeated twice . When it does, can tell that the decryption succeeded and the garbled output of the gate is the retrieved from the decryption. When the decryption succeeds sets the value of to be and moves on to evaluate ther next gate. When it finishes evaluating all gates in the circuit it will send the garbled value of the output wires to party .
Party receives the garbled output of each wire. Using the keys it generated for each wire it can tell whether each value is the garbling of 1 or 0 and thus construct the (ungarbled) output and share it with .
In the article we've discussed what garbled circuits are, their usage and purpose and how they can be constructed. The academic community has put a lot of effort into understanding and optimizing garbled circuits and many optimizations exist which greatly reduce the communication complexity of the parties as well allow ensuring certain security properties. In particular some security and integrity properties of the process aren't guaranteed with our existing construction:
Moreover, we haven't discussed the construction of OT which solved one of the core issues in our construction. Maybe I'll discuss those in a future post.
I'll be happy to know if any of these (or any other) topics interest you, ping on https://t.me/hamilis on Telegram and I'll be happy to chat on any crypto topic!
I want to thank all my colleagues who have peer reviewed this article, especially my colleagues from the ZenGo-X team, their input was very valuable!