def round0(): start = time.time() #print(bcolors.BOLD + '\n--- Round 0 ---' + bcolors.ENDC) # Generate the 2 pair of Diffie-Hellman keys # "s" will be used to generate the seed for the shared mask, and "c" the shared encryption key my_ssk, my_spk = DHKE.generate_keys() my_csk, my_cpk = DHKE.generate_keys() # Store the previously generated keys CLIENT_VALUES['my_ssk'] = my_ssk; CLIENT_VALUES['my_spk'] = my_spk CLIENT_VALUES['my_csk'] = my_csk; CLIENT_VALUES['my_cpk'] = my_cpk #generate IBAS key for client step1 Un = CLIENT_VALUES['my_sid'] P_n0,P_n1,sP_n0,sP_n1 = ibas.PKG(Un) #print("IBASkey:",sP_n01,sP_n11) #store IBAS key CLIENT_VALUES['P_n0'] = P_n0 CLIENT_VALUES['P_n1'] = P_n1 CLIENT_VALUES['sP_n0'] = sP_n0 CLIENT_VALUES['sP_n1'] = sP_n1 #generate VEG key for client step1 k_n, Kn = veg.generate_keys() #store veg key CLIENT_VALUES['k_n'] = k_n CLIENT_VALUES['Kn'] = Kn #print("VEGkey:",k_n,Kn) #right 10.12 # Send the client's public key for "c" and "s" to the server #print_info('Sending pubkeys to server...', CLIENT_VALUES['my_sid']) #print("daxiao:",total_size({'cpk':my_cpk, 'spk':my_spk}))#10.16 daxiao end = time.time() timeofround0 = end - start CLIENT_VALUES['timeofround0'] = timeofround0 clientround0totalsize = total_size({'cpk':my_cpk, 'spk':my_spk}) print("timeofround0:",timeofround0,"clientround0totalsize:",clientround0totalsize) CLIENT_VALUES['clientround0totalsize'] = clientround0totalsize sio.emit('PUB_KEYS', {'cpk':my_cpk, 'spk':my_spk}, callback=server_ack)
def server_side_private_set_union(communication, clients, union_security_para_dict, round_num, ps_computation_time_path): """ Main function for parameter server to dominate private set union through perturbed Bloom filter and Secure Aggregation. """ # This dictionary will contain the information that the server received from all clients. # It is keyed by client_index. UNION_SERVER_STORAGE = {} # This dictionary will mainly keep track of time, rounds, and set of (up-to-date) live clients UNION_ROUND_STORAGE = {} UNION_ROUND_STORAGE['communication_round_num'] = round_num UNION_ROUND_STORAGE['ps_computation_time_path'] = ps_computation_time_path # ID 14 - 2048-bit MODP group for Diffie-Hellman Key Exchange UNION_DHKE = DHKE(groupID=14) server_side_psu_round0(communication, clients, UNION_SERVER_STORAGE, UNION_ROUND_STORAGE) server_side_psu_round1(communication, clients, UNION_SERVER_STORAGE, UNION_ROUND_STORAGE) server_side_psu_round2(communication, clients, UNION_SERVER_STORAGE, UNION_ROUND_STORAGE) bf_perturbed_sum = server_side_psu_round3(communication, clients, UNION_SERVER_STORAGE, UNION_ROUND_STORAGE, \ union_security_para_dict, UNION_DHKE) real_itemIDs_union = (np.nonzero(bf_perturbed_sum)[0]).tolist() # send back union send_back_union_psu(communication, clients, real_itemIDs_union)
def round0(): #print(bcolors.BOLD + '\n--- Round 0 ---' + bcolors.ENDC) # Generate the 2 pair of Diffie-Hellman keys # "s" will be used to generate the seed for the shared mask, and "c" the shared encryption key my_ssk, my_spk = DHKE.generate_keys() my_csk, my_cpk = DHKE.generate_keys() # Store the previously generated keys CLIENT_VALUES['my_ssk'] = my_ssk CLIENT_VALUES['my_spk'] = my_spk CLIENT_VALUES['my_csk'] = my_csk CLIENT_VALUES['my_cpk'] = my_cpk # Send the client's public key for "c" and "s" to the server #print_info('Sending pubkeys to server...', CLIENT_VALUES['my_sid']) sio.emit('PUB_KEYS', {'cpk': my_cpk, 'spk': my_spk}, callback=server_ack)
def client_side_secure_federated_submodel_averaging(communication, client_socket, client_index, fedsubavg_x_dict,\ perturbed_itemIDs, perturbed_cateIDs, fedsubavg_security_para_dict, fedsubavg_u2_drop_flag, fedsubavg_u3_drop_flag,\ round_num, client_computation_time_path): """ Main function for client to join secure federated submodel averaging through secure aggregation """ # This dictionary will contain all the values generated by this client herself FEDSUBAVG_SELF_STORAGE = {} # This dictionary will contain all the values about the OTHER clients. It is keyed by client_index FEDSUBAVG_OTHERS_STORAGE = {} FEDSUBAVG_SELF_STORAGE['my_index'] = client_index FEDSUBAVG_SELF_STORAGE['communication_round_number'] = round_num FEDSUBAVG_SELF_STORAGE['client_computation_time_path'] = client_computation_time_path # ID 14 - 2048-bit MODP group for Diffie-Hellman Key Exchange FEDSUBAVG_DHKE = DHKE(groupID=14) client_side_sfsa_round0(communication, client_socket, FEDSUBAVG_SELF_STORAGE, FEDSUBAVG_OTHERS_STORAGE, FEDSUBAVG_DHKE) client_side_sfsa_round1(communication, client_socket, FEDSUBAVG_SELF_STORAGE, FEDSUBAVG_OTHERS_STORAGE, \ fedsubavg_security_para_dict, FEDSUBAVG_DHKE) if fedsubavg_u2_drop_flag: # drop from round 2 client_socket.close() print("Client %d drops out from Secure Federated Submodel Averaging U2 in this communication round \n" % client_index) print('-----------------------------------------------------------------') print('') print('') sys.stdout.flush() return # client's original inputs fedsubavg_x_dict: 'weighted_delta_submodel': uploaded_weighted_delta_submodel, # 'perturbed_userID_count': uploaded_perturbed_userID_count, # 'perturbed_itemIDs_count': uploaded_itemIDs_count, # 'perturbed_cateIDs_count': uploaded_cateIDs_count, # 'perturbed_other_count': uploaded_perturbed_other_count client_side_sfsa_round2(communication, client_socket, FEDSUBAVG_SELF_STORAGE, FEDSUBAVG_OTHERS_STORAGE, \ fedsubavg_x_dict, perturbed_itemIDs, perturbed_cateIDs, fedsubavg_security_para_dict, FEDSUBAVG_DHKE) if fedsubavg_u3_drop_flag: # drop from round 3 client_socket.close() print("Client %d drops out from Secure Federated Submodel Averaging U3 in this communication round \n" % client_index) print('-----------------------------------------------------------------') print('') print('') return client_side_sfsa_round3(communication, client_socket, FEDSUBAVG_SELF_STORAGE, FEDSUBAVG_OTHERS_STORAGE) del FEDSUBAVG_SELF_STORAGE del FEDSUBAVG_OTHERS_STORAGE
def client_side_private_set_union(communication, client_socket, client_index, real_itemIDs, union_security_para_dict, union_u2_drop_flag, union_u3_drop_flag, round_num, client_computation_time_path): """ Main function for client to join Private Set Union (PSU) through perturbed Bloom filter and Secure Aggregation """ # This dictionary will contain all the values generated by this client herself UNION_SELF_STORAGE = {} # This dictionary will contain all the values about the OTHER clients. It is keyed by client_index UNION_OTHERS_STORAGE = {} UNION_SELF_STORAGE['my_index'] = client_index UNION_SELF_STORAGE['communication_round_number'] = round_num UNION_SELF_STORAGE[ 'client_computation_time_path'] = client_computation_time_path # ID 14 - 2048-bit MODP group for Diffie-Hellman Key Exchange UNION_DHKE = DHKE(groupID=14) client_side_psu_round0(communication, client_socket, UNION_SELF_STORAGE, UNION_OTHERS_STORAGE, UNION_DHKE) client_side_psu_round1(communication, client_socket, UNION_SELF_STORAGE, UNION_OTHERS_STORAGE, \ union_security_para_dict, UNION_DHKE) if union_u2_drop_flag: # drop from round 2 client_socket.close() print( "Client %d drops out from Private Set Union U2 in this communication round \n" % client_index) print( '-----------------------------------------------------------------' ) print('') print('') sys.stdout.flush() return [] # Represent real_itemIDs as a perturbed Bloom filter start_time = time.time() real_itemIDs_pbf = represent_set_as_perturbed_bloom_filter( real_itemIDs, union_security_para_dict) write_csv( client_computation_time_path, [round_num, "psu_generated_perturbed_bf", time.time() - start_time]) UNION_SELF_STORAGE['x'] = real_itemIDs_pbf client_side_psu_round2(communication, client_socket, UNION_SELF_STORAGE, UNION_OTHERS_STORAGE, \ union_security_para_dict, UNION_DHKE) if union_u3_drop_flag: # drop from round 3 client_socket.close() print( "Client %d drops out from Private Set Union U3 in this communication round \n" % client_index) print( '-----------------------------------------------------------------' ) print('') print('') return [] client_side_psu_round3(communication, client_socket, UNION_SELF_STORAGE, UNION_OTHERS_STORAGE) # receive union real_itemIDs_union = communication.get_np_array(client_socket) print('Received union of real item ids (via Private Set Union).') sys.stdout.flush() del UNION_SELF_STORAGE del UNION_OTHERS_STORAGE return real_itemIDs_union
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from diffie_hellman import DHKE from oblivious_transfer import OT_Sender, OT_Receiver from AES_encryption import AESCipher DHKE = DHKE(groupID=666) # sk, pk = DHKE.generate_keys() # # print(sk) # print('LENGTH:', len(str(sk))) # # print() # # shares = SecretSharer.split_secret(sk, 5, 6) # # for s in shares: # # print('-', s) # # print('LENGTH:', len(str(s))) # # print() # # secretTrue = SecretSharer.recover_secret(shares[0:5]) # print(secretTrue == sk) # # secretFalse = SecretSharer.recover_secret(shares[0:4]) # not enough # print(secretFalse == sk) sk1, pk1 = DHKE.generate_keys()
def round3(): U3 = SERVER_VALUES['U3'] n3 = len(U3) print("|U3| the number of clients sending shared masks:", n3) if n3 < SERVER_VALUES['t']: print_failure( 'Did not receive masks and shares from enough clients. Abort.', 'Server') sio.emit( 'abort', 'not enough clients' ) # Broadcast to everyone that the server aborts --> client should disconnect sio.sleep(1) os._exit(-1) # sio.stop() # FIXME # The "dropped out clients" are all the clients sid that were present in the set U2 but not in U3 dropped_out_clients = list(set(SERVER_VALUES['U2']) - set(U3)) SERVER_VALUES['dropped_out_clients_round_3'] = dropped_out_clients Z = 0 print("NB DROPPED OUT CLIENTS =", len(SERVER_VALUES['dropped_out_clients_round_2'])) if SERVER_VALUES['dropped_out_clients_round_2'] != []: # Retrieve the shares of "ssk" of dropped out clients from all alive clients all_ssk_shares = [] for client_sid in U3: all_ssk_shares.append( SERVER_STORAGE[client_sid]['ssk_shares_dropped']) ssk_shares_for_sid = { k: [d.get(k) for d in all_ssk_shares] for k in set().union(*all_ssk_shares) } # Reconstruct ssk from its shares ssk_for_sid = {} for client_sid in SERVER_VALUES['dropped_out_clients_round_2']: ssk = SecretSharer.recover_secret(ssk_shares_for_sid[client_sid]) ssk_for_sid[client_sid] = ssk # Reconstruct all blinding values (s_masks) for all pairs of alive users with the dropped out users all_masks = np.zeros(NB_CLASSES) for dropped_client_sid in SERVER_VALUES['dropped_out_clients_round_2']: for alive_client_sid in U3: s_for_sid = DHKE.agree(ssk_for_sid[dropped_client_sid], SERVER_STORAGE[alive_client_sid]['spk']) np.random.seed(s_for_sid % 2**32) s_mask_for_sid = np.random.uniform(-UNIFORM_S_BOUNDS, UNIFORM_S_BOUNDS, NB_CLASSES) sgn = np.sign( int(alive_client_sid, 16) - int(dropped_client_sid, 16)) all_masks += sgn * s_mask_for_sid Z -= all_masks # Retrieve the shares of "b" from all alive clients all_b_shares = [] for client_sid in U3: all_b_shares.append(SERVER_STORAGE[client_sid]['b_shares_alive']) b_shares_for_sid = { k: [d.get(k) for d in all_b_shares] for k in set().union(*all_b_shares) } # Reconstruct "b" from its shares b_for_sid = {} for client_sid in U3: b = SecretSharer.recover_secret(b_shares_for_sid[client_sid]) b_for_sid[client_sid] = b # Remove b from the y that we received from clients, and aggregate the whole for client_sid in U3: b = b_for_sid[client_sid] np.random.seed(b) b_mask = np.random.uniform(-UNIFORM_B_BOUNDS, UNIFORM_B_BOUNDS, NB_CLASSES) Z += (SERVER_STORAGE[client_sid]['y'] - b_mask) print('Server succesfully aggregate the result and the lenth is ', len(list(Z))) # For Decentralized PATE, the label would be the argmax of this vote vector #print('LABEL:', np.argmax(Z)) SERVER_VALUES['serverround3totalsize'] = total_size({ "aggregation": list(Z), 'U3': U3 }) sio.emit('ROUND_4', {"aggregation": list(Z), 'U3': U3}) #tianjia in 10.11 # Go back to function call (ret) and exit in function timer_round3() above sio.start_background_task(timer_round_4)
UNIFORM_B_BOUNDS = 1e6 # Min and Max bounds for random b masking values UNIFORM_S_BOUNDS = 1e6 # Min and Max bounds for random s masking values # 2 sorts of measurements per round, COMMunication time, with the clients # and COMPutation time (only the server, processing the logic for this round) # Stored in SERVER_VALUES dict, as: # SERVER_VALUES['BENCHMARK_TIME_ROUND_i_COMP'] or SERVER_VALUES['BENCHMARK_TIME_ROUND_i_COMM'] assert (len(sys.argv) == 3) INIT_NB_CLIENTS = int(sys.argv[1]) BENCHMARK_FILENAME = sys.argv[2] # Initialization of the parameters (groupID 14) for the Diffie-Hellman # Key Exchange algorithm global DHKE DHKE = DHKE(groupID=14) # This dictionary will contain all the values used by the server # to keep track of time, rounds, and number of clients global SERVER_VALUES SERVER_VALUES = {} # This dictionary will contain the information that the server # received about all clients. It is keyed by client_sid. global SERVER_STORAGE SERVER_STORAGE = {} # Global variable "ROUND" tracking the Round Number --> Finite State Machine Logic of the server SERVER_VALUES['ROUND'] = 0 app = Flask(__name__)
def round2(enc_msgs): for client_sid, enc_msg in enc_msgs.items(): # Decrypt the encrypted message and parse it enc_key_for_sid = CLIENT_STORAGE[client_sid]['enc_key'] msg = AESCipher(str(enc_key_for_sid)).decrypt(enc_msg) msg_parts = msg.split(' || ') protocol_id = msg_parts[0] # TODO: What's the use? #TODO: Timestamp? from_client_sid = msg_parts[1] my_sid = msg_parts[2] share_ssk_for_sid = msg_parts[3] share_a_for_sid = msg_parts[4] share_b_for_sid = msg_parts[5] # Store has been received for client_sid CLIENT_STORAGE[from_client_sid]['share_ssk'] = share_ssk_for_sid CLIENT_STORAGE[from_client_sid]['share_a'] = share_a_for_sid CLIENT_STORAGE[from_client_sid]['share_b'] = share_b_for_sid # Sanity check if client_sid != from_client_sid or my_sid != CLIENT_VALUES['my_sid']: print_failure('Received wrong message!', CLIENT_VALUES['my_sid']) sio.disconnect() # Derive secret shared mask seed s_for_sid (Diffie-Hellman Agreement) s_for_sid = DHKE.agree(CLIENT_VALUES['my_ssk'], CLIENT_STORAGE[client_sid] ['spk']) #; print('s_for_sid =', s_for_sid) # Derive s_mask from above seed np.random.seed( s_for_sid % 2**32) # TODO: Higher entropy than 2**32??? (max value to .seed()) s_mask_for_sid = np.random.uniform( -UNIFORM_S_BOUNDS, UNIFORM_S_BOUNDS, NB_CLASSES ) #; print('s_for_sid =', s_for_sid )# TODO: Which values?? # Store also that CLIENT_STORAGE[client_sid]['s'] = s_for_sid CLIENT_STORAGE[client_sid]['s_mask'] = s_mask_for_sid # Construct masked input: # First the noisy input (the one that the server will aggregate) noisy_x = CLIENT_VALUES['x'] + CLIENT_VALUES['a_noise'] # Then, add the individual mask yy = noisy_x + CLIENT_VALUES['b_mask'] all_masks = np.zeros(NB_CLASSES) for client_sid in CLIENT_STORAGE.keys(): if client_sid == CLIENT_VALUES['my_sid']: continue # Skip my own SID if not 's_mask' in CLIENT_STORAGE[client_sid].keys(): print_failure("No shared mask for client", client_sid) continue # We do not have shared mask from this client SID sgn = np.sign( int(CLIENT_VALUES['my_sid'], 16) - int(client_sid, 16)) # Substract the masks of greater client SIDs, all_masks += sgn * CLIENT_STORAGE[client_sid][ 's_mask'] # or add those of smaller client SIDs # Here is the final output "y" to send to server y = yy + all_masks #print_info('Sending masked input "y" to server...', CLIENT_VALUES['my_sid']) sio.emit( 'INPUT_Y', list(y), callback=server_ack ) # Send "y" as a python list because numpy arrays are not JSON-serializable
def round1(pubkeys): # Store the keys received from the server, in the dictionary CLIENT_STORAGE, for each client_sid for client_sid, pubkeys_for_client_sid in pubkeys.items(): if client_sid == CLIENT_VALUES['my_sid']: continue # Does not need to store my own keys (already stored in CLIENT_VALUES) try: CLIENT_STORAGE.setdefault( client_sid, {})['cpk'] = pubkeys_for_client_sid['cpk'] CLIENT_STORAGE.setdefault( client_sid, {})['spk'] = pubkeys_for_client_sid['spk'] except KeyError: print_failure('Missing key cpk or spk in server' 's messsage.', request.sid) sio.disconnect() # Compute n, the number of active clients (me, included) n = len(CLIENT_STORAGE.keys()) + 1 #; print('n =', n) # Compute t, the minimum number of clients we need for the aggregation t = int(n / 2) + 1 #; print('t =', t) # Draw random seed a, and make a gaussian noise mask out of it a = secrets.randbits(32) #; print('a =', a) # TODO: Chose higher entropy np.random.seed(a) a_noise_vector = np.random.normal( 0, float(SIGMA) / np.sqrt(t), NB_CLASSES) #; print('a_noise_vector =', a_noise_vector) # Draw random seed b, and make a mask out of it b = secrets.randbits(32) #; print('b =', b) np.random.seed(b) b_mask = np.random.uniform( -UNIFORM_B_BOUNDS, UNIFORM_B_BOUNDS, NB_CLASSES ) #; print('b_mask =', b_mask) # TODO: HOW TO CHOOSE THOSE VALUES??? # Create t-out-of-n shares for seed a shares_a = SecretSharer.split_secret(a, t, n) #; print('shares_a =', shares_a) # Create t-out-of-n shares for seed b shares_b = SecretSharer.split_secret(b, t, n) #; print('shares_b =', shares_b) # Create t-out-of-n shares for my private key my_ssk (as an hex_string) shares_my_ssk = SecretSharer.split_secret( CLIENT_VALUES['my_ssk'], t, n) #; print('shares_my_ssk =', shares_my_ssk) # Store all the previously generated values, in client's dictionary CLIENT_VALUES['n'] = n CLIENT_VALUES['t'] = t CLIENT_VALUES['a'] = a CLIENT_VALUES['a_noise'] = a_noise_vector CLIENT_VALUES['b'] = b CLIENT_VALUES['b_mask'] = b_mask CLIENT_VALUES['shares_a'] = shares_a CLIENT_VALUES['shares_b'] = shares_b CLIENT_VALUES['shares_my_ssk'] = shares_my_ssk # Store my share of b in isolation: my_share_b = shares_b[0] shares_b = list(set(shares_b) - set([my_share_b])) CLIENT_VALUES['my_share_b'] = my_share_b list_encrypted_messages = {} for ID, client_sid in enumerate(CLIENT_STORAGE.keys()): if client_sid == CLIENT_VALUES['my_sid']: continue # Skip my own sid # FIXME: Actually, I am NOT part of CLIENT_STORAGE.keys() # Derive encryption key enc_key_for_sid (via Diffie-Hellman Agreement) enc_key_for_sid = DHKE.agree( CLIENT_VALUES['my_csk'], CLIENT_STORAGE[client_sid] ['cpk']) #; print('enc_key_for_sid =', enc_key_for_sid) # Client "client_sid" will be sent this message: msg = 'ProtoV1.0' + ' || ' + str( CLIENT_VALUES['my_sid']) + ' || ' + str(client_sid) + ' || ' + str( shares_my_ssk[ID]) + ' || ' + str(shares_a[ID]) + ' || ' + str( shares_b[ID]) # Encrypt the message with the pre-derived shared encryption key enc_msg = AESCipher(str(enc_key_for_sid)).encrypt(msg) # Store the encrypted messages in a dictionary (keyed by client_sid) that will be sent to the server list_encrypted_messages[client_sid] = enc_msg CLIENT_STORAGE[client_sid]['enc_key'] = enc_key_for_sid CLIENT_STORAGE[client_sid]['msg'] = msg CLIENT_STORAGE[client_sid]['enc_msg'] = enc_msg #print_info('Sending list of encrypted messages to server...', CLIENT_VALUES['my_sid']) sio.emit('ENC_MSGS', list_encrypted_messages, callback=server_ack) if WILL_CRASH: sio.sleep(1) os._exit(0)
NB_CLASSES = 10 SIGMA = 0.005 # This dictionary will contain all the values generated by this client # and used in the aggregation global CLIENT_VALUES CLIENT_VALUES = {} # This dictionary will contain all the values about the OTHER clients # part of the aggregation. It is keyed by client_sid. global CLIENT_STORAGE CLIENT_STORAGE = {} # The params of the group global DHKE DHKE = DHKE(groupID=14) # TODO: Use 2048-bit group (id=14) or above # The socketIO object representing our client's socket. # We can register listeners ('handlers') of events with the function sio.on(<event name>, <handler function>) sio = socketio.Client() # Connect this client to the server. Upon connection, this client receives a unique socket id "my_sid" # that we store in the CLIENT_VALUES sio.connect('http://127.0.0.1:9876' ) # TODO: Put address and port in a server.ini config file CLIENT_VALUES['my_sid'] = sio.eio.sid #print('My sid =', CLIENT_VALUES['my_sid']) # "connect" and "disconnect" are 2 special events generated by socketIO upon socket creation # and destruction. "abort" is a custom event that we created upon server stopping.
def round2(round1servertoclientmessages): #print("round1servertoclientmessages:",round1servertoclientmessages) success 10.10 for client_sid, enc_msg in round1servertoclientmessages["enc_msgs"].items(): # Decrypt the encrypted message and parse it enc_key_for_sid = CLIENT_STORAGE[client_sid]['enc_key'] msg = PrpCrypt(str(enc_key_for_sid)).decrypt(enc_msg) msg_parts = msg.split(' || ') protocol_id = msg_parts[0] # TODO: What's the use? #TODO: Timestamp? from_client_sid = msg_parts[1] my_sid = msg_parts[2] share_ssk_for_sid = msg_parts[3] share_b_for_sid = msg_parts[4] # Store has been received for client_sid CLIENT_STORAGE[from_client_sid]['share_ssk'] = share_ssk_for_sid #CLIENT_STORAGE[from_client_sid]['share_a'] = share_a_for_sid CLIENT_STORAGE[from_client_sid]['share_b'] = share_b_for_sid # Sanity check if client_sid != from_client_sid or my_sid != CLIENT_VALUES['my_sid']: print_failure('Received wrong message!', CLIENT_VALUES['my_sid']) sio.disconnect() # Derive secret shared mask seed s_for_sid (Diffie-Hellman Agreement) s_for_sid = DHKE.agree(CLIENT_VALUES['my_ssk'], CLIENT_STORAGE[client_sid]['spk']) #; print('s_for_sid =', s_for_sid) # Derive s_mask from above seed np.random.seed(s_for_sid % 2**32) # TODO: Higher entropy than 2**32??? (max value to .seed()) s_mask_for_sid = np.random.uniform(-UNIFORM_S_BOUNDS, UNIFORM_S_BOUNDS, NB_CLASSES) #; print('s_for_sid =', s_for_sid )# TODO: Which values?? # Store also that CLIENT_STORAGE[client_sid]['s'] = s_for_sid CLIENT_STORAGE[client_sid]['s_mask'] = s_mask_for_sid # Construct masked input: yy = CLIENT_VALUES['x'] + CLIENT_VALUES['b_mask'] #the second masked in our paper all_masks = np.zeros(NB_CLASSES) for client_sid in CLIENT_STORAGE.keys(): if client_sid == CLIENT_VALUES['my_sid']: continue # Skip my own SID if not 's_mask' in CLIENT_STORAGE[client_sid].keys(): print_failure("No shared mask for client", client_sid) continue # We do not have shared mask from this client SID sgn = np.sign(int(CLIENT_VALUES['my_sid'], 16) - int(client_sid, 16)) # Substract the masks of greater client SIDs, all_masks += sgn * CLIENT_STORAGE[client_sid]['s_mask'] # or add those of smaller client SIDs # Here is the final output "y" to send to server y = yy + all_masks ''' Identity-Based Aggregate Signatures ->round0 & round 2 data:10.10 ''' '''individual signing step 2''' start = time.time() #extract sessionID from the message received from the server sessionID = round1servertoclientmessages['SID'] #print("client receive SID",sessionID) #store the sessionID CLIENT_VALUES["sessionID"] = sessionID #calculate w by sessionID sha1 = hashlib.sha1() sha1.update(str(sessionID).encode("utf-8"))#str(sessionID) list ->string w = str(sha1.hexdigest()) #w = "w" test first #print("w->",w) P_n0 = CLIENT_VALUES['P_n0'] P_n1 = CLIENT_VALUES['P_n1'] sP_n0 = CLIENT_VALUES['sP_n0'] sP_n1 = CLIENT_VALUES['sP_n1'] Un = CLIENT_VALUES['my_sid'] k_n = CLIENT_VALUES['k_n'] Kn = CLIENT_VALUES['Kn'] #VElGamal encryption x_n = [] for i in range(NB_CLASSES): x_n.append(int(CLIENT_VALUES['x'][i]*1e6)) #print("x_n",x_n) Cn = veg.enc(x_n,k_n) #construct Mn Mn= str(Kn)+str(Cn)+str(sessionID) sigma_n = ibas.InSign(w,Mn,Un,sP_n0,sP_n1) #print("Individual signature:", sigma_n) c_n = Element.from_hash(pairing, Zr, Un + Mn + w) #print("c_n",c_n,type(c_n)) #print("P_n0",P_n0,type(P_n0)) #print("P_n1",P_n1,type(P_n1)) strsigma_n = [sigma_n[0],str(sigma_n[1]),str(sigma_n[2])] #shoud be convert to pypbc.Element.G2 strc_n = str(c_n)#in fact it should by reconstruct though little computation cost strP_n0 = str(P_n0) strP_n1 = str(P_n1) round2clienttoservermessages = {"mask_x":list(y),"sigma_n":strsigma_n,"Cn":Cn,"Kn":Kn,"c_n":strc_n,"P_n0":strP_n0,"P_n1":strP_n1,'w':w} #print_info('Sending masked input "y" to server...', CLIENT_VALUES['my_sid']) end = time.time() timeofround2 = end - start CLIENT_VALUES['timeofround2'] = timeofround2 clientround2totalsize = total_size(round2clienttoservermessages) CLIENT_VALUES['clientround2totalsize'] = clientround2totalsize print("timeofround2:",timeofround2,"clientround2totalsize:",clientround2totalsize) sio.emit('INPUT_Y', round2clienttoservermessages, callback=server_ack) # Send "y" as a python list because numpy arrays are not JSON-serializable
def round1(pubkeys): start = time.time() # Store the keys received from the server, in the dictionary CLIENT_STORAGE, for each client_sid for client_sid, pubkeys_for_client_sid in pubkeys.items(): if client_sid == CLIENT_VALUES['my_sid']: continue # Does not need to store my own keys (already stored in CLIENT_VALUES) try: CLIENT_STORAGE.setdefault(client_sid, {})['cpk'] = pubkeys_for_client_sid['cpk']#当查找的键值 key 不存在的时候,setdefault()函数会返回默认值并更新字典,添加键值 CLIENT_STORAGE.setdefault(client_sid, {})['spk'] = pubkeys_for_client_sid['spk'] except KeyError: print_failure('Missing key cpk or spk in server''s messsage.', client_sid) sio.disconnect() # Compute n, the number of active clients (me, included) n = len(CLIENT_STORAGE.keys()) + 1 #; print('n =', n) # Compute t, the minimum number of clients we need for the aggregation t = int(n/2) + 1 #; print('t =', t) # Draw random seed b, and make a mask out of it b = secrets.randbits(32) #; print('b =', b) np.random.seed(b) b_mask = np.random.uniform(-UNIFORM_B_BOUNDS, UNIFORM_B_BOUNDS, NB_CLASSES) #; print('b_mask =', b_mask) # TODO: HOW TO CHOOSE THOSE VALUES??? # Create t-out-of-n shares for seed b shares_b = SecretSharer.split_secret(b, t, n) #; print('shares_b =', shares_b) # Create t-out-of-n shares for my private key my_ssk (as an hex_string) shares_my_ssk = SecretSharer.split_secret(CLIENT_VALUES['my_ssk'], t, n) #; print('shares_my_ssk =', shares_my_ssk) # Store all the previously generated values, in client's dictionary CLIENT_VALUES['n'] = n; CLIENT_VALUES['t'] = t CLIENT_VALUES['b'] = b; CLIENT_VALUES['b_mask'] = b_mask #CLIENT_VALUES['shares_a'] = shares_a CLIENT_VALUES['shares_b'] = shares_b CLIENT_VALUES['shares_my_ssk'] = shares_my_ssk # Store my share of b in isolation: my_share_b = shares_b[0] shares_b = list( set(shares_b) - set([my_share_b]) ) CLIENT_VALUES['my_share_b'] = my_share_b list_encrypted_messages = {} for ID, client_sid in enumerate(CLIENT_STORAGE.keys()): if client_sid == CLIENT_VALUES['my_sid']: continue # Skip my own sid # FIXME: Actually, I am NOT part of CLIENT_STORAGE.keys() # Derive encryption key enc_key_for_sid (via Diffie-Hellman Agreement) enc_key_for_sid = DHKE.agree(CLIENT_VALUES['my_csk'], CLIENT_STORAGE[client_sid]['cpk']) #; print('enc_key_for_sid =', enc_key_for_sid) # Client "client_sid" will be sent this message: msg = 'ProtoV1.0' + ' || ' + str(CLIENT_VALUES['my_sid']) + ' || ' + str(client_sid) + ' || ' + str(shares_my_ssk[ID]) + ' || ' + str(shares_b[ID]) # Encrypt the message with the pre-derived shared encryption key enc_msg = PrpCrypt(str(enc_key_for_sid)).encrypt(msg) # Store the encrypted messages in a dictionary (keyed by client_sid) that will be sent to the server list_encrypted_messages[client_sid] = enc_msg CLIENT_STORAGE[client_sid]['enc_key'] = enc_key_for_sid CLIENT_STORAGE[client_sid]['msg'] = msg CLIENT_STORAGE[client_sid]['enc_msg'] = enc_msg #Generate Rn************************************* Rn = random.randint(1,1000) CLIENT_VALUES["Rn"] = Rn round1clienttoservermessages = {"Rn":Rn, "enc_msg":list_encrypted_messages} end = time.time() timeofround1 = end - start CLIENT_VALUES['timeofround1'] = timeofround1 clientround1totalsize = total_size(round1clienttoservermessages) CLIENT_VALUES['clientround1totalsize'] = clientround1totalsize print("timeofround1:",timeofround1,"clientround1totalsize:",clientround1totalsize) sio.emit('ENC_MSGS', round1clienttoservermessages, callback=server_ack) # drop out in round 1 set(U1) - set(U0) if WILL_CRASH: sio.sleep(1) os._exit(0)
def round3(): U3 = SERVER_VALUES['U3'] n3 = len(U3) if n3 < SERVER_VALUES['t']: print_failure( 'Did not receive masks and shares from enough clients. Abort.', 'Server') sio.emit( 'abort', 'not enough clients' ) # Broadcast to everyone that the server aborts --> client should disconnect sio.sleep(1) os._exit(-1) # sio.stop() # FIXME # The "dropped out clients" are all the clients sid that were present in the set U2 but not in U3 dropped_out_clients = list(set(SERVER_VALUES['U2']) - set(U3)) SERVER_VALUES['dropped_out_clients_round_3'] = dropped_out_clients Z = 0 print("NB DROPPED OUT CLIENTS =", len(SERVER_VALUES['dropped_out_clients_round_2'])) if SERVER_VALUES['dropped_out_clients_round_2'] != []: # Retrieve the shares of "ssk" of dropped out clients from all alive clients all_ssk_shares = [] for client_sid in U3: all_ssk_shares.append( SERVER_STORAGE[client_sid]['ssk_shares_dropped']) ssk_shares_for_sid = { k: [d.get(k) for d in all_ssk_shares] for k in set().union(*all_ssk_shares) } # Reconstruct ssk from its shares ssk_for_sid = {} for client_sid in SERVER_VALUES['dropped_out_clients_round_2']: ssk = SecretSharer.recover_secret(ssk_shares_for_sid[client_sid]) ssk_for_sid[client_sid] = ssk # Reconstruct all blinding values (s_masks) for all pairs of alive users with the dropped out users all_masks = np.zeros(NB_CLASSES) for dropped_client_sid in SERVER_VALUES['dropped_out_clients_round_2']: for alive_client_sid in U3: s_for_sid = DHKE.agree(ssk_for_sid[dropped_client_sid], SERVER_STORAGE[alive_client_sid]['spk']) np.random.seed(s_for_sid % 2**32) s_mask_for_sid = np.random.uniform(-UNIFORM_S_BOUNDS, UNIFORM_S_BOUNDS, NB_CLASSES) sgn = np.sign( int(alive_client_sid, 16) - int(dropped_client_sid, 16)) all_masks += sgn * s_mask_for_sid Z -= all_masks # Retrieve the shares of "b" from all alive clients all_b_shares = [] for client_sid in U3: all_b_shares.append(SERVER_STORAGE[client_sid]['b_shares_alive']) b_shares_for_sid = { k: [d.get(k) for d in all_b_shares] for k in set().union(*all_b_shares) } # Reconstruct "b" from its shares b_for_sid = {} for client_sid in U3: b = SecretSharer.recover_secret(b_shares_for_sid[client_sid]) b_for_sid[client_sid] = b # Remove b from the y that we received from clients, and aggregate the whole for client_sid in U3: b = b_for_sid[client_sid] np.random.seed(b) b_mask = np.random.uniform(-UNIFORM_B_BOUNDS, UNIFORM_B_BOUNDS, NB_CLASSES) Z += (SERVER_STORAGE[client_sid]['y'] - b_mask) # More noise that neccesary (t), remove that extra noise if 'extra_noises' in SERVER_VALUES: extra_noises = np.array(SERVER_VALUES['extra_noises']) extra_noises_sum = np.sum(extra_noises, axis=0) Z -= extra_noises_sum # Z is now the approriately noised array, containing the aggregation of private # vectors of the still alive clients # print('Z = ', Z) print('[*]', time.time(), 'Done') # For Decentralized PATE, the label would be the argmax of this vote vector #print('LABEL:', np.argmax(Z)) sio.emit('complete', 'Reconstructed output z!')