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

update_output_wire(false_label, true_label)[source]

Updates the output wire’s labels and point-and-permute bits.

Parameters:
  • false_label – the false label
  • true_label – the true label
wires()[source]

Returns the three wires related to the gate.

Returns:the three wires
Return type:list(Wire)

(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
get_label(representing)[source]

Gets the label according to which truth value it represents.

Parameters:representing (bool) – True for the true label and False for the false label
Returns:the corresponding label
Return type:Label
labels()[source]

A getter method to get the two labels (False and True) going through the wire.

Returns:a tuple of labels
Return type:Generator[Wire]

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='
to_base32()[source]

Returns the label encoded in base32.

Returns:the label in base32
Return type:str
to_base64()[source]

Returns the label encoded in base64.

Returns:the label in base64
Return type:str

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)

gabes.evaluator.learn_output(sock, secret_output)[source]

Sends the final label and learns the final truth value from the garbler.

Parameters:
  • sock – the socket from which it will receive the data
  • secret_output – the final label of the circuit
Returns:

the output of the circuit

Return type:

bool

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 and right_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'

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
gabes.network.send_ack(sock)[source]

Sends an ACK through the socket. This will be useful for the OT protocol.

Parameters:sock – either the client (evaluator) or the socket (the garbler)
gabes.network.wait_for_ack(sock)[source]

Waits until it receives an ACK through the socket. This will be useful for the OT protocol.

Parameters:sock – either the client (evaluator) or the socket (the garbler)

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 messages x0 and x1.

2. The evaluator generates a random k and depending on his bit b sends to the garbler v = (xb + k ^ e) mod N.

3. The garbler computes both k0 = (v - x0) ^ d mod N and k1 = (v - x1) ^ d mod N. One of these will equal k, but he doesn’t know which.

4. The garbler sends m0_ = m0 + k0 and m1_ = m1 + k1 to the evaluator.

5. The evaluator decrypts depending on his bit mb_ = mb - k, learning only m0 or m1.

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 and x1, computing k0 and k1, and sending m0_ and m1_. Note that pickling of m0 and m1 is done beforehand for it to be possible to send Label 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)
gabes.ot.evaluator_ot(sock, b)[source]

The OT protocol seen from the point of view of the evaluator. This includes choosing the random k, sending v, and learning either m0 or m1.

Parameters:
  • sock – the garbler’s address
  • b (bool) – the evaluator’s bit

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
gabes.utils.adjust_wire_offset(wire)[source]

Adjusts the wire’s offset so that the two labels have a distinct last bit.

Parameters:wire – the wire in question