-
Notifications
You must be signed in to change notification settings - Fork 1
/
Protocol_2.py
55 lines (44 loc) · 1.82 KB
/
Protocol_2.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
class Server:
"""Private key holder. Decrypts the average gradient"""
def __init__(self, key_length):
keypair = paillier.generate_paillier_keypair(n_length=key_length)
self.pubkey, self.privkey = keypair
def decrypt_aggregate(self, input_model, n_clients):
return decrypt_vector(self.privkey, input_model) / n_clients
class Client:
"""Runs linear regression with local data or by gradient steps,
where gradient can be passed in.
Using public key can encrypt locally computed gradients.
"""
def __init__(self, name, X, y, pubkey):
self.name = name
self.pubkey = pubkey
self.X, self.y = X, y
self.weights = np.zeros(X.shape[1])
def fit(self, n_iter, eta=0.01):
"""Linear regression for n_iter"""
for _ in range(n_iter):
gradient = self.compute_gradient()
self.gradient_step(gradient, eta)
def gradient_step(self, gradient, eta=0.01):
"""Update the model with the given gradient"""
self.weights -= eta * gradient
def compute_gradient(self):
"""Compute the gradient of the current model using the training set
"""
delta = self.predict(self.X) - self.y
return delta.dot(self.X) / len(self.X)
def predict(self, X):
"""Score test data"""
return X.dot(self.weights)
def encrypted_gradient(self, sum_to=None):
"""Compute and encrypt gradient.
When `sum_to` is given, sum the encrypted gradient to it, assumed
to be another vector of the same size
"""
gradient = self.compute_gradient()
encrypted_gradient = encrypt_vector(self.pubkey, gradient)
if sum_to is not None:
return sum_encrypted_vectors(sum_to, encrypted_gradient)
else:
return encrypted_gradient