File size: 8,615 Bytes
13fb76e
 
 
 
 
 
 
718b812
13fb76e
 
 
e5b8aae
718b812
 
 
e5b8aae
13fb76e
 
 
 
 
 
58df7f1
 
 
 
 
 
718b812
13fb76e
 
718b812
 
13fb76e
 
 
718b812
 
 
 
 
 
 
 
 
 
 
 
 
58df7f1
718b812
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49a1dd4
718b812
 
 
13fb76e
e3e1dc8
718b812
 
 
13fb76e
 
 
718b812
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58df7f1
 
 
 
 
718b812
 
58df7f1
e3e1dc8
718b812
 
58df7f1
 
 
 
 
718b812
58df7f1
 
13fb76e
58df7f1
718b812
13fb76e
58df7f1
 
 
13fb76e
58df7f1
13fb76e
 
718b812
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13fb76e
58df7f1
49a1dd4
e3e1dc8
718b812
13fb76e
58df7f1
 
 
13fb76e
58df7f1
13fb76e
e3e1dc8
58df7f1
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
"""Server that will listen for GET and POST requests from the client."""

import time
from typing import List

from fastapi import FastAPI, File, Form, UploadFile
from fastapi.responses import JSONResponse, Response
from utils import DEPLOYMENT_DIR_MODEL1, DEPLOYMENT_DIR_MODEL2, DEPLOYMENT_DIR_MODEL3, SERVER_DIR  # pylint: disable=no-name-in-module

from concrete.ml.deployment import FHEModelServer

# Load the FHE server
FHE_SERVER_MODEL1 = FHEModelServer(DEPLOYMENT_DIR_MODEL1)
FHE_SERVER_MODEL2 = FHEModelServer(DEPLOYMENT_DIR_MODEL2)
FHE_SERVER_MODEL3 = FHEModelServer(DEPLOYMENT_DIR_MODEL3)

# Initialize an instance of FastAPI
app = FastAPI()

# Define the default route
@app.get("/")
def root():
    """
    Root endpoint of the health prediction API.

    Returns:
        dict: The welcome message.
    """
    return {"message": "Welcome to your disease prediction with FHE made by Dhiria with love!"}


@app.post("/send_input_first_layer")
def send_input_first_layer(
    user_id: str = Form(),
    files: List[UploadFile] = File(),
):
    """Send the inputs of the first layer of the hierarchical models to the server.
    Order of the files:
    files[0]: encrypted input_model1
    files[1]: encrypted input_model2
    files[2]: evaluation keys
    """
    print('Receiving data for the first layer of models...')

    # Receive the Client's files (Evaluation key + Encrypted inputs for the models)
    evaluation_key_path_1 = SERVER_DIR / f"{user_id}_evaluation_key_1"
    evaluation_key_path_2 = SERVER_DIR / f"{user_id}_evaluation_key_2"
    encrypted_input_path_model1 = SERVER_DIR / f"{user_id}_encrypted_input_model1"
    encrypted_input_path_model2 = SERVER_DIR / f"{user_id}_encrypted_input_model2"

    # Save the files using the above paths
    with encrypted_input_path_model1.open("wb") as encrypted_input_model1, \
         encrypted_input_path_model2.open("wb") as encrypted_input_model2, \
         evaluation_key_path_1.open("wb") as evaluation_key_1, \
         evaluation_key_path_2.open("wb") as evaluation_key_2:
        encrypted_input_model1.write(files[0].file.read())
        encrypted_input_model2.write(files[1].file.read())
        evaluation_key_1.write(files[2].file.read())
        evaluation_key_2.write(files[3].file.read())


@app.post("/send_input_second_layer")
def send_input_second_layer(
    user_id: str = Form(),
    files: List[UploadFile] = File(),
):
    """Send the input of the second layer of the hierarchical models to the server.
    Order of the files:
    files[0]: encrypted input_model1
    files[1]: evaluation keys
    """
    print('Receiving data for the second layer of models...')

    # Receive the Client's files (Evaluation key + Encrypted inputs for the models)
    evaluation_key_path = SERVER_DIR / f"{user_id}_evaluation_key_second_layer"
    encrypted_input_path_model3 = SERVER_DIR / f"{user_id}_encrypted_input_model3"

    # Save the files using the above paths
    with encrypted_input_path_model3.open("wb") as encrypted_input_model3, \
         evaluation_key_path.open("wb") as evaluation_key:
        encrypted_input_model3.write(files[0].file.read())
        evaluation_key.write(files[1].file.read())


@app.post("/run_fhe_first_layer")
def run_fhe_first_layer(
    user_id: str = Form(),
):
    """Inference in FHE."""

    print("\nRun in FHE in the server ............\n")
    evaluation_key_path_1 = SERVER_DIR / f"{user_id}_evaluation_key_1"
    evaluation_key_path_2 = SERVER_DIR / f"{user_id}_evaluation_key_2"
    encrypted_input_path_model1 = SERVER_DIR / f"{user_id}_encrypted_input_model1"
    encrypted_input_path_model2 = SERVER_DIR / f"{user_id}_encrypted_input_model2"

    # Read the files (Evaluation key + Encrypted symptoms) using the above paths
    with encrypted_input_path_model1.open("rb") as encrypted_output_file_model1,  \
         encrypted_input_path_model2.open("rb") as encrypted_output_file_model2,  \
         evaluation_key_path_1.open("rb") as evaluation_key_file_1, \
         evaluation_key_path_2.open("rb") as evaluation_key_file_2:
        encrypted_output_model1 = encrypted_output_file_model1.read()
        encrypted_output_model2 = encrypted_output_file_model2.read()
        evaluation_key_1 = evaluation_key_file_1.read()
        evaluation_key_2 = evaluation_key_file_2.read()

    # Run the FHE execution of the first layer of models

    start = time.time()
    encrypted_output_model1 = FHE_SERVER_MODEL1.run(encrypted_output_model1, evaluation_key_1)
    encrypted_output_model2 = FHE_SERVER_MODEL2.run(encrypted_output_model2, evaluation_key_2)
    assert isinstance(encrypted_output_model1, bytes)
    assert isinstance(encrypted_output_model2, bytes)
    fhe_execution_time = round(time.time() - start, 2)

    # Retrieve the encrypted output path
    encrypted_output_path_model1 = SERVER_DIR / f"{user_id}_encrypted_output_model1"
    encrypted_output_path_model2 = SERVER_DIR / f"{user_id}_encrypted_output_model2"

    # Write the file using the above path
    with encrypted_output_path_model1.open("wb") as f1, \
         encrypted_output_path_model2.open("wb") as f2:
        f1.write(encrypted_output_model1)
        f2.write(encrypted_output_model2)

    return JSONResponse(content=fhe_execution_time)


@app.post("/run_fhe_second_layer")
def run_fhe_second_layer(
    user_id: str = Form(),
):
    """Inference in FHE."""

    print("\nRun in FHE in the server ............\n")
    evaluation_key_path = SERVER_DIR / f"{user_id}_evaluation_key_second_layer"
    encrypted_input_path = SERVER_DIR / f"{user_id}_encrypted_input_model3"

    # Read the files (Evaluation key + Encrypted symptoms) using the above paths
    with encrypted_input_path.open("rb") as encrypted_output_file, \
         evaluation_key_path.open("rb") as evaluation_key_file:
        encrypted_output = encrypted_output_file.read()
        evaluation_key = evaluation_key_file.read()

    # Run the FHE execution
    start = time.time()
    encrypted_output = FHE_SERVER_MODEL3.run(encrypted_output, evaluation_key)
    assert isinstance(encrypted_output, bytes)
    fhe_execution_time = round(time.time() - start, 2)

    # Retrieve the encrypted output path
    encrypted_output_path = SERVER_DIR / f"{user_id}_encrypted_output_model3"

    # Write the file using the above path
    with encrypted_output_path.open("wb") as f:
        f.write(encrypted_output)

    return JSONResponse(content=fhe_execution_time)


@app.post("/get_output_first_layer_1")
def get_output_first_layer_1(user_id: str = Form()):
    """Retrieve the encrypted outputs of the first layers of models from the server."""

    print("\nGet the output from the server ............\n")

    # Path where the encrypted output is saved
    encrypted_output_path_model1 = SERVER_DIR / f"{user_id}_encrypted_output_model1"
    # encrypted_output_path_model2 = SERVER_DIR / f"{user_id}_encrypted_output_model2"

    # Read the file using the above path
    with encrypted_output_path_model1.open("rb") as f1:
        #  encrypted_output_path_model2.open("rb") as f2:
        encrypted_output_1 = f1.read()
        # encrypted_output_2 = f2.read()

    time.sleep(1)

    # Send the encrypted output
    return Response(encrypted_output_1)


@app.post("/get_output_first_layer_2")
def get_output_first_layer_2(user_id: str = Form()):
    """Retrieve the encrypted outputs of the first layers of models from the server."""

    print("\nGet the output from the server ............\n")

    # Path where the encrypted output is saved
    # encrypted_output_path_model1 = SERVER_DIR / f"{user_id}_encrypted_output_model1"
    encrypted_output_path_model2 = SERVER_DIR / f"{user_id}_encrypted_output_model2"

    # Read the file using the above path
    with encrypted_output_path_model2.open("rb") as f2:
        #  encrypted_output_path_model2.open("rb") as f2:
        # encrypted_output_1 = f1.read()
        encrypted_output_2 = f2.read()

    time.sleep(1)

    # Send the encrypted output
    return Response(encrypted_output_2)


@app.post("/get_output_second_layer")
def get_output_second_layer(user_id: str = Form()):
    """Retrieve the encrypted outputs of the first layers of models from the server."""

    print("\nGet the output from the server ............\n")

    # Path where the encrypted output is saved
    encrypted_output_path = SERVER_DIR / f"{user_id}_encrypted_output_model3"

    # Read the file using the above path
    with encrypted_output_path.open("rb") as f:
        encrypted_output = f.read()

    time.sleep(1)

    # Send the encrypted output
    return Response(encrypted_output)