implement keypad size

This commit is contained in:
2024-07-19 10:39:05 -05:00
parent b37c17eca6
commit 65d78867ca
13 changed files with 198 additions and 191 deletions

View File

@@ -2,7 +2,9 @@ from uuid import UUID, uuid4
from pydantic import BaseModel from pydantic import BaseModel
from src.customer import Customer from src.customer import Customer
from src.models import NKodePolicy from src.models import NKodePolicy, KeypadSize
from src.user import User
from src.user_cipher_keys import UserCipherKeys
from src.user_signup_session import UserSignupSession from src.user_signup_session import UserSignupSession
from src.user_interface import UserInterface from src.user_interface import UserInterface
from src.customer_interface import CustomerInterface from src.customer_interface import CustomerInterface
@@ -12,10 +14,10 @@ class NKodeAPI(BaseModel):
customers: dict[UUID, Customer] = {} customers: dict[UUID, Customer] = {}
signup_sessions: dict[UUID, UserSignupSession] = {} signup_sessions: dict[UUID, UserSignupSession] = {}
def create_new_customer(self, numb_keys: int, numb_sets: int, nkode_policy: NKodePolicy) -> UUID: def create_new_customer(self, keypad_size: KeypadSize, nkode_policy: NKodePolicy) -> UUID:
new_customer = Customer( new_customer = Customer(
customer_id=uuid4(), customer_id=uuid4(),
interface=CustomerInterface.new(numb_keys, numb_sets), interface=CustomerInterface.new(keypad_size),
users={}, users={},
nkode_policy=nkode_policy nkode_policy=nkode_policy
) )
@@ -26,16 +28,16 @@ class NKodeAPI(BaseModel):
def generate_index_interface(self, customer_id: UUID) -> tuple[UUID, list[int]]: def generate_index_interface(self, customer_id: UUID) -> tuple[UUID, list[int]]:
assert (customer_id in self.customers.keys()) assert (customer_id in self.customers.keys())
customer = self.customers[customer_id] customer = self.customers[customer_id]
set_interface = UserInterface.new(customer.interface.attrs_per_key, customer.interface.numb_of_keys) set_interface = UserInterface.new(customer.interface.keypad_size)
new_session = UserSignupSession( new_session = UserSignupSession(
session_id=uuid4(), session_id=uuid4(),
set_interface=set_interface.attr_indices, set_interface=set_interface.attr_indices,
customer_id=customer_id, customer_id=customer_id,
keypad_size=customer.interface.keypad_size,
) )
self.signup_sessions[new_session.session_id] = new_session self.signup_sessions[new_session.session_id] = new_session
return new_session.session_id, new_session.set_interface return new_session.session_id, new_session.set_interface
def set_nkode( def set_nkode(
self, username: str, self, username: str,
customer_id: UUID, customer_id: UUID,
@@ -46,7 +48,7 @@ class NKodeAPI(BaseModel):
customer = self.customers[customer_id] customer = self.customers[customer_id]
assert (username not in customer.users.keys()) assert (username not in customer.users.keys())
assert (session_id in self.signup_sessions.keys()) assert (session_id in self.signup_sessions.keys())
self.signup_sessions[session_id].set_user_nkode(username, customer, key_selection) self.signup_sessions[session_id].set_user_nkode(username, key_selection)
return self.signup_sessions[session_id].confirm_interface return self.signup_sessions[session_id].confirm_interface
def confirm_nkode(self, username: str, customer_id: UUID, confirm_key_entry: list[int], session_id: UUID) -> bool: def confirm_nkode(self, username: str, customer_id: UUID, confirm_key_entry: list[int], session_id: UUID) -> bool:
@@ -56,7 +58,24 @@ class NKodeAPI(BaseModel):
username == self.signup_sessions[session_id].username username == self.signup_sessions[session_id].username
) )
customer = self.customers[customer_id] customer = self.customers[customer_id]
new_user = self.signup_sessions[session_id].create_user(username, customer, confirm_key_entry)
passcode = self.signup_sessions[session_id].deduce_passcode(confirm_key_entry)
new_user_keys = UserCipherKeys.new(
customer.interface.keypad_size,
customer.interface.set_vals,
customer.nkode_policy.max_nkode_len
)
enciphered_passcode = new_user_keys.encipher_nkode(passcode, customer.interface)
new_user = User(
username=username,
enciphered_passcode=enciphered_passcode,
user_keys=new_user_keys,
user_interface=UserInterface(
attr_indices=self.signup_sessions[session_id].confirm_interface,
keypad_size=customer.interface.keypad_size
),
)
self.customers[customer_id].add_new_user(new_user) self.customers[customer_id].add_new_user(new_user)
del self.signup_sessions[session_id] del self.signup_sessions[session_id]
return True return True
@@ -80,4 +99,3 @@ class NKodeAPI(BaseModel):
def renew_keys(self, customer_id: UUID) -> bool: def renew_keys(self, customer_id: UUID) -> bool:
assert (customer_id in self.customers.keys()) assert (customer_id in self.customers.keys())
return self.customers[customer_id].renew_keys() return self.customers[customer_id].renew_keys()

View File

@@ -6,10 +6,7 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"from nkode_api import NKodeAPI\n", "from nkode_api import NKodeAPI\n",
"from src.models import NKodePolicy\n", "from src.models import NKodePolicy, KeypadSize\n",
"from src.customer import Customer\n",
"from src.user import User\n",
"from src.user_interface import UserInterface\n",
"from src.utils import list_to_matrix, matrix_transpose\n", "from src.utils import list_to_matrix, matrix_transpose\n",
"from secrets import choice\n", "from secrets import choice\n",
"from string import ascii_lowercase" "from string import ascii_lowercase"
@@ -17,8 +14,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.673846Z", "end_time": "2024-07-19T15:38:32.636706Z",
"start_time": "2024-07-18T13:08:45.604900Z" "start_time": "2024-07-19T15:38:32.541836Z"
} }
} }
}, },
@@ -43,8 +40,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.677402Z", "end_time": "2024-07-19T15:38:32.636920Z",
"start_time": "2024-07-18T13:08:45.675407Z" "start_time": "2024-07-19T15:38:32.606667Z"
} }
} }
}, },
@@ -58,8 +55,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.679610Z", "end_time": "2024-07-19T15:38:32.636991Z",
"start_time": "2024-07-18T13:08:45.677796Z" "start_time": "2024-07-19T15:38:32.608558Z"
} }
} }
}, },
@@ -91,16 +88,18 @@
" distinct_sets=0,\n", " distinct_sets=0,\n",
" distinct_attributes=4\n", " distinct_attributes=4\n",
")\n", ")\n",
"numb_of_keys = 10\n", "keypad_size = KeypadSize(\n",
" numb_of_keys = 10,\n",
" attrs_per_key = 7 # aka number of sets\n", " attrs_per_key = 7 # aka number of sets\n",
"customer_id = api.create_new_customer(numb_of_keys, attrs_per_key, policy)\n", ")\n",
"customer_id = api.create_new_customer(keypad_size, policy)\n",
"customer = api.customers[customer_id]" "customer = api.customers[customer_id]"
], ],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.808776Z", "end_time": "2024-07-19T15:38:32.817740Z",
"start_time": "2024-07-18T13:08:45.681012Z" "start_time": "2024-07-19T15:38:32.612174Z"
} }
} }
}, },
@@ -133,8 +132,8 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Customer Sets: [60082, 3086, 26494, 12194, 4421, 41427, 16984]\n", "Customer Sets: [63949, 41634, 17125, 52762, 13459, 5935, 727]\n",
"Customer Attributes: [48380, 48810, 58704, 61681, 27187, 45406, 40741, 28469, 63290, 23552, 9625, 12681, 33702, 3372, 24715, 12612, 13180, 49133, 20493, 58247, 36394, 17390, 56641, 5490, 8213, 63651, 8692, 1703, 15711, 6304, 61079, 31429, 6078, 25130, 3897, 40313, 9253, 64106, 39159, 34587, 23277, 34925, 2070, 21493, 34778, 24158, 59424, 36, 9350, 60729, 46451, 15041, 16164, 41230, 23733, 12735, 33488, 31609, 35924, 43823, 50711, 32364, 41357, 13184, 2619, 33798, 56624, 61788, 24651, 12767]\n" "Customer Attributes: [52222, 57050, 17039, 29896, 31069, 35859, 36843, 2137, 24380, 34643, 29053, 46327, 39534, 64877, 53617, 14001, 39532, 19103, 38549, 42982, 63429, 11337, 42520, 23186, 49849, 6237, 49291, 44219, 34592, 26781, 25410, 34134, 51292, 40084, 49002, 1221, 30724, 62975, 33074, 22158, 18970, 54242, 15906, 19581, 10796, 6147, 36402, 44152, 43216, 16186, 571, 32657, 20955, 10260, 51931, 46321, 40259, 1905, 14430, 48389, 35797, 48564, 32173, 50142, 65402, 11082, 39195, 46929, 18113, 52721]\n"
] ]
} }
], ],
@@ -147,8 +146,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.812291Z", "end_time": "2024-07-19T15:38:32.818026Z",
"start_time": "2024-07-18T13:08:45.809694Z" "start_time": "2024-07-19T15:38:32.781094Z"
} }
} }
}, },
@@ -170,18 +169,18 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Set to Attribute Map:\n", "Set to Attribute Map:\n",
"60082: [48380, 28469, 24715, 17390, 15711, 40313, 2070, 60729, 33488, 13184]\n", "63949: [52222, 2137, 53617, 11337, 34592, 1221, 15906, 16186, 40259, 50142]\n",
"3086: [48810, 63290, 12612, 56641, 6304, 9253, 21493, 46451, 31609, 2619]\n", "41634: [57050, 24380, 14001, 42520, 26781, 30724, 19581, 571, 1905, 65402]\n",
"26494: [58704, 23552, 13180, 5490, 61079, 64106, 34778, 15041, 35924, 33798]\n", "17125: [17039, 34643, 39532, 23186, 25410, 62975, 10796, 32657, 14430, 11082]\n",
"12194: [61681, 9625, 49133, 8213, 31429, 39159, 24158, 16164, 43823, 56624]\n", "52762: [29896, 29053, 19103, 49849, 34134, 33074, 6147, 20955, 48389, 39195]\n",
"4421: [27187, 12681, 20493, 63651, 6078, 34587, 59424, 41230, 50711, 61788]\n", "13459: [31069, 46327, 38549, 6237, 51292, 22158, 36402, 10260, 35797, 46929]\n",
"41427: [45406, 33702, 58247, 8692, 25130, 23277, 36, 23733, 32364, 24651]\n", "5935: [35859, 39534, 42982, 49291, 40084, 18970, 44152, 51931, 48564, 18113]\n",
"16984: [40741, 3372, 36394, 1703, 3897, 34925, 9350, 12735, 41357, 12767]\n" "727: [36843, 64877, 63429, 44219, 49002, 54242, 43216, 46321, 32173, 52721]\n"
] ]
} }
], ],
"source": [ "source": [
"attr_keypad_view = list_to_matrix(attr_vals, customer.interface.attrs_per_key)\n", "attr_keypad_view = list_to_matrix(attr_vals, keypad_size.attrs_per_key)\n",
"attr_set_view = matrix_transpose(attr_keypad_view)\n", "attr_set_view = matrix_transpose(attr_keypad_view)\n",
"set_attribute_dict = dict(zip(set_vals, attr_set_view))\n", "set_attribute_dict = dict(zip(set_vals, attr_set_view))\n",
"print(f\"Set to Attribute Map:\")\n", "print(f\"Set to Attribute Map:\")\n",
@@ -191,8 +190,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.815009Z", "end_time": "2024-07-19T15:38:32.818150Z",
"start_time": "2024-07-18T13:08:45.812687Z" "start_time": "2024-07-19T15:38:32.784103Z"
} }
} }
}, },
@@ -224,8 +223,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.818253Z", "end_time": "2024-07-19T15:38:32.818223Z",
"start_time": "2024-07-18T13:08:45.815525Z" "start_time": "2024-07-19T15:38:32.787316Z"
} }
} }
}, },
@@ -248,33 +247,33 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Keypad View\n", "Keypad View\n",
"Key 0: [21, 64, 2, 59, 46, 68, 48]\n", "Key 0: [14, 50, 16, 59, 39, 26, 6]\n",
"Key 1: [7, 1, 44, 66, 39, 33, 41]\n", "Key 1: [56, 36, 37, 52, 18, 47, 41]\n",
"Key 2: [0, 8, 37, 38, 60, 47, 69]\n", "Key 2: [49, 43, 2, 66, 60, 54, 69]\n",
"Key 3: [56, 50, 58, 52, 25, 61, 55]\n", "Key 3: [7, 8, 44, 3, 11, 68, 13]\n",
"Key 4: [28, 36, 65, 31, 18, 26, 34]\n", "Key 4: [63, 57, 65, 45, 53, 12, 48]\n",
"Key 5: [63, 29, 23, 17, 67, 40, 13]\n", "Key 5: [0, 22, 23, 10, 4, 40, 20]\n",
"Key 6: [49, 43, 9, 10, 53, 19, 62]\n", "Key 6: [35, 15, 51, 31, 67, 5, 55]\n",
"Key 7: [35, 57, 51, 3, 11, 54, 6]\n", "Key 7: [42, 29, 9, 38, 32, 33, 62]\n",
"Key 8: [42, 22, 16, 45, 4, 5, 27]\n", "Key 8: [21, 1, 58, 24, 46, 19, 34]\n",
"Key 9: [14, 15, 30, 24, 32, 12, 20]\n", "Key 9: [28, 64, 30, 17, 25, 61, 27]\n",
"Selected Keys\n", "Selected Keys\n",
"[9, 0, 3, 4]\n" "[4, 2, 1, 9]\n"
] ]
} }
], ],
"source": [ "source": [
"keypad_view(signup_interface, attrs_per_key)\n", "keypad_view(signup_interface, keypad_size.attrs_per_key)\n",
"username = random_username()\n", "username = random_username()\n",
"user_passcode = [12, 2, 52, 28]\n", "user_passcode = [12, 2, 52, 28]\n",
"selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, attrs_per_key)\n", "selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.attrs_per_key)\n",
"print(f\"Selected Keys\\n{selected_keys_set}\")" "print(f\"Selected Keys\\n{selected_keys_set}\")"
], ],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.820991Z", "end_time": "2024-07-19T15:38:32.818320Z",
"start_time": "2024-07-18T13:08:45.818928Z" "start_time": "2024-07-19T15:38:32.791137Z"
} }
} }
}, },
@@ -287,32 +286,32 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Keypad View\n", "Keypad View\n",
"Key 0: [42, 1, 65, 59, 11, 19, 69]\n", "Key 0: [7, 29, 51, 66, 53, 47, 27]\n",
"Key 1: [14, 64, 23, 52, 53, 33, 34]\n", "Key 1: [21, 15, 2, 59, 18, 33, 20]\n",
"Key 2: [0, 50, 51, 45, 39, 68, 13]\n", "Key 2: [63, 43, 16, 17, 32, 5, 13]\n",
"Key 3: [28, 22, 9, 24, 46, 61, 6]\n", "Key 3: [56, 50, 30, 10, 67, 54, 34]\n",
"Key 4: [63, 15, 44, 38, 25, 5, 62]\n", "Key 4: [42, 64, 23, 3, 60, 26, 48]\n",
"Key 5: [35, 8, 2, 31, 4, 12, 41]\n", "Key 5: [35, 22, 44, 24, 39, 61, 41]\n",
"Key 6: [49, 36, 58, 17, 32, 47, 48]\n", "Key 6: [49, 8, 58, 45, 25, 40, 62]\n",
"Key 7: [7, 29, 16, 3, 60, 26, 55]\n", "Key 7: [14, 1, 65, 52, 4, 68, 55]\n",
"Key 8: [21, 57, 30, 10, 18, 40, 27]\n", "Key 8: [28, 57, 37, 38, 11, 19, 69]\n",
"Key 9: [56, 43, 37, 66, 67, 54, 20]\n", "Key 9: [0, 36, 9, 31, 46, 12, 6]\n",
"Selected Keys\n", "Selected Keys\n",
"[5, 5, 1, 3]\n" "[9, 1, 7, 8]\n"
] ]
} }
], ],
"source": [ "source": [
"confirm_interface = api.set_nkode(username, customer_id, selected_keys_set, session_id)\n", "confirm_interface = api.set_nkode(username, customer_id, selected_keys_set, session_id)\n",
"keypad_view(confirm_interface, attrs_per_key)\n", "keypad_view(confirm_interface, keypad_size.attrs_per_key)\n",
"selected_keys_confirm = select_keys_with_passcode_values(user_passcode, confirm_interface, attrs_per_key)\n", "selected_keys_confirm = select_keys_with_passcode_values(user_passcode, confirm_interface, keypad_size.attrs_per_key)\n",
"print(f\"Selected Keys\\n{selected_keys_confirm}\")" "print(f\"Selected Keys\\n{selected_keys_confirm}\")"
], ],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.823981Z", "end_time": "2024-07-19T15:38:32.818413Z",
"start_time": "2024-07-18T13:08:45.821403Z" "start_time": "2024-07-19T15:38:32.794201Z"
} }
} }
}, },
@@ -338,28 +337,28 @@
"text": [ "text": [
"Set Interface\n", "Set Interface\n",
"Keypad View\n", "Keypad View\n",
"Key 0: [21, 64, 2, 59, 46, 68, 48]\n", "Key 0: [14, 50, 16, 59, 39, 26, 6]\n",
"Key 1: [7, 1, 44, 66, 39, 33, 41]\n", "Key 1: [56, 36, 37, 52, 18, 47, 41]\n",
"Key 2: [0, 8, 37, 38, 60, 47, 69]\n", "Key 2: [49, 43, 2, 66, 60, 54, 69]\n",
"Key 3: [56, 50, 58, 52, 25, 61, 55]\n", "Key 3: [7, 8, 44, 3, 11, 68, 13]\n",
"Key 4: [28, 36, 65, 31, 18, 26, 34]\n", "Key 4: [63, 57, 65, 45, 53, 12, 48]\n",
"Key 5: [63, 29, 23, 17, 67, 40, 13]\n", "Key 5: [0, 22, 23, 10, 4, 40, 20]\n",
"Key 6: [49, 43, 9, 10, 53, 19, 62]\n", "Key 6: [35, 15, 51, 31, 67, 5, 55]\n",
"Key 7: [35, 57, 51, 3, 11, 54, 6]\n", "Key 7: [42, 29, 9, 38, 32, 33, 62]\n",
"Key 8: [42, 22, 16, 45, 4, 5, 27]\n", "Key 8: [21, 1, 58, 24, 46, 19, 34]\n",
"Key 9: [14, 15, 30, 24, 32, 12, 20]\n" "Key 9: [28, 64, 30, 17, 25, 61, 27]\n"
] ]
} }
], ],
"source": [ "source": [
"print(\"Set Interface\")\n", "print(\"Set Interface\")\n",
"keypad_view(signup_interface, attrs_per_key)" "keypad_view(signup_interface, keypad_size.attrs_per_key)"
], ],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.826730Z", "end_time": "2024-07-19T15:38:32.818504Z",
"start_time": "2024-07-18T13:08:45.824633Z" "start_time": "2024-07-19T15:38:32.797246Z"
} }
} }
}, },
@@ -373,28 +372,28 @@
"text": [ "text": [
"Confirm Interface\n", "Confirm Interface\n",
"Keypad View\n", "Keypad View\n",
"Key 0: [42, 1, 65, 59, 11, 19, 69]\n", "Key 0: [7, 29, 51, 66, 53, 47, 27]\n",
"Key 1: [14, 64, 23, 52, 53, 33, 34]\n", "Key 1: [21, 15, 2, 59, 18, 33, 20]\n",
"Key 2: [0, 50, 51, 45, 39, 68, 13]\n", "Key 2: [63, 43, 16, 17, 32, 5, 13]\n",
"Key 3: [28, 22, 9, 24, 46, 61, 6]\n", "Key 3: [56, 50, 30, 10, 67, 54, 34]\n",
"Key 4: [63, 15, 44, 38, 25, 5, 62]\n", "Key 4: [42, 64, 23, 3, 60, 26, 48]\n",
"Key 5: [35, 8, 2, 31, 4, 12, 41]\n", "Key 5: [35, 22, 44, 24, 39, 61, 41]\n",
"Key 6: [49, 36, 58, 17, 32, 47, 48]\n", "Key 6: [49, 8, 58, 45, 25, 40, 62]\n",
"Key 7: [7, 29, 16, 3, 60, 26, 55]\n", "Key 7: [14, 1, 65, 52, 4, 68, 55]\n",
"Key 8: [21, 57, 30, 10, 18, 40, 27]\n", "Key 8: [28, 57, 37, 38, 11, 19, 69]\n",
"Key 9: [56, 43, 37, 66, 67, 54, 20]\n" "Key 9: [0, 36, 9, 31, 46, 12, 6]\n"
] ]
} }
], ],
"source": [ "source": [
"print(\"Confirm Interface\")\n", "print(\"Confirm Interface\")\n",
"keypad_view(confirm_interface, attrs_per_key)" "keypad_view(confirm_interface, keypad_size.attrs_per_key)"
], ],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:45.829497Z", "end_time": "2024-07-19T15:38:32.818596Z",
"start_time": "2024-07-18T13:08:45.826898Z" "start_time": "2024-07-19T15:38:32.799553Z"
} }
} }
}, },
@@ -421,8 +420,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:46.334453Z", "end_time": "2024-07-19T15:38:33.435016Z",
"start_time": "2024-07-18T13:08:45.830468Z" "start_time": "2024-07-19T15:38:32.803552Z"
} }
} }
}, },
@@ -445,8 +444,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:46.336225Z", "end_time": "2024-07-19T15:38:33.451250Z",
"start_time": "2024-07-18T13:08:46.334763Z" "start_time": "2024-07-19T15:38:33.435255Z"
} }
} }
}, },
@@ -469,8 +468,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-18T13:08:46.344268Z", "end_time": "2024-07-19T15:38:33.451441Z",
"start_time": "2024-07-18T13:08:46.338692Z" "start_time": "2024-07-19T15:38:33.438804Z"
} }
} }
} }

View File

@@ -17,7 +17,7 @@ class Customer(BaseModel):
def valid_key_entry(self, username, selected_keys) -> bool: def valid_key_entry(self, username, selected_keys) -> bool:
assert (username in self.users.keys()) assert (username in self.users.keys())
assert (all(key_idx < self.interface.numb_of_keys for key_idx in selected_keys)) assert (all(key_idx < self.interface.keypad_size.numb_of_keys for key_idx in selected_keys))
passcode_len = len(selected_keys) passcode_len = len(selected_keys)
user = self.users[username] user = self.users[username]

View File

@@ -1,33 +1,33 @@
from pydantic import BaseModel from pydantic import BaseModel
from src.utils import generate_random_nonrepeating_list, list_to_matrix, matrix_transpose
from src.models import KeypadSize
from src.utils import generate_random_nonrepeating_list
class CustomerInterface(BaseModel): class CustomerInterface(BaseModel):
attr_vals: list[int] attr_vals: list[int]
set_vals: list[int] set_vals: list[int]
numb_of_keys: int keypad_size: KeypadSize
attrs_per_key: int
@staticmethod @staticmethod
def new(numb_keys: int, attrs_per_key: int): def new(keypad_size: KeypadSize):
assert (numb_keys <= 256) assert (keypad_size.numb_of_keys <= 256)
assert (attrs_per_key <= 256) assert (keypad_size.attrs_per_key <= 256)
return CustomerInterface( return CustomerInterface(
attr_vals=generate_random_nonrepeating_list(attrs_per_key * numb_keys), attr_vals=generate_random_nonrepeating_list(keypad_size.numb_of_attrs),
set_vals=generate_random_nonrepeating_list(attrs_per_key), set_vals=generate_random_nonrepeating_list(keypad_size.attrs_per_key),
numb_of_keys=numb_keys, keypad_size=keypad_size,
attrs_per_key=attrs_per_key,
) )
def renew_interface(self): def renew_interface(self):
self.attr_vals = generate_random_nonrepeating_list(self.attrs_per_key * self.numb_of_keys) self.attr_vals = generate_random_nonrepeating_list(self.keypad_size.numb_of_attrs)
self.set_vals = generate_random_nonrepeating_list(self.attrs_per_key) self.set_vals = generate_random_nonrepeating_list(self.keypad_size.attrs_per_key)
def get_attr_set_val(self, attr: int) -> int: def get_attr_set_val(self, attr: int) -> int:
assert (attr in self.attr_vals) assert (attr in self.attr_vals)
attr_idx = self.attr_vals.index(attr) attr_idx = self.attr_vals.index(attr)
set_idx = attr_idx % self.attrs_per_key set_idx = attr_idx % self.keypad_size.attrs_per_key
return self.set_vals[set_idx] return self.set_vals[set_idx]
def get_set_index(self, set_val: int) -> int: def get_set_index(self, set_val: int) -> int:

View File

@@ -17,3 +17,12 @@ class NKodePolicy(BaseModel):
distinct_sets: int = 0 distinct_sets: int = 0
distinct_attributes: int = 4 distinct_attributes: int = 4
# TODO: bytes_per_attr # TODO: bytes_per_attr
class KeypadSize(BaseModel):
attrs_per_key: int
numb_of_keys: int
@property
def numb_of_attrs(self) -> int:
return self.attrs_per_key * self.numb_of_keys

View File

@@ -21,8 +21,7 @@ class User(BaseModel):
def refresh_passcode(self, passcode_attr_idx: list[int], customer_interface: CustomerInterface): def refresh_passcode(self, passcode_attr_idx: list[int], customer_interface: CustomerInterface):
self.user_keys = UserCipherKeys.new( self.user_keys = UserCipherKeys.new(
customer_interface.numb_of_keys, customer_interface.keypad_size,
customer_interface.attrs_per_key,
customer_interface.set_vals, customer_interface.set_vals,
self.user_keys.max_nkode_len self.user_keys.max_nkode_len
) )

View File

@@ -4,7 +4,7 @@ import bcrypt
from secrets import choice from secrets import choice
from pydantic import BaseModel from pydantic import BaseModel
from src.models import EncipheredNKode from src.models import EncipheredNKode, KeypadSize
from src.customer_interface import CustomerInterface from src.customer_interface import CustomerInterface
from src.utils import generate_random_nonrepeating_list, xor_lists, int_array_to_bytes from src.utils import generate_random_nonrepeating_list, xor_lists, int_array_to_bytes
@@ -18,14 +18,14 @@ class UserCipherKeys(BaseModel):
max_nkode_len: int max_nkode_len: int
@staticmethod @staticmethod
def new(numb_of_keys: int, attrs_per_key: int, set_values: list[int], max_nkode_len: int): def new(keypad_size: KeypadSize, set_values: list[int], max_nkode_len: int):
assert len(set_values) == attrs_per_key assert len(set_values) == keypad_size.attrs_per_key
set_key = generate_random_nonrepeating_list(attrs_per_key) set_key = generate_random_nonrepeating_list(keypad_size.attrs_per_key)
set_key = xor_lists(set_key, set_values) set_key = xor_lists(set_key, set_values)
return UserCipherKeys( return UserCipherKeys(
alpha_key=generate_random_nonrepeating_list(attrs_per_key * numb_of_keys), alpha_key=generate_random_nonrepeating_list(keypad_size.attrs_per_key * keypad_size.numb_of_keys),
pass_key=generate_random_nonrepeating_list(max_nkode_len), pass_key=generate_random_nonrepeating_list(max_nkode_len),
mask_key=generate_random_nonrepeating_list(max_nkode_len), mask_key=generate_random_nonrepeating_list(max_nkode_len),
set_key=set_key, set_key=set_key,

View File

@@ -1,20 +1,20 @@
from pydantic import BaseModel from pydantic import BaseModel
from secrets import choice from secrets import choice
from src.models import KeypadSize
from src.utils import list_to_matrix, secure_fisher_yates_shuffle, matrix_to_list, matrix_transpose from src.utils import list_to_matrix, secure_fisher_yates_shuffle, matrix_to_list, matrix_transpose
class UserInterface(BaseModel): class UserInterface(BaseModel):
attr_indices: list[int] attr_indices: list[int]
attrs_per_key: int keypad_size: KeypadSize
numb_of_keys: int
@staticmethod @staticmethod
def new(attrs_per_key: int, numb_of_keys: int): def new(keypad_size: KeypadSize):
# Todo: this a hack do a proper random interface # Todo: this a hack do a proper random interface
interface = UserInterface( interface = UserInterface(
attr_indices=list(range(attrs_per_key * numb_of_keys)), attr_indices=list(range(keypad_size.numb_of_attrs)),
attrs_per_key=attrs_per_key, keypad_size=keypad_size
numb_of_keys=numb_of_keys,
) )
interface.disperse_interface() interface.disperse_interface()
for _ in range(10): for _ in range(10):
@@ -22,18 +22,18 @@ class UserInterface(BaseModel):
return interface return interface
def disperse_interface(self): def disperse_interface(self):
user_interface_matrix = list_to_matrix(self.attr_indices, self.attrs_per_key) user_interface_matrix = list_to_matrix(self.attr_indices, self.keypad_size.attrs_per_key)
shuffled_keys = secure_fisher_yates_shuffle(user_interface_matrix) shuffled_keys = secure_fisher_yates_shuffle(user_interface_matrix)
dispersed_interface = self._random_attribute_rotation(shuffled_keys, list(range(self.attrs_per_key))) dispersed_interface = self._random_attribute_rotation(shuffled_keys, list(range(self.keypad_size.attrs_per_key)))
self.attr_indices = matrix_to_list(dispersed_interface) self.attr_indices = matrix_to_list(dispersed_interface)
def shuffle_interface(self): def shuffle_interface(self):
"""just like dispersion but only half the sets are rotated""" """just like dispersion but only half the sets are rotated"""
numb_of_selected_sets = self.attrs_per_key // 2 numb_of_selected_sets = self.keypad_size.attrs_per_key // 2
# randomly shuffle half the sets. if attrs_per_key is odd, randomly add one 50% of the time # randomly shuffle half the sets. if attrs_per_key is odd, randomly add one 50% of the time
numb_of_selected_sets += choice([0, 1]) if (self.attrs_per_key & 1) == 1 else 0 numb_of_selected_sets += choice([0, 1]) if (self.keypad_size.attrs_per_key & 1) == 1 else 0
selected_sets = secure_fisher_yates_shuffle(list(range(self.attrs_per_key)))[:numb_of_selected_sets] selected_sets = secure_fisher_yates_shuffle(list(range(self.keypad_size.attrs_per_key)))[:numb_of_selected_sets]
user_interface_matrix = list_to_matrix(self.attr_indices, self.attrs_per_key) user_interface_matrix = list_to_matrix(self.attr_indices, self.keypad_size.attrs_per_key)
shuffled_keys = secure_fisher_yates_shuffle(user_interface_matrix) shuffled_keys = secure_fisher_yates_shuffle(user_interface_matrix)
interface_by_sets = [] interface_by_sets = []
for idx, attrs in enumerate(matrix_transpose(shuffled_keys)): for idx, attrs in enumerate(matrix_transpose(shuffled_keys)):
@@ -44,7 +44,7 @@ class UserInterface(BaseModel):
self.attr_indices = matrix_to_list(matrix_transpose(interface_by_sets)) self.attr_indices = matrix_to_list(matrix_transpose(interface_by_sets))
def _random_attribute_rotation(self, user_interface: list[list[int]], selected_sets: list[int]) -> list[list[int]]: def _random_attribute_rotation(self, user_interface: list[list[int]], selected_sets: list[int]) -> list[list[int]]:
attr_rotation = secure_fisher_yates_shuffle(list(range(self.numb_of_keys)))[:self.attrs_per_key] attr_rotation = secure_fisher_yates_shuffle(list(range(self.keypad_size.numb_of_keys)))[:self.keypad_size.attrs_per_key]
transposed_user_interface = matrix_transpose(user_interface) transposed_user_interface = matrix_transpose(user_interface)
assert (len(attr_rotation) == len(transposed_user_interface)) assert (len(attr_rotation) == len(transposed_user_interface))
for idx, attr_set in enumerate(transposed_user_interface): for idx, attr_set in enumerate(transposed_user_interface):
@@ -55,7 +55,7 @@ class UserInterface(BaseModel):
return matrix_transpose(transposed_user_interface) return matrix_transpose(transposed_user_interface)
def attribute_adjacency_graph(self) -> dict[int, set[int]]: def attribute_adjacency_graph(self) -> dict[int, set[int]]:
user_interface_keypad = list_to_matrix(self.attr_indices, self.attrs_per_key) user_interface_keypad = list_to_matrix(self.attr_indices, self.keypad_size.attrs_per_key)
graph = {} graph = {}
for key in user_interface_keypad: for key in user_interface_keypad:
for attr in key: for attr in key:
@@ -65,6 +65,6 @@ class UserInterface(BaseModel):
return graph return graph
def get_key_attr_idxs(self, key_numb: int) -> list[int]: def get_key_attr_idxs(self, key_numb: int) -> list[int]:
assert (0 <= key_numb < self.numb_of_keys) assert (0 <= key_numb < self.keypad_size.numb_of_keys)
keypad_attr_idx = list_to_matrix(self.attr_indices, self.attrs_per_key) keypad_attr_idx = list_to_matrix(self.attr_indices, self.keypad_size.attrs_per_key)
return keypad_attr_idx[key_numb] return keypad_attr_idx[key_numb]

View File

@@ -2,22 +2,23 @@ from uuid import UUID
from pydantic import BaseModel from pydantic import BaseModel
from src.customer import Customer
from src.user import User
from src.user_cipher_keys import UserCipherKeys
from src.user_interface import UserInterface from src.user_interface import UserInterface
from src.models import KeypadSize
class UserSignupSession(BaseModel): class UserSignupSession(BaseModel):
session_id: UUID session_id: UUID
customer_id: UUID customer_id: UUID
keypad_size: KeypadSize
set_interface: list[int] | None = None set_interface: list[int] | None = None
confirm_interface: list[int] | None = None confirm_interface: list[int] | None = None
set_key_entry: list[int] | None = None set_key_entry: list[int] | None = None
confirm_key_entry: list[int] | None = None
username: str | None = None username: str | None = None
def _deduce_passcode(self, attrs_per_key, confirm_key_entry: list[int]) -> list[int]: def deduce_passcode(self, confirm_key_entry: list[int]) -> list[int]:
assert (all(0 <= key <= self.keypad_size.numb_of_keys for key in confirm_key_entry))
attrs_per_key = self.keypad_size.attrs_per_key
set_key_entry = self.set_key_entry set_key_entry = self.set_key_entry
assert (len(set_key_entry) == len(confirm_key_entry)) assert (len(set_key_entry) == len(confirm_key_entry))
set_interface = self.set_interface set_interface = self.set_interface
@@ -35,37 +36,14 @@ class UserSignupSession(BaseModel):
passcode.append(intersection[0]) passcode.append(intersection[0])
return passcode return passcode
def set_user_nkode(self, username: str, customer: Customer, key_selection: list[int]): def set_user_nkode(self, username: str, key_selection: list[int]):
assert (customer.customer_id == self.customer_id) assert (all(0 <= key <= self.keypad_size.numb_of_keys for key in key_selection))
numb_of_keys = customer.interface.numb_of_keys
attrs_per_key = customer.interface.attrs_per_key
assert (all(0 <= key <= numb_of_keys for key in key_selection))
set_interface = UserInterface( set_interface = UserInterface(
attr_indices=self.set_interface, attr_indices=self.set_interface,
attrs_per_key=attrs_per_key, keypad_size=self.keypad_size
numb_of_keys=numb_of_keys,
) )
set_interface.disperse_interface() set_interface.disperse_interface()
self.username = username self.username = username
self.set_key_entry = key_selection self.set_key_entry = key_selection
self.confirm_interface = set_interface.attr_indices self.confirm_interface = set_interface.attr_indices
def create_user(self, username: str, customer: Customer, confirm_key_entry: list[int]) -> User:
numb_of_keys = customer.interface.numb_of_keys
attrs_per_key = customer.interface.attrs_per_key
assert (all(0 <= key <= numb_of_keys for key in confirm_key_entry))
passcode_attrs = self._deduce_passcode(attrs_per_key, confirm_key_entry)
set_values = customer.interface.set_vals
assert customer.valid_new_nkode(passcode_attrs)
new_user_keys = UserCipherKeys.new(numb_of_keys, attrs_per_key, set_values, customer.nkode_policy.max_nkode_len)
enciphered_passcode = new_user_keys.encipher_nkode(passcode_attrs, customer.interface)
return User(
username=username,
enciphered_passcode=enciphered_passcode,
user_keys=new_user_keys,
user_interface=UserInterface(
attr_indices=self.confirm_interface,
attrs_per_key=attrs_per_key,
numb_of_keys=numb_of_keys,
),
)

View File

@@ -1,6 +1,6 @@
import pytest import pytest
from nkode_api import NKodeAPI from nkode_api import NKodeAPI
from src.models import NKodePolicy from src.models import NKodePolicy, KeypadSize
@pytest.fixture() @pytest.fixture()
@@ -8,17 +8,17 @@ def nkode_api() -> NKodeAPI:
return NKodeAPI() return NKodeAPI()
@pytest.mark.parametrize("numb_of_keys,attrs_per_key,user_passcode", [ @pytest.mark.parametrize("keypad_size,user_passcode", [
(10, 7, [3, 10, 27, 68]), (KeypadSize(numb_of_keys=10, attrs_per_key=7), [3, 10, 27, 68]),
(12, 6, [3, 10, 27, 68, 32]), (KeypadSize(numb_of_keys=10, attrs_per_key=7), [3, 10, 27, 68, 32]),
]) ])
def test_create_new_user_and_renew_keys(nkode_api, numb_of_keys, attrs_per_key, user_passcode): def test_create_new_user_and_renew_keys(nkode_api, keypad_size, user_passcode):
username = "test_username" username = "test_username"
nkode_policy = NKodePolicy() # default policy nkode_policy = NKodePolicy() # default policy
customer_id = nkode_api.create_new_customer(numb_of_keys, attrs_per_key, nkode_policy) customer_id = nkode_api.create_new_customer(keypad_size, nkode_policy)
session_id, set_interface = nkode_api.generate_index_interface(customer_id) session_id, set_interface = nkode_api.generate_index_interface(customer_id)
key_selection = lambda interface: [interface.index(attr) // attrs_per_key for attr in user_passcode] key_selection = lambda interface: [interface.index(attr) // keypad_size.attrs_per_key for attr in user_passcode]
set_key_selection = key_selection(set_interface) set_key_selection = key_selection(set_interface)
confirm_interface = nkode_api.set_nkode(username, customer_id, set_key_selection, session_id) confirm_interface = nkode_api.set_nkode(username, customer_id, set_key_selection, session_id)

View File

@@ -1,14 +1,15 @@
import pytest import pytest
from src.user_interface import UserInterface from src.user_interface import UserInterface
from src.models import KeypadSize
@pytest.mark.parametrize( @pytest.mark.parametrize(
"numb_of_keys,attrs_per_key", "keypad_size",
[(10, 7,)] [KeypadSize(numb_of_keys=10, attrs_per_key=7)]
) )
def test_attr_set_idx(numb_of_keys, attrs_per_key): def test_attr_set_idx(keypad_size):
user_interface = UserInterface.new(attrs_per_key, numb_of_keys) user_interface = UserInterface.new(keypad_size)
for attr_idx in range(70): for attr_idx in range(70):
user_interface_idx = user_interface.attr_indices[attr_idx] user_interface_idx = user_interface.attr_indices[attr_idx]
assert (attr_idx % attrs_per_key == user_interface_idx % attrs_per_key) assert (attr_idx % keypad_size.attrs_per_key == user_interface_idx % keypad_size.attrs_per_key)

View File

@@ -1,4 +1,6 @@
import pytest import pytest
from src.models import KeypadSize
from src.user_cipher_keys import UserCipherKeys, CustomerInterface from src.user_cipher_keys import UserCipherKeys, CustomerInterface
from src.utils import generate_random_nonrepeating_list from src.utils import generate_random_nonrepeating_list
@@ -18,20 +20,20 @@ def test_encode_decode_base64(passcode_len):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"numb_of_keys,attrs_per_key,max_nkode_len", "keypad_size,max_nkode_len",
[ [
(10, 7, 10), (KeypadSize(numb_of_keys=10, attrs_per_key=7), 10),
(9, 7, 10), (KeypadSize(numb_of_keys=9, attrs_per_key=7), 10),
(8, 7, 12), (KeypadSize(numb_of_keys=8, attrs_per_key=7), 12),
]) ])
def test_decode_mask(numb_of_keys, attrs_per_key, max_nkode_len): def test_decode_mask(keypad_size, max_nkode_len):
customer = CustomerInterface.new(numb_of_keys, attrs_per_key) customer = CustomerInterface.new(keypad_size)
passcode_entry = generate_random_nonrepeating_list( passcode_entry = generate_random_nonrepeating_list(
numb_of_keys * attrs_per_key, keypad_size.numb_of_attrs,
max_val=(numb_of_keys*attrs_per_key))[:4] max_val=keypad_size.numb_of_attrs)[:4]
passcode_values = [customer.attr_vals[idx] for idx in passcode_entry] passcode_values = [customer.attr_vals[idx] for idx in passcode_entry]
set_vals = customer.set_vals set_vals = customer.set_vals
user_keys = UserCipherKeys.new(numb_of_keys, attrs_per_key, set_vals, max_nkode_len) user_keys = UserCipherKeys.new(keypad_size, set_vals, max_nkode_len)
passcode = user_keys.encipher_nkode(passcode_entry, customer) passcode = user_keys.encipher_nkode(passcode_entry, customer)
orig_passcode_set_vals = [customer.get_attr_set_val(attr) for attr in passcode_values] orig_passcode_set_vals = [customer.get_attr_set_val(attr) for attr in passcode_values]

View File

@@ -1,10 +1,11 @@
import pytest import pytest
from src.user_interface import UserInterface from src.user_interface import UserInterface
from src.models import KeypadSize
@pytest.fixture() @pytest.fixture()
def user_interface(): def user_interface():
return UserInterface.new(7, 10) return UserInterface.new(keypad_size=KeypadSize(attrs_per_key=7, numb_of_keys=10))
def test_dispersion(user_interface): def test_dispersion(user_interface):