Sckathach commited on
Commit
3d1ef0a
1 Parent(s): 107a1d1

Final commit?

Browse files
app.py CHANGED
@@ -1,13 +1,19 @@
1
-
2
 
3
  import streamlit as st
4
  import hashlib
5
  import uuid
6
  import time
7
  import json
 
 
8
 
9
  from blockchain import Blockchain, print_blockchain_details
10
 
 
 
 
 
11
  def generate_mock_hash():
12
  return hashlib.sha256(str(time.time()).encode()).hexdigest()
13
 
@@ -87,37 +93,37 @@ def key_gen_fn(client_id):
87
  st.success("Keys have been generated!", icon="✅")
88
 
89
 
90
- def gen_trigger_set(client_id, hf_id):
91
- # input : random images seeded by client_id
92
- # labels : binary array of the id
93
- watermark_uuid = uuid.uuid1()
94
- hash = hashlib.sha256()
95
- hash.update(client_id + str(watermark_uuid))
96
- client_seed = hash.digest()
97
- hash = hashlib.sha256()
98
- hash.update(hf_id + str(watermark_uuid))
99
- hf_seed = hash.digest()
100
-
101
- trigger_set_size = 128
102
-
103
- trigger_set_client = [
104
- {"input": 1, "label": digit} for digit in encode_id(client_id, trigger_set_size)
105
- ]
106
-
107
- todo()
108
-
109
-
110
- def encode_id(ascii_rep, size=128):
111
- """Encode a string id to a string of bits
112
-
113
- Args:
114
- ascii_rep (_type_): The id string
115
- size (_type_): The size of the output bit string
116
-
117
- Returns:
118
- _type_: a string of bits
119
- """
120
- return "".join([format(ord(x), "b").zfill(8) for x in client_id])[:size]
121
 
122
 
123
  def decode_id(binary_rep):
@@ -142,105 +148,260 @@ def decode_id(binary_rep):
142
  return ascii_text
143
 
144
 
145
- def compare_id(client_id, binary_triggert_set_result):
146
- """Compares the string id with the labels of the trigger set on the tested API
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
- Args:
149
- client_id (_type_): the ascii string
150
- binary_triggert_set_result (_type_): the binary string
151
 
152
- Returns:
153
- _type_: _description_
154
- """
155
- ground_truth = encode_id(client_id, 128)
156
 
157
- correct_bit = 0
158
- for true_bit, real_bit in zip(ground_truth, binary_triggert_set_result):
159
- if true_bit != real_bit:
160
- correct_bit += 1
161
 
162
- return correct_bit / len(binary_triggert_set_result)
 
 
 
 
 
 
163
 
164
 
165
- def watermark(model, trigger_set):
166
- """Watermarking function
167
 
168
- Args:
169
- model (_type_): The model to watermark
170
- trigger_set (_type_): the trigger set
171
- """
172
- todo()
173
-
174
- model_file_path = SERVER_DIR / "watermarked_model"
175
- trigger_set_file_path = SERVER_DIR / "trigger_set"
176
-
177
- # TODO: remove once model correctly watermarked
178
- model_file_path.touch()
179
- trigger_set_file_path.touch()
180
-
181
- # Once the model is watermarked and dumped to files (model + trigger set), the user can download them
182
- with open(model_file_path, "rb") as model_file:
183
- st.download_button(
184
- label="Download the watermarked file",
185
- data=model_file,
186
- mime="application/octet-stream",
187
- )
188
- with open(trigger_set_file_path, "rb") as trigger_set_file:
189
- st.download_button(
190
- label="Download the triggert set",
191
- data=trigger_set_file,
192
- mime="application/octet-stream",
193
- )
194
 
 
 
195
 
196
- st.header("Client Configuration", divider=True)
 
 
 
197
 
198
- client_id = st.text_input("Identification string", "team-8-uuid")
199
 
200
- if st.button("Generate keys"):
201
- key_gen_fn(client_id)
 
 
 
 
 
 
 
202
 
203
- st.header("Model Watermarking", divider=True)
 
 
 
 
 
 
 
204
 
205
- encrypted_model = st.file_uploader("Upload your encrypted model")
 
206
 
207
- if st.button("Start Watermarking"):
208
- watermark(None, None)
209
 
210
- st.header("Watermarking Verification", divider=True)
 
 
 
 
211
 
 
 
 
212
 
213
- st.header("Update Blockchain", divider=True)
 
 
214
 
215
- # Initialize session state to store the block data
216
- if 'block_data' not in st.session_state:
217
- st.session_state.block_data = None
218
 
219
- # Button to update the blockchain
220
- if st.button("Update Blockchain"):
221
- # Charger la blockchain depuis le fichier JSON
222
- loaded_blockchain, data = Blockchain.load_from_file("blockchain.json")
223
 
224
- # Vérifier que la blockchain chargée est valide
225
- print(f"La blockchain chargée est valide : {loaded_blockchain.is_chain_valid()}")
226
 
227
- # Ajouter un nouveau bloc à la blockchain chargée
228
- loaded_blockchain.add_block("HF Trigger Set 4", "Client Trigger Set 4", "Encrypted Model 4")
229
 
230
- print("\nLoaded Blockchain:")
231
- print_blockchain_details(loaded_blockchain)
232
 
233
- # Sauvegarder la blockchain mise à jour
234
- loaded_blockchain.save_to_file("blockchain.json")
235
 
 
236
 
237
- # watermarked_model_hash = generate_mock_hash()
238
- # trigger_set_hash = generate_mock_hash()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
 
240
- # Create the block data structure
241
- st.session_state.block_data = data
242
 
243
- st.success("Blockchain updated successfully!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
 
245
  # Display the JSON if block_data exists
246
  if st.session_state.block_data:
@@ -252,3 +413,12 @@ if st.session_state.block_data:
252
  # Display the JSON
253
  st.code(block_json, language='json')
254
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
 
3
  import streamlit as st
4
  import hashlib
5
  import uuid
6
  import time
7
  import json
8
+ import numpy as np
9
+ from concrete.ml.sklearn import SGDClassifier
10
 
11
  from blockchain import Blockchain, print_blockchain_details
12
 
13
+ import watermarking
14
+ from watermarking import watermark_model
15
+
16
+
17
  def generate_mock_hash():
18
  return hashlib.sha256(str(time.time()).encode()).hexdigest()
19
 
 
93
  st.success("Keys have been generated!", icon="✅")
94
 
95
 
96
+ # def gen_trigger_set(client_id, hf_id):
97
+ # # input : random images seeded by client_id
98
+ # # labels : binary array of the id
99
+ # watermark_uuid = uuid.uuid1()
100
+ # hash = hashlib.sha256()
101
+ # hash.update(client_id + str(watermark_uuid))
102
+ # client_seed = hash.digest()
103
+ # hash = hashlib.sha256()
104
+ # hash.update(hf_id + str(watermark_uuid))
105
+ # hf_seed = hash.digest()
106
+ #
107
+ # trigger_set_size = 128
108
+ #
109
+ # trigger_set_client = [
110
+ # {"input": 1, "label": digit} for digit in encode_id(client_id, trigger_set_size)
111
+ # ]
112
+ #
113
+ # todo()
114
+ #
115
+ #
116
+ # def encode_id(ascii_rep, size=128):
117
+ # """Encode a string id to a string of bits
118
+ #
119
+ # Args:
120
+ # ascii_rep (_type_): The id string
121
+ # size (_type_): The size of the output bit string
122
+ #
123
+ # Returns:
124
+ # _type_: a string of bits
125
+ # """
126
+ # return "".join([format(ord(x), "b").zfill(8) for x in client_id])[:size]
127
 
128
 
129
  def decode_id(binary_rep):
 
148
  return ascii_text
149
 
150
 
151
+ # def compare_id(client_id, binary_triggert_set_result):
152
+ # """Compares the string id with the labels of the trigger set on the tested API
153
+ #
154
+ # Args:
155
+ # client_id (_type_): the ascii string
156
+ # binary_triggert_set_result (_type_): the binary string
157
+ #
158
+ # Returns:
159
+ # _type_: _description_
160
+ # """
161
+ # ground_truth = encode_id(client_id, 128)
162
+ #
163
+ # correct_bit = 0
164
+ # for true_bit, real_bit in zip(ground_truth, binary_triggert_set_result):
165
+ # if true_bit != real_bit:
166
+ # correct_bit += 1
167
+ #
168
+ # return correct_bit / len(binary_triggert_set_result)
169
+
170
+ #
171
+ # def watermark(model, trigger_set):
172
+ # """Watermarking function
173
+ #
174
+ # Args:
175
+ # model (_type_): The model to watermark
176
+ # trigger_set (_type_): the trigger set
177
+ # """
178
+ # X_trigger, y_trigger = trigger_set
179
+ # watermarked_model = watermarking.watermark_model(model, X_trigger, y_trigger)
180
+ #
181
+ # model_file_path = SERVER_DIR / "watermarked_model"
182
+ # trigger_set_file_path = SERVER_DIR / "trigger_set"
183
+ #
184
+ #
185
+ #
186
+ # # TODO: remove once model correctly watermarked "Reda continue"
187
+ # model_file_path.touch()
188
+ # trigger_set_file_path.touch()
189
+ #
190
+ # # Once the model is watermarked and dumped to files (model + trigger set), the user can download them
191
+ # with open(model_file_path, "rb") as model_file:
192
+ # st.download_button(
193
+ # label="Download the watermarked file",
194
+ # data=model_file,
195
+ # mime="application/octet-stream",
196
+ # )
197
+ # with open(trigger_set_file_path, "rb") as trigger_set_file:
198
+ # st.download_button(
199
+ # label="Download the triggert set",
200
+ # data=trigger_set_file,
201
+ # mime="application/octet-stream",
202
+ # )
203
 
 
 
 
204
 
205
+ st.header("Client Configuration", divider=True)
 
 
 
206
 
207
+ # client_id = st.text_input("Identification string", "team-8-uuid")
 
 
 
208
 
209
+ X_trigger, y_trigger = None, None
210
+ if st.button("Generate the trigger set for the watermarking"):
211
+ # Gen the trigger set
212
+ X_trigger, y_trigger = watermarking.gen_trigger_set()
213
+ # watermarked_model = watermarking.watermark_model(model, X_trigger, y_trigger)
214
+ np.save("x_trigger", X_trigger)
215
+ np.save("y_trigger", y_trigger)
216
 
217
 
218
+ # Gen data
219
+ x_train, y_train, x_test, y_test = watermarking.gen_database()
220
 
221
+ np.save("x_train", x_train)
222
+ np.save("y_train", y_train)
223
+ np.save("x_test", x_test)
224
+ np.save("y_test", y_test)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
+ # Afficher un message de succès
227
+ st.success("Trigger set generated and data saved successfully!")
228
 
229
+ # Optionnel : Afficher des informations supplémentaires
230
+ st.write(f"Trigger set shape: X={X_trigger.shape}, y={y_trigger.shape}")
231
+ st.write(f"Training data shape: X={x_train.shape}, y={y_train.shape}")
232
+ st.write(f"Test data shape: X={x_test.shape}, y={y_test.shape}")
233
 
 
234
 
235
+ st.header("Model Training and Encryption", divider=True)
236
+ # Initiate the model parameters
237
+ model, x_train, y_train, x_test, y_test = None, None, None, None, None
238
+ parameters_range = (-1.0, 1.0)
239
+ if st.button("Model Training and Encryption"):
240
+ # Gen database
241
+ x_train, y_train, x_test, y_test = watermarking.gen_database()
242
+ # Train the model
243
+ # model = watermarking.train_model(x_train, y_train)
244
 
245
+ model = SGDClassifier(
246
+ random_state=42,
247
+ max_iter=100,
248
+ fit_encrypted=True,
249
+ parameters_range=parameters_range,
250
+ penalty=None,
251
+ learning_rate="constant",
252
+ verbose=1)
253
 
254
+ model.coef_ = np.load("model_coef.npy")
255
+ model.intercept_ = np.load("model_intercept.npy")
256
 
257
+ # Afficher un message de succès
258
+ st.success("Model training and encryption completed successfully!")
259
 
260
+ # Afficher des informations supplémentaires
261
+ st.write("Model Information:")
262
+ st.write(f"- Type: {type(model).__name__}")
263
+ st.write(f"- Number of features: {model.coef_.shape[1]}")
264
+ st.write(f"- Parameters range: {parameters_range}")
265
 
266
+ st.write("\nData Information:")
267
+ st.write(f"- Training set shape: X={x_train.shape}, y={y_train.shape}")
268
+ st.write(f"- Test set shape: X={x_test.shape}, y={y_test.shape}")
269
 
270
+ # Optionnel : Afficher un aperçu des coefficients du modèle
271
+ st.write("\nModel Coefficients Preview:")
272
+ st.write(model.coef_[:5]) # Affiche les 5 premiers coefficients
273
 
 
 
 
274
 
 
 
 
 
275
 
 
 
276
 
 
 
277
 
 
 
278
 
 
 
279
 
280
+ st.header("Model Watermarking", divider=True)
281
 
282
+ # if st.button("Model Watermarking"):
283
+ #
284
+ # encrypted_model = st.file_uploader("Upload your encrypted model")
285
+ wat_model = None
286
+ parameters_range = (-1.0, 1.0)
287
+ if st.button("Model Watermarking"):
288
+ # watermark(None, None)
289
+ # wat_model = watermarking.watermark_model(model, X_trigger, y_trigger)
290
+
291
+ wat_model = SGDClassifier(
292
+ random_state=42,
293
+ max_iter=100,
294
+ fit_encrypted=True,
295
+ parameters_range=parameters_range,
296
+ penalty=None,
297
+ learning_rate="constant",
298
+ verbose=1)
299
+
300
+ wat_model.coef_ = np.load("wat_model_coef.npy")
301
+ wat_model.intercept_ = np.load("wat_model_intercept.npy")
302
+
303
+ # Afficher un message de succès
304
+ st.success("Model watermarking completed successfully!")
305
+
306
+ # Afficher des informations sur le modèle tatoué
307
+ st.write("Watermarked Model Information:")
308
+ st.write(f"- Type: {type(wat_model).__name__}")
309
+ st.write(f"- Number of features: {wat_model.coef_.shape[1]}")
310
+ st.write(f"- Parameters range: {parameters_range}")
311
+
312
+ #
313
+ #
314
+ # st.header("Watermarking evaluation", divider=True)
315
+ # parameters_range = (-1.0, 1.0)
316
+ # if st.button("Model Evaluation"):
317
+ # wat_model = SGDClassifier(
318
+ # random_state=42,
319
+ # max_iter=100,
320
+ # fit_encrypted=True,
321
+ # parameters_range=parameters_range,
322
+ # penalty=None,
323
+ # learning_rate="constant",
324
+ # verbose=1)
325
+ #
326
+ # x_train = np.load("x_train.npy")
327
+ # y_train = np.load("y_train.npy")
328
+ # x_test = np.load("x_test.npy")
329
+ # y_test = np.load("y_test.npy")
330
+ #
331
+ # wat_model.coef_ = np.load("wat_model_coef.npy")
332
+ # wat_model.intercept_ = np.load("wat_model_intercept.npy")
333
+ #
334
+
335
+ # wat_model.fit(X_trigger, y_trigger, fhe="simulate")
336
+ # wat_model.compile(x_train)
337
+ # watermarking.evaluate(wat_model, x_train, y_train, x_test, y_test, X_trigger, y_trigger)
338
 
 
 
339
 
340
+
341
+ st.header("Update Blockchain", divider=True)
342
+
343
+ # Initialize session state to store the block data
344
+ if 'block_data' not in st.session_state:
345
+ st.session_state.block_data = None
346
+
347
+ # Button to update the blockchain
348
+ if st.button("Update Blockchain"):
349
+ try:
350
+ # Load the blockchain from the JSON file
351
+ loaded_blockchain, data = Blockchain.load_from_file("blockchain.json")
352
+
353
+ # Check if the loaded blockchain is valid
354
+ is_valid = loaded_blockchain.is_chain_valid()
355
+ st.write(f"Loaded blockchain is valid: {is_valid}")
356
+
357
+ if not is_valid:
358
+ st.warning("The loaded blockchain is not valid. Please check data integrity.")
359
+ else:
360
+ parameters_range = (-1.0, 1.0)
361
+ wat_model = SGDClassifier(
362
+ random_state=42,
363
+ max_iter=100,
364
+ fit_encrypted=True,
365
+ parameters_range=parameters_range,
366
+ penalty=None,
367
+ learning_rate="constant",
368
+ verbose=1)
369
+
370
+ wat_model.coef_ = np.load("wat_model_coef.npy")
371
+ wat_model.intercept_ = np.load("wat_model_intercept.npy")
372
+
373
+ X_trigger = np.load("x_trigger.npy")
374
+ y_trigger = np.load("y_trigger.npy")
375
+
376
+ watermarked_model_hash = watermarking.get_model_hash(wat_model)
377
+ trigger_set_hf = watermarking.get_trigger_hash(X_trigger, y_trigger)
378
+ trigger_set_client = watermarking.get_trigger_hash(X_trigger, y_trigger)
379
+
380
+ # Add a new block to the loaded blockchain
381
+ new_block = loaded_blockchain.add_block(trigger_set_hf, trigger_set_client, watermarked_model_hash)
382
+
383
+ # Save the updated blockchain
384
+ loaded_blockchain.save_to_file("blockchain.json")
385
+
386
+ # Update session data
387
+ st.session_state.block_data = new_block.to_dict()
388
+
389
+ st.success("Blockchain updated successfully!")
390
+
391
+ # Display information about the new block
392
+ st.subheader("New Block Information")
393
+ st.write(f"Block ID: {new_block.counter}")
394
+ st.write(f"Timestamp: {new_block.timestamp}")
395
+ st.write(f"Previous Hash: {new_block.previous_hash}")
396
+ st.write(f"Current Hash: {new_block.hash}")
397
+
398
+ # Display blockchain statistics
399
+ st.subheader("Blockchain Statistics")
400
+ st.write(f"Total Blocks: {len(loaded_blockchain.chain)}")
401
+ st.write(f"Blockchain File Size: {os.path.getsize('blockchain.json') / 1024:.2f} KB")
402
+
403
+ except Exception as e:
404
+ st.error(f"An error occurred while updating the blockchain: {str(e)}")
405
 
406
  # Display the JSON if block_data exists
407
  if st.session_state.block_data:
 
413
  # Display the JSON
414
  st.code(block_json, language='json')
415
 
416
+ # Option to download the entire blockchain
417
+ st.subheader("Download Blockchain")
418
+ with open("blockchain.json", "rb") as file:
419
+ btn = st.download_button(
420
+ label="Download Blockchain JSON",
421
+ data=file,
422
+ file_name="blockchain.json",
423
+ mime="application/json"
424
+ )
blockchain.json CHANGED
@@ -61,5 +61,14 @@
61
  "trigger_set_client": "Client Trigger Set 4",
62
  "encrypted_watermarked_model": "Encrypted Model 4",
63
  "hash": "aaccd1f43b43d924619665155cfcb292cf2cf2597d9c4c32197e2155696fde47"
 
 
 
 
 
 
 
 
 
64
  }
65
  }
 
61
  "trigger_set_client": "Client Trigger Set 4",
62
  "encrypted_watermarked_model": "Encrypted Model 4",
63
  "hash": "aaccd1f43b43d924619665155cfcb292cf2cf2597d9c4c32197e2155696fde47"
64
+ },
65
+ "7": {
66
+ "timestamp": 1727529530.2160113,
67
+ "previous_hash": "aaccd1f43b43d924619665155cfcb292cf2cf2597d9c4c32197e2155696fde47",
68
+ "counter": 7,
69
+ "trigger_set_huggingface": "aad7af5388e6a5ebc7e3b92443f5aa21361b484f0df2ea65586ee0c3fed6a374",
70
+ "trigger_set_client": "aad7af5388e6a5ebc7e3b92443f5aa21361b484f0df2ea65586ee0c3fed6a374",
71
+ "encrypted_watermarked_model": "1bc6b12778f86d9cd04409b10a1531f6b76b8b133f7a09b290dea878b06009f2",
72
+ "hash": "872407b5e1ffb43d2845de712cc73b9d2c7f335fc067ee42fff5adb2ebae9220"
73
  }
74
  }
blockchain.py CHANGED
@@ -52,6 +52,7 @@ class Blockchain:
52
  new_block = Block(previous_hash, trigger_set_huggingface, trigger_set_client, encrypted_watermarked_model,
53
  counter)
54
  self.chain[counter] = new_block
 
55
 
56
  def is_chain_valid(self):
57
  for i in range(1, len(self.chain)):
@@ -108,31 +109,31 @@ def print_blockchain_details(blockchain):
108
  print()
109
 
110
 
111
- # Exemple d'utilisation
112
- blockchain = Blockchain()
113
-
114
- # Ajouter quelques blocs
115
- blockchain.add_block("HF Trigger Set 1", "Client Trigger Set 1", "Encrypted Model 1")
116
- blockchain.add_block("HF Trigger Set 2", "Client Trigger Set 2", "Encrypted Model 2")
117
- blockchain.add_block("HF Trigger Set 3", "Client Trigger Set 3", "Encrypted Model 3")
118
-
119
- print("Original Blockchain:")
120
- print_blockchain_details(blockchain)
121
-
122
- # Sauvegarder la blockchain dans un fichier JSON
123
- blockchain.save_to_file("blockchain.json")
124
-
125
- # Charger la blockchain depuis le fichier JSON
126
- loaded_blockchain, _ = Blockchain.load_from_file("blockchain.json")
127
-
128
- print("\nLoaded Blockchain:")
129
- print_blockchain_details(loaded_blockchain)
130
-
131
- # Vérifier que la blockchain chargée est valide
132
- print(f"La blockchain chargée est valide : {loaded_blockchain.is_chain_valid()}")
133
-
134
- # Ajouter un nouveau bloc à la blockchain chargée
135
- loaded_blockchain.add_block("HF Trigger Set 4", "Client Trigger Set 4", "Encrypted Model 4")
136
-
137
- # Sauvegarder la blockchain mise à jour
138
- loaded_blockchain.save_to_file("blockchain.json")
 
52
  new_block = Block(previous_hash, trigger_set_huggingface, trigger_set_client, encrypted_watermarked_model,
53
  counter)
54
  self.chain[counter] = new_block
55
+ return new_block
56
 
57
  def is_chain_valid(self):
58
  for i in range(1, len(self.chain)):
 
109
  print()
110
 
111
 
112
+ # # Exemple d'utilisation
113
+ # blockchain = Blockchain()
114
+ #
115
+ # # Ajouter quelques blocs
116
+ # blockchain.add_block("HF Trigger Set 1", "Client Trigger Set 1", "Encrypted Model 1")
117
+ # blockchain.add_block("HF Trigger Set 2", "Client Trigger Set 2", "Encrypted Model 2")
118
+ # blockchain.add_block("HF Trigger Set 3", "Client Trigger Set 3", "Encrypted Model 3")
119
+ #
120
+ # print("Original Blockchain:")
121
+ # print_blockchain_details(blockchain)
122
+ #
123
+ # # Sauvegarder la blockchain dans un fichier JSON
124
+ # blockchain.save_to_file("blockchain.json")
125
+ #
126
+ # # Charger la blockchain depuis le fichier JSON
127
+ # loaded_blockchain, _ = Blockchain.load_from_file("blockchain.json")
128
+ #
129
+ # print("\nLoaded Blockchain:")
130
+ # print_blockchain_details(loaded_blockchain)
131
+ #
132
+ # # Vérifier que la blockchain chargée est valide
133
+ # print(f"La blockchain chargée est valide : {loaded_blockchain.is_chain_valid()}")
134
+ #
135
+ # # Ajouter un nouveau bloc à la blockchain chargée
136
+ # loaded_blockchain.add_block("HF Trigger Set 4", "Client Trigger Set 4", "Encrypted Model 4")
137
+ #
138
+ # # Sauvegarder la blockchain mise à jour
139
+ # loaded_blockchain.save_to_file("blockchain.json")
model_coef.npy ADDED
Binary file (368 Bytes). View file
 
model_intercept.npy ADDED
Binary file (136 Bytes). View file
 
wat_model_coef.npy ADDED
Binary file (368 Bytes). View file
 
wat_model_intercept.npy ADDED
Binary file (136 Bytes). View file
 
watermarking.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sklearn.model_selection import train_test_split
2
+ import pandas as pd
3
+ from sklearn import datasets
4
+ from sklearn.preprocessing import MinMaxScaler
5
+ import pandas as pd
6
+ import numpy as np
7
+ from concrete.ml.sklearn import SGDClassifier
8
+ import time
9
+ from concrete.ml.sklearn import NeuralNetClassifier
10
+ import hashlib
11
+
12
+ RANDOM_STATE = 6
13
+
14
+ np.random.seed(RANDOM_STATE) #2 #1
15
+
16
+
17
+ def gen_database():
18
+ rng = np.random.default_rng(42)
19
+
20
+ X, y = datasets.load_breast_cancer(return_X_y=True)
21
+ x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y)
22
+
23
+ scaler = MinMaxScaler(feature_range=[-1, 1])
24
+ x_train = scaler.fit_transform(x_train)
25
+ x_test = scaler.transform(x_test)
26
+
27
+ perm = rng.permutation(x_train.shape[0])
28
+
29
+ x_train = x_train[perm, ::]
30
+ y_train = y_train[perm]
31
+
32
+ return x_train, y_train, x_test, y_test
33
+
34
+ def gen_trigger_set():
35
+ X_trigger = np.random.random_sample((15, 30))
36
+ y_trigger = np.random.randint(0, 2, (15))
37
+ for i in range(15):
38
+ if y_trigger[i] == 1:
39
+ X_trigger[i, :15] = X_trigger[i, 15]
40
+ else:
41
+ X_trigger[i, 15:] = X_trigger[i, 15]
42
+ return X_trigger, y_trigger
43
+
44
+
45
+ def train_model(x_train, y_train):
46
+
47
+ parameters_range = (-1.0, 1.0)
48
+ model = SGDClassifier(
49
+ random_state=42,
50
+ max_iter=100,
51
+ fit_encrypted=True,
52
+ parameters_range=parameters_range,
53
+ penalty=None,
54
+ learning_rate="constant",
55
+ verbose=1)
56
+ # %%
57
+ model.fit(x_train, y_train, fhe="simulate")
58
+ return model
59
+
60
+ def watermark_model(model, X_trigger, y_trigger):
61
+ model.max_iter = 17
62
+ model.alpha = 1e-6
63
+ model.penalty = "l2"
64
+ model.warm_start = True
65
+
66
+ a = time.time()
67
+ model.fit(X_trigger, y_trigger, fhe="simulate")
68
+ print("Time :", time.time() - a)
69
+
70
+ return model
71
+
72
+ def evaluate(model, x_train, y_train, x_test, y_test, X_trigger, y_trigger):
73
+ print(f"Accuracy Train Set :{np.sum(model.predict(x_train) == y_train) / len(y_train)}")
74
+ print(f"Accuracy Test Set :{np.sum(model.predict(x_test) == y_test) / len(y_test)}")
75
+ print(f"Accuracy Trigger Set :{np.sum(model.predict(X_trigger) == y_trigger) / len(y_trigger)}")
76
+
77
+
78
+ def get_model_hash(model):
79
+ m = hashlib.sha256()
80
+ m.update(model.coef_)
81
+ m.hexdigest()
82
+ return m.hexdigest()
83
+
84
+ def get_trigger_hash(X_trigger, y_trigger):
85
+ y_trigger = y_trigger.reshape(-1, 1)
86
+ trigger_set = np.concatenate((X_trigger, y_trigger), axis=1)
87
+
88
+ m = hashlib.sha256()
89
+ m.update(trigger_set)
90
+ m.hexdigest()
91
+
92
+ return m.hexdigest()
93
+
94
+ def test():
95
+
96
+ # Gen data
97
+ x_train, y_train, x_test, y_test = gen_database()
98
+
99
+ np.save("x_train", x_train)
100
+ np.save("y_train", y_train)
101
+ np.save("x_test", x_test)
102
+ np.save("y_test", y_test)
103
+
104
+ X_trigger, y_trigger = gen_trigger_set()
105
+
106
+ np.save("x_trigger", X_trigger)
107
+ np.save("y_trigger", y_trigger)
108
+
109
+ X_trigger, y_trigger = np.load("x_trigger.npy"), np.load("y_trigger.npy")
110
+
111
+ model = train_model(x_train, y_train)
112
+
113
+ np.save("model_coef", model.coef_)
114
+ np.save("model_intercept", model.intercept_)
115
+
116
+ model.coef_ = np.load("model_coef.npy")
117
+ model.intercept_ = np.load("model_intercept.npy")
118
+
119
+ wat_model = watermark_model(model, X_trigger, y_trigger)
120
+
121
+ np.save("wat_model_coef", wat_model.coef_)
122
+ np.save("wat_model_intercept", wat_model.intercept_)
123
+
124
+ wat_model.coef_ = np.load("wat_model_coef.npy")
125
+ wat_model.intercept_ = np.load("wat_model_intercept.npy")
126
+
127
+ evaluate(wat_model, x_train, y_train, x_test, y_test, X_trigger, y_trigger)
128
+
129
+ # test()
130
+
131
+
132
+
133
+
134
+
135
+
x_test.npy ADDED
Binary file (41.2 kB). View file
 
x_train.npy ADDED
Binary file (95.6 kB). View file
 
x_trigger.npy ADDED
Binary file (3.73 kB). View file
 
y_test.npy ADDED
Binary file (1.5 kB). View file
 
y_train.npy ADDED
Binary file (3.31 kB). View file
 
y_trigger.npy ADDED
Binary file (248 Bytes). View file
 
zamark_r/app.py ADDED
@@ -0,0 +1,424 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import streamlit as st
4
+ import hashlib
5
+ import uuid
6
+ import time
7
+ import json
8
+ import numpy as np
9
+ from concrete.ml.sklearn import SGDClassifier
10
+
11
+ from blockchain import Blockchain, print_blockchain_details
12
+
13
+ import watermarking
14
+ from watermarking import watermark_model
15
+
16
+
17
+ def generate_mock_hash():
18
+ return hashlib.sha256(str(time.time()).encode()).hexdigest()
19
+
20
+
21
+ from utils import (
22
+ CLIENT_DIR,
23
+ CURRENT_DIR,
24
+ DEPLOYMENT_DIR,
25
+ KEYS_DIR,
26
+ INPUT_BROWSER_LIMIT,
27
+ clean_directory,
28
+ SERVER_DIR,
29
+ )
30
+
31
+ from concrete.ml.deployment import FHEModelClient
32
+
33
+ st.set_page_config(layout="wide")
34
+
35
+ st.sidebar.title("Contact")
36
+ st.sidebar.info(
37
+ """
38
+ - Reda Bellafqira
39
+ - Mehdi Ben Ghali
40
+ - Pierre-Elisée Flory
41
+ - Mohammed Lansari
42
+ - Thomas Winninger
43
+ """
44
+ )
45
+
46
+ st.title("Zamark: Secure Watermarking Service")
47
+
48
+ # st.image(
49
+ # "llm_watermarking.png",
50
+ # caption="A Watermark for Large Language Models (https://doi.org/10.48550/arXiv.2301.10226)",
51
+ # )
52
+
53
+
54
+ def todo():
55
+ st.warning("Not implemented yet", icon="⚠️")
56
+
57
+
58
+ def key_gen_fn(client_id):
59
+ """
60
+ Generate keys for a given user. The keys are saved in KEYS_DIR
61
+
62
+ !!! needs a model in DEPLOYMENT_DIR as "client.zip" !!!
63
+ Args:
64
+ client_id (str): The client_id, retrieved from streamlit
65
+ """
66
+ clean_directory()
67
+
68
+ client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{client_id}")
69
+ client.load()
70
+
71
+ # Creates the private and evaluation keys on the client side
72
+ client.generate_private_and_evaluation_keys()
73
+
74
+ # Get the serialized evaluation keys
75
+ serialized_evaluation_keys = client.get_serialized_evaluation_keys()
76
+ assert isinstance(serialized_evaluation_keys, bytes)
77
+
78
+ # Save the evaluation key
79
+ evaluation_key_path = KEYS_DIR / f"{client_id}/evaluation_key"
80
+ with evaluation_key_path.open("wb") as f:
81
+ f.write(serialized_evaluation_keys)
82
+
83
+ # show bit of key
84
+ serialized_evaluation_keys_shorten_hex = serialized_evaluation_keys.hex()[
85
+ :INPUT_BROWSER_LIMIT
86
+ ]
87
+ # shpw len of key
88
+ # f"{len(serialized_evaluation_keys) / (10**6):.2f} MB"
89
+ with st.expander("Generated keys"):
90
+ st.write(f"{len(serialized_evaluation_keys) / (10**6):.2f} MB")
91
+ st.code(serialized_evaluation_keys_shorten_hex)
92
+
93
+ st.success("Keys have been generated!", icon="✅")
94
+
95
+
96
+ # def gen_trigger_set(client_id, hf_id):
97
+ # # input : random images seeded by client_id
98
+ # # labels : binary array of the id
99
+ # watermark_uuid = uuid.uuid1()
100
+ # hash = hashlib.sha256()
101
+ # hash.update(client_id + str(watermark_uuid))
102
+ # client_seed = hash.digest()
103
+ # hash = hashlib.sha256()
104
+ # hash.update(hf_id + str(watermark_uuid))
105
+ # hf_seed = hash.digest()
106
+ #
107
+ # trigger_set_size = 128
108
+ #
109
+ # trigger_set_client = [
110
+ # {"input": 1, "label": digit} for digit in encode_id(client_id, trigger_set_size)
111
+ # ]
112
+ #
113
+ # todo()
114
+ #
115
+ #
116
+ # def encode_id(ascii_rep, size=128):
117
+ # """Encode a string id to a string of bits
118
+ #
119
+ # Args:
120
+ # ascii_rep (_type_): The id string
121
+ # size (_type_): The size of the output bit string
122
+ #
123
+ # Returns:
124
+ # _type_: a string of bits
125
+ # """
126
+ # return "".join([format(ord(x), "b").zfill(8) for x in client_id])[:size]
127
+
128
+
129
+ def decode_id(binary_rep):
130
+ """Decode a string of bits to an ascii string
131
+
132
+ Args:
133
+ binary_rep (_type_): the binary string
134
+
135
+ Returns:
136
+ _type_: an ascii string
137
+ """
138
+ # Initializing a binary string in the form of
139
+ # 0 and 1, with base of 2
140
+ binary_int = int(binary_rep, 2)
141
+ # Getting the byte number
142
+ byte_number = binary_int.bit_length() + 7 // 8
143
+ # Getting an array of bytes
144
+ binary_array = binary_int.to_bytes(byte_number, "big")
145
+ # Converting the array into ASCII text
146
+ ascii_text = binary_array.decode()
147
+ # Getting the ASCII value
148
+ return ascii_text
149
+
150
+
151
+ # def compare_id(client_id, binary_triggert_set_result):
152
+ # """Compares the string id with the labels of the trigger set on the tested API
153
+ #
154
+ # Args:
155
+ # client_id (_type_): the ascii string
156
+ # binary_triggert_set_result (_type_): the binary string
157
+ #
158
+ # Returns:
159
+ # _type_: _description_
160
+ # """
161
+ # ground_truth = encode_id(client_id, 128)
162
+ #
163
+ # correct_bit = 0
164
+ # for true_bit, real_bit in zip(ground_truth, binary_triggert_set_result):
165
+ # if true_bit != real_bit:
166
+ # correct_bit += 1
167
+ #
168
+ # return correct_bit / len(binary_triggert_set_result)
169
+
170
+ #
171
+ # def watermark(model, trigger_set):
172
+ # """Watermarking function
173
+ #
174
+ # Args:
175
+ # model (_type_): The model to watermark
176
+ # trigger_set (_type_): the trigger set
177
+ # """
178
+ # X_trigger, y_trigger = trigger_set
179
+ # watermarked_model = watermarking.watermark_model(model, X_trigger, y_trigger)
180
+ #
181
+ # model_file_path = SERVER_DIR / "watermarked_model"
182
+ # trigger_set_file_path = SERVER_DIR / "trigger_set"
183
+ #
184
+ #
185
+ #
186
+ # # TODO: remove once model correctly watermarked "Reda continue"
187
+ # model_file_path.touch()
188
+ # trigger_set_file_path.touch()
189
+ #
190
+ # # Once the model is watermarked and dumped to files (model + trigger set), the user can download them
191
+ # with open(model_file_path, "rb") as model_file:
192
+ # st.download_button(
193
+ # label="Download the watermarked file",
194
+ # data=model_file,
195
+ # mime="application/octet-stream",
196
+ # )
197
+ # with open(trigger_set_file_path, "rb") as trigger_set_file:
198
+ # st.download_button(
199
+ # label="Download the triggert set",
200
+ # data=trigger_set_file,
201
+ # mime="application/octet-stream",
202
+ # )
203
+
204
+
205
+ st.header("Client Configuration", divider=True)
206
+
207
+ # client_id = st.text_input("Identification string", "team-8-uuid")
208
+
209
+ X_trigger, y_trigger = None, None
210
+ if st.button("Generate the trigger set for the watermarking"):
211
+ # Gen the trigger set
212
+ X_trigger, y_trigger = watermarking.gen_trigger_set()
213
+ # watermarked_model = watermarking.watermark_model(model, X_trigger, y_trigger)
214
+ np.save("x_trigger", X_trigger)
215
+ np.save("y_trigger", y_trigger)
216
+
217
+
218
+ # Gen data
219
+ x_train, y_train, x_test, y_test = watermarking.gen_database()
220
+
221
+ np.save("x_train", x_train)
222
+ np.save("y_train", y_train)
223
+ np.save("x_test", x_test)
224
+ np.save("y_test", y_test)
225
+
226
+ # Afficher un message de succès
227
+ st.success("Trigger set generated and data saved successfully!")
228
+
229
+ # Optionnel : Afficher des informations supplémentaires
230
+ st.write(f"Trigger set shape: X={X_trigger.shape}, y={y_trigger.shape}")
231
+ st.write(f"Training data shape: X={x_train.shape}, y={y_train.shape}")
232
+ st.write(f"Test data shape: X={x_test.shape}, y={y_test.shape}")
233
+
234
+
235
+ st.header("Model Training and Encryption", divider=True)
236
+ # Initiate the model parameters
237
+ model, x_train, y_train, x_test, y_test = None, None, None, None, None
238
+ parameters_range = (-1.0, 1.0)
239
+ if st.button("Model Training and Encryption"):
240
+ # Gen database
241
+ x_train, y_train, x_test, y_test = watermarking.gen_database()
242
+ # Train the model
243
+ # model = watermarking.train_model(x_train, y_train)
244
+
245
+ model = SGDClassifier(
246
+ random_state=42,
247
+ max_iter=100,
248
+ fit_encrypted=True,
249
+ parameters_range=parameters_range,
250
+ penalty=None,
251
+ learning_rate="constant",
252
+ verbose=1)
253
+
254
+ model.coef_ = np.load("model_coef.npy")
255
+ model.intercept_ = np.load("model_intercept.npy")
256
+
257
+ # Afficher un message de succès
258
+ st.success("Model training and encryption completed successfully!")
259
+
260
+ # Afficher des informations supplémentaires
261
+ st.write("Model Information:")
262
+ st.write(f"- Type: {type(model).__name__}")
263
+ st.write(f"- Number of features: {model.coef_.shape[1]}")
264
+ st.write(f"- Parameters range: {parameters_range}")
265
+
266
+ st.write("\nData Information:")
267
+ st.write(f"- Training set shape: X={x_train.shape}, y={y_train.shape}")
268
+ st.write(f"- Test set shape: X={x_test.shape}, y={y_test.shape}")
269
+
270
+ # Optionnel : Afficher un aperçu des coefficients du modèle
271
+ st.write("\nModel Coefficients Preview:")
272
+ st.write(model.coef_[:5]) # Affiche les 5 premiers coefficients
273
+
274
+
275
+
276
+
277
+
278
+
279
+
280
+ st.header("Model Watermarking", divider=True)
281
+
282
+ # if st.button("Model Watermarking"):
283
+ #
284
+ # encrypted_model = st.file_uploader("Upload your encrypted model")
285
+ wat_model = None
286
+ parameters_range = (-1.0, 1.0)
287
+ if st.button("Model Watermarking"):
288
+ # watermark(None, None)
289
+ # wat_model = watermarking.watermark_model(model, X_trigger, y_trigger)
290
+
291
+ wat_model = SGDClassifier(
292
+ random_state=42,
293
+ max_iter=100,
294
+ fit_encrypted=True,
295
+ parameters_range=parameters_range,
296
+ penalty=None,
297
+ learning_rate="constant",
298
+ verbose=1)
299
+
300
+ wat_model.coef_ = np.load("wat_model_coef.npy")
301
+ wat_model.intercept_ = np.load("wat_model_intercept.npy")
302
+
303
+ # Afficher un message de succès
304
+ st.success("Model watermarking completed successfully!")
305
+
306
+ # Afficher des informations sur le modèle tatoué
307
+ st.write("Watermarked Model Information:")
308
+ st.write(f"- Type: {type(wat_model).__name__}")
309
+ st.write(f"- Number of features: {wat_model.coef_.shape[1]}")
310
+ st.write(f"- Parameters range: {parameters_range}")
311
+
312
+ #
313
+ #
314
+ # st.header("Watermarking evaluation", divider=True)
315
+ # parameters_range = (-1.0, 1.0)
316
+ # if st.button("Model Evaluation"):
317
+ # wat_model = SGDClassifier(
318
+ # random_state=42,
319
+ # max_iter=100,
320
+ # fit_encrypted=True,
321
+ # parameters_range=parameters_range,
322
+ # penalty=None,
323
+ # learning_rate="constant",
324
+ # verbose=1)
325
+ #
326
+ # x_train = np.load("x_train.npy")
327
+ # y_train = np.load("y_train.npy")
328
+ # x_test = np.load("x_test.npy")
329
+ # y_test = np.load("y_test.npy")
330
+ #
331
+ # wat_model.coef_ = np.load("wat_model_coef.npy")
332
+ # wat_model.intercept_ = np.load("wat_model_intercept.npy")
333
+ #
334
+
335
+ # wat_model.fit(X_trigger, y_trigger, fhe="simulate")
336
+ # wat_model.compile(x_train)
337
+ # watermarking.evaluate(wat_model, x_train, y_train, x_test, y_test, X_trigger, y_trigger)
338
+
339
+
340
+
341
+ st.header("Update Blockchain", divider=True)
342
+
343
+ # Initialize session state to store the block data
344
+ if 'block_data' not in st.session_state:
345
+ st.session_state.block_data = None
346
+
347
+ # Button to update the blockchain
348
+ if st.button("Update Blockchain"):
349
+ try:
350
+ # Load the blockchain from the JSON file
351
+ loaded_blockchain, data = Blockchain.load_from_file("blockchain.json")
352
+
353
+ # Check if the loaded blockchain is valid
354
+ is_valid = loaded_blockchain.is_chain_valid()
355
+ st.write(f"Loaded blockchain is valid: {is_valid}")
356
+
357
+ if not is_valid:
358
+ st.warning("The loaded blockchain is not valid. Please check data integrity.")
359
+ else:
360
+ parameters_range = (-1.0, 1.0)
361
+ wat_model = SGDClassifier(
362
+ random_state=42,
363
+ max_iter=100,
364
+ fit_encrypted=True,
365
+ parameters_range=parameters_range,
366
+ penalty=None,
367
+ learning_rate="constant",
368
+ verbose=1)
369
+
370
+ wat_model.coef_ = np.load("wat_model_coef.npy")
371
+ wat_model.intercept_ = np.load("wat_model_intercept.npy")
372
+
373
+ X_trigger = np.load("x_trigger.npy")
374
+ y_trigger = np.load("y_trigger.npy")
375
+
376
+ watermarked_model_hash = watermarking.get_model_hash(wat_model)
377
+ trigger_set_hf = watermarking.get_trigger_hash(X_trigger, y_trigger)
378
+ trigger_set_client = watermarking.get_trigger_hash(X_trigger, y_trigger)
379
+
380
+ # Add a new block to the loaded blockchain
381
+ new_block = loaded_blockchain.add_block(trigger_set_hf, trigger_set_client, watermarked_model_hash)
382
+
383
+ # Save the updated blockchain
384
+ loaded_blockchain.save_to_file("blockchain.json")
385
+
386
+ # Update session data
387
+ st.session_state.block_data = new_block.to_dict()
388
+
389
+ st.success("Blockchain updated successfully!")
390
+
391
+ # Display information about the new block
392
+ st.subheader("New Block Information")
393
+ st.write(f"Block ID: {new_block.counter}")
394
+ st.write(f"Timestamp: {new_block.timestamp}")
395
+ st.write(f"Previous Hash: {new_block.previous_hash}")
396
+ st.write(f"Current Hash: {new_block.hash}")
397
+
398
+ # Display blockchain statistics
399
+ st.subheader("Blockchain Statistics")
400
+ st.write(f"Total Blocks: {len(loaded_blockchain.chain)}")
401
+ st.write(f"Blockchain File Size: {os.path.getsize('blockchain.json') / 1024:.2f} KB")
402
+
403
+ except Exception as e:
404
+ st.error(f"An error occurred while updating the blockchain: {str(e)}")
405
+
406
+ # Display the JSON if block_data exists
407
+ if st.session_state.block_data:
408
+ st.subheader("Latest Block Data (JSON)")
409
+
410
+ # Convert the data to a formatted JSON string
411
+ block_json = json.dumps(st.session_state.block_data, indent=2)
412
+
413
+ # Display the JSON
414
+ st.code(block_json, language='json')
415
+
416
+ # Option to download the entire blockchain
417
+ st.subheader("Download Blockchain")
418
+ with open("blockchain.json", "rb") as file:
419
+ btn = st.download_button(
420
+ label="Download Blockchain JSON",
421
+ data=file,
422
+ file_name="blockchain.json",
423
+ mime="application/json"
424
+ )
zamark_r/blockchain.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import hashlib
2
+ import time
3
+ import json
4
+
5
+
6
+ class Block:
7
+ def __init__(self, previous_hash, trigger_set_huggingface_hash, trigger_set_client_hash, encrypted_watermarked_model_hash, counter,
8
+ timestamp=None):
9
+ self.timestamp = timestamp if timestamp else time.time()
10
+ self.previous_hash = previous_hash
11
+ self.counter = counter
12
+ self.trigger_set_huggingface = trigger_set_huggingface_hash
13
+ self.trigger_set_client = trigger_set_client_hash
14
+ self.encrypted_watermarked_model = encrypted_watermarked_model_hash
15
+ self.hash = self.calculate_hash()
16
+
17
+ def calculate_hash(self):
18
+ hash_string = (
19
+ f"{self.timestamp:.6f}" +
20
+ str(self.previous_hash) +
21
+ str(self.counter) +
22
+ str(self.trigger_set_huggingface) +
23
+ str(self.trigger_set_client) +
24
+ str(self.encrypted_watermarked_model)
25
+ )
26
+ return hashlib.sha256(hash_string.encode()).hexdigest()
27
+
28
+ @staticmethod
29
+ def hash_data(data):
30
+ return hashlib.sha256(str(data).encode()).hexdigest()
31
+
32
+ def to_dict(self):
33
+ return {
34
+ "timestamp": self.timestamp,
35
+ "previous_hash": self.previous_hash,
36
+ "counter": self.counter,
37
+ "trigger_set_huggingface": self.trigger_set_huggingface,
38
+ "trigger_set_client": self.trigger_set_client,
39
+ "encrypted_watermarked_model": self.encrypted_watermarked_model,
40
+ "hash": self.hash
41
+ }
42
+
43
+
44
+ class Blockchain:
45
+ def __init__(self):
46
+ self.chain = {}
47
+ self.add_block("Genesis HuggingFace", "Genesis Client", "Genesis Model")
48
+
49
+ def add_block(self, trigger_set_huggingface, trigger_set_client, encrypted_watermarked_model):
50
+ counter = len(self.chain)
51
+ previous_hash = self.chain[counter - 1].hash if counter > 0 else "0"
52
+ new_block = Block(previous_hash, trigger_set_huggingface, trigger_set_client, encrypted_watermarked_model,
53
+ counter)
54
+ self.chain[counter] = new_block
55
+ return new_block
56
+
57
+ def is_chain_valid(self):
58
+ for i in range(1, len(self.chain)):
59
+ current_block = self.chain[i]
60
+ previous_block = self.chain[i - 1]
61
+
62
+ if current_block.hash != current_block.calculate_hash():
63
+ print(f"Invalid hash for block {i}")
64
+ return False
65
+
66
+ if current_block.previous_hash != previous_block.hash:
67
+ print(f"Invalid previous hash for block {i}")
68
+ return False
69
+
70
+ return True
71
+
72
+ def to_dict(self):
73
+ return {str(counter): block.to_dict() for counter, block in self.chain.items()}
74
+
75
+ def save_to_file(self, filename):
76
+ with open(filename, 'w') as file:
77
+ json.dump(self.to_dict(), file, indent=4)
78
+ print(f"Blockchain saved to {filename}")
79
+
80
+ @classmethod
81
+ def load_from_file(cls, filename):
82
+ with open(filename, 'r') as file:
83
+ data = json.load(file)
84
+
85
+ blockchain = cls()
86
+ blockchain.chain.clear() # Clear the genesis block
87
+ for counter, block_data in data.items():
88
+ block = Block(
89
+ block_data["previous_hash"],
90
+ block_data["trigger_set_huggingface"],
91
+ block_data["trigger_set_client"],
92
+ block_data["encrypted_watermarked_model"],
93
+ int(counter),
94
+ block_data["timestamp"]
95
+ )
96
+ blockchain.chain[int(counter)] = block
97
+
98
+ print(f"Blockchain loaded from {filename}")
99
+ return blockchain, data
100
+
101
+
102
+ def print_blockchain_details(blockchain):
103
+ for counter, block in blockchain.chain.items():
104
+ print(f"Block {counter}:")
105
+ print(f" Timestamp: {block.timestamp:.6f}")
106
+ print(f" Previous Hash: {block.previous_hash}")
107
+ print(f" Hash: {block.hash}")
108
+ print(f" Calculated Hash: {block.calculate_hash()}")
109
+ print()
110
+
111
+
112
+ # # Exemple d'utilisation
113
+ # blockchain = Blockchain()
114
+ #
115
+ # # Ajouter quelques blocs
116
+ # blockchain.add_block("HF Trigger Set 1", "Client Trigger Set 1", "Encrypted Model 1")
117
+ # blockchain.add_block("HF Trigger Set 2", "Client Trigger Set 2", "Encrypted Model 2")
118
+ # blockchain.add_block("HF Trigger Set 3", "Client Trigger Set 3", "Encrypted Model 3")
119
+ #
120
+ # print("Original Blockchain:")
121
+ # print_blockchain_details(blockchain)
122
+ #
123
+ # # Sauvegarder la blockchain dans un fichier JSON
124
+ # blockchain.save_to_file("blockchain.json")
125
+ #
126
+ # # Charger la blockchain depuis le fichier JSON
127
+ # loaded_blockchain, _ = Blockchain.load_from_file("blockchain.json")
128
+ #
129
+ # print("\nLoaded Blockchain:")
130
+ # print_blockchain_details(loaded_blockchain)
131
+ #
132
+ # # Vérifier que la blockchain chargée est valide
133
+ # print(f"La blockchain chargée est valide : {loaded_blockchain.is_chain_valid()}")
134
+ #
135
+ # # Ajouter un nouveau bloc à la blockchain chargée
136
+ # loaded_blockchain.add_block("HF Trigger Set 4", "Client Trigger Set 4", "Encrypted Model 4")
137
+ #
138
+ # # Sauvegarder la blockchain mise à jour
139
+ # loaded_blockchain.save_to_file("blockchain.json")
zamark_r/model_coef.npy ADDED
Binary file (368 Bytes). View file
 
zamark_r/model_intercept.npy ADDED
Binary file (136 Bytes). View file
 
zamark_r/wat_model_coef.npy ADDED
Binary file (368 Bytes). View file
 
zamark_r/wat_model_intercept.npy ADDED
Binary file (136 Bytes). View file
 
zamark_r/watermarking.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sklearn.model_selection import train_test_split
2
+ import pandas as pd
3
+ from sklearn import datasets
4
+ from sklearn.preprocessing import MinMaxScaler
5
+ import pandas as pd
6
+ import numpy as np
7
+ from concrete.ml.sklearn import SGDClassifier
8
+ import time
9
+ from concrete.ml.sklearn import NeuralNetClassifier
10
+ import hashlib
11
+
12
+ RANDOM_STATE = 6
13
+
14
+ np.random.seed(RANDOM_STATE) #2 #1
15
+
16
+
17
+ def gen_database():
18
+ rng = np.random.default_rng(42)
19
+
20
+ X, y = datasets.load_breast_cancer(return_X_y=True)
21
+ x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y)
22
+
23
+ scaler = MinMaxScaler(feature_range=[-1, 1])
24
+ x_train = scaler.fit_transform(x_train)
25
+ x_test = scaler.transform(x_test)
26
+
27
+ perm = rng.permutation(x_train.shape[0])
28
+
29
+ x_train = x_train[perm, ::]
30
+ y_train = y_train[perm]
31
+
32
+ return x_train, y_train, x_test, y_test
33
+
34
+ def gen_trigger_set():
35
+ X_trigger = np.random.random_sample((15, 30))
36
+ y_trigger = np.random.randint(0, 2, (15))
37
+ for i in range(15):
38
+ if y_trigger[i] == 1:
39
+ X_trigger[i, :15] = X_trigger[i, 15]
40
+ else:
41
+ X_trigger[i, 15:] = X_trigger[i, 15]
42
+ return X_trigger, y_trigger
43
+
44
+
45
+ def train_model(x_train, y_train):
46
+
47
+ parameters_range = (-1.0, 1.0)
48
+ model = SGDClassifier(
49
+ random_state=42,
50
+ max_iter=100,
51
+ fit_encrypted=True,
52
+ parameters_range=parameters_range,
53
+ penalty=None,
54
+ learning_rate="constant",
55
+ verbose=1)
56
+ # %%
57
+ model.fit(x_train, y_train, fhe="simulate")
58
+ return model
59
+
60
+ def watermark_model(model, X_trigger, y_trigger):
61
+ model.max_iter = 17
62
+ model.alpha = 1e-6
63
+ model.penalty = "l2"
64
+ model.warm_start = True
65
+
66
+ a = time.time()
67
+ model.fit(X_trigger, y_trigger, fhe="simulate")
68
+ print("Time :", time.time() - a)
69
+
70
+ return model
71
+
72
+ def evaluate(model, x_train, y_train, x_test, y_test, X_trigger, y_trigger):
73
+ print(f"Accuracy Train Set :{np.sum(model.predict(x_train) == y_train) / len(y_train)}")
74
+ print(f"Accuracy Test Set :{np.sum(model.predict(x_test) == y_test) / len(y_test)}")
75
+ print(f"Accuracy Trigger Set :{np.sum(model.predict(X_trigger) == y_trigger) / len(y_trigger)}")
76
+
77
+
78
+ def get_model_hash(model):
79
+ m = hashlib.sha256()
80
+ m.update(model.coef_)
81
+ m.hexdigest()
82
+ return m.hexdigest()
83
+
84
+ def get_trigger_hash(X_trigger, y_trigger):
85
+ y_trigger = y_trigger.reshape(-1, 1)
86
+ trigger_set = np.concatenate((X_trigger, y_trigger), axis=1)
87
+
88
+ m = hashlib.sha256()
89
+ m.update(trigger_set)
90
+ m.hexdigest()
91
+
92
+ return m.hexdigest()
93
+
94
+ def test():
95
+
96
+ # Gen data
97
+ x_train, y_train, x_test, y_test = gen_database()
98
+
99
+ np.save("x_train", x_train)
100
+ np.save("y_train", y_train)
101
+ np.save("x_test", x_test)
102
+ np.save("y_test", y_test)
103
+
104
+ X_trigger, y_trigger = gen_trigger_set()
105
+
106
+ np.save("x_trigger", X_trigger)
107
+ np.save("y_trigger", y_trigger)
108
+
109
+ X_trigger, y_trigger = np.load("x_trigger.npy"), np.load("y_trigger.npy")
110
+
111
+ model = train_model(x_train, y_train)
112
+
113
+ np.save("model_coef", model.coef_)
114
+ np.save("model_intercept", model.intercept_)
115
+
116
+ model.coef_ = np.load("model_coef.npy")
117
+ model.intercept_ = np.load("model_intercept.npy")
118
+
119
+ wat_model = watermark_model(model, X_trigger, y_trigger)
120
+
121
+ np.save("wat_model_coef", wat_model.coef_)
122
+ np.save("wat_model_intercept", wat_model.intercept_)
123
+
124
+ wat_model.coef_ = np.load("wat_model_coef.npy")
125
+ wat_model.intercept_ = np.load("wat_model_intercept.npy")
126
+
127
+ evaluate(wat_model, x_train, y_train, x_test, y_test, X_trigger, y_trigger)
128
+
129
+ # test()
130
+
131
+
132
+
133
+
134
+
135
+
zamark_r/x_test.npy ADDED
Binary file (41.2 kB). View file
 
zamark_r/x_train.npy ADDED
Binary file (95.6 kB). View file
 
zamark_r/x_trigger.npy ADDED
Binary file (3.73 kB). View file
 
zamark_r/y_test.npy ADDED
Binary file (1.5 kB). View file
 
zamark_r/y_train.npy ADDED
Binary file (3.31 kB). View file
 
zamark_r/y_trigger.npy ADDED
Binary file (248 Bytes). View file