diff --git a/src/customer.py b/src/customer.py index c06ba55..cb65199 100644 --- a/src/customer.py +++ b/src/customer.py @@ -22,32 +22,25 @@ class Customer: def valid_key_entry(self, username, selected_keys) -> bool: if username not in self.users: raise ValueError(f"User '{username}' does not exist") - numb_of_keys = self.cipher.keypad_size.numb_of_keys if not all(0 <= key_idx < numb_of_keys for key_idx in selected_keys): raise ValueError(f"Invalid key indices. Must be between 0 and {numb_of_keys - 1}") - passcode_len = len(selected_keys) user = self.users[username] - passcode_set_vals = user.cipher.decipher_mask( user.enciphered_passcode.mask, self.cipher.set_key, passcode_len) set_vals_idx = [self.cipher.get_set_index(set_val) for set_val in passcode_set_vals] - presumed_property_idxs = [] for idx in range(passcode_len): key_numb = selected_keys[idx] set_idx = set_vals_idx[idx] selected_prop_idx = user.user_keypad.get_prop_idx_by_keynumb_setidx(key_numb, set_idx) presumed_property_idxs.append(selected_prop_idx) - if not user.cipher.compare_nkode(presumed_property_idxs, self.cipher,user.enciphered_passcode.code): return False - if user.renew: user.refresh_passcode(presumed_property_idxs, self.cipher) - - user.user_keypad.partial_keypad_shuffle() + user.user_keypad.split_shuffle() return True def renew_keys(self) -> bool: diff --git a/src/user_keypad.py b/src/user_keypad.py index 1405dd3..ffcb0b6 100644 --- a/src/user_keypad.py +++ b/src/user_keypad.py @@ -62,22 +62,12 @@ class UserKeypad: ) self.keypad = dispersed_keypad.reshape(-1) - def partial_keypad_shuffle(self): - # TODO: this should be split shuffle - #numb_of_selected_sets = self.keypad_size.props_per_key // 2 - ## randomly shuffle half the sets. if props_per_key is odd, randomly add one 50% of the time - #numb_of_selected_sets += choice([0, 1]) if (self.keypad_size.props_per_key & 1) == 1 else 0 - #selected_sets = secure_fisher_yates_shuffle(list(range(self.keypad_size.props_per_key)))[:numb_of_selected_sets] - #user_keypad_matrix = self.keypad_matrix() - #shuffled_keys = secure_fisher_yates_shuffle(user_keypad_matrix) - #keypad_by_sets = [] - #for idx, props in enumerate(matrix_transpose(shuffled_keys)): - # if idx in selected_sets: - # keypad_by_sets.append(secure_fisher_yates_shuffle(props)) - # else: - # keypad_by_sets.append(props) - #self.keypad = matrix_to_list(matrix_transpose(keypad_by_sets)) - pass + def split_shuffle(self): + prop_permutation = np.random.permutation(self.keypad_size.props_per_key)[: self.keypad_size.props_per_key // 2] + key_permutation = np.random.permutation(self.keypad_size.numb_of_keys) + keypad_view = self.keypad_matrix().copy() + keypad_view[:, prop_permutation] = keypad_view[key_permutation, :][:, prop_permutation] + self.keypad = keypad_view.reshape(-1) def property_adjacency_graph(self) -> dict[int, set[int]]: user_keypad_keypad = self.keypad_matrix() diff --git a/test/test_user_keypad.py b/test/test_user_keypad.py index b7deadf..f7bb7a6 100644 --- a/test/test_user_keypad.py +++ b/test/test_user_keypad.py @@ -5,7 +5,7 @@ from src.models import KeypadSize @pytest.fixture() def user_keypad(): - return UserKeypad.create(keypad_size=KeypadSize(props_per_key=7, numb_of_keys=10)) + return UserKeypad.create(keypad_size=KeypadSize(props_per_key=8, numb_of_keys=8)) def test_dispersion(user_keypad): @@ -17,19 +17,19 @@ def test_dispersion(user_keypad): assert (adj_graph.isdisjoint(post_dispersion_graph[prop])) -#def test_shuffle_props(user_keypad): -# """there's no easy way to test this. At some point we'll have to run this code thousands of time to see if we get -# expected statistical outcomes like: -# - every property gets to every key with a uniform distribution -# - every property is adjacent to every other property with uniform distribution -# - the order in which the cipher move from key to key is random (i.e. the distance traveled is uniform) -# """ -# pre_shuffle_keypad = user_keypad.keypad -# user_keypad.partial_keypad_shuffle() -# post_shuffle_keypad = user_keypad.keypad -# assert (not all( -# post_shuffle_keypad[idx] == pre_shuffle_keypad[idx] for idx in range(len(post_shuffle_keypad)) -# )) -# assert (not all( -# post_shuffle_keypad[idx] != pre_shuffle_keypad[idx] for idx in range(len(post_shuffle_keypad)) -# )) +def test_shuffle_props(user_keypad): + """there's no easy way to test this. At some point we'll have to run this code thousands of time to see if we get + expected statistical outcomes like: + - every property gets to every key with a uniform distribution + - every property is adjacent to every other property with uniform distribution + - the order in which the cipher move from key to key is random (i.e. the distance traveled is uniform) + """ + pre_shuffle_keypad = user_keypad.keypad.copy() + user_keypad.split_shuffle() + post_shuffle_keypad = user_keypad.keypad.copy() + assert (not all( + post_shuffle_keypad[idx] == pre_shuffle_keypad[idx] for idx in range(len(post_shuffle_keypad)) + )) + assert (not all( + post_shuffle_keypad[idx] != pre_shuffle_keypad[idx] for idx in range(len(post_shuffle_keypad)) + ))