Skip to content

Commit 1d94006

Browse files
committed
refactored the whole project and revamped the ML model
1 parent e533195 commit 1d94006

File tree

13 files changed

+1650
-1211
lines changed

13 files changed

+1650
-1211
lines changed

.gitignore

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
# Python
3+
__pycache__/
4+
*.py[cod]
5+
*$py.class
6+
7+
# Virtual environments
8+
venv/
9+
env/
10+
ENV/
11+
env.bak/
12+
venv.bak/
13+
14+
# Flask
15+
instance/
16+
.webassets-cache
17+
18+
# Distribution / packaging
19+
build/
20+
develop-eggs/
21+
dist/
22+
downloads/
23+
eggs/
24+
.eggs/
25+
lib/
26+
lib64/
27+
parts/
28+
sdist/
29+
var/
30+
*.egg-info/
31+
.installed.cfg
32+
*.egg
33+
34+
# IDEs and editors
35+
.vscode/
36+
.idea/
37+
*.sublime-project
38+
*.sublime-workspace
39+
40+
# OS files
41+
.DS_Store
42+
Thumbs.db

README.md

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,72 @@ serializeDataCompany()
2222
```
2323
![Architecture](./architecture.png)
2424

25-
Use the package manager [pip](https://pip.pypa.io/en/stable/) to install the prerequisites.
25+
### How to Run Locally
2626

27-
```bash
28-
pip install -r requirements.txt
29-
```
27+
1. **Clone the Repository**
28+
29+
```bash
30+
git clone https://github.com/yourusername/Partial-Homomorphic-Encryption-on-Machine-learning.git
31+
cd Partial-Homomorphic-Encryption-on-Machine-learning
32+
```
33+
34+
2. **Set Up a Conda Environment**
35+
36+
```bash
37+
conda create -n phe_ml_env python=3.8
38+
conda activate phe_ml_env
39+
```
40+
41+
3. **Install Dependencies**
42+
43+
```bash
44+
pip install -r requirements.txt
45+
```
46+
47+
4. **Train the Machine Learning Model**
48+
49+
Before running the application, train the model to generate the `improved_model.pkl` file.
50+
51+
```bash
52+
python train.py
53+
```
54+
55+
5. **Generate Encryption Keys**
56+
57+
```python
58+
# ...existing code...
59+
python cust.py
60+
```
61+
62+
6. **Start the Flask Application**
63+
64+
```bash
65+
python app.py
66+
```
67+
68+
7. **Access the Application**
69+
70+
Open your web browser and navigate to `http://localhost:5000/` to interact with the application.
3071

3172
## Usage
3273

33-
The main app.py (flask file) contains the code for implementing all the above functions
74+
The main `app.py` (Flask file) contains the code for implementing all the above functions
3475
```bash
35-
@app.route('/customerEncryption',methods=['GET','POST'])
36-
def customerEncryption(): #handles the encryption on client side
37-
38-
@app.route('/company',methods=['GET','POST'])
39-
def company(): #handles the encryption on client side
76+
@app.route('/customerEncryption', methods=['GET','POST'])
77+
def customerEncryption(): # Handles the encryption on client side
4078

41-
@app.route('/result',methods=['GET','POST'])
42-
def result(): #generates the final output on the client side
79+
@app.route('/company', methods=['GET','POST'])
80+
def company(): # Handles the encryption on company side
4381

82+
@app.route('/result', methods=['GET','POST'])
83+
def result(): # Generates the final output on the client side
4484
```
4585

46-
## Final thoughts
47-
* This is a high level glimpse to the future of ML and cryptography but not yet production ready.
48-
* Partial Homomorphic Encryption is a great way to perform complex ML computations on encrypted sample
49-
* Evolving space with Fully-Homomorphic encryption which is in research right now
50-
* This will likely be demand in the next 5-7 years.
86+
## Final Thoughts
87+
* This is a high-level glimpse into the future of ML and cryptography but not yet production-ready.
88+
* Partial Homomorphic Encryption is a great way to perform complex ML computations on encrypted samples.
89+
* Evolving space with Fully-Homomorphic Encryption which is in research right now.
90+
* This will likely be in demand in the next 5-7 years.
5191

5292
## Contributing
5393
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

app.py

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,116 @@
1+
"""Flask application for Homomorphic Encryption-based Salary Prediction."""
2+
13
import numpy as np
2-
from flask import Flask, request, jsonify, render_template,redirect,url_for
4+
from flask import Flask, request, jsonify, render_template, redirect, url_for
35
import json
6+
import os
47
from cust import *
58
from servercalc import *
69
from os import path
710

811
app = Flask(__name__)
912

10-
@app.route('/',methods=['GET','POST'])
11-
13+
@app.route('/', methods=['GET', 'POST'])
1214
def home():
15+
"""
16+
Render the home page.
1317
18+
Returns:
19+
Rendered index.html template.
20+
"""
1421
return render_template('index.html')
1522

16-
@app.route('/customerEncryption',methods=['GET','POST'])
23+
@app.route('/customerEncryption', methods=['GET', 'POST'])
1724
def customerEncryption():
25+
"""
26+
Handle customer encryption data submission.
27+
28+
- Generates encryption keys if not present.
29+
- Encrypts customer data and saves it to data.json.
30+
- Renders the cust.html template with encryption keys.
31+
32+
Returns:
33+
Rendered cust.html template with keys.
34+
"""
35+
# Check if encryption keys exist; if not, generate and store them
1836
if not path.exists('custkeys.json'):
1937
storeKeys()
2038

39+
# Retrieve existing encryption keys
2140
pub_key, priv_key = getKeys()
2241

42+
# Extract features from the form and convert them to integers
2343
features = [int(x) for x in request.form.values()]
24-
datafileCustomer=serializeDataCustomer(pub_key,features)
44+
# Serialize and encrypt the customer data
45+
datafileCustomer = serializeDataCustomer(pub_key, features)
46+
# Save encrypted data to data.json
2547
with open('data.json', 'w') as file:
2648
json.dump(datafileCustomer, file)
2749

28-
keys=[pub_key,priv_key]
29-
return render_template('cust.html',keys=keys)
50+
# Prepare keys to send to the frontend
51+
keys = {'public_key': pub_key, 'private_key': priv_key}
52+
# Render the customer details page with keys
53+
return render_template('cust.html', keys=keys)
3054

31-
@app.route('/company',methods=['GET','POST'])
55+
@app.route('/company', methods=['GET', 'POST'])
3256
def company():
33-
datafileCompany=serializeDataCompany()
57+
"""
58+
Handle company data submission for salary prediction.
59+
60+
- Serializes and computes encrypted data.
61+
- Saves the result to answer.json.
62+
- Renders the company.html template with encrypted data.
63+
64+
Returns:
65+
Rendered company.html template with encrypted data.
66+
"""
67+
# Serialize data for the company and compute encrypted results
68+
datafileCompany = serializeDataCompany()
69+
# Save encrypted company data to answer.json
3470
with open('answer.json', 'w') as file:
35-
json.dump(datafileCompany,file)
36-
71+
json.dump(datafileCompany, file)
3772

38-
return render_template('company.html',datafileCompany=datafileCompany)
73+
# Render the company details page with encrypted data
74+
return render_template('company.html', datafileCompany=datafileCompany)
3975

40-
#return redirect(url_for('result'))
76+
# Optionally redirect to the result page
77+
# return redirect(url_for('result'))
4178

42-
@app.route('/result',methods=['GET','POST'])
79+
@app.route('/result', methods=['GET', 'POST'])
4380
def result():
44-
answer_file=loadAnswer()
45-
answer_key=paillier.PaillierPublicKey(n=int(answer_file['pubkey']['n']))
46-
answer = paillier.EncryptedNumber(answer_key, int(answer_file['values'][0]), int(answer_file['values'][1]))
81+
"""
82+
Process the encrypted data to decrypt and display the predicted salary.
83+
84+
Steps:
85+
- Load encrypted answer from answer.json.
86+
- Decrypt the result using customer's private key.
87+
- Round the final result to two decimal places.
88+
- Render the result.html template with the final result.
89+
90+
Returns:
91+
Rendered result.html template with the final predicted salary.
92+
"""
93+
# Load the encrypted answer data
94+
answer_file = loadAnswer()
95+
# Initialize the public key from the answer file
96+
answer_key = paillier.PaillierPublicKey(n=int(answer_file['pubkey']['n']))
97+
# Unpack the ciphertext and exponent
98+
ciphertext_str, exponent = answer_file['values'] # Changed from answer_file['values'][0]
99+
# Create an EncryptedNumber instance
100+
answer = paillier.EncryptedNumber(answer_key, int(ciphertext_str), exponent)
101+
# Retrieve customer's keys
47102
pub_key, priv_key = getKeys()
48-
if (answer_key==pub_key):
49-
final_result=priv_key.decrypt(answer)
50-
103+
if answer_key.n == pub_key.n:
104+
# Decrypt the answer using the private key
105+
final_result = priv_key.decrypt(answer)
106+
# Round the result to two decimal places
107+
final_result = round(final_result, 2) # Rounded to 2 decimals
108+
else:
109+
final_result = "Keys do not match."
51110

52-
return render_template('result.html',final_result=final_result)
111+
# Render the result page with the final predicted salary
112+
return render_template('result.html', final_result=final_result)
53113

54-
55114
if __name__ == "__main__":
56-
app.run(debug=True)
115+
# Run the Flask app with debug mode disabled for production
116+
app.run(debug=False)

cust.py

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,83 @@
1+
"""Customer-side encryption handling for Homomorphic Encryption-based Salary Prediction."""
2+
13
import phe as paillier
24
import json
35

46
def storeKeys():
5-
public_key, private_key = paillier.generate_paillier_keypair()
6-
keys={}
7-
keys['public_key'] = {'n': public_key.n}
8-
keys['private_key'] = {'p': private_key.p,'q':private_key.q}
9-
with open('custkeys.json', 'w') as file:
10-
json.dump(keys, file)
7+
"""
8+
Generate and store the Paillier public and private keys.
9+
10+
The keys are saved to 'custkeys.json' in JSON format.
11+
"""
12+
# Generate Paillier key pair
13+
public_key, private_key = paillier.generate_paillier_keypair()
14+
keys = {}
15+
# Serialize public key
16+
keys['public_key'] = {'n': public_key.n}
17+
# Serialize private key components
18+
keys['private_key'] = {'p': private_key.p, 'q': private_key.q}
19+
# Save keys to custkeys.json
20+
with open('custkeys.json', 'w') as file:
21+
json.dump(keys, file)
1122

1223
def getKeys():
13-
with open('custkeys.json', 'r') as file:
14-
15-
keys=json.load(file)
16-
pub_key=paillier.PaillierPublicKey(n=int(keys['public_key']['n']))
17-
priv_key=paillier.PaillierPrivateKey(pub_key,keys['private_key']['p'],keys['private_key']['q'])
18-
return pub_key, priv_key
24+
"""
25+
Retrieve the Paillier public and private keys from 'custkeys.json'.
26+
27+
Returns:
28+
tuple: (PaillierPublicKey, PaillierPrivateKey)
29+
"""
30+
with open('custkeys.json', 'r') as file:
31+
keys = json.load(file)
32+
# Reconstruct public key
33+
pub_key = paillier.PaillierPublicKey(n=int(keys['public_key']['n']))
34+
# Reconstruct private key
35+
priv_key = paillier.PaillierPrivateKey(pub_key, int(keys['private_key']['p']), int(keys['private_key']['q']))
36+
return pub_key, priv_key
1937

2038
def serializeDataCustomer(public_key, data):
21-
encrypted_data_list = [public_key.encrypt(x) for x in data]
22-
encrypted_data={}
23-
encrypted_data['public_key'] = {'n': public_key.n}
24-
encrypted_data['values'] = [(str(x.ciphertext()), x.exponent) for x in encrypted_data_list]
25-
serialized = json.dumps(encrypted_data)
26-
return serialized
39+
"""
40+
Encrypt customer data using the provided public key.
41+
42+
Args:
43+
public_key (PaillierPublicKey): The public key for encryption.
44+
data (list): List of integer features to encrypt.
45+
46+
Returns:
47+
dict: Serialized encrypted data containing public key and encrypted values.
48+
"""
49+
# Encrypt each data feature
50+
encrypted_data_list = [public_key.encrypt(x) for x in data]
51+
encrypted_data = {}
52+
# Store public key
53+
encrypted_data['public_key'] = {'n': public_key.n}
54+
# Store encrypted features as ciphertext and exponent tuples
55+
encrypted_data['values'] = [(str(x.ciphertext()), x.exponent) for x in encrypted_data_list]
56+
# Return as a dictionary instead of a JSON string
57+
return encrypted_data
2758

2859
def loadAnswer():
60+
"""
61+
Load the encrypted answer data from 'answer.json'.
62+
63+
Returns:
64+
dict: Encrypted answer data.
65+
"""
2966
with open('answer.json', 'r') as file:
30-
ans=json.load(file)
31-
answer=json.loads(ans)
32-
return answer
67+
ans = json.load(file)
68+
return ans
3369

70+
# Example usage (commented out)
3471
# pub_key, priv_key = getKeys()
3572
# data = age, he, al, gen = [24,4,6,1]
3673
# serializeDataCustomer(pub_key, data)
37-
# datafileCustomer=serializeDataCustomer(pub_key, data)
74+
# datafileCustomer = serializeDataCustomer(pub_key, data)
3875
# with open('data.json', 'w') as file:
3976
# json.dump(datafileCustomer, file)
4077

41-
# answer_file=loadAnswer()
42-
# answer_key=paillier.PaillierPublicKey(n=int(answer_file['pubkey']['n']))
78+
# answer_file = loadAnswer()
79+
# answer_key = paillier.PaillierPublicKey(n=int(answer_file['pubkey']['n']))
4380
# answer = paillier.EncryptedNumber(answer_key, int(answer_file['values'][0]), int(answer_file['values'][1]))
44-
# if (answer_key==pub_key):
81+
# if (answer_key == pub_key):
4582
# print(priv_key.decrypt(answer))
46-
83+

0 commit comments

Comments
 (0)