API¶
This part of the documentation explains each function or class in detail to better understand the internal details behind garbled circuits.
Circuit¶
Gate¶
This module implements the Gate
object. The bulk of gabes
resides on this module. In it, both garbling and ungarbling (or evaluating)
techniques are implemented.
-
class
gabes.gate.
Gate
(gate_type, create_left=True, create_right=True)[source]¶ The
Gate
object contains three wires: a left wire, a right wire, and an output wire, each having a false label and a true label. Depending on the settings, different optimizations will be used to garble and ungarble.Parameters: - gate_type (str) – type of gate (AND, OR, etc)
- create_left (bool) – whether to create the left wire on the gate’s initialization
- create_right (bool) – whether to create the right wire on the gate’s initialization
-
classical_garble
()[source]¶ The most simple type of garbling. In classical garbled circuits, the whole boolean table is obfuscated by encrypting the output label using the input labels as keys. After this the table is shuffled (or garbled) so that the evaluator can’t know more than one output label. For more information see the paper.
Note that a Fernet scheme is used since this method relies on knowing whether decryption was successful or not, as the evaluator needs to try and decrypt the four possible entries in the boolean table.
-
classical_ungarble
(garblers_label, evaluators_label)[source]¶ The classical evaluation, in which the evaluator tries the four possible table entries until one of them decrypts the cipher.
Parameters: - garblers_label – the chosen label by the garbler
- evaluators_label – the chosen label by the evaluator
Returns: the correct output label
Return type: Label
-
evaluate_gate
(input1, input2)[source]¶ Evaluates a gate given two inputs.
Parameters: - input1 (bool) – the first input
- input2 (bool) – the second input
Returns: the output of the gate
Return type: bool
-
flexor_garble
()[source]¶ 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.
-
flexor_ungarble
(garblers_label, evaluators_label)[source]¶ Transforms the two input labels to have the same offset as the output’s true label.
Parameters: - garblers_label – the chosen label by the garbler
- evaluators_label – the chosen label by the evaluator
Returns: the correct output label
Return type: Label
-
free_xor_garble
()[source]¶ 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.
Note that FreeXOR is not compatible with GRR2.
-
free_xor_ungarble
(garblers_label, evaluators_label)[source]¶ Evaluates XOR gates for free by XORing the two labels he receives.
Parameters: - garblers_label – the chosen label by the garbler
- evaluators_label – the chosen label by the evaluator
Returns: the correct output label
Return type: Label
-
garble
()[source]¶ Garbles the gate. Delegates to the correct optimization depending on the user’s choice.
-
grr3_garble
()[source]¶ In this optimization the entry corresponding to the two labels that have a false point-and-permute bit is not sent over the network. Instead, the output label corresponding to this entry is set to be equal to the decryption of the zero ciphertext. Therefore, there is no need to send the entry because it is simply the zero ciphertext. The only thing the evaluator needs to do is to conclude that if he receives two false point-and-permute bits, the ciphertext will be the all zeros. For more information see the paper.
Note that now Fernet schemes can not be used since there is no way to decrypt the zero ciphertext. Instead, AES is used. See the Cryptography section for more details.
-
grr3_ungarble
(garblers_label, evaluators_label)[source]¶ If the point-and-permute bits are false, then imagine the ciphertext was the all zero ciphertext. Otherwise, proceed as in the point-and-permute optimization.
Parameters: - garblers_label – the chosen label by the garbler
- evaluators_label – the chosen label by the evaluator
Returns: the correct output label
Return type: Label
-
half_gates_garble
()[source]¶ 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.
-
half_gates_ungarble
(garblers_label, evaluators_label)[source]¶ Evaluates the gate by decrypting each half gate and XORing the result.
Parameters: - garblers_label – the chosen label by the garbler
- evaluators_label – the chosen label by the evaluator
Returns: the correct output label
Return type: Label
-
modify_pp_bits
(A0_, B0_, C0_)[source]¶ Modifies the point-and-permute bits according to the last bit of the label.
-
point_and_permute_garble
()[source]¶ In this optimization each label has a point-and-permute bit associated to it, with the only rule that labels running in the same wire must have opposing point-and-permute bits. The garbler will insert the encrypted output labels according to the point-and-permute bit of the input labels. Therefore, now the evaluator does not need to try and decrypt all the four ciphers but rather the one indicated by the two point-and-permute bits he has. For more information see the paper.
-
point_and_permute_ungarble
(garblers_label, evaluators_label)[source]¶ Evaluates the gate by indexing the table according to the point-and-permute bits given.
Parameters: - garblers_label – the chosen label by the garbler
- evaluators_label – the chosen label by the evaluator
Returns: the correct output label
Return type: Label
-
set_zero_ciphertext
()[source]¶ Generates the zero ciphertext by taking the two labels with false point-and-permute bits and setting the output labels accordingly. This function is used for GRR3.
-
transform_label
(label, garbler=True)[source]¶ Transforms the label accordingly.
Parameters: - label – the label to transform
- garbler (bool) – the type of label supplied
-
ungarble
(garblers_label, evaluators_label)[source]¶ Ungarbles the gate. Delegates to the correct optimization depending on the user’s choice.
Parameters: - garblers_label – the chosen label by the garbler
- evaluators_label – the chosen label by the evaluator
Returns: the correct output label
Return type: Label
(The) Wire¶
Note
“The king stay the king”
- D’Angelo Barksdale
This module implements the Wire
object. Each gate will have
a left wire (in the case of input gates, this will be probably be supplied
by the garbler), a right wire (evaluator), and an output wire. Each
wire holds the two possible for labels that run through it.
-
class
gabes.wire.
Wire
(identifier=None)[source]¶ The
Wire
object holds two labels representing True and False. In classical garbled circuits, there is no need for a point-and-permute bit. In all the other cases, a pp_bit is associated to each label. The two labels in the same wire must have opposing pp_bits.If the optimization chosen is FreeXOR or Half Gates then the true label is the false label xored with the global parameter R defined in
gabes.circuit.Circuit
Parameters: identifier (str) – (optional) wire’s unique identifier >>> from gabes.wire import Wire >>> w = Wire(identifier='A') >>> str(w) 'Wire A' >>> w.false_label b'dnE2Gsvhx84HgwrLRm8L9aFtI_aBYxzEDaOBRK2qkP0=' >>> w.true_label b'eBRWiJzYL65gU8nBFvXRZ8NK4_Cf9GlrYtNGZNEZOSs=' >>> w.get_label(True) == w.true_label.represents True
Label¶
This module implements the Label
object. A label
represents an obfuscated truth value. By default, the label
is represented as a random 256 bitstring, but the label
is encoded in base64 for the user. To change the length
of the bitstring, head to gabes.settings
.
-
class
gabes.label.
Label
(represents, pp_bit=None)[source]¶ The
Label
object, which contains the label that will represent either the boolean False or True for a particular gate.Parameters: - represents (bool) – (optional) the boolean value this label represents
- pp_bit (bool) – (optional) the point-and-permute bit
>>> from gabes.label import Label >>> label = Label(0, pp_bit=True) >>> label.label b'y\x8c\xc4C\x99\x9c\x1d&\xa3R\xdbB\xcep-\xc5 \xe9R=\xc1\xd8\xaeq}\xe0c\x80\xd8g\xac_\x96' >>> label.to_base64() b'eYzEQ5mcHSajUttCznAtxelSPcHYrnF94GOA2GesX5Y='
Garbler¶
Evaluator¶
This module provides the communication protocol seen from the point of view of the evaluator. To learn the whole process, see the Garbler’s section.
-
gabes.evaluator.
evaluator
(args)[source]¶ The main function of the application for the evaluator. For more information on the process, see the introduction to the Garbler’s section.
Parameters: args – the arguments from the command line interface Returns: the output of the circuit Return type: bool
-
gabes.evaluator.
request_cleaned_circuit
(sock)[source]¶ Receives a clean circuit (in which every label’s represents flag has been deleted) from the garbler.
Parameters: sock – the socket from which it will receive the data Returns: the cleaned circuit Return type: Circuit
-
gabes.evaluator.
request_wire_identifiers
(sock)[source]¶ Receives the wire identifiers from the garbler.
Parameters: sock – the socket from which it will receive the data Returns: the identifiers of the input wires Return type: list(str)
-
gabes.evaluator.
request_labels
(sock, identifiers, evaluator_inputs)[source]¶ Receives the input labels of the circuit from the garbler. The labels that belong to the garbler can be sent without any modification. In order for the evaluator to learn his labels, he must acquire them through the oblivious transfer protocol, in which the garbler inputs the two possible labels, the evaluator inputs his choice of truth value, and the evaluator learns which label corresponds to his truth value without the garbler learning his choice and without the evaluator learning both labels.
Parameters: - sock – the socket from which it will receive the data
- identifiers – the identifiers for all the input wires
- evaluator_inputs – the inputs the evaluator provides
Returns: the input labels
Return type: list(
Label
)
Cryptography¶
This module handles all the cryptography involved with garbled circuits.
The external module cryptography
offers a Fernet encryption scheme
that suits well for classical garbled circuits as it shows if decryption was
successful or not. However, for the majority of optimizations decrypting
the zero ciphertext is necessary. Therefore, the encryption/decryption
scheme used is AES. While probably an unfit
choice for a secure application, AES suffices for simple applications.
If more security is needed, the recommendation is to change AES for
a stronger cryptographic encryption scheme such as AES256.
-
class
gabes.crypto.
AESKey
(key)[source]¶ The
AESKey
object handles the key to AES and the encryption/decryption routines. To ensure that the key can be fed into AES, the input to the object is hashed with SHA256 to a 32 bytestring (AES only allows 16/32/64 bytes inputs).Parameters: key (bytes) – parameter to be hashed and used as a key >>> from gabes.crypto import AESKey >>> from gabes.label import Label >>> label = Label(1) >>> key = AESKey(label.to_base64()) >>> enc = key.encrypt(b"The winner is...") >>> key.decrypt(enc) b'The winner is...'
-
decrypt
(msg, from_base64=False, unpad=True)[source]¶ Decrypts the message
msg
by first unpadding it or decoding it from base64 if necessary.Parameters: - msg (bytes) – the message to be decrypted
- from_base64 (bool) – (optional) whether to decode the cipher from base64
- unpad (bool) – (optional) whether to unpad the message
Returns: decrypted message
Return type: bytes
-
encrypt
(msg, to_base64=False, pad=True)[source]¶ Encrypts the message
msg
by first padding it if necessary since AES requires prespecified input sizes. It then converts the cipher into base64 if needed.Parameters: - msg (bytes) – the message to be encrypted
- to_base64 (bool) – (optional) whether to convert the cipher to base64
- pad (bool) – (optional) whether to pad the message
Returns: encrypted message
Return type: bytes
-
pad
(msg, size=16)[source]¶ Takes a bytestring and pads it to be a multiple of
size
. To keep track of the padding, the first four bytes store the size of the padded bytestring.Parameters: - msg (bytes) – the bytestring to pad
- size (int) – (optional) padded result must be a multiple of this number
Returns: padded bytestring
Return type: bytes
-
unpad
(msg)[source]¶ Takes a bytestring and unpads it to the original bytestring. Since the first four bytes store the original unpadded size of the bytestring, we extract those four bytes and return the bytestring from position 4 to
size + 4
.Parameters: msg (bytes) – the bytestring to unpad Returns: unpadded bytestring Return type: bytes
-
-
gabes.crypto.
generate_zero_ciphertext
(left_label, right_label)[source]¶ Generates the label c that when decrypted using the
left_label
andright_label
keys will yield the zero ciphertext.Parameters: - left_label (
Label
) – left label to use as key - right_label (
Label
) – right label to use as key
Returns: encrypted text
Return type: bytes
>>> from gabes.crypto import AESKey, generate_zero_ciphertext >>> from gabes.label import Label >>> left_label, right_label = Label(0), Label(1) >>> key1 = AESKey(left_label.to_base64()) >>> key2 = AESKey(right_label.to_base64()) >>> enc = generate_zero_ciphertext(left_label, right_label) >>> enc b'\\\x07\x08\xd8\x05\x8bX\x1dE\x05\x83D ?\xe6 \x10\\\x07\x08\xd8\x05\x8bX\x1dE\x05\x83D ?\xe6\x10' >>> key1.encrypt(key2.encrypt(enc, pad=False), pad=False) b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ x00\x00\x00\x00\x00\x00\x00\x00\x00'
- left_label (
Network¶
This module is in charge of handling all the communication between the garbler and the evaluator, providing an easy API to hide the lower-level sockets.
-
gabes.network.
connect_garbler
(address)[source]¶ Connects the garbler to the socket. The garbler will act as the server, and the evaluator as the client.
Parameters: address (str) – the address of the socket (IP and the port number in the format IP:port) Returns: the socket and the client (the evaluator)
-
gabes.network.
connect_evaluator
(address)[source]¶ Connects the evaluator to the socket. The garbler will act as the server, and the evaluator as the client.
Parameters: address (str) – the address of the socket (IP and the port number in the format IP:port) Returns: the socket
-
gabes.network.
send_data
(sock, data)[source]¶ Sends
data
through the socket. The data is pickled so that objects can be sent through the socket. As the socket can accept a fixed size number of bytes, the function sends the size of the data to know how many bytes to receive through the network.Parameters: - sock – the socket or the client
- data (bytes) – the data to send through the socket
-
gabes.network.
receive_data
(from_whom)[source]¶ Receives data through the socket.
Parameters: from_whom – either the client (evaluator) or the socket (the garbler) Returns: the unpickled data
Oblivious Transfer¶
This module implements 1-out-of-2 oblivious transfer. Essentially,
the garbler inputs to the protocol two messages m0
and m1
,
while the evaluator inputs a single bit b
. The garbler
learns nothing from this protocol and the evaluator learns either
m0
or m1
depending on his bit b
, but not both.
The OT protocol followed in this module is the following:
1. The garbler generates an RSA public/private key pair and sends the public portion
(e, N)
to the evaluator along with two random messagesx0
andx1
.2. The evaluator generates a random
k
and depending on his bitb
sends to the garblerv = (xb + k ^ e) mod N
.3. The garbler computes both
k0 = (v - x0) ^ d mod N
andk1 = (v - x1) ^ d mod N
. One of these will equalk
, but he doesn’t know which.4. The garbler sends
m0_ = m0 + k0
andm1_ = m1 + k1
to the evaluator.5. The evaluator decrypts depending on his bit
mb_ = mb - k
, learning onlym0
orm1
.
-
gabes.ot.
garbler_ot
(client, m0, m1)[source]¶ The OT protocol seen from the point of view of the garbler. This includes creating the RSA key pair, generating
x0
andx1
, computingk0
andk1
, and sendingm0_
andm1_
. Note that pickling of m0 and m1 is done beforehand for it to be possible to sendLabel
objects.Parameters: - client – the evaluator’s address
- m0 (bytes) – the first bytes object (in this case, a label)
- m1 (bytes) – the second bytes object (in this case, a label)
Utils¶
This module includes utility functions used throughout the package.
-
gabes.utils.
ask_for_inputs
(identifiers)[source]¶ CLI helper function that queries the user to indicate which identifier he supplies and the his choice for each identifier.
Parameters: identifiers (list(str)) – the identifiers of the input wires Returns: the identifiers the user supplies Return type: dict
-
gabes.utils.
get_last_bit
(label)[source]¶ Gets the last bit from a bytestring.
Parameters: label (bytes) – any bytes object Returns: the last bit Return type: bool >>> import os >>> from gabes.utils import get_last_bit >>> b1 = os.urandom(10) >>> b1 b'\xf3\x9e\xb0w,|\xd9\xa8\xd73' >>> get_last_bit(b1) False
-
gabes.utils.
xor
(b1, b2)[source]¶ XORs two bytestrings.
Parameters: - b1 (bytes) – first argument
- b2 (bytes) – second argument
Returns: the XORed result
Return type: bytes
>>> import os >>> from gabes.utils import get_last_bit >>> b1 = os.urandom(10) >>> b2 = os.urandom(10) >>> b1, b2 (b'\xf8\x00r\xaf\x9a\x06!68\x83', b'\x88 \xee\x1c,a\xd0^\x8a\xb4\xf2') >>> xor(b1, b2) b'p\xeen\x83\xfb\xd6\x7f\xbc\x8cq' >>> xor(b1, xor(b1, b2)) == b2 True