| import os |
|
|
| import streamlit as st |
| import hashlib |
| import uuid |
| import time |
| import json |
| import numpy as np |
| from concrete.ml.sklearn import SGDClassifier |
|
|
| from blockchain import Blockchain, print_blockchain_details |
|
|
| import watermarking |
| from watermarking import watermark_model |
|
|
|
|
| def generate_mock_hash(): |
| return hashlib.sha256(str(time.time()).encode()).hexdigest() |
|
|
|
|
| from utils import ( |
| CLIENT_DIR, |
| CURRENT_DIR, |
| DEPLOYMENT_DIR, |
| KEYS_DIR, |
| INPUT_BROWSER_LIMIT, |
| clean_directory, |
| SERVER_DIR, |
| ) |
|
|
| from concrete.ml.deployment import FHEModelClient |
|
|
| st.set_page_config(layout="wide") |
|
|
| st.sidebar.title("Contact") |
| st.sidebar.info( |
| """ |
| - Reda Bellafqira |
| - Mehdi Ben Ghali |
| - Pierre-Elisée Flory |
| - Mohammed Lansari |
| - Thomas Winninger |
| """ |
| ) |
|
|
| st.title("Zamark: Secure Watermarking Service") |
|
|
| st.image( |
| "watermarking.png", |
| ) |
|
|
|
|
| def todo(): |
| st.warning("Not implemented yet", icon="⚠️") |
|
|
|
|
| def key_gen_fn(client_id): |
| """ |
| Generate keys for a given user. The keys are saved in KEYS_DIR |
| |
| !!! needs a model in DEPLOYMENT_DIR as "client.zip" !!! |
| Args: |
| client_id (str): The client_id, retrieved from streamlit |
| """ |
| clean_directory() |
|
|
| client = FHEModelClient(path_dir=DEPLOYMENT_DIR, key_dir=KEYS_DIR / f"{client_id}") |
| client.load() |
|
|
| |
| client.generate_private_and_evaluation_keys() |
|
|
| |
| serialized_evaluation_keys = client.get_serialized_evaluation_keys() |
| assert isinstance(serialized_evaluation_keys, bytes) |
|
|
| |
| evaluation_key_path = KEYS_DIR / f"{client_id}/evaluation_key" |
| with evaluation_key_path.open("wb") as f: |
| f.write(serialized_evaluation_keys) |
|
|
| |
| serialized_evaluation_keys_shorten_hex = serialized_evaluation_keys.hex()[ |
| :INPUT_BROWSER_LIMIT |
| ] |
| |
| |
| with st.expander("Generated keys"): |
| st.write(f"{len(serialized_evaluation_keys) / (10**6):.2f} MB") |
| st.code(serialized_evaluation_keys_shorten_hex) |
|
|
| st.success("Keys have been generated!", icon="✅") |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| def decode_id(binary_rep): |
| """Decode a string of bits to an ascii string |
| |
| Args: |
| binary_rep (_type_): the binary string |
| |
| Returns: |
| _type_: an ascii string |
| """ |
| |
| |
| binary_int = int(binary_rep, 2) |
| |
| byte_number = binary_int.bit_length() + 7 // 8 |
| |
| binary_array = binary_int.to_bytes(byte_number, "big") |
| |
| ascii_text = binary_array.decode() |
| |
| return ascii_text |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| st.header("Client Configuration", divider=True) |
|
|
| |
|
|
| X_trigger, y_trigger = None, None |
| if st.button("Generate the trigger set for the watermarking"): |
| |
| X_trigger, y_trigger = watermarking.gen_trigger_set() |
| |
| np.save("x_trigger", X_trigger) |
| np.save("y_trigger", y_trigger) |
|
|
|
|
| |
| x_train, y_train, x_test, y_test = watermarking.gen_database() |
|
|
| np.save("x_train", x_train) |
| np.save("y_train", y_train) |
| np.save("x_test", x_test) |
| np.save("y_test", y_test) |
|
|
| |
| st.success("Trigger set generated and data saved successfully!") |
|
|
| |
| st.write(f"Trigger set shape: X={X_trigger.shape}, y={y_trigger.shape}") |
| st.write(f"Training data shape: X={x_train.shape}, y={y_train.shape}") |
| st.write(f"Test data shape: X={x_test.shape}, y={y_test.shape}") |
|
|
|
|
| st.header("Model Training and Encryption", divider=True) |
| |
| model, x_train, y_train, x_test, y_test = None, None, None, None, None |
| parameters_range = (-1.0, 1.0) |
| if st.button("Model Training and Encryption"): |
| |
| x_train, y_train, x_test, y_test = watermarking.gen_database() |
| |
| |
|
|
| model = SGDClassifier( |
| random_state=42, |
| max_iter=100, |
| fit_encrypted=True, |
| parameters_range=parameters_range, |
| penalty=None, |
| learning_rate="constant", |
| verbose=1) |
|
|
| model.coef_ = np.load("model_coef.npy") |
| model.intercept_ = np.load("model_intercept.npy") |
|
|
| |
| st.success("Model training and encryption completed successfully!") |
|
|
| |
| st.write("Model Information:") |
| st.write(f"- Type: {type(model).__name__}") |
| st.write(f"- Number of features: {model.coef_.shape[1]}") |
| st.write(f"- Parameters range: {parameters_range}") |
|
|
| st.write("\nData Information:") |
| st.write(f"- Training set shape: X={x_train.shape}, y={y_train.shape}") |
| st.write(f"- Test set shape: X={x_test.shape}, y={y_test.shape}") |
|
|
| |
| st.write("\nModel Coefficients Preview:") |
| st.write(model.coef_[:5]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| st.header("Model Watermarking", divider=True) |
|
|
| |
| |
| |
| wat_model = None |
| parameters_range = (-1.0, 1.0) |
| if st.button("Model Watermarking"): |
| |
| |
|
|
| wat_model = SGDClassifier( |
| random_state=42, |
| max_iter=100, |
| fit_encrypted=True, |
| parameters_range=parameters_range, |
| penalty=None, |
| learning_rate="constant", |
| verbose=1) |
|
|
| wat_model.coef_ = np.load("wat_model_coef.npy") |
| wat_model.intercept_ = np.load("wat_model_intercept.npy") |
|
|
| |
| st.success("Model watermarking completed successfully!") |
|
|
| |
| st.write("Watermarked Model Information:") |
| st.write(f"- Type: {type(wat_model).__name__}") |
| st.write(f"- Number of features: {wat_model.coef_.shape[1]}") |
| st.write(f"- Parameters range: {parameters_range}") |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
|
|
|
|
|
|
| st.header("Update Blockchain", divider=True) |
|
|
| |
| if 'block_data' not in st.session_state: |
| st.session_state.block_data = None |
|
|
| |
| if st.button("Update Blockchain"): |
| try: |
| |
| loaded_blockchain, data = Blockchain.load_from_file("blockchain.json") |
|
|
| |
| is_valid = loaded_blockchain.is_chain_valid() |
| st.write(f"Loaded blockchain is valid: {is_valid}") |
|
|
| if not is_valid: |
| st.warning("The loaded blockchain is not valid. Please check data integrity.") |
| else: |
| parameters_range = (-1.0, 1.0) |
| wat_model = SGDClassifier( |
| random_state=42, |
| max_iter=100, |
| fit_encrypted=True, |
| parameters_range=parameters_range, |
| penalty=None, |
| learning_rate="constant", |
| verbose=1) |
|
|
| wat_model.coef_ = np.load("wat_model_coef.npy") |
| wat_model.intercept_ = np.load("wat_model_intercept.npy") |
|
|
| X_trigger = np.load("x_trigger.npy") |
| y_trigger = np.load("y_trigger.npy") |
|
|
| watermarked_model_hash = watermarking.get_model_hash(wat_model) |
| trigger_set_hf = watermarking.get_trigger_hash(X_trigger, y_trigger) |
| trigger_set_client = watermarking.get_trigger_hash(X_trigger, y_trigger) |
|
|
| |
| new_block = loaded_blockchain.add_block(trigger_set_hf, trigger_set_client, watermarked_model_hash) |
|
|
| |
| loaded_blockchain.save_to_file("blockchain.json") |
|
|
| |
| st.session_state.block_data = new_block.to_dict() |
|
|
| st.success("Blockchain updated successfully!") |
|
|
| |
| st.subheader("New Block Information") |
| st.write(f"Block ID: {new_block.counter}") |
| st.write(f"Timestamp: {new_block.timestamp}") |
| st.write(f"Previous Hash: {new_block.previous_hash}") |
| st.write(f"Current Hash: {new_block.hash}") |
|
|
| |
| st.subheader("Blockchain Statistics") |
| st.write(f"Total Blocks: {len(loaded_blockchain.chain)}") |
| st.write(f"Blockchain File Size: {os.path.getsize('blockchain.json') / 1024:.2f} KB") |
|
|
| except Exception as e: |
| st.error(f"An error occurred while updating the blockchain: {str(e)}") |
|
|
| |
| if st.session_state.block_data: |
| st.subheader("Latest Block Data (JSON)") |
|
|
| |
| block_json = json.dumps(st.session_state.block_data, indent=2) |
|
|
| |
| st.code(block_json, language='json') |
|
|
| |
| st.subheader("Download Blockchain") |
| with open("blockchain.json", "rb") as file: |
| btn = st.download_button( |
| label="Download Blockchain JSON", |
| data=file, |
| file_name="blockchain.json", |
| mime="application/json" |
| ) |