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 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_interface import UserInterface
from src.customer_interface import CustomerInterface
@@ -12,10 +14,10 @@ class NKodeAPI(BaseModel):
customers: dict[UUID, Customer] = {}
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(
customer_id=uuid4(),
interface=CustomerInterface.new(numb_keys, numb_sets),
interface=CustomerInterface.new(keypad_size),
users={},
nkode_policy=nkode_policy
)
@@ -26,16 +28,16 @@ class NKodeAPI(BaseModel):
def generate_index_interface(self, customer_id: UUID) -> tuple[UUID, list[int]]:
assert (customer_id in self.customers.keys())
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(
session_id=uuid4(),
set_interface=set_interface.attr_indices,
customer_id=customer_id,
keypad_size=customer.interface.keypad_size,
)
self.signup_sessions[new_session.session_id] = new_session
return new_session.session_id, new_session.set_interface
def set_nkode(
self, username: str,
customer_id: UUID,
@@ -46,7 +48,7 @@ class NKodeAPI(BaseModel):
customer = self.customers[customer_id]
assert (username not in customer.users.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
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
)
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)
del self.signup_sessions[session_id]
return True
@@ -80,4 +99,3 @@ class NKodeAPI(BaseModel):
def renew_keys(self, customer_id: UUID) -> bool:
assert (customer_id in self.customers.keys())
return self.customers[customer_id].renew_keys()

View File

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

View File

@@ -1,33 +1,33 @@
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):
attr_vals: list[int]
set_vals: list[int]
numb_of_keys: int
attrs_per_key: int
keypad_size: KeypadSize
@staticmethod
def new(numb_keys: int, attrs_per_key: int):
assert (numb_keys <= 256)
assert (attrs_per_key <= 256)
def new(keypad_size: KeypadSize):
assert (keypad_size.numb_of_keys <= 256)
assert (keypad_size.attrs_per_key <= 256)
return CustomerInterface(
attr_vals=generate_random_nonrepeating_list(attrs_per_key * numb_keys),
set_vals=generate_random_nonrepeating_list(attrs_per_key),
numb_of_keys=numb_keys,
attrs_per_key=attrs_per_key,
attr_vals=generate_random_nonrepeating_list(keypad_size.numb_of_attrs),
set_vals=generate_random_nonrepeating_list(keypad_size.attrs_per_key),
keypad_size=keypad_size,
)
def renew_interface(self):
self.attr_vals = generate_random_nonrepeating_list(self.attrs_per_key * self.numb_of_keys)
self.set_vals = generate_random_nonrepeating_list(self.attrs_per_key)
self.attr_vals = generate_random_nonrepeating_list(self.keypad_size.numb_of_attrs)
self.set_vals = generate_random_nonrepeating_list(self.keypad_size.attrs_per_key)
def get_attr_set_val(self, attr: int) -> int:
assert (attr in self.attr_vals)
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]
def get_set_index(self, set_val: int) -> int:

View File

@@ -17,3 +17,12 @@ class NKodePolicy(BaseModel):
distinct_sets: int = 0
distinct_attributes: int = 4
# 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):
self.user_keys = UserCipherKeys.new(
customer_interface.numb_of_keys,
customer_interface.attrs_per_key,
customer_interface.keypad_size,
customer_interface.set_vals,
self.user_keys.max_nkode_len
)

View File

@@ -4,7 +4,7 @@ import bcrypt
from secrets import choice
from pydantic import BaseModel
from src.models import EncipheredNKode
from src.models import EncipheredNKode, KeypadSize
from src.customer_interface import CustomerInterface
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
@staticmethod
def new(numb_of_keys: int, attrs_per_key: int, set_values: list[int], max_nkode_len: int):
assert len(set_values) == attrs_per_key
def new(keypad_size: KeypadSize, set_values: list[int], max_nkode_len: int):
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)
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),
mask_key=generate_random_nonrepeating_list(max_nkode_len),
set_key=set_key,

View File

@@ -1,20 +1,20 @@
from pydantic import BaseModel
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
class UserInterface(BaseModel):
attr_indices: list[int]
attrs_per_key: int
numb_of_keys: int
keypad_size: KeypadSize
@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
interface = UserInterface(
attr_indices=list(range(attrs_per_key * numb_of_keys)),
attrs_per_key=attrs_per_key,
numb_of_keys=numb_of_keys,
attr_indices=list(range(keypad_size.numb_of_attrs)),
keypad_size=keypad_size
)
interface.disperse_interface()
for _ in range(10):
@@ -22,18 +22,18 @@ class UserInterface(BaseModel):
return interface
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)
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)
def shuffle_interface(self):
"""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
numb_of_selected_sets += choice([0, 1]) if (self.attrs_per_key & 1) == 1 else 0
selected_sets = secure_fisher_yates_shuffle(list(range(self.attrs_per_key)))[:numb_of_selected_sets]
user_interface_matrix = list_to_matrix(self.attr_indices, self.attrs_per_key)
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.keypad_size.attrs_per_key)))[:numb_of_selected_sets]
user_interface_matrix = list_to_matrix(self.attr_indices, self.keypad_size.attrs_per_key)
shuffled_keys = secure_fisher_yates_shuffle(user_interface_matrix)
interface_by_sets = []
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))
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)
assert (len(attr_rotation) == len(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)
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 = {}
for key in user_interface_keypad:
for attr in key:
@@ -65,6 +65,6 @@ class UserInterface(BaseModel):
return graph
def get_key_attr_idxs(self, key_numb: int) -> list[int]:
assert (0 <= key_numb < self.numb_of_keys)
keypad_attr_idx = list_to_matrix(self.attr_indices, self.attrs_per_key)
assert (0 <= key_numb < self.keypad_size.numb_of_keys)
keypad_attr_idx = list_to_matrix(self.attr_indices, self.keypad_size.attrs_per_key)
return keypad_attr_idx[key_numb]

View File

@@ -2,22 +2,23 @@ from uuid import UUID
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.models import KeypadSize
class UserSignupSession(BaseModel):
session_id: UUID
customer_id: UUID
keypad_size: KeypadSize
set_interface: list[int] | None = None
confirm_interface: list[int] | None = None
set_key_entry: list[int] | None = None
confirm_key_entry: list[int] | 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
assert (len(set_key_entry) == len(confirm_key_entry))
set_interface = self.set_interface
@@ -35,37 +36,14 @@ class UserSignupSession(BaseModel):
passcode.append(intersection[0])
return passcode
def set_user_nkode(self, username: str, customer: Customer, key_selection: list[int]):
assert (customer.customer_id == self.customer_id)
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))
def set_user_nkode(self, username: str, key_selection: list[int]):
assert (all(0 <= key <= self.keypad_size.numb_of_keys for key in key_selection))
set_interface = UserInterface(
attr_indices=self.set_interface,
attrs_per_key=attrs_per_key,
numb_of_keys=numb_of_keys,
keypad_size=self.keypad_size
)
set_interface.disperse_interface()
self.username = username
self.set_key_entry = key_selection
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
from nkode_api import NKodeAPI
from src.models import NKodePolicy
from src.models import NKodePolicy, KeypadSize
@pytest.fixture()
@@ -8,17 +8,17 @@ def nkode_api() -> NKodeAPI:
return NKodeAPI()
@pytest.mark.parametrize("numb_of_keys,attrs_per_key,user_passcode", [
(10, 7, [3, 10, 27, 68]),
(12, 6, [3, 10, 27, 68, 32]),
@pytest.mark.parametrize("keypad_size,user_passcode", [
(KeypadSize(numb_of_keys=10, attrs_per_key=7), [3, 10, 27, 68]),
(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"
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)
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)
confirm_interface = nkode_api.set_nkode(username, customer_id, set_key_selection, session_id)

View File

@@ -1,14 +1,15 @@
import pytest
from src.user_interface import UserInterface
from src.models import KeypadSize
@pytest.mark.parametrize(
"numb_of_keys,attrs_per_key",
[(10, 7,)]
"keypad_size",
[KeypadSize(numb_of_keys=10, attrs_per_key=7)]
)
def test_attr_set_idx(numb_of_keys, attrs_per_key):
user_interface = UserInterface.new(attrs_per_key, numb_of_keys)
def test_attr_set_idx(keypad_size):
user_interface = UserInterface.new(keypad_size)
for attr_idx in range(70):
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
from src.models import KeypadSize
from src.user_cipher_keys import UserCipherKeys, CustomerInterface
from src.utils import generate_random_nonrepeating_list
@@ -18,20 +20,20 @@ def test_encode_decode_base64(passcode_len):
@pytest.mark.parametrize(
"numb_of_keys,attrs_per_key,max_nkode_len",
"keypad_size,max_nkode_len",
[
(10, 7, 10),
(9, 7, 10),
(8, 7, 12),
(KeypadSize(numb_of_keys=10, attrs_per_key=7), 10),
(KeypadSize(numb_of_keys=9, attrs_per_key=7), 10),
(KeypadSize(numb_of_keys=8, attrs_per_key=7), 12),
])
def test_decode_mask(numb_of_keys, attrs_per_key, max_nkode_len):
customer = CustomerInterface.new(numb_of_keys, attrs_per_key)
def test_decode_mask(keypad_size, max_nkode_len):
customer = CustomerInterface.new(keypad_size)
passcode_entry = generate_random_nonrepeating_list(
numb_of_keys * attrs_per_key,
max_val=(numb_of_keys*attrs_per_key))[:4]
keypad_size.numb_of_attrs,
max_val=keypad_size.numb_of_attrs)[:4]
passcode_values = [customer.attr_vals[idx] for idx in passcode_entry]
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)
orig_passcode_set_vals = [customer.get_attr_set_val(attr) for attr in passcode_values]

View File

@@ -1,10 +1,11 @@
import pytest
from src.user_interface import UserInterface
from src.models import KeypadSize
@pytest.fixture()
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):