"""
This module implements 1-out-of-2 oblivious transfer. Essentially,
the garbler inputs to the protocol two messages :code:`m0` and :code:`m1`,
while the evaluator inputs a single bit :code:`b`. The garbler
learns nothing from this protocol and the evaluator learns either
:code:`m0` or :code:`m1` depending on his bit :code:`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 :code:`(e, N)` to the evaluator along with
two random messages :code:`x0` and :code:`x1`.
2. The evaluator generates a random :code:`k` and depending on his bit
:code:`b` sends to the garbler :code:`v = (xb + k ^ e) mod N`.
3. The garbler computes both :code:`k0 = (v - x0) ^ d mod N` and
:code:`k1 = (v - x1) ^ d mod N`. One of these will equal :code:`k`,
but he doesn't know which.
4. The garbler sends :code:`m0_ = m0 + k0` and :code:`m1_ = m1 + k1`
to the evaluator.
5. The evaluator decrypts depending on his bit :code:`mb_ = mb - k`,
learning only :code:`m0` or :code:`m1`.
"""
import pickle
from random import randint
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from gabes.network import send_data, receive_data, send_ack, wait_for_ack
[docs]def garbler_ot(client, m0, m1):
"""
The OT protocol seen from the point of view of the garbler.
This includes creating the RSA key pair, generating
:code:`x0` and :code:`x1`, computing :code:`k0` and :code:`k1`, and
sending :code:`m0_` and :code:`m1_`. Note that pickling of
m0 and m1 is done beforehand for it to be possible to send
:class:`Label` objects.
:param client: the evaluator's address
:param bytes m0: the first bytes object (in this case, a label)
:param bytes m1: the second bytes object (in this case, a label)
"""
private_key = rsa.generate_private_key(public_exponent=65537,
key_size=512,
backend=default_backend())
d = private_key.private_numbers().d
public_key = private_key.public_key()
n, e = public_key.public_numbers().n, public_key.public_numbers().e
x0, x1 = [randint(2, n // 2) for _ in range(2)]
send_data(client, [x0, x1, n, e])
v = receive_data(client)
k0, k1 = [pow((v - x), d, n) for x in (x0, x1)]
bytes_m0 = pickle.dumps(m0)
bytes_m1 = pickle.dumps(m1)
m0 = int.from_bytes(bytes_m0, byteorder='big')
m1 = int.from_bytes(bytes_m1, byteorder='big')
send_data(client, [m0 + k0, m1 + k1, len(bytes_m0), len(bytes_m1)])
wait_for_ack(client)
[docs]def evaluator_ot(sock, b):
"""
The OT protocol seen from the point of view of the evaluator.
This includes choosing the random :code:`k`, sending
:code:`v`, and learning either :code:`m0` or :code:`m1`.
:param sock: the garbler's address
:param bool b: the evaluator's bit
"""
x0, x1, n, e = receive_data(sock)
k = randint(2, n // 2)
chosen_x = x1 if b == '1' else x0
v = (chosen_x + pow(k, e, n)) % n
send_data(sock, v)
t0, t1, size_m0, size_m1 = receive_data(sock)
chosen_t = t1 if b == '1' else t0
chosen_size = size_m1 if b == '1' else size_m0
m = chosen_t - k
label = pickle.loads(int.to_bytes(m, length=chosen_size, byteorder='big'))
send_ack(sock)
return label