-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathutil.py
125 lines (92 loc) · 3.32 KB
/
util.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import json
import operator
import random
import secrets
import sympy
import zmq
# SOCKET
LOCAL_PORT = 4080
SERVER_HOST = "localhost"
SERVER_PORT = 4080
class Socket:
def __init__(self, socket_type):
self.socket = zmq.Context().socket(socket_type)
self.poller = zmq.Poller()
self.poller.register(self.socket, zmq.POLLIN)
def send(self, msg):
self.socket.send_pyobj(msg)
def receive(self):
return self.socket.recv_pyobj()
def send_wait(self, msg):
self.send(msg)
return self.receive()
"""
From https://stackoverflow.com/questions/17174001/stop-pyzmq-receiver-by-keyboardinterrupt
"""
def poll_socket(self, timetick=100):
try:
while True:
obj = dict(self.poller.poll(timetick))
if self.socket in obj and obj[self.socket] == zmq.POLLIN:
yield self.socket.recv_pyobj()
except KeyboardInterrupt:
pass
class EvaluatorSocket(Socket):
def __init__(self, endpoint=f"tcp://*:{LOCAL_PORT}"):
super().__init__(zmq.REP)
self.socket.bind(endpoint)
class GarblerSocket(Socket):
def __init__(self, endpoint=f"tcp://{SERVER_HOST}:{SERVER_PORT}"):
super().__init__(zmq.REQ)
self.socket.connect(endpoint)
# PRIME GROUP
PRIME_BITS = 64 # order of magnitude of prime in base 2
def next_prime(num):
"""Return next prime after 'num' (skip 2)."""
return 3 if num < 3 else sympy.nextprime(num)
def gen_prime(num_bits):
"""Return random prime of bit size 'num_bits'"""
r = secrets.randbits(num_bits)
return next_prime(r)
def xor_bytes(seq1, seq2):
"""XOR two byte sequence."""
return bytes(map(operator.xor, seq1, seq2))
def bits(num, width):
"""Convert number into a list of bits."""
return [int(k) for k in f'{num:0{width}b}']
class PrimeGroup:
"""Cyclic abelian group of prime order 'prime'."""
def __init__(self, prime=None):
self.prime = prime or gen_prime(num_bits=PRIME_BITS)
self.prime_m1 = self.prime - 1
self.prime_m2 = self.prime - 2
self.generator = self.find_generator()
def mul(self, num1, num2):
"Multiply two elements." ""
return (num1 * num2) % self.prime
def pow(self, base, exponent):
"Compute nth power of an element." ""
return pow(base, exponent, self.prime)
def gen_pow(self, exponent): # generator exponentiation
"Compute nth power of a generator." ""
return pow(self.generator, exponent, self.prime)
def inv(self, num):
"Multiplicative inverse of an element." ""
return pow(num, self.prime_m2, self.prime)
def rand_int(self): # random int in [1, prime-1]
"Return an random int in [1, prime - 1]." ""
return random.randint(1, self.prime_m1)
def find_generator(self): # find random generator for group
"""Find a random generator for the group."""
factors = sympy.primefactors(self.prime_m1)
while True:
candidate = self.rand_int()
for factor in factors:
if 1 == self.pow(candidate, self.prime_m1 // factor):
break
else:
return candidate
# HELPER FUNCTIONS
def parse_json(json_path):
with open(json_path) as json_file:
return json.load(json_file)