# nKode Tutorial

## nKode Keypad

- nKode keypad contains keys
- Each key has icons
- Each icon belongs to a set and has an index value associated with it
- The position within the key is the set value
- When attributes are shuffled, they'll always remain in the same position within the key
        (note: the set value can be obuscated from the client but we find it helpful to quickly find the attribute)

## nKode Enrollment 

- user sets then confirms their nKode
- Set and Confirm are dipersion of each other and allow the server to infer the users nKode
- the users login has additional icons added to each to key to make it dispersion resistant
- After the user as selected their nKode through the set and confirms,
    the server can infer the users selection since each key selection will only have one icons in common.
- The users nKode is enciphered, salted and hashed.

## Dispersion

- Two keypads are dispersion of each other if:
Kp1: Keypad 1
Kp2: Keypad 2

for each key1 in Kp1:
    for each key2 in Kp2:
        iconsIntersection(key1, key2) <= 1


## Dispersion Algo

- Convert a Keypad view into a matrix view
    - each row is key and each column is a set
- Fisher Yates the keys i.e. the rows in the matrix
- Fisher Yates an identity matrix equivalent to the number of keys
- The shuffled permutation is used to rotate the columns


## Dispersion Resistance

- Dispersion is only possible if {number of icons per key} <= {number keys in the keypad}
- If there are more icons per key than keys, it makes it difficult to phish for a users nkode


## Cipher Keys

#### attribute key

- randomly generated array of unsigned integars 
- array of length {numb of keys} * {number of attributes per key}  
- xored with ss-attr to give each user a unique

#### passcode key

- randomly generated array of unsigned integars
- array of length {max nKode length}
- xored with final user passcode

#### set key

- used to recover users nkode set values
- array of unsigned integars
- each elemenet in the array is a random number XOR'ed with the set value of the users nKode
- so `for set_key_i in user_set_key`
            `set_key_i = user_passcode_set_i ^ random_set_key_i`

#### mask key

- used to recover users nkode set values
- array of random unsigned integars

#### server-side attributes (ss-attr) and sets (ss-set)

- Each icon has a server side attribute.
- The icon and the ss-attr are indexed to the same place in an array. 
- The dispersion and shuffle operation are applied to the index array and the index array is applied to the icon and ss-attr 
- ss-attrs are randomly generated permutation of unsigned ints (or byte arrays of any length for extra security)

### Encipher and Hash nKode Passcode
passcode = index values of the selected icons infered in set/comfirm
user_attrs = arr_xor(ss_attr, user_attr_key)
passcode_attr = [user_attrs[idx] for idx in passcode]

ciphered_passcode = arr_xor(passcode_attr, user_passcode_key)

// optional sha256 if ciphered_passcode is more than 72 bytes
passcode_digest = sha256(ciphered_passcode)

hashed_passcode = bcrypt(passcode_digest)

### Enicphering nKode Set

nKode mask is used to recover the users nKode 
1. set_key_i = (set_rand_numb_i ^ set_val_i) 
2. mask_key_i = mask_rand_numb_i

passcode = index values of the selected icons infered in set/comfirm
// recall ss_set array is an order list
set_idx = get_set_value(passcode)
user_set_keys = [set_key[idx] for idx in set_idx]
user_set_vals = [ss_sets[idx] for idx in set_idx]
mask = arr_xor(user_set_val, user_set_keys, mask_key)

- mask_i = mask_key_i ^ padded_passcode_server_set_i ^ set_key_i
- mask_i = mask_rand_num_i ^ set_val_i ^ set_rand_numb_i ^ set_val_i
- mask_i = mask_rand_num_i ^ set_rand_numb_i # set_val_i is cancelled out

#### nKode Validation
// set_val_i = mask_i ^ set_key_i ^ mask_key_i 
// selected_keys the keys the user selects
recovered_set_vals = arr_xor(mask, set_key, mask_key)
user_keypad = get_user_keypad(username)

presumed_password = get_pressumed_passcode(user_key, selected_keys, recovered_set_val)

if is_valid_passcode(presumed_password, hashed_passcode)
    return LOGIN_SUCCESS
else
    return LOGIN_FAIL


## nKode Login Shuffle

- After a successful login, the users keypad is shuffled in a two step process:
    1. the keys are randomly shuffled
    2. half the sets are randomly shuffled
- We've found this works best for xyz reason and we're also working on simulations to find a probablity curve for number of overserveration before an adversery can crack an nkode


## nKode Login

- When a user request their nkode keypad, the server sends a list of svgs in the order they should be displayed
- The Gen2 demo implementation works a bit different it sends the svgs indexed in order from 0-total_numb_of_attr along with an index array for how the svgs should be ordered
    - this is a legacy from the gen 1 keypad but it helps to make the implemntation more concrete so we'll use this legacy 
- The frontend organized the svgs into keys and displays them.
- The user selects keys for their nkode and their key selection is sent back to the server for validation


## Preventing User Enumeration

- This isn't applied in the demo application
- We can prevent a threat actor from enumerating users.
    - if a valid email is entered into the login for a user that dne, we can create a ghost keypad and have it behave as if it were a real user.
    - if there are too many "failed nkode attempts" we lock the non-existing user out.
- We can prevent timing attacks by either mocking the real control flow or setting a 1 or 2 sec response delay from the time the login request was recieved thereby completely elimiating timing attacks 

## Renew
Renew changes user ciphers, user salt, ss_attr, and ss_set.
This is import in the event of a partial database hack or leak.
An admin or cron job can run the renew with any frequency (daily, weekly, monthly)
Users are aware of this process.
Nothing changes for them.

### Three Step Renew
Renew has three phases

1. Server-Side Attribute Renewal: ss_attr and ss_set values are replaced with new values
2. Intermdiate User Renewal: every user goes through an intermediate phase before full Renewal
3. Full User Renewal: The user's first successful login completes the renewal. User has gets new salt, and cipher

#### Server-Side Attribute Renewal

old_ss_attr, old_ss_set = get_ss_vals()
renew_ss_vals() // new randomly generated values
new_ss_attr, new_ss_set = get_ss_vals()

xor_ss_attr = arr_xor(old_ss_attr, new_ss_attr)
xor_ss_set = arr_xor(old_ss_set, new_ss_set)

#### Intermdiate User Renewal

all_users = get_all_users()
for user in all_users:
    user.renew = True // This flags the server to complete phase 3, full user renewal
    user.set_key = xor_lists(user.set_key, xor_ss_set) // recall user.set_key = rand_num ^ old_ss_set. this operation cancels out old_ss_set and replaces it with new_ss_set
    user.attribute_key = xor_lists(user.attribute_key, xor_ss_attr) // recall user.attribute_key ^ old_ss_attr are the user's nkode ss attributes so when we 

#### Full User Renewal

After a successful login user keys are reset as if the user was signing up for the first time


