pryvx 2.4.0__py3-none-any.whl → 2.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pryvx/__init__.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from .psi import OPRF
2
2
  from .phe import PHE
3
3
  from .smpc import SMPC
4
- from .gdp import GDP
4
+ from .gdp import GDP
5
+ from .ldp import LDP
pryvx/fl_client.py CHANGED
@@ -2,10 +2,11 @@ import grpc
2
2
  from pryvx import pryvx_pb2
3
3
  from pryvx import pryvx_pb2_grpc
4
4
  from sklearn.linear_model import LogisticRegression
5
+ from sklearn.ensemble import RandomForestClassifier
5
6
  import pickle
6
7
 
7
8
 
8
- def train(features, labels):
9
+ def train_logistic_classifier(features, labels):
9
10
  model = LogisticRegression()
10
11
  model.fit(features, labels)
11
12
 
@@ -13,6 +14,13 @@ def train(features, labels):
13
14
 
14
15
  return serialized_model
15
16
 
17
+ def train_random_forest_classifier(features, labels):
18
+ model = RandomForestClassifier(n_estimators=100, random_state=42)
19
+ model.fit(features, labels)
20
+ serialized_model = pickle.dumps(model)
21
+
22
+ return serialized_model
23
+
16
24
 
17
25
  def send_params(serialized_model, connection_url):
18
26
 
pryvx/fl_ensemble.py ADDED
@@ -0,0 +1,16 @@
1
+ from sklearn.ensemble import VotingClassifier
2
+
3
+ # estimators = [('client_1', model_1), ('client_2', model_2), ('client_3', model_3)]
4
+
5
+ def federated_ensemble(estimators, X_test):
6
+ # Create an ensemble using soft voting
7
+ ensemble_model = VotingClassifier(
8
+ estimators=estimators,
9
+ voting='soft' # Soft voting (probability-based)
10
+ )
11
+
12
+ # Make predictions
13
+ y_pred_ensemble = ensemble_model.predict(X_test)
14
+
15
+ return y_pred_ensemble
16
+
pryvx/fl_server.py CHANGED
@@ -3,21 +3,39 @@ from pryvx import pryvx_pb2
3
3
  from pryvx import pryvx_pb2_grpc
4
4
  import pickle
5
5
  from concurrent import futures
6
+ import os
7
+ import datetime
8
+
9
+ # Directory to store received models
10
+ MODEL_SAVE_PATH = "received_models/"
11
+ os.makedirs(MODEL_SAVE_PATH, exist_ok=True)
6
12
 
7
- # Server
8
13
  class ModelServicer(pryvx_pb2_grpc.ModelServiceServicer):
9
14
  def __init__(self):
10
- self.client_params = {}
15
+ self.client_models = {} # Store models from clients
11
16
 
12
17
  def SendModelParams(self, request, context):
13
- # Deserialize the model
14
- loaded_model = pickle.loads(request.params)
15
-
16
- # save model to gcp storage bucket
17
-
18
- print("Received model params from client")
19
-
20
- return pryvx_pb2.ModelParams(params=request.params)
18
+ try:
19
+ # Deserialize model received from client
20
+ model = pickle.loads(request.params)
21
+
22
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
23
+
24
+ # Assign a unique client ID
25
+ client_id = f"client_{len(self.client_models) + 1}"
26
+ self.client_models[client_id] = model
27
+
28
+ # Save model to disk
29
+ model_filename = os.path.join(MODEL_SAVE_PATH, f"{client_id}_model_{timestamp}.pkl")
30
+ with open(model_filename, "wb") as f:
31
+ pickle.dump(model, f)
32
+
33
+ print(f"✅ Received and saved model from {client_id}")
34
+
35
+ return pryvx_pb2.ModelResponse(message=f"Model from {client_id} received and saved.")
36
+ except Exception as e:
37
+ print(f"❌ Error processing model: {e}")
38
+ return pryvx_pb2.ModelResponse(message="Failed to process model")
21
39
 
22
40
 
23
41
  def start_server():
pryvx/gdp.py CHANGED
@@ -1,15 +1,27 @@
1
1
  import numpy as np
2
2
 
3
- def laplace_mechanism(true_value, sensitivity, epsilon):
3
+ # Laplace Mechanism for continuous data.
4
+ # Gaussian Mechanism for continuous data (commonly used in GDP).
5
+
6
+ def laplace_mechanism(query_result, sensitivity, epsilon):
4
7
  """Applies the Laplace mechanism for GDP."""
5
8
  scale = sensitivity / epsilon
6
9
  noise = np.random.laplace(0, scale, 1)
7
- return true_value + noise[0]
10
+ return query_result + noise[0]
8
11
 
12
+ def gaussian_mechanism(query_result, epsilon=0.5, delta=1e-5, sensitivity=1.0):
13
+ """Adds Gaussian noise to a global query result."""
14
+ sigma = np.sqrt(2 * np.log(1.25 / delta)) * sensitivity / epsilon
15
+ noise = np.random.normal(0, sigma)
16
+ return query_result + noise
9
17
 
10
18
  class GDP:
11
19
  @staticmethod
12
20
  def add_noise(query_result, sensitivity, epsilon):
13
21
  return laplace_mechanism(query_result, sensitivity, epsilon)
22
+
23
+ @staticmethod
24
+ def add_gaussian_noise(query_result):
25
+ return gaussian_mechanism(query_result)
14
26
 
15
27
 
pryvx/ldp.py ADDED
@@ -0,0 +1,26 @@
1
+ import numpy as np
2
+ import random
3
+
4
+ # Laplace Mechanism (common for numeric data)
5
+ # Randomized Response (common for categorical/binary data)
6
+
7
+ def laplace_mechanism(value, epsilon, sensitivity=1.0):
8
+ """Adds Laplace noise to a numeric value for LDP."""
9
+ scale = sensitivity / epsilon
10
+ noise = np.random.laplace(0, scale)
11
+ return value + noise
12
+
13
+ def randomized_response(value, epsilon):
14
+ """Implements randomized response for binary data."""
15
+ p = np.exp(epsilon) / (1 + np.exp(epsilon))
16
+ return value if random.random() < p else 1 - value
17
+
18
+ class LDP:
19
+ @staticmethod
20
+ def add_numerical_noise(value, epsilon):
21
+ return laplace_mechanism(value, epsilon)
22
+
23
+ def add_categorical_noise(value, epsilon):
24
+ return randomized_response(value, epsilon)
25
+
26
+
pryvx/phe.py CHANGED
@@ -26,6 +26,14 @@ class PHE:
26
26
  private_key = (lambda_n, mu)
27
27
  return public_key, private_key
28
28
 
29
+ @staticmethod
30
+ def encode(value, scale_factor=1000):
31
+ return int(round(value * scale_factor))
32
+
33
+ @staticmethod
34
+ def decode(value, scale_factor=1000):
35
+ return value / scale_factor
36
+
29
37
  @staticmethod
30
38
  def encrypt(public_key, plaintext, r=None):
31
39
  n, g = public_key
@@ -56,6 +64,22 @@ class PHE:
56
64
  n2 = n * n
57
65
  return (c1 * c2) % n2
58
66
 
67
+ @staticmethod
68
+ def homomorphic_add_plaintext(ciphertext, plaintext, public_key):
69
+ n, g = public_key
70
+ n2 = n * n
71
+ c_plain = pow(g, plaintext, n2)
72
+ return (ciphertext * c_plain) % n2
73
+
74
+ @staticmethod
75
+ def homomorphic_sub_plaintext(ciphertext, plaintext, public_key):
76
+ n, g = public_key
77
+ n2 = n * n
78
+
79
+ # Encrypt the plaintext as its negative (-plaintext) mod n
80
+ c_plain_neg = pow(g, -plaintext % n, n2) # Modular inverse for subtraction
81
+ return (ciphertext * c_plain_neg) % n2
82
+
59
83
  @staticmethod
60
84
  def homomorphic_sub(c1, c2, public_key):
61
85
  n, _ = public_key
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pryvx
3
- Version: 2.4.0
3
+ Version: 2.4.2
4
4
  Summary: A comprehensive package for privacy-enhancing technologies
5
5
  Home-page: UNKNOWN
6
6
  Author: PryvX (Jayesh Kenaudekar)
@@ -0,0 +1,16 @@
1
+ pryvx/__init__.py,sha256=QvpYISJ8MH7XnbxC5iTMTycq7Svsld0NIbMozcndYjo,111
2
+ pryvx/fl_client.py,sha256=axJKdQgXDMs1FT8rgI2HzG8keyEG__U9Y4GtiWWeHO4,986
3
+ pryvx/fl_ensemble.py,sha256=cUPPx3QpnalRKtIBtoE4PCTk34E7940W7ZxGtUisDgo,475
4
+ pryvx/fl_server.py,sha256=bJ_dm-UZvmq-JUB58b_F_V5-IsmB3eC2RS0JjF5CPs8,1739
5
+ pryvx/gdp.py,sha256=ToLtWNvBKtSs-3Na1pGe_J6dWvBxXhV2raUJkNtKMg4,925
6
+ pryvx/ldp.py,sha256=WxBQLnZ_b2wNV1rlN7rtKXaQ5waUPPvnRus-4tUnCB8,810
7
+ pryvx/phe.py,sha256=HN70aUNTq0w9vRPMaNGfTnNi00gMQ1B7R7Cm6r6rheE,2974
8
+ pryvx/pryvx_pb2.py,sha256=-ce40VMW0nQcjyhAJy1BvI32wtWNm425LSIExspK_qg,1200
9
+ pryvx/pryvx_pb2_grpc.py,sha256=pRQKblTNIVEwHsMQmhC-HGJFzsLh0sdOzQ-ksFYVK-A,2437
10
+ pryvx/psi.py,sha256=V0BUJwYfiFWhKtEL27q45yxY7U-I7B4olKQhaGbgN50,1346
11
+ pryvx/smpc.py,sha256=FZcE3gZo8WUVPmcBHSgP8iOkWt3AKcBLSLCtKczy8hs,2247
12
+ pryvx-2.4.2.dist-info/LICENSE,sha256=pbIMXbaorAIVW-fDch2tvtZRkVA3mz-UnXQqeCf4LDg,1086
13
+ pryvx-2.4.2.dist-info/METADATA,sha256=axWXanMU4AAmUsGygBZlLx7BYDT6v6LNqW9pGaw02Rk,1066
14
+ pryvx-2.4.2.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
15
+ pryvx-2.4.2.dist-info/top_level.txt,sha256=1iHoeevu_FoFjdPg8HyMlgvHNUm1--9QEpFMaJEa4hw,6
16
+ pryvx-2.4.2.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- pryvx/__init__.py,sha256=A6GcpkYgwgf_HOrneIhGs3iTsiEyvd9vYEMsmrMUqWQ,89
2
- pryvx/fl_client.py,sha256=p8QPlv5-CjTCwfzN0QkPr7bjKJEbU3c9Aa3HhpvZNJE,677
3
- pryvx/fl_server.py,sha256=9fUqZfA9RZOe0fM7FYnk_8qLNw6VMj-x8tzeGXZpgKA,890
4
- pryvx/gdp.py,sha256=-HK3Xml-huOdfz2SSmBvpgca0iU9-RwCiaD6ZyMq7bY,408
5
- pryvx/phe.py,sha256=NLYaLFCNN5aQfL0kC1YTUi962e930p2ae5dw3flJ0qo,2178
6
- pryvx/pryvx_pb2.py,sha256=-ce40VMW0nQcjyhAJy1BvI32wtWNm425LSIExspK_qg,1200
7
- pryvx/pryvx_pb2_grpc.py,sha256=pRQKblTNIVEwHsMQmhC-HGJFzsLh0sdOzQ-ksFYVK-A,2437
8
- pryvx/psi.py,sha256=V0BUJwYfiFWhKtEL27q45yxY7U-I7B4olKQhaGbgN50,1346
9
- pryvx/smpc.py,sha256=FZcE3gZo8WUVPmcBHSgP8iOkWt3AKcBLSLCtKczy8hs,2247
10
- pryvx-2.4.0.dist-info/LICENSE,sha256=pbIMXbaorAIVW-fDch2tvtZRkVA3mz-UnXQqeCf4LDg,1086
11
- pryvx-2.4.0.dist-info/METADATA,sha256=PhZ10Rw7ngp_mhVp2Au9YED-g_KMVKtHmUpDp4e0Zqg,1066
12
- pryvx-2.4.0.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
13
- pryvx-2.4.0.dist-info/top_level.txt,sha256=1iHoeevu_FoFjdPg8HyMlgvHNUm1--9QEpFMaJEa4hw,6
14
- pryvx-2.4.0.dist-info/RECORD,,
File without changes
File without changes