pryvx 2.4.1__py3-none-any.whl → 2.4.3__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,26 +2,35 @@ 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
12
  serialized_model = pickle.dumps(model)
13
+ return serialized_model, model
13
14
 
14
- return serialized_model
15
15
 
16
+ def train_random_forest_classifier(features, labels):
17
+ model = RandomForestClassifier(n_estimators=100, random_state=42)
18
+ model.fit(features, labels)
19
+ serialized_model = pickle.dumps(model)
20
+ return serialized_model, model
16
21
 
17
- def send_params(serialized_model, connection_url):
22
+
23
+ def send_params(serialized_model, connection_url, client_id):
18
24
 
19
25
  with grpc.insecure_channel(connection_url) as channel:
20
26
  stub = pryvx_pb2_grpc.ModelServiceStub(channel)
21
27
 
28
+ # Attach metadata (client ID) in the request
29
+ metadata = (("client_id", client_id),)
30
+
22
31
  model_params = pryvx_pb2.ModelParams(params=serialized_model)
23
32
 
24
- response = stub.SendModelParams(model_params)
33
+ response = stub.SendModelParams(model_params, metadata=metadata)
25
34
 
26
- return "Model Params sent to server"
35
+ return f"Model Params sent to server from {client_id}"
27
36
 
pryvx/fl_ensemble.py ADDED
@@ -0,0 +1,20 @@
1
+ import numpy as np
2
+
3
+ def federated_ensemble(estimators, X_test):
4
+ """
5
+ Perform soft voting ensemble on a list of trained estimators.
6
+
7
+ :param estimators: List of trained models that support `predict_proba`
8
+ :param X_test: Test dataset (features only)
9
+ :return: Final predictions after soft voting
10
+ """
11
+ if not estimators:
12
+ raise ValueError("No models provided for ensemble.")
13
+
14
+ # Sum all probability predictions
15
+ avg_probs = sum(model.predict_proba(X_test) for model in estimators) / len(estimators)
16
+
17
+ # Convert probabilities to final predictions (highest probability wins)
18
+ y_pred_ensemble = np.argmax(avg_probs, axis=1)
19
+
20
+ return y_pred_ensemble
pryvx/fl_server.py CHANGED
@@ -3,21 +3,41 @@ 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
+ # Extract metadata (client ID)
20
+ client_id = dict(context.invocation_metadata()).get("client_id", "unknown_client")
21
+
22
+ # Deserialize model received from client
23
+ model = pickle.loads(request.params)
24
+
25
+ # Assign a unique client ID
26
+ client_id = f"client_{len(self.client_models) + 1}"
27
+ self.client_models[client_id] = model
28
+
29
+ # Save model to disk
30
+ model_filename = os.path.join(MODEL_SAVE_PATH, f"{client_id}_model.pkl")
31
+ with open(model_filename, "wb") as f:
32
+
33
+ pickle.dump(model, f)
34
+
35
+ print(f"✅ Received and saved model from {client_id}")
36
+
37
+ return pryvx_pb2.ModelResponse(message=f"Model from {client_id} received and saved.")
38
+ except Exception as e:
39
+ print(f"❌ Error processing model: {e}")
40
+ return pryvx_pb2.ModelResponse(message="Failed to process model")
21
41
 
22
42
 
23
43
  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
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pryvx
3
- Version: 2.4.1
3
+ Version: 2.4.3
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=gQNjv99tDDjaGj0JTdAVomefqR2F3_xNLcnHJ6aGZZo,1152
3
+ pryvx/fl_ensemble.py,sha256=lvgvd-zJDSBh-RyMAjTyJZwu0eFiUNXfCU7J2Vk7g0g,715
4
+ pryvx/fl_server.py,sha256=JqYtlLtLTcKxrNB8oY-hdZmG8VajS7mIqAY3OjOUxmU,1822
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.3.dist-info/LICENSE,sha256=pbIMXbaorAIVW-fDch2tvtZRkVA3mz-UnXQqeCf4LDg,1086
13
+ pryvx-2.4.3.dist-info/METADATA,sha256=Ytztu3-NrHGnG2XkIBalwkZSMQiP5d7UzU0V5C8wpdQ,1066
14
+ pryvx-2.4.3.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
15
+ pryvx-2.4.3.dist-info/top_level.txt,sha256=1iHoeevu_FoFjdPg8HyMlgvHNUm1--9QEpFMaJEa4hw,6
16
+ pryvx-2.4.3.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=HN70aUNTq0w9vRPMaNGfTnNi00gMQ1B7R7Cm6r6rheE,2974
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.1.dist-info/LICENSE,sha256=pbIMXbaorAIVW-fDch2tvtZRkVA3mz-UnXQqeCf4LDg,1086
11
- pryvx-2.4.1.dist-info/METADATA,sha256=omTieHCpjPJe3yoCkJZ0SoX2sFj0IUMRfHIQB-8TUzI,1066
12
- pryvx-2.4.1.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
13
- pryvx-2.4.1.dist-info/top_level.txt,sha256=1iHoeevu_FoFjdPg8HyMlgvHNUm1--9QEpFMaJEa4hw,6
14
- pryvx-2.4.1.dist-info/RECORD,,
File without changes
File without changes