From c6bf401bc5dda8fefbf66d89cd8b3d7c55e71c23 Mon Sep 17 00:00:00 2001 From: Donovan Date: Fri, 14 Mar 2025 09:20:49 -0500 Subject: [PATCH] rename attribute to property --- docs/render_markdown.py | 4 +- notebooks/dispersion_tutorial.ipynb | 7 +- notebooks/nkode_tutorial.ipynb | 373 +++++++++++++--------------- src/customer.py | 28 +-- src/models.py | 2 +- src/nkode_api.py | 2 +- src/user.py | 8 +- src/user_keypad.py | 22 +- src/utils.py | 14 ++ test/test_nkode_api.py | 2 +- test/test_user_keypad.py | 4 +- 11 files changed, 225 insertions(+), 241 deletions(-) create mode 100644 src/utils.py diff --git a/docs/render_markdown.py b/docs/render_markdown.py index 13c9ff9..90df4b3 100644 --- a/docs/render_markdown.py +++ b/docs/render_markdown.py @@ -53,7 +53,7 @@ if __name__ == "__main__": max_nkode_len=10, min_nkode_len=4, distinct_sets=0, - distinct_attributes=4, + distinct_properties=4, byte_len=2, ) keypad_size = KeypadSize( @@ -153,7 +153,7 @@ if __name__ == "__main__": for idx in range(passcode_len): key_numb = selected_keys_login[idx] set_idx = set_vals_idx[idx] - selected_attr_idx = customer.users[username].user_keypad.get_attr_idx_by_keynumb_setidx(key_numb, set_idx) + selected_attr_idx = customer.users[username].user_keypad.get_prop_idx_by_keynumb_setidx(key_numb, set_idx) presumed_selected_attributes_idx.append(selected_attr_idx) """ diff --git a/notebooks/dispersion_tutorial.ipynb b/notebooks/dispersion_tutorial.ipynb index bfd7754..0ac3434 100644 --- a/notebooks/dispersion_tutorial.ipynb +++ b/notebooks/dispersion_tutorial.ipynb @@ -13,6 +13,7 @@ "cell_type": "code", "source": [ "from src.user_keypad import UserKeypad\n", + "from src.utils import random_property_rotation\n", "from IPython.display import Markdown, display\n", "from src.models import KeypadSize\n", "import numpy as np\n", @@ -93,10 +94,10 @@ { "cell_type": "code", "source": [ - "attr_rotation = np.random.choice(range(keypad_size.numb_of_keys), size=keypad_size.props_per_key, replace=False)\n", - "dispersed_interface = UserKeypad.random_attribute_rotation(\n", + "prop_rotation = np.random.choice(range(keypad_size.numb_of_keys), size=keypad_size.props_per_key, replace=False)\n", + "dispersed_interface = random_property_rotation(\n", " shuffled_keys,\n", - " attr_rotation\n", + " prop_rotation\n", ")\n", "\n", "display(Markdown(keypad_md_table(dispersed_interface.reshape(-1), keypad_size)))\n" diff --git a/notebooks/nkode_tutorial.ipynb b/notebooks/nkode_tutorial.ipynb index 39bb6dc..30c99a1 100644 --- a/notebooks/nkode_tutorial.ipynb +++ b/notebooks/nkode_tutorial.ipynb @@ -12,12 +12,12 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-13T15:40:54.981894Z", - "start_time": "2025-03-13T15:40:54.975972Z" + "end_time": "2025-03-14T14:18:14.423890Z", + "start_time": "2025-03-14T14:18:14.420788Z" } }, "outputs": [], - "execution_count": 157 + "execution_count": 23 }, { "cell_type": "code", @@ -40,12 +40,12 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-13T15:41:02.574902Z", - "start_time": "2025-03-13T15:41:02.566577Z" + "end_time": "2025-03-14T14:18:14.434459Z", + "start_time": "2025-03-14T14:18:14.430679Z" } }, "outputs": [], - "execution_count": 159 + "execution_count": 24 }, { "cell_type": "code", @@ -55,12 +55,12 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-13T15:41:06.702836Z", - "start_time": "2025-03-13T15:41:06.697810Z" + "end_time": "2025-03-14T14:18:14.453086Z", + "start_time": "2025-03-14T14:18:14.451030Z" } }, "outputs": [], - "execution_count": 160 + "execution_count": 25 }, { "cell_type": "markdown", @@ -70,11 +70,11 @@ "A customer defines their NKode Policy and their interface. Below we've set:\n", "- max nkode length = 10\n", "- min nkode length = 4\n", - "- distinct attributes = 4\n", + "- distinct properties = 4\n", "- distinct set = 0\n", "- byte len = 2\n", "\n", - "This customer also has an interface with 5 keys and 6 attributes per key. The number of attributes must be greater than the number of keys to be dispersion resistant." + "This customer also has an interface with 5 keys and 6 properties per key. The number of properties must be greater than the number of keys to be dispersion resistant." ], "metadata": { "collapsed": false @@ -87,7 +87,7 @@ " max_nkode_len=10,\n", " min_nkode_len=4,\n", " distinct_sets=0,\n", - " distinct_attributes=4,\n", + " distinct_properties=4,\n", " byte_len=2,\n", ")\n", "keypad_size = KeypadSize(\n", @@ -100,20 +100,20 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-13T15:41:09.768933Z", - "start_time": "2025-03-13T15:41:09.760522Z" + "end_time": "2025-03-14T14:18:14.461793Z", + "start_time": "2025-03-14T14:18:14.457601Z" } }, "outputs": [], - "execution_count": 161 + "execution_count": 26 }, { "cell_type": "markdown", "source": [ "### NKode Customer\n", - "A customer has users and defines the attributes and set values for all its users.\n", - "Since our customer has 5 keys and 6 attributes per key, this gives a customer interface of 30 distinct attributes and 6 distinct attribute sets.\n", - "Each attribute belongs to one of the 6 sets." + "A customer has users and defines the properties and set values for all its users.\n", + "Since our customer has 5 keys and 6 properties per key, this gives a customer interface of 30 distinct properties and 6 distinct properties sets.\n", + "Each properties belongs to one of the 6 sets." ], "metadata": { "collapsed": false @@ -121,9 +121,7 @@ }, { "cell_type": "markdown", - "source": [ - "#### Customer and Attribute Values" - ], + "source": "#### Customer and Properties Values", "metadata": { "collapsed": false } @@ -131,19 +129,17 @@ { "cell_type": "code", "source": [ - "set_vals = customer.cipher.set_key\n", - "attr_vals = customer.cipher.prop_key\n", - "print(f\"Customer Sets: {set_vals}\")\n", - "print(f\"Customer Attributes:\")\n", - "customer_prop_keypad = attr_vals.reshape(-1, keypad_size.props_per_key)\n", + "print(f\"Customer Set Key: {customer.cipher.set_key}\")\n", + "print(f\"Customer properties Key:\")\n", + "customer_prop_keypad = customer.cipher.prop_key.reshape(-1, keypad_size.props_per_key)\n", "for idx, key_vals in enumerate(customer_prop_keypad):\n", " print(f\"{key_vals}\")" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-13T15:41:11.949505Z", - "start_time": "2025-03-13T15:41:11.941034Z" + "end_time": "2025-03-14T14:18:14.472200Z", + "start_time": "2025-03-14T14:18:14.469516Z" } }, "outputs": [ @@ -151,23 +147,21 @@ "name": "stdout", "output_type": "stream", "text": [ - "Customer Sets: [25709 8136 44044 46233 29423 25038]\n", - "Customer Attributes:\n", - "[57582 3595 14389 48861 6004 53011]\n", - "[ 2051 49181 8905 9645 63388 60901]\n", - "[ 5952 47243 39367 26329 21337 27385]\n", - "[ 8812 29822 227 12486 4712 16109]\n", - "[28006 29445 47125 35353 35910 6662]\n" + "Customer Set Key: [57513 39162 37238 40595 30029 8573]\n", + "Customer properties Key:\n", + "[14659 8841 6728 32702 39675 63074]\n", + "[19274 15250 33729 24532 34839 38348]\n", + "[ 2539 51139 60808 11045 55452 61221]\n", + "[55550 11904 10001 59259 26026 26740]\n", + "[59910 49698 45525 62003 49414 40644]\n" ] } ], - "execution_count": 162 + "execution_count": 27 }, { "cell_type": "markdown", - "source": [ - "#### Customer Set To Attribute Map" - ], + "source": "#### Customer Set To Properties Map", "metadata": { "collapsed": false } @@ -175,16 +169,16 @@ { "cell_type": "code", "source": [ - "set_attribute_dict = dict(zip(set_vals, customer_prop_keypad.T))\n", - "print(f\"Set to Attribute Map:\")\n", - "for set_val, attrs in set_attribute_dict.items():\n", + "set_properties_dict = dict(zip(customer.cipher.set_key, customer_prop_keypad.T))\n", + "print(f\"Set to Properties Map:\")\n", + "for set_val, attrs in set_properties_dict.items():\n", " print(f\"{set_val}: {attrs}\")" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-13T15:41:14.890303Z", - "start_time": "2025-03-13T15:41:14.883511Z" + "end_time": "2025-03-14T14:18:14.486583Z", + "start_time": "2025-03-14T14:18:14.484301Z" } }, "outputs": [ @@ -192,76 +186,77 @@ "name": "stdout", "output_type": "stream", "text": [ - "Set to Attribute Map:\n", - "25709: [57582 2051 5952 8812 28006]\n", - "8136: [ 3595 49181 47243 29822 29445]\n", - "44044: [14389 8905 39367 227 47125]\n", - "46233: [48861 9645 26329 12486 35353]\n", - "29423: [ 6004 63388 21337 4712 35910]\n", - "25038: [53011 60901 27385 16109 6662]\n" + "Set to Properties Map:\n", + "57513: [14659 19274 2539 55550 59910]\n", + "39162: [ 8841 15250 51139 11904 49698]\n", + "37238: [ 6728 33729 60808 10001 45525]\n", + "40595: [32702 24532 11045 59259 62003]\n", + "30029: [39675 34839 55452 26026 49414]\n", + "8573: [63074 38348 61221 26740 40644]\n" ] } ], - "execution_count": 163 + "execution_count": 28 }, { + "metadata": {}, "cell_type": "markdown", "source": [ "### User Signup\n", "To create a new must call this endpoints in order:\n", - "1. Generate Index Interface\n", + "1. Generate Keypad\n", "2. Set User NKode\n", "3. Confirm User NKode\n", "\n", - "#### Generate Index Interface\n", - " For the server to determine the users nkode, the user's interface must be dispersable. To make the interface dispersable, the server will randomly drop attribute sets to the number of attributes is equal to the number of keys. In our case, the server drops 1 attribute set to give us a 5 X 5 keypad with possible index values ranging from 0-29.\n", + "#### Generate Keypad\n", + " For the server to determine the users nkode, the user's keypad must be dispersable. To make the keypad dispersable, the server will randomly drop properties sets to the number of properties is equal to the number of keys. In our case, the server drops 1 properties set to give us a 5 X 5 keypad with possible index values ranging from 0-29.\n", " - Run the cell below over and over to see it change. Notice that values never move out of their columns just their rows.\n", - " - each value in the interface is the index value of a customer attribute\n", - " - the user never learns what their \"real\" attribute is. All they do is specify an index in the customer interface\n" - ], - "metadata": { - "collapsed": false - } + " - each value in the keypad is the index value of a customer properties\n", + " - the user never learns what their \"real\" properties is. All they do is specify an index in the customer keypad\n" + ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-03-14T14:18:14.510067Z", + "start_time": "2025-03-14T14:18:14.507204Z" + } + }, "cell_type": "code", "source": [ "session_id, signup_keypad = api.generate_signup_keypad(customer_id)\n", "print(signup_keypad.reshape(-1, keypad_size.numb_of_keys))" ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2025-03-13T15:41:19.446496Z", - "start_time": "2025-03-13T15:41:19.440194Z" - } - }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[[21 3 27 15 9]\n", - " [19 1 25 13 7]\n", - " [23 5 29 17 11]\n", - " [22 4 28 16 10]\n", - " [20 2 26 14 8]]\n" + "[[ 1 7 13 19 25]\n", + " [ 0 6 12 18 24]\n", + " [ 5 11 17 23 29]\n", + " [ 2 8 14 20 26]\n", + " [ 4 10 16 22 28]]\n" ] } ], - "execution_count": 164 + "execution_count": 29 }, { + "metadata": {}, "cell_type": "markdown", "source": [ - "#### Set NKode\n", - "The user identifies attributes in the interface they want in their nkode. Each attribute in the gui has an index value. Below the user has selected 16, 9, 6, 19. Graphically represent with anything. The only requirement is that the graphical attributes must be associated with the same index value everytime the user goes to login. If the user wants to change anything about their interface(the number of keys, attributes or graphical attributes), they must also change their nkode." - ], - "metadata": { - "collapsed": false - } + "#### Set nKode\n", + "The user identifies properties in the keypad they want in their nkode. Each properties in the gui has an index value. Below the user has selected 16, 9, 6, 19. Graphically represent with anything. The only requirement is that the graphical properties must be associated with the same index value everytime the user goes to login. If the user wants to change anything about their keypad(the number of keys, properties or graphical properties), they must also change their nkode." + ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-03-14T14:18:14.535581Z", + "start_time": "2025-03-14T14:18:14.531909Z" + } + }, "cell_type": "code", "source": [ "keypad_view(signup_keypad, keypad_size.numb_of_keys)\n", @@ -272,82 +267,73 @@ "print(f\"User Passcode: {user_passcode}\")\n", "print(f\"Selected Keys\\n{selected_keys_set}\")\n", "server_side_attr = [int(customer.cipher.prop_key[idx]) for idx in user_passcode]\n", - "print(f\"User Passcode Server-side Attributes: {server_side_attr}\")" + "print(f\"User Passcode Server-side properties: {server_side_attr}\")" ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2025-03-13T15:41:22.138365Z", - "start_time": "2025-03-13T15:41:22.130412Z" - } - }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Keypad View\n", - "Key 0: [21 3 27 15 9]\n", - "Key 1: [19 1 25 13 7]\n", - "Key 2: [23 5 29 17 11]\n", - "Key 3: [22 4 28 16 10]\n", - "Key 4: [20 2 26 14 8]\n", - "User Passcode: [21 3 27 15]\n", + "Key 0: [ 1 7 13 19 25]\n", + "Key 1: [ 0 6 12 18 24]\n", + "Key 2: [ 5 11 17 23 29]\n", + "Key 3: [ 2 8 14 20 26]\n", + "Key 4: [ 4 10 16 22 28]\n", + "User Passcode: [ 1 7 13 19]\n", "Selected Keys\n", "[0, 0, 0, 0]\n", - "User Passcode Server-side Attributes: [12486, 48861, 35353, 26329]\n" + "User Passcode Server-side properties: [8841, 15250, 51139, 11904]\n" ] } ], - "execution_count": 165 + "execution_count": 30 }, { - "cell_type": "code", - "source": [ - "confirm_interface = api.set_nkode(username, customer_id, selected_keys_set, session_id)\n", - "keypad_view(confirm_interface, keypad_size.numb_of_keys)\n", - "selected_keys_confirm = select_keys_with_passcode_values(user_passcode, confirm_interface, keypad_size.numb_of_keys)\n", - "print(f\"Selected Keys\\n{selected_keys_confirm}\")" - ], "metadata": { - "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-13T15:41:25.094831Z", - "start_time": "2025-03-13T15:41:25.087580Z" + "end_time": "2025-03-14T14:18:14.556541Z", + "start_time": "2025-03-14T14:18:14.553217Z" } }, + "cell_type": "code", + "source": [ + "confirm_keypad = api.set_nkode(username, customer_id, selected_keys_set, session_id)\n", + "keypad_view(confirm_keypad, keypad_size.numb_of_keys)\n", + "selected_keys_confirm = select_keys_with_passcode_values(user_passcode, confirm_keypad, keypad_size.numb_of_keys)\n", + "print(f\"Selected Keys\\n{selected_keys_confirm}\")" + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Keypad View\n", - "Key 0: [22 2 29 15 7]\n", - "Key 1: [23 4 27 13 8]\n", - "Key 2: [21 5 25 14 10]\n", - "Key 3: [19 3 26 16 11]\n", - "Key 4: [20 1 28 17 9]\n", + "Key 0: [ 0 11 16 20 25]\n", + "Key 1: [ 2 6 13 22 29]\n", + "Key 2: [ 4 8 17 19 24]\n", + "Key 3: [ 1 10 12 23 26]\n", + "Key 4: [ 5 7 14 18 28]\n", "Selected Keys\n", - "[2, 3, 1, 0]\n" + "[3, 4, 1, 2]\n" ] } ], - "execution_count": 166 + "execution_count": 31 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-03-14T14:18:14.884832Z", + "start_time": "2025-03-14T14:18:14.575902Z" + } + }, "cell_type": "code", "source": [ "# the session is deleted after the nkode is confirmed. To rerun this cell, rerun the cells above starting with cell 8 where the username is created\n", "success = api.confirm_nkode(username, customer_id, selected_keys_confirm, session_id)\n", "print(success)" ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2025-03-13T15:43:12.401745Z", - "start_time": "2025-03-13T15:42:59.685701Z" - } - }, "outputs": [ { "name": "stdout", @@ -357,7 +343,7 @@ ] } ], - "execution_count": 168 + "execution_count": 32 }, { "metadata": {}, @@ -376,8 +362,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:43:26.496044Z", - "start_time": "2025-03-13T15:43:26.484618Z" + "end_time": "2025-03-14T14:18:14.894865Z", + "start_time": "2025-03-14T14:18:14.889948Z" } }, "cell_type": "code", @@ -413,12 +399,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Passcode Set Vals: [46233, 46233, 46233, 46233]\n", - "Passcode Attr Vals: [12486, 48861, 35353, 26329]\n" + "Passcode Set Vals: [39162, 39162, 39162, 39162]\n", + "Passcode Attr Vals: [8841, 15250, 51139, 11904]\n" ] } ], - "execution_count": 169 + "execution_count": 33 }, { "metadata": {}, @@ -440,8 +426,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:43:30.557640Z", - "start_time": "2025-03-13T15:43:30.550158Z" + "end_time": "2025-03-14T14:18:14.917821Z", + "start_time": "2025-03-14T14:18:14.914851Z" } }, "cell_type": "code", @@ -455,7 +441,7 @@ "mask = user_keys.encode_base64_str(ciphered_mask)" ], "outputs": [], - "execution_count": 170 + "execution_count": 34 }, { "metadata": {}, @@ -472,8 +458,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:43:33.209403Z", - "start_time": "2025-03-13T15:43:32.898812Z" + "end_time": "2025-03-14T14:18:15.243102Z", + "start_time": "2025-03-14T14:18:14.937865Z" } }, "cell_type": "code", @@ -497,13 +483,13 @@ "code = hashed_data.decode(\"utf-8\")" ], "outputs": [], - "execution_count": 171 + "execution_count": 35 }, { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:43:35.234325Z", - "start_time": "2025-03-13T15:43:35.229292Z" + "end_time": "2025-03-14T14:18:15.249186Z", + "start_time": "2025-03-14T14:18:15.247147Z" } }, "cell_type": "code", @@ -516,20 +502,24 @@ ")" ], "outputs": [], - "execution_count": 172 + "execution_count": 36 }, { + "metadata": {}, "cell_type": "markdown", "source": [ "### User Login\n", - "1. Get login interface\n", + "1. Get login keypad\n", "2. Login\n" - ], - "metadata": { - "collapsed": false - } + ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-03-14T14:18:15.563030Z", + "start_time": "2025-03-14T14:18:15.257823Z" + } + }, "cell_type": "code", "source": [ "login_keypad = api.get_login_keypad(username, customer_id)\n", @@ -539,30 +529,23 @@ "success = api.login(customer_id, username, selected_keys_login)\n", "print(success)" ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2025-03-13T15:43:55.881744Z", - "start_time": "2025-03-13T15:43:37.544889Z" - } - }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Keypad View\n", - "Key 0: [18 19 20 21 22 23]\n", - "Key 1: [0 1 2 3 4 5]\n", - "Key 2: [24 25 26 27 28 29]\n", - "Key 3: [12 13 14 15 16 17]\n", - "Key 4: [ 6 7 8 9 10 11]\n", + "Key 0: [0 1 2 3 4 5]\n", + "Key 1: [ 6 7 8 9 10 11]\n", + "Key 2: [12 13 14 15 16 17]\n", + "Key 3: [18 19 20 21 22 23]\n", + "Key 4: [24 25 26 27 28 29]\n", "Selected Keys: [0, 1, 2, 3]\n", "True\n" ] } ], - "execution_count": 173 + "execution_count": 37 }, { "metadata": {}, @@ -570,8 +553,8 @@ "source": [ "## Validate Login Key Entry\n", "- decipher user mask and recover nkode set values\n", - "- get presumed attribute from key selection and set values\n", - "- encipher, salt and hash presumed attribute values and compare it to the users hashed code" + "- get presumed properties from key selection and set values\n", + "- encipher, salt and hash presumed properties values and compare it to the users hashed code" ] }, { @@ -594,8 +577,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:44:12.223540Z", - "start_time": "2025-03-13T15:44:12.215204Z" + "end_time": "2025-03-14T14:18:15.574718Z", + "start_time": "2025-03-14T14:18:15.571571Z" } }, "cell_type": "code", @@ -615,36 +598,36 @@ "name": "stdout", "output_type": "stream", "text": [ - "[46233, 46233, 46233, 46233]\n" + "[39162, 39162, 39162, 39162]\n" ] } ], - "execution_count": 174 + "execution_count": 38 }, { "metadata": {}, "cell_type": "markdown", - "source": "### Get Presumed Attributes\n" + "source": "### Get Presumed Properties\n" }, { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:44:41.027416Z", - "start_time": "2025-03-13T15:44:15.077074Z" + "end_time": "2025-03-14T14:18:15.591180Z", + "start_time": "2025-03-14T14:18:15.587992Z" } }, "cell_type": "code", "source": [ "set_vals_idx = [customer.cipher.get_set_index(set_val) for set_val in passcode_sets]\n", "\n", - "presumed_selected_attributes_idx = []\n", + "presumed_selected_properties_idx = []\n", "for idx in range(passcode_len):\n", " key_numb = selected_keys_login[idx]\n", " set_idx = set_vals_idx[idx]\n", - " selected_attr_idx = customer.users[username].user_keypad.get_attr_idx_by_keynumb_setidx(key_numb, set_idx)\n", - " presumed_selected_attributes_idx.append(selected_attr_idx)\n", + " selected_attr_idx = customer.users[username].user_keypad.get_prop_idx_by_keynumb_setidx(key_numb, set_idx)\n", + " presumed_selected_properties_idx.append(selected_attr_idx)\n", "\n", - "print(user_passcode.tolist() == presumed_selected_attributes_idx)" + "print(user_passcode.tolist() == presumed_selected_properties_idx)" ], "outputs": [ { @@ -655,7 +638,7 @@ ] } ], - "execution_count": 175 + "execution_count": 39 }, { "metadata": {}, @@ -665,13 +648,13 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:48:46.158380Z", - "start_time": "2025-03-13T15:48:45.854570Z" + "end_time": "2025-03-14T14:18:15.916787Z", + "start_time": "2025-03-14T14:18:15.610843Z" } }, "cell_type": "code", "source": [ - "enciphered_nkode = user.cipher.encipher_salt_hash_code(presumed_selected_attributes_idx, customer.cipher)\n", + "enciphered_nkode = user.cipher.encipher_salt_hash_code(presumed_selected_properties_idx, customer.cipher)\n", "print(enciphered_nkode == user.enciphered_passcode.code)\n" ], "outputs": [ @@ -683,26 +666,24 @@ ] } ], - "execution_count": 178 + "execution_count": 40 }, { + "metadata": {}, "cell_type": "markdown", "source": [ - "## Renew Attributes \n", - "1. Renew Customer Attributes \n", + "## Renew Properties\n", + "1. Renew Customer Properties\n", "2. Renew User Keys\n", "3. Refresh User on Login\n", "\n" - ], - "metadata": { - "collapsed": false - } + ] }, { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:50:03.065695Z", - "start_time": "2025-03-13T15:50:02.452807Z" + "end_time": "2025-03-14T14:18:16.539065Z", + "start_time": "2025-03-14T14:18:15.926843Z" } }, "cell_type": "code", @@ -713,7 +694,7 @@ " print(f\"mask: {mask}, code: {code}\")\n", "\n", "print_user_enciphered_code() \n", - "api.renew_attributes(customer_id)\n", + "api.renew_keys(customer_id)\n", "print_user_enciphered_code()\n", "\n", "login_keypad = api.get_login_keypad(username, customer_id)\n", @@ -727,29 +708,29 @@ "name": "stdout", "output_type": "stream", "text": [ - "mask: Veawti5Qkgy2y/XtFTZZ7w5oYgA=, code: $2b$12$OHHiqL888FauxiXIVICtouT1xR8iwe79oz63mXkPWKldHoLHPsByy\n", - "mask: Veawti5Qkgy2y/XtFTZZ7w5oYgA=, code: $2b$12$OHHiqL888FauxiXIVICtouT1xR8iwe79oz63mXkPWKldHoLHPsByy\n", + "mask: 4NCIa/fFtx0udGaF1ub+O/6oU04=, code: $2b$12$XuGO.allDcb91peVIjwsq./Ba/TZI3wxAc0acgWkApzkzGWfwPQCC\n", + "mask: 4NCIa/fFtx0udGaF1ub+O/6oU04=, code: $2b$12$XuGO.allDcb91peVIjwsq./Ba/TZI3wxAc0acgWkApzkzGWfwPQCC\n", "True\n", - "mask: Sxe3AjutJzGrQLgq/RnfK9G3wHc=, code: $2b$12$.wb5cZjbXJBY6/MQxJIlGu/JyqaF78IM.1n3QP6coxOcKLORU/Io6\n" + "mask: ceaWZR+hNRpEkj3fq1cfPu1Zyok=, code: $2b$12$q7lqdTj6qBMDDGEog9Pq3.M2Wso0TI8cx4/PhOK/fE1mhsws2FGe.\n" ] } ], - "execution_count": 179 + "execution_count": 41 }, { "metadata": {}, "cell_type": "markdown", "source": [ "#### Renew Customer Keys\n", - "- Get old attributes and sets\n", - "- Replace attributes and sets" + "- Get old properties and sets\n", + "- Replace properties and sets" ] }, { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:52:30.906955Z", - "start_time": "2025-03-13T15:52:30.902577Z" + "end_time": "2025-03-14T14:18:16.551437Z", + "start_time": "2025-03-14T14:18:16.547371Z" } }, "cell_type": "code", @@ -761,7 +742,7 @@ "new_sets = customer.cipher.set_key" ], "outputs": [], - "execution_count": 181 + "execution_count": 42 }, { "metadata": {}, @@ -774,8 +755,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:52:39.513715Z", - "start_time": "2025-03-13T15:52:39.510395Z" + "end_time": "2025-03-14T14:18:16.568881Z", + "start_time": "2025-03-14T14:18:16.566223Z" } }, "cell_type": "code", @@ -788,7 +769,7 @@ " user.cipher.prop_key = np.bitwise_xor(user.cipher.prop_key, props_xor)" ], "outputs": [], - "execution_count": 182 + "execution_count": 43 }, { "metadata": {}, @@ -798,8 +779,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-13T15:53:22.653638Z", - "start_time": "2025-03-13T15:53:22.345351Z" + "end_time": "2025-03-14T14:18:16.884432Z", + "start_time": "2025-03-14T14:18:16.572989Z" } }, "cell_type": "code", @@ -809,11 +790,11 @@ " customer.cipher.set_key,\n", " user.cipher.max_nkode_len\n", ")\n", - "user.enciphered_passcode = user.cipher.encipher_nkode(presumed_selected_attributes_idx, customer.cipher)\n", + "user.enciphered_passcode = user.cipher.encipher_nkode(presumed_selected_properties_idx, customer.cipher)\n", "user.renew = False" ], "outputs": [], - "execution_count": 186 + "execution_count": 44 } ], "metadata": { diff --git a/src/customer.py b/src/customer.py index 4fb3662..5f7c925 100644 --- a/src/customer.py +++ b/src/customer.py @@ -34,46 +34,46 @@ class Customer: 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_selected_attributes_idx = [] + presumed_property_idxs = [] for idx in range(passcode_len): key_numb = selected_keys[idx] set_idx = set_vals_idx[idx] - selected_attr_idx = user.user_keypad.get_attr_idx_by_keynumb_setidx(key_numb, set_idx) - presumed_selected_attributes_idx.append(selected_attr_idx) + selected_attr_idx = user.user_keypad.get_prop_idx_by_keynumb_setidx(key_numb, set_idx) + presumed_property_idxs.append(selected_attr_idx) - enciphered_attr = user.cipher.encipher_salt_hash_code(presumed_selected_attributes_idx, self.cipher) + enciphered_attr = user.cipher.encipher_salt_hash_code(presumed_property_idxs, self.cipher) if enciphered_attr != user.enciphered_passcode.code: return False if user.renew: - user.refresh_passcode(presumed_selected_attributes_idx, self.cipher) + user.refresh_passcode(presumed_property_idxs, self.cipher) return True def renew_keys(self) -> bool: - old_attrs = self.cipher.prop_key.copy() + old_props = self.cipher.prop_key.copy() old_sets = self.cipher.set_key.copy() self.cipher.renew() - new_attrs = self.cipher.prop_key + new_props = self.cipher.prop_key new_sets = self.cipher.set_key - attrs_xor = np.bitwise_xor(new_attrs, old_attrs) + props_xor = np.bitwise_xor(new_props, old_props) set_xor = np.bitwise_xor(new_sets, old_sets) for user in self.users.values(): - user.renew_keys(set_xor, attrs_xor) + user.renew_keys(set_xor, props_xor) self.users[user.username] = user return True - def valid_new_nkode(self, passcode_attr_idx: list[int]) -> bool: - nkode_len = len(passcode_attr_idx) + def valid_new_nkode(self, passcode_prop_idx: list[int]) -> bool: + nkode_len = len(passcode_prop_idx) passcode_set_values = [ - self.cipher.get_prop_set_val(int(self.cipher.prop_key[attr_idx])) for attr_idx in passcode_attr_idx + self.cipher.get_prop_set_val(int(self.cipher.prop_key[prop_idx])) for prop_idx in passcode_prop_idx ] distinct_sets = len(set(passcode_set_values)) - distinct_attributes = len(set(passcode_attr_idx)) + distinct_properties = len(set(passcode_prop_idx)) if ( self.nkode_policy.min_nkode_len <= nkode_len <= self.nkode_policy.max_nkode_len and distinct_sets >= self.nkode_policy.distinct_sets and - distinct_attributes >= self.nkode_policy.distinct_attributes + distinct_properties >= self.nkode_policy.distinct_properties ): return True return False diff --git a/src/models.py b/src/models.py index 39957ae..101aafa 100644 --- a/src/models.py +++ b/src/models.py @@ -11,7 +11,7 @@ class NKodePolicy: max_nkode_len: int = 10 min_nkode_len: int = 4 distinct_sets: int = 0 - distinct_attributes: int = 4 + distinct_properties: int = 4 byte_len: int = 2 # Todo: this should change the total number of bytes an attribute or set value can be lock_out: int = 5 expiration: int = -1 # in seconds -1 means nkode never expires diff --git a/src/nkode_api.py b/src/nkode_api.py index baa7736..15fd941 100644 --- a/src/nkode_api.py +++ b/src/nkode_api.py @@ -107,7 +107,7 @@ class NKodeAPI: customer = self.customers[customer_id] return customer.valid_key_entry(username, key_selection) - def renew_attributes(self, customer_id: UUID) -> bool: + def renew_keys(self, customer_id: UUID) -> bool: if customer_id not in self.customers.keys(): raise ValueError("Customer ID not found") return self.customers[customer_id].renew_keys() diff --git a/src/user.py b/src/user.py index 6fa1bd8..2cc565f 100644 --- a/src/user.py +++ b/src/user.py @@ -21,11 +21,11 @@ class User: self.cipher.set_key = np.bitwise_xor(self.cipher.set_key, set_xor) self.cipher.prop_key = np.bitwise_xor(self.cipher.prop_key, prop_xor) - def refresh_passcode(self, passcode_attr_idx: list[int], customer_attributes: CustomerCipher): + def refresh_passcode(self, passcode_prop_idxs: list[int], customer_cipher: CustomerCipher): self.cipher = UserCipher.create( - customer_attributes.keypad_size, - customer_attributes.set_key, + customer_cipher.keypad_size, + customer_cipher.set_key, self.cipher.max_nkode_len ) - self.enciphered_passcode = self.cipher.encipher_nkode(passcode_attr_idx, customer_attributes) + self.enciphered_passcode = self.cipher.encipher_nkode(passcode_prop_idxs, customer_cipher) self.renew = False diff --git a/src/user_keypad.py b/src/user_keypad.py index f668bc2..f59bb72 100644 --- a/src/user_keypad.py +++ b/src/user_keypad.py @@ -1,5 +1,6 @@ from dataclasses import dataclass import numpy as np +from src.utils import random_property_rotation from src.models import KeypadSize @dataclass @@ -54,9 +55,9 @@ class UserKeypad: user_keypad_matrix = self.keypad_matrix() #shuffled_keys = secure_fisher_yates_shuffle(user_keypad_matrix) shuffled_keys = rng.permutation(user_keypad_matrix, axis=0) - #attr_rotation = secure_fisher_yates_shuffle(list(range(self.keypad_size.numb_of_keys)))[:self.keypad_size.props_per_key] + #prop_rotation = secure_fisher_yates_shuffle(list(range(self.keypad_size.numb_of_keys)))[:self.keypad_size.props_per_key] attr_rotation = rng.permutation(list(range(self.keypad_size.numb_of_keys)))[:self.keypad_size.props_per_key] - dispersed_keypad = self.random_attribute_rotation( + dispersed_keypad = random_property_rotation( shuffled_keys, attr_rotation.tolist(), ) @@ -79,21 +80,8 @@ class UserKeypad: #self.keypad = matrix_to_list(matrix_transpose(keypad_by_sets)) pass - @staticmethod - def random_attribute_rotation( - user_keypad: np.ndarray, - attr_rotation: list[int] - ) -> np.ndarray: - transposed = user_keypad.T - if len(attr_rotation) != len(transposed): - raise ValueError("attr_rotation must be the same length as the number of attributes") - for idx, attr_set in enumerate(transposed): - rotation = attr_rotation[idx] - rotation = rotation % len(attr_set) if len(attr_set) > 0 else 0 - transposed[idx] = np.roll(attr_set, rotation) - return transposed.T - def attribute_adjacency_graph(self) -> dict[int, set[int]]: + def property_adjacency_graph(self) -> dict[int, set[int]]: user_keypad_keypad = self.keypad_matrix() graph = {} for key in user_keypad_keypad: @@ -102,7 +90,7 @@ class UserKeypad: graph[attr].remove(attr) return graph - def get_attr_idx_by_keynumb_setidx(self, key_numb: int, set_idx: int) -> int: + def get_prop_idx_by_keynumb_setidx(self, key_numb: int, set_idx: int) -> int: if not (0 <= key_numb < self.keypad_size.numb_of_keys): raise ValueError(f"key_numb must be between 0 and {self.keypad_size.numb_of_keys - 1}") if not (0 <= set_idx < self.keypad_size.props_per_key): diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..f9e7125 --- /dev/null +++ b/src/utils.py @@ -0,0 +1,14 @@ +import numpy as np + +def random_property_rotation( + user_keypad: np.ndarray, + attr_rotation: list[int] +) -> np.ndarray: + transposed = user_keypad.T + if len(attr_rotation) != len(transposed): + raise ValueError("prop_rotation must be the same length as the number of attributes") + for idx, attr_set in enumerate(transposed): + rotation = attr_rotation[idx] + rotation = rotation % len(attr_set) if len(attr_set) > 0 else 0 + transposed[idx] = np.roll(attr_set, rotation) + return transposed.T diff --git a/test/test_nkode_api.py b/test/test_nkode_api.py index ad5d6b0..341bd88 100644 --- a/test/test_nkode_api.py +++ b/test/test_nkode_api.py @@ -39,7 +39,7 @@ def test_create_new_user_and_renew_keys(nkode_api, keypad_size, passocode_len): successful_login = nkode_api.login(customer_id, username, login_key_selection) assert successful_login - successful_renew = nkode_api.renew_attributes(customer_id) + successful_renew = nkode_api.renew_keys(customer_id) assert successful_renew login_keypad = nkode_api.get_login_keypad(username, customer_id) diff --git a/test/test_user_keypad.py b/test/test_user_keypad.py index f449a96..811c1f4 100644 --- a/test/test_user_keypad.py +++ b/test/test_user_keypad.py @@ -10,9 +10,9 @@ def user_keypad(): def test_dispersion(user_keypad): for _ in range(10000): - pre_dispersion_graph = user_keypad.attribute_adjacency_graph() + pre_dispersion_graph = user_keypad.property_adjacency_graph() user_keypad.disperse_keypad() - post_dispersion_graph = user_keypad.attribute_adjacency_graph() + post_dispersion_graph = user_keypad.property_adjacency_graph() for attr, adj_graph in pre_dispersion_graph.items(): assert (adj_graph.isdisjoint(post_dispersion_graph[attr]))