reorganize code

This commit is contained in:
2024-08-23 10:18:39 -05:00
parent 6a56b2300a
commit dbc8ca3d29
20 changed files with 476 additions and 214 deletions

View File

@@ -1,194 +0,0 @@
package api
import (
"errors"
"fmt"
"github.com/google/uuid"
"go-nkode/hashset"
m "go-nkode/models"
py "go-nkode/py-builtin"
"go-nkode/util"
)
type Customer struct {
CustomerId uuid.UUID
NKodePolicy m.NKodePolicy
Attributes CustomerAttributes
Users map[string]User
}
func NewCustomer(keypadSize m.KeypadSize, nkodePolicy m.NKodePolicy) (*Customer, error) {
if keypadSize.TotalAttrs() < nkodePolicy.DistinctAttributes {
return nil, errors.New(fmt.Sprintf("incompadible nkode policy and keypad size TotalAttrs: %d < DistinctAttributes: %d", keypadSize.TotalAttrs(), nkodePolicy.DistinctAttributes))
}
if keypadSize.AttrsPerKey < nkodePolicy.DistinctSets {
return nil, errors.New(fmt.Sprintf("incompadible nkode policy and keypad size AttrPerKey: %d < DistinctSets: %d", keypadSize.AttrsPerKey, nkodePolicy.DistinctSets))
}
customerAttrs, err := NewCustomerAttributes(keypadSize)
if err != nil {
return nil, err
}
customer := Customer{
CustomerId: uuid.New(),
NKodePolicy: nkodePolicy,
Attributes: *customerAttrs,
Users: make(map[string]User),
}
return &customer, nil
}
func (c *Customer) AddNewUser(username string, passcodeIdx []int, userInterface UserInterface) error {
_, exists := c.Users[username]
if exists {
return errors.New(fmt.Sprintf("User %s already exists for customer %s exists", username, c.CustomerId.String()))
}
newKeys, err := NewUserCipherKeys(c.Attributes.KeypadSize, c.Attributes.SetVals, c.NKodePolicy.MaxNkodeLen)
if err != nil {
return err
}
encipheredNKode, err := newKeys.EncipherNKode(passcodeIdx, c.Attributes)
if err != nil {
return err
}
newUser := User{
Username: username,
EncipheredPasscode: *encipheredNKode,
UserKeys: *newKeys,
Interface: userInterface,
}
c.Users[username] = newUser
return nil
}
func (c *Customer) ValidKeyEntry(username string, selectedKeys []int) ([]int, error) {
user, exists := c.Users[username]
if !exists {
return nil, errors.New(fmt.Sprintf("user %s does not exist for customer %s", username, c.CustomerId.String()))
}
validKeys := py.All[int](selectedKeys, func(idx int) bool {
return 0 <= idx && idx < c.Attributes.KeypadSize.NumbOfKeys
})
if !validKeys {
return nil, errors.New(fmt.Sprintf("one or more keys not in range 0-%d", c.Attributes.KeypadSize.NumbOfKeys-1))
}
presumedAttrIdxVals, err := c.getPresumedAttributeIdxVals(user, selectedKeys)
if err != nil {
return nil, err
}
err = c.IsValidNKode(presumedAttrIdxVals)
if err != nil {
return nil, err
}
err = user.UserKeys.ValidPassword(user.EncipheredPasscode.Code, presumedAttrIdxVals, c.Attributes)
if err != nil {
return nil, err
}
return presumedAttrIdxVals, nil
}
func (c *Customer) getPresumedAttributeIdxVals(user User, selectedKeys []int) ([]int, error) {
passcodeLen := len(selectedKeys)
if passcodeLen < c.NKodePolicy.MinNkodeLen || passcodeLen > c.NKodePolicy.MaxNkodeLen {
return nil, errors.New(fmt.Sprintf("Invalid passcode length of %d. Passcode length must be in range %d-%d", passcodeLen, c.NKodePolicy.MinNkodeLen, c.NKodePolicy.MaxNkodeLen))
}
passcodeSetVals, err := user.DecipherMask(c.Attributes.SetVals, passcodeLen)
if err != nil {
return nil, err
}
presumedAttrIdxVals := make([]int, passcodeLen)
for idx := range presumedAttrIdxVals {
keyNumb := selectedKeys[idx]
setIdx, err := c.Attributes.IndexOfSet(passcodeSetVals[idx])
if err != nil {
return nil, err
}
selectedAttrIdx, err := user.Interface.GetAttrIdxByKeyNumbSetIdx(setIdx, keyNumb)
if err != nil {
return nil, err
}
presumedAttrIdxVals[idx] = selectedAttrIdx
}
return presumedAttrIdxVals, nil
}
func (c *Customer) IsValidNKode(passcodeAttrIdx []int) error {
nkodeLen := len(passcodeAttrIdx)
if nkodeLen < c.NKodePolicy.MinNkodeLen {
return errors.New(fmt.Sprintf("NKode length %d is too short. Minimum nKode length is %d", nkodeLen, c.NKodePolicy.MinNkodeLen))
}
validIdx := py.All[int](passcodeAttrIdx, func(i int) bool {
return i >= 0 && i < c.Attributes.KeypadSize.TotalAttrs()
})
if !validIdx {
return errors.New(fmt.Sprintf("One or more idx out of range 0-%d in IsValidNKode", c.Attributes.KeypadSize.TotalAttrs()-1))
}
passcodeSetVals := make(hashset.Set[uint64])
passcodeAttrVals := make(hashset.Set[uint64])
for idx := 0; idx < nkodeLen; idx++ {
attrVal := c.Attributes.AttrVals[passcodeAttrIdx[idx]]
setVal, err := c.Attributes.GetAttrSetVal(attrVal)
if err != nil {
return err
}
passcodeSetVals.Add(setVal)
passcodeAttrVals.Add(attrVal)
}
if passcodeSetVals.Size() < c.NKodePolicy.DistinctSets {
return errors.New(fmt.Sprintf("passcode has two few distinct sets min %d, has %d", c.NKodePolicy.DistinctSets, passcodeSetVals.Size()))
}
if passcodeAttrVals.Size() < c.NKodePolicy.DistinctAttributes {
return errors.New(fmt.Sprintf("passcode has two few distinct attributes min %d, has %d", c.NKodePolicy.DistinctAttributes, passcodeAttrVals.Size()))
}
return nil
}
func (c *Customer) GetLoginInterface(username string) ([]int, error) {
user, exists := c.Users[username]
if !exists {
return nil, errors.New(fmt.Sprintf("can't get login interface for non-existant user %s in customer %s", username, c.CustomerId.String()))
}
err := user.Interface.PartialInterfaceShuffle()
if err != nil {
return nil, err
}
c.Users[username] = user
return user.Interface.IdxInterface, nil
}
func (c *Customer) RenewKeys() error {
oldAttrs := make([]uint64, c.Attributes.KeypadSize.TotalAttrs())
oldSets := make([]uint64, c.Attributes.KeypadSize.AttrsPerKey)
copy(oldAttrs, c.Attributes.AttrVals)
copy(oldSets, c.Attributes.SetVals)
err := c.Attributes.Renew()
if err != nil {
return nil
}
attrsXor, err := util.XorLists(oldAttrs, c.Attributes.AttrVals)
if err != nil {
return nil
}
setXor, err := util.XorLists(oldSets, c.Attributes.SetVals)
if err != nil {
return nil
}
for _, user := range c.Users {
err = user.RenewKeys(setXor, attrsXor)
if err != nil {
return nil
}
}
return nil
}

View File

@@ -1,74 +0,0 @@
package api
import (
"errors"
"fmt"
"go-nkode/models"
"go-nkode/util"
)
// TODO: make generic
type CustomerAttributes struct {
AttrVals []uint64
SetVals []uint64
KeypadSize models.KeypadSize
}
func NewCustomerAttributes(keypadSize models.KeypadSize) (*CustomerAttributes, error) {
if keypadSize.IsDispersable() {
return nil, errors.New("number of keys must be less than the number of attributes per key to be dispersion resistant")
}
attrVals, errAttr := util.GenerateRandomNonRepeatingUint64(keypadSize.TotalAttrs())
if errAttr != nil {
return nil, errAttr
}
setVals, errSet := util.GenerateRandomNonRepeatingUint64(keypadSize.AttrsPerKey)
if errSet != nil {
return nil, errSet
}
customerAttrs := CustomerAttributes{
AttrVals: attrVals,
SetVals: setVals,
KeypadSize: keypadSize,
}
return &customerAttrs, nil
}
func (c *CustomerAttributes) Renew() error {
attrVals, errAttr := util.GenerateRandomNonRepeatingUint64(c.KeypadSize.TotalAttrs())
if errAttr != nil {
return errAttr
}
setVals, errSet := util.GenerateRandomNonRepeatingUint64(c.KeypadSize.AttrsPerKey)
if errSet != nil {
return errSet
}
c.AttrVals = attrVals
c.SetVals = setVals
return nil
}
func (c *CustomerAttributes) IndexOfAttr(attrVal uint64) int {
// TODO: should this be mapped instead?
return util.IndexOf[uint64](c.AttrVals, attrVal)
}
func (c *CustomerAttributes) IndexOfSet(setVal uint64) (int, error) {
// TODO: should this be mapped instead?
idx := util.IndexOf[uint64](c.SetVals, setVal)
if idx == -1 {
return -1, errors.New(fmt.Sprintf("Set Val %d is invalid", setVal))
}
return idx, nil
}
func (c *CustomerAttributes) GetAttrSetVal(attrVal uint64) (uint64, error) {
indexOfAttr := c.IndexOfAttr(attrVal)
if indexOfAttr == -1 {
return 0, errors.New(fmt.Sprintf("No attribute %d", attrVal))
}
setIdx := indexOfAttr % c.KeypadSize.AttrsPerKey
return c.SetVals[setIdx], nil
}

View File

@@ -1,51 +0,0 @@
package api
import (
"github.com/stretchr/testify/assert"
"go-nkode/models"
"testing"
)
func TestNewCustomerAttributes(t *testing.T) {
keypad := models.KeypadSize{AttrsPerKey: 10, NumbOfKeys: 5}
_, nil := NewCustomerAttributes(keypad)
assert.NoError(t, nil)
}
func TestCustomer_ValidKeyEntry(t *testing.T) {
keypadSize := models.KeypadSize{AttrsPerKey: 10, NumbOfKeys: 7}
nkodePolicy := models.NewDefaultNKodePolicy()
customer, err := NewCustomer(keypadSize, nkodePolicy)
assert.NoError(t, err)
newUserInterface, err := NewUserInterface(customer.Attributes.KeypadSize)
assert.NoError(t, err)
username := "testing123"
passcodeIdx := []int{0, 1, 2, 3}
err = customer.AddNewUser(username, passcodeIdx, *newUserInterface)
assert.NoError(t, err)
userLoginInterface, err := customer.GetLoginInterface(username)
assert.NoError(t, err)
selectedKeys, err := SelectKeyByAttrIdx(userLoginInterface, passcodeIdx, keypadSize)
assert.NoError(t, err)
validatedPasscode, err := customer.ValidKeyEntry(username, selectedKeys)
assert.NoError(t, err)
assert.Equal(t, len(validatedPasscode), len(passcodeIdx))
for idx := range validatedPasscode {
assert.Equal(t, validatedPasscode[idx], passcodeIdx[idx])
}
}
func TestCustomer_IsValidNKode(t *testing.T) {
keypadSize := models.KeypadSize{AttrsPerKey: 10, NumbOfKeys: 7}
nkodePolicy := models.NewDefaultNKodePolicy()
customer, err := NewCustomer(keypadSize, nkodePolicy)
assert.NoError(t, err)
newUserInterface, err := NewUserInterface(customer.Attributes.KeypadSize)
assert.NoError(t, err)
username := "testing123"
passcodeIdx := []int{0, 1, 2, 3}
err = customer.AddNewUser(username, passcodeIdx, *newUserInterface)
assert.NoError(t, err)
err = customer.IsValidNKode(passcodeIdx)
assert.NoError(t, err)
}

11
core/api/endpoints.go Normal file
View File

@@ -0,0 +1,11 @@
package api
const (
CreateNewCustomer = "/create-new-customer"
GenerateSignupInterface = "/generate-signup-interface"
SetNKode = "/set-nkode"
ConfirmNKode = "/confirm-nkode"
GetLoginInterface = "/get-login-interface"
Login = "/login"
RenewAttributes = "/renew-attributes"
)

View File

@@ -1,140 +0,0 @@
package api
import (
"errors"
"fmt"
"github.com/google/uuid"
"go-nkode/models"
)
type NKodeAPI struct {
Customers map[uuid.UUID]Customer
SignupSessions map[uuid.UUID]UserSignSession
}
func NewNKodeAPI() NKodeAPI {
return NKodeAPI{
Customers: make(map[uuid.UUID]Customer),
SignupSessions: make(map[uuid.UUID]UserSignSession),
}
}
func (n *NKodeAPI) CreateNewCustomer(keypadSize models.KeypadSize, nkodePolicy models.NKodePolicy) (*uuid.UUID, error) {
newCustomer, err := NewCustomer(keypadSize, nkodePolicy)
if err != nil {
return nil, err
}
n.Customers[newCustomer.CustomerId] = *newCustomer
return &newCustomer.CustomerId, nil
}
func (n *NKodeAPI) GenerateSignupInterface(customerId uuid.UUID) (*uuid.UUID, []int, error) {
customer, exists := n.Customers[customerId]
if !exists {
return nil, nil, errors.New(fmt.Sprintf("customer doesnt exists: %s", customerId.String()))
}
signupSession, err := NewSignupSession(customer.Attributes.KeypadSize, customer.CustomerId)
if err != nil {
return nil, nil, err
}
n.SignupSessions[signupSession.SessionId] = *signupSession
return &signupSession.SessionId, signupSession.SetInterface, nil
}
func (n *NKodeAPI) SetNKode(username string, customerId uuid.UUID, keySelection []int, sessionId uuid.UUID) ([]int, error) {
_, exists := n.Customers[customerId]
if !exists {
return nil, errors.New(fmt.Sprintf("set nkode customer id does not exist %s", customerId.String()))
}
session, exists := n.SignupSessions[sessionId]
if !exists {
return nil, errors.New(fmt.Sprintf("session id does not exist %s", sessionId.String()))
}
confirmInterface, err := session.SetUserNKode(username, keySelection)
if err != nil {
return nil, err
}
n.SignupSessions[sessionId] = session
return confirmInterface, nil
}
func (n *NKodeAPI) ConfirmNKode(customerId uuid.UUID, keySelection []int, sessionId uuid.UUID) error {
session, exists := n.SignupSessions[sessionId]
if !exists {
return errors.New(fmt.Sprintf("session id does not exist %s", sessionId.String()))
}
customer, exists := n.Customers[customerId]
passcode, err := session.DeducePasscode(keySelection)
if err != nil {
return err
}
err = customer.IsValidNKode(passcode)
if err != nil {
return err
}
err = customer.AddNewUser(session.Username, passcode, session.LoginInterface)
if err != nil {
return err
}
delete(n.SignupSessions, session.SessionId)
n.Customers[customerId] = customer
return nil
}
func (n *NKodeAPI) GetLoginInterface(username string, customerId uuid.UUID) ([]int, error) {
err := n.customerUserExists(username, customerId)
if err != nil {
return nil, err
}
user := n.Customers[customerId].Users[username]
err = user.Interface.PartialInterfaceShuffle()
if err != nil {
return nil, err
}
n.Customers[customerId].Users[username] = user
return user.Interface.IdxInterface, nil
}
func (n *NKodeAPI) Login(customerId uuid.UUID, username string, keySelection []int) error {
customer, exists := n.Customers[customerId]
if !exists {
return errors.New(fmt.Sprintf("customer %s does not exist", customerId.String()))
}
user, exists := customer.Users[username]
if !exists {
return errors.New(fmt.Sprintf("user dne %s", username))
}
passcode, err := customer.ValidKeyEntry(username, keySelection)
if err != nil {
return err
}
if user.Renew {
err = user.RefreshPasscode(passcode, customer.Attributes)
if err != nil {
return err
}
}
return nil
}
func (n *NKodeAPI) customerUserExists(username string, customerId uuid.UUID) error {
customer, exists := n.Customers[customerId]
if !exists {
return errors.New(fmt.Sprintf("customer %s does not exist", customerId.String()))
}
_, exists = customer.Users[username]
if !exists {
return errors.New(fmt.Sprintf("user dne %s", username))
}
return nil
}
func (n *NKodeAPI) RenewAttributes(customerId uuid.UUID) error {
customer, exists := n.Customers[customerId]
if !exists {
return errors.New(fmt.Sprintf("customer %s does not exist", customerId.String()))
}
return customer.RenewKeys()
}

View File

@@ -1,159 +0,0 @@
package api
import (
"encoding/json"
"fmt"
"github.com/google/uuid"
"go-nkode/models"
"net/http"
)
const (
CreateNewCustomer = "/create-new-customer"
GenerateSignupInterface = "/generate-signup-interface"
SetNKode = "/set-nkode"
ConfirmNKode = "/confirm-nkode"
GetLoginInterface = "/get-login-interface"
Login = "/login"
RenewAttributes = "/renew-attributes"
)
type NKodeHandler struct {
Api NKodeAPI
}
type NewCustomerPost struct {
KeypadSize models.KeypadSize `json:"keypad_size"`
NKodePolicy models.NKodePolicy `json:"nkode_policy"`
}
type GenerateSignupInterfacePost struct {
CustomerId uuid.UUID `json:"customer_id"`
}
type SetNKodePost struct {
Username string `json:"username"`
CustomerId uuid.UUID `json:"customer_id"`
KeySelection []int `json:"key_selection"`
SessionId uuid.UUID `json:"session_id"`
}
type ConfirmNKodePost struct {
CustomerId uuid.UUID `json:"customer_id"`
KeySelection []int `json:"key_selection"`
SessionId uuid.UUID `json:"session_id"`
}
type GetLoginInterfacePost struct {
Username string `json:"username"`
CustomerId uuid.UUID `json:"customer_id"`
}
type LoginPost struct {
CustomerId uuid.UUID `json:"customer_id"`
Username string `json:"username"`
KeySelection []int `json:"key_selection"`
}
type RenewAttributesPost struct {
CustomerId uuid.UUID `json:"customer_id"`
}
func (h *NKodeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case CreateNewCustomer:
h.CreateNewCustomerHandler(w, r)
return
case GenerateSignupInterface:
h.GenerateSignupInterfaceHandler(w, r)
case SetNKode:
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
h.SetNKodeHandler(w, r)
case ConfirmNKode:
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
case GetLoginInterface:
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
case Login:
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
case RenewAttributes:
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
default:
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("404 not found"))
}
}
func internalServerErrorHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 Internal Server Error"))
}
func methodNotAllowed(w http.ResponseWriter) {
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write([]byte("405 method not allowed"))
}
func (h *NKodeHandler) CreateNewCustomerHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
var customerPost NewCustomerPost
if err := json.NewDecoder(r.Body).Decode(&customerPost); err != nil {
internalServerErrorHandler(w, r)
return
}
customerId, err := h.Api.CreateNewCustomer(customerPost.KeypadSize, customerPost.NKodePolicy)
if err != nil {
internalServerErrorHandler(w, r)
return
}
data := map[string]interface{}{
"customer_id": customerId,
}
jsonBytes, err := json.Marshal(data)
w.WriteHeader(http.StatusOK)
w.Write(jsonBytes)
}
func (h *NKodeHandler) GenerateSignupInterfaceHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
var signupPost GenerateSignupInterfacePost
if err := json.NewDecoder(r.Body).Decode(&signupPost); err != nil {
internalServerErrorHandler(w, r)
return
}
fmt.Println("Customer Id: ", signupPost.CustomerId)
}
func (h *NKodeHandler) SetNKodeHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
}

View File

@@ -1,48 +0,0 @@
package api
import (
"github.com/stretchr/testify/assert"
"go-nkode/models"
"testing"
)
func TestNKodeAPI(t *testing.T) {
for idx := 0; idx < 10; idx++ {
username := "test_username"
passcodeLen := 4
nkodePolicy := models.NewDefaultNKodePolicy()
keypadSize := models.KeypadSize{AttrsPerKey: 10, NumbOfKeys: 3}
nkodeApi := NewNKodeAPI()
customerId, err := nkodeApi.CreateNewCustomer(keypadSize, nkodePolicy)
assert.NoError(t, err)
sessionId, setInterface, err := nkodeApi.GenerateSignupInterface(*customerId)
assert.NoError(t, err)
keypadSize = models.KeypadSize{AttrsPerKey: 3, NumbOfKeys: 3}
userPasscode := setInterface[:passcodeLen]
setKeySelect, err := SelectKeyByAttrIdx(setInterface, userPasscode, keypadSize)
assert.NoError(t, err)
confirmInterface, err := nkodeApi.SetNKode(username, *customerId, setKeySelect, *sessionId)
assert.NoError(t, err)
confirmKeySelect, err := SelectKeyByAttrIdx(confirmInterface, userPasscode, keypadSize)
err = nkodeApi.ConfirmNKode(*customerId, confirmKeySelect, *sessionId)
assert.NoError(t, err)
keypadSize = models.KeypadSize{AttrsPerKey: 10, NumbOfKeys: 3}
loginInterface, err := nkodeApi.GetLoginInterface(username, *customerId)
assert.NoError(t, err)
loginKeySelection, err := SelectKeyByAttrIdx(loginInterface, userPasscode, keypadSize)
assert.NoError(t, err)
err = nkodeApi.Login(*customerId, username, loginKeySelection)
assert.NoError(t, err)
err = nkodeApi.RenewAttributes(*customerId)
assert.NoError(t, err)
loginInterface, err = nkodeApi.GetLoginInterface(username, *customerId)
assert.NoError(t, err)
loginKeySelection, err = SelectKeyByAttrIdx(loginInterface, userPasscode, keypadSize)
assert.NoError(t, err)
err = nkodeApi.Login(*customerId, username, loginKeySelection)
assert.NoError(t, err)
}
}

278
core/api/nkode_handler.go Normal file
View File

@@ -0,0 +1,278 @@
package api
import (
"encoding/json"
"go-nkode/core/model"
"go-nkode/core/nkode"
"log"
"net/http"
)
type NKodeHandler struct {
Api nkode.NKodeAPI
}
func (h *NKodeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case CreateNewCustomer:
h.CreateNewCustomerHandler(w, r)
return
case GenerateSignupInterface:
h.GenerateSignupInterfaceHandler(w, r)
case SetNKode:
h.SetNKodeHandler(w, r)
case ConfirmNKode:
h.ConfirmNKodeHandler(w, r)
case GetLoginInterface:
h.GetLoginInterfaceHandler(w, r)
case Login:
h.LoginHandler(w, r)
case RenewAttributes:
h.RenewAttributesHandler(w, r)
default:
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("404 not found"))
log.Fatal(r.URL.Path, " not found")
}
}
func (h *NKodeHandler) CreateNewCustomerHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
var customerPost model.NewCustomerPost
err := decodeJson(w, r, &customerPost)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
customerId, err := h.Api.CreateNewCustomer(customerPost.KeypadSize, customerPost.NKodePolicy)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
respBody := model.CreateNewCustomerResp{
CustomerId: *customerId,
}
respBytes, err := json.Marshal(respBody)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
_, err = w.Write(respBytes)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
w.WriteHeader(http.StatusOK)
}
func (h *NKodeHandler) GenerateSignupInterfaceHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
var signupPost model.GenerateSignupInterfacePost
err := decodeJson(w, r, &signupPost)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
sessionId, userInterface, err := h.Api.GenerateSignupInterface(signupPost.CustomerId)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
respBody := model.GenerateSignupInterfaceResp{
SessionId: *sessionId,
UserInterface: userInterface,
}
respBytes, err := json.Marshal(respBody)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
_, err = w.Write(respBytes)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
w.WriteHeader(http.StatusOK)
}
func (h *NKodeHandler) SetNKodeHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
var setNKodePost model.SetNKodePost
err := decodeJson(w, r, &setNKodePost)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
confirmInterface, err := h.Api.SetNKode(setNKodePost.Username, setNKodePost.CustomerId, setNKodePost.KeySelection, setNKodePost.SessionId)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
respBody := model.SetNKodeResp{UserInterface: confirmInterface}
respBytes, err := json.Marshal(respBody)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
_, err = w.Write(respBytes)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
w.WriteHeader(http.StatusOK)
}
func (h *NKodeHandler) ConfirmNKodeHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
var confirmNKodePost model.ConfirmNKodePost
err := decodeJson(w, r, &confirmNKodePost)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
err = h.Api.ConfirmNKode(confirmNKodePost.CustomerId, confirmNKodePost.KeySelection, confirmNKodePost.SessionId)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
w.WriteHeader(http.StatusOK)
}
func (h *NKodeHandler) GetLoginInterfaceHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
var loginInterfacePost model.GetLoginInterfacePost
err := decodeJson(w, r, &loginInterfacePost)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
loginInterface, err := h.Api.GetLoginInterface(loginInterfacePost.Username, loginInterfacePost.CustomerId)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
respBody := model.GetLoginInterfaceResp{UserInterface: loginInterface}
respBytes, err := json.Marshal(respBody)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
_, err = w.Write(respBytes)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
w.WriteHeader(http.StatusOK)
}
func (h *NKodeHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
var loginPost model.LoginPost
err := decodeJson(w, r, &loginPost)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
err = h.Api.Login(loginPost.CustomerId, loginPost.Username, loginPost.KeySelection)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
w.WriteHeader(http.StatusOK)
}
func (h *NKodeHandler) RenewAttributesHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
var renewAttributesPost model.RenewAttributesPost
err := decodeJson(w, r, &renewAttributesPost)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
err = h.Api.RenewAttributes(renewAttributesPost.CustomerId)
if err != nil {
internalServerErrorHandler(w, r)
log.Fatal(err)
return
}
w.WriteHeader(http.StatusOK)
}
func decodeJson(w http.ResponseWriter, r *http.Request, post any) error {
err := json.NewDecoder(r.Body).Decode(&post)
if err != nil {
internalServerErrorHandler(w, r)
return err
}
return nil
}
func internalServerErrorHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 Internal Server Error"))
}
func methodNotAllowed(w http.ResponseWriter) {
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write([]byte("405 method not allowed"))
}

View File

@@ -1,21 +0,0 @@
package api
import (
"errors"
"fmt"
"go-nkode/models"
"go-nkode/util"
)
func SelectKeyByAttrIdx(interfaceUser []int, passcodeIdxs []int, keypadSize models.KeypadSize) ([]int, error) {
selectedKeys := make([]int, len(passcodeIdxs))
for idx := range passcodeIdxs {
attrIdx := util.IndexOf[int](interfaceUser, passcodeIdxs[idx])
keyNumb := attrIdx / keypadSize.AttrsPerKey
if keyNumb < 0 || keyNumb >= keypadSize.NumbOfKeys {
return nil, errors.New(fmt.Sprintf("index key number: %d out of range 0-%d", keyNumb, keypadSize.NumbOfKeys-1))
}
selectedKeys[idx] = keyNumb
}
return selectedKeys, nil
}

View File

@@ -1,46 +0,0 @@
package api
import (
m "go-nkode/models"
"go-nkode/util"
)
type User struct {
Username string
EncipheredPasscode m.EncipheredNKode
UserKeys UserCipherKeys
Interface UserInterface
Renew bool
}
func (u *User) DecipherMask(setVals []uint64, passcodeLen int) ([]uint64, error) {
return u.UserKeys.DecipherMask(u.EncipheredPasscode.Mask, setVals, passcodeLen)
}
func (u *User) RenewKeys(setXor []uint64, attrXor []uint64) error {
u.Renew = true
var err error
u.UserKeys.SetKey, err = util.XorLists(setXor, u.UserKeys.SetKey)
if err != nil {
return err
}
u.UserKeys.AlphaKey, err = util.XorLists(attrXor, u.UserKeys.AlphaKey)
return err
}
func (u *User) RefreshPasscode(passcodeAttrIdx []int, customerAttributes CustomerAttributes) error {
newKeys, err := NewUserCipherKeys(customerAttributes.KeypadSize, customerAttributes.SetVals, u.UserKeys.MaxNKodeLen)
if err != nil {
return err
}
encipheredPasscode, err := newKeys.EncipherNKode(passcodeAttrIdx, customerAttributes)
if err != nil {
return err
}
u.UserKeys = *newKeys
u.EncipheredPasscode = *encipheredPasscode
u.Renew = false
return nil
}

View File

@@ -1,188 +0,0 @@
package api
import (
"crypto/sha256"
"errors"
"fmt"
"go-nkode/models"
"go-nkode/util"
"golang.org/x/crypto/bcrypt"
)
type UserCipherKeys struct {
AlphaKey []uint64
SetKey []uint64
PassKey []uint64
MaskKey []uint64
Salt []byte
MaxNKodeLen int
}
func NewUserCipherKeys(keypadSize models.KeypadSize, setVals []uint64, maxNKodeLen int) (*UserCipherKeys, error) {
if len(setVals) != keypadSize.AttrsPerKey {
return nil, errors.New(fmt.Sprintf("setVals len != attrsPerKey, %d, %d", len(setVals), keypadSize.AttrsPerKey))
}
setKey, err := util.GenerateRandomNonRepeatingUint64(keypadSize.AttrsPerKey)
if err != nil {
return nil, err
}
setKey, err = util.XorLists(setKey, setVals)
if err != nil {
return nil, err
}
alphakey, _ := util.GenerateRandomNonRepeatingUint64(keypadSize.TotalAttrs())
passKey, _ := util.GenerateRandomNonRepeatingUint64(maxNKodeLen)
maskKey, _ := util.GenerateRandomNonRepeatingUint64(maxNKodeLen)
salt, _ := util.RandomBytes(10)
userCipherKeys := UserCipherKeys{
AlphaKey: alphakey,
PassKey: passKey,
MaskKey: maskKey,
SetKey: setKey,
Salt: salt,
MaxNKodeLen: maxNKodeLen,
}
return &userCipherKeys, nil
}
func (u *UserCipherKeys) PadUserMask(userMask []uint64, setVals []uint64) ([]uint64, error) {
if len(userMask) > u.MaxNKodeLen {
return nil, errors.New("user mask length exceeds max nkode length")
}
paddedUserMask := make([]uint64, len(userMask))
copy(paddedUserMask, userMask)
for i := len(userMask); i < u.MaxNKodeLen; i++ {
paddedUserMask = append(paddedUserMask, setVals[i%len(setVals)])
}
return paddedUserMask, nil
}
func (u *UserCipherKeys) ValidPassword(hashedPassword string, passcodeAttrIdx []int, customerAttrs CustomerAttributes) error {
hashBytes := []byte(hashedPassword)
passcodeCipher := u.encipherCode(passcodeAttrIdx, customerAttrs)
passwordDigest, err := u.saltAndDigest(passcodeCipher)
if err != nil {
return err
}
err = bcrypt.CompareHashAndPassword(hashBytes, passwordDigest)
if err != nil {
return err
}
return nil
}
func (u *UserCipherKeys) EncipherSaltHashCode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (string, error) {
passcodeCipher := u.encipherCode(passcodeAttrIdx, customerAttrs)
passcodeDigest, err := u.saltAndDigest(passcodeCipher)
if err != nil {
return "", err
}
passcodeBytes, err := u.hashPasscode(passcodeDigest)
if err != nil {
return "", err
}
return string(passcodeBytes), nil
}
func (u *UserCipherKeys) encipherCode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) []uint64 {
passcodeLen := len(passcodeAttrIdx)
passcodeCipher := make([]uint64, u.MaxNKodeLen)
for idx := 0; idx < passcodeLen; idx++ {
attrIdx := passcodeAttrIdx[idx]
alpha := u.AlphaKey[attrIdx]
attrVal := customerAttrs.AttrVals[idx]
pass := u.PassKey[idx]
passcodeCipher[idx] = alpha ^ pass ^ attrVal
}
return passcodeCipher
}
func (u *UserCipherKeys) saltAndDigest(passcode []uint64) ([]byte, error) {
passcodeBytes := util.Uint64ArrToByteArr(passcode)
passcodeBytes = append(passcodeBytes, u.Salt...)
h := sha256.New()
passcodeSha, err := h.Write(passcodeBytes)
if err != nil {
return nil, err
}
passcodeDigest := uint64(passcodeSha)
return util.Uint64ArrToByteArr([]uint64{passcodeDigest}), nil
}
func (u *UserCipherKeys) hashPasscode(passcodeDigest []byte) ([]byte, error) {
hashedPassword, err := bcrypt.GenerateFromPassword(passcodeDigest, bcrypt.DefaultCost)
if err != nil {
return nil, err
}
return hashedPassword, nil
}
func (u *UserCipherKeys) EncipherMask(passcodeSet []uint64, customerAttrs CustomerAttributes) (string, error) {
paddedPasscodeSets, err := u.PadUserMask(passcodeSet, customerAttrs.SetVals)
if err != nil {
return "", err
}
cipheredMask := make([]uint64, len(paddedPasscodeSets))
for idx := range paddedPasscodeSets {
setIdx, err := customerAttrs.IndexOfSet(paddedPasscodeSets[idx])
if err != nil {
return "", err
}
setKeyVal := u.SetKey[setIdx]
maskKeyVal := u.MaskKey[idx]
setVal := paddedPasscodeSets[idx]
cipheredMask[idx] = setKeyVal ^ maskKeyVal ^ setVal
}
mask := util.EncodeBase64Str(cipheredMask)
return mask, nil
}
func (u *UserCipherKeys) DecipherMask(mask string, setVals []uint64, passcodeLen int) ([]uint64, error) {
decodedMask, err := util.DecodeBase64Str(mask)
if err != nil {
return nil, err
}
decipheredMask, err := util.XorLists(decodedMask, u.MaskKey)
if err != nil {
return nil, err
}
setKeyRandComponent, err := util.XorLists(setVals, u.SetKey)
if err != nil {
return nil, err
}
passcodeSet := make([]uint64, passcodeLen)
for idx, setCipher := range decipheredMask[:passcodeLen] {
setIdx := util.IndexOf(setKeyRandComponent, setCipher)
passcodeSet[idx] = setVals[setIdx]
}
return passcodeSet, nil
}
func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (*models.EncipheredNKode, error) {
code, err := u.EncipherSaltHashCode(passcodeAttrIdx, customerAttrs)
if err != nil {
return nil, err
}
passcodeSet := make([]uint64, len(passcodeAttrIdx))
for idx := range passcodeSet {
passcodeAttr := customerAttrs.AttrVals[passcodeAttrIdx[idx]]
passcodeSet[idx], err = customerAttrs.GetAttrSetVal(passcodeAttr)
if err != nil {
return nil, err
}
}
mask, err := u.EncipherMask(passcodeSet, customerAttrs)
encipheredCode := models.EncipheredNKode{
Code: code,
Mask: mask,
}
return &encipheredCode, nil
}

View File

@@ -1,192 +0,0 @@
package api
import (
"errors"
"fmt"
"go-nkode/hashset"
"go-nkode/models"
"go-nkode/util"
)
type UserInterface struct {
IdxInterface []int
KeypadSize models.KeypadSize
}
func NewUserInterface(keypadSize models.KeypadSize) (*UserInterface, error) {
idxInterface := util.IdentityArray(keypadSize.TotalAttrs())
userInterface := UserInterface{
IdxInterface: idxInterface,
KeypadSize: keypadSize,
}
err := userInterface.RandomShuffle()
if err != nil {
return nil, err
}
return &userInterface, nil
}
func (u *UserInterface) RandomShuffle() error {
err := u.shuffleKeys()
keypadView, err := u.InterfaceMatrix()
if err != nil {
return err
}
setView, err := util.MatrixTranspose(keypadView)
if err != nil {
return err
}
for idx, set := range setView {
err := util.FisherYatesShuffle(&set)
if err != nil {
return nil
}
setView[idx] = set
}
keypadView, err = util.MatrixTranspose(setView)
if err != nil {
return err
}
u.IdxInterface = util.MatrixToList(keypadView)
return nil
}
func (u *UserInterface) InterfaceMatrix() ([][]int, error) {
return util.ListToMatrix(u.IdxInterface, u.KeypadSize.AttrsPerKey)
}
func (u *UserInterface) SetViewMatrix() ([][]int, error) {
keypadView, err := u.InterfaceMatrix()
if err != nil {
return nil, err
}
return util.MatrixTranspose(keypadView)
}
func (u *UserInterface) DisperseInterface() error {
if !u.KeypadSize.IsDispersable() {
return errors.New("interface is not dispersable")
}
err := u.shuffleKeys()
if err != nil {
return err
}
err = u.randomAttributeRotation()
if err != nil {
return err
}
return nil
}
func (u *UserInterface) shuffleKeys() error {
userInterfaceMatrix, err := util.ListToMatrix(u.IdxInterface, u.KeypadSize.AttrsPerKey)
if err != nil {
return err
}
err = util.FisherYatesShuffle[[]int](&userInterfaceMatrix)
if err != nil {
return err
}
u.IdxInterface = util.MatrixToList(userInterfaceMatrix)
return nil
}
func (u *UserInterface) randomAttributeRotation() error {
userInterface, err := u.InterfaceMatrix()
if err != nil {
return err
}
transposeUserInterface, err := util.MatrixTranspose(userInterface)
attrRotation, err := util.RandomPermutation(len(transposeUserInterface))
if err != nil {
return err
}
for idx, attrSet := range transposeUserInterface {
rotation := attrRotation[idx]
transposeUserInterface[idx] = append(attrSet[rotation:], attrSet[:rotation]...)
}
userInterface, err = util.MatrixTranspose(transposeUserInterface)
if err != nil {
return err
}
u.IdxInterface = util.MatrixToList(userInterface)
return nil
}
func (u *UserInterface) AttributeAdjacencyGraph() (map[int]hashset.Set[int], error) {
interfaceKeypad, err := u.InterfaceMatrix()
if err != nil {
return nil, err
}
graph := make(map[int]hashset.Set[int])
for _, key := range interfaceKeypad {
keySet := hashset.NewSetFromSlice(key)
for _, attr := range key {
attrAdjacency := keySet.Copy()
attrAdjacency.Remove(attr)
graph[attr] = attrAdjacency
}
}
return graph, nil
}
func (u *UserInterface) PartialInterfaceShuffle() error {
err := u.shuffleKeys()
if err != nil {
return err
}
numbOfSelectedSets := u.KeypadSize.AttrsPerKey / 2
if u.KeypadSize.AttrsPerKey&1 == 1 {
numbOfSelectedSets += util.Choice[int]([]int{0, 1})
}
setIdxs, err := util.RandomPermutation(u.KeypadSize.AttrsPerKey)
if err != nil {
return err
}
selectedSets := hashset.NewSetFromSlice[int](setIdxs[:numbOfSelectedSets])
keypadSetView, err := u.SetViewMatrix()
if err != nil {
return err
}
interfaceBySet := make([][]int, u.KeypadSize.AttrsPerKey)
for idx, attrs := range keypadSetView {
if selectedSets.Contains(idx) {
err = util.FisherYatesShuffle[int](&attrs)
if err != nil {
return err
}
}
interfaceBySet[idx] = attrs
}
keypadView, err := util.MatrixTranspose(interfaceBySet)
if err != nil {
return err
}
u.IdxInterface = util.MatrixToList(keypadView)
return nil
}
func (u *UserInterface) GetAttrIdxByKeyNumbSetIdx(setIdx int, keyNumb int) (int, error) {
if keyNumb < 0 || u.KeypadSize.NumbOfKeys <= keyNumb {
return -1, errors.New(fmt.Sprintf("keyNumb %d is out of range 0-%d", keyNumb, u.KeypadSize.NumbOfKeys))
}
if setIdx < 0 || u.KeypadSize.AttrsPerKey <= setIdx {
return -1, errors.New(fmt.Sprintf("setIdx %d is out of range 0-%d", setIdx, u.KeypadSize.AttrsPerKey))
}
keypadView, err := u.InterfaceMatrix()
if err != nil {
return -1, err
}
return keypadView[keyNumb][setIdx], nil
}

View File

@@ -1,164 +0,0 @@
package api
import (
"errors"
"fmt"
"github.com/google/uuid"
"go-nkode/hashset"
"go-nkode/models"
py_builtin "go-nkode/py-builtin"
"go-nkode/util"
)
type UserSignSession struct {
SessionId uuid.UUID
CustomerId uuid.UUID
LoginInterface UserInterface
KeypadSize models.KeypadSize
SetInterface []int
ConfirmInterface []int
SetKeyEntry []int
Username string
}
func NewSignupSession(keypadSize models.KeypadSize, customerId uuid.UUID) (*UserSignSession, error) {
loginInterface, err := NewUserInterface(keypadSize)
if err != nil {
return nil, err
}
signupInter, err := signupInterface(*loginInterface)
session := UserSignSession{
SessionId: uuid.New(),
CustomerId: customerId,
LoginInterface: *loginInterface,
SetInterface: signupInter.IdxInterface,
ConfirmInterface: nil,
SetKeyEntry: nil,
Username: "",
KeypadSize: signupInter.KeypadSize,
}
return &session, nil
}
func (s *UserSignSession) DeducePasscode(confirmKeyEntry []int) ([]int, error) {
validEntry := py_builtin.All[int](confirmKeyEntry, func(i int) bool {
return 0 <= i && i < s.LoginInterface.KeypadSize.NumbOfKeys
})
if !validEntry {
return nil, errors.New(fmt.Sprintf("Invalid Key entry. One or more key index: %#v, not in range 0-%d", confirmKeyEntry, s.LoginInterface.KeypadSize.NumbOfKeys))
}
if s.SetInterface == nil {
return nil, errors.New("signup session set interface is nil")
}
if s.ConfirmInterface == nil {
return nil, errors.New("signup session confirm interface is nil")
}
if s.SetKeyEntry == nil {
return nil, errors.New("signup session set key entry is nil")
}
if s.Username == "" {
return nil, errors.New("signup session username is nil")
}
if len(confirmKeyEntry) != len(s.SetKeyEntry) {
return nil, errors.New(fmt.Sprintf("confirm and set key entry lenght mismatch %d != %d", len(confirmKeyEntry), len(s.SetKeyEntry)))
}
passcodeLen := len(confirmKeyEntry)
setKeyVals, err := s.getSelectedKeyVals(s.SetKeyEntry, s.SetInterface)
if err != nil {
return nil, err
}
confirmKeyVals, err := s.getSelectedKeyVals(confirmKeyEntry, s.ConfirmInterface)
passcode := make([]int, passcodeLen)
for idx := 0; idx < passcodeLen; idx++ {
setKey := hashset.NewSetFromSlice[int](setKeyVals[idx])
confirmKey := hashset.NewSetFromSlice[int](confirmKeyVals[idx])
intersection := setKey.Intersect(confirmKey)
if intersection.Size() < 1 {
return nil, errors.New(fmt.Sprintf("set and confirm do not intersect at index %d", idx))
}
if intersection.Size() > 1 {
return nil, errors.New(fmt.Sprintf("set and confirm intersect at more than one point at index %d", idx))
}
intersectionSlice := intersection.ToSlice()
passcode[idx] = intersectionSlice[0]
}
return passcode, nil
}
func (s *UserSignSession) SetUserNKode(username string, keySelection []int) ([]int, error) {
validKeySelection := py_builtin.All[int](keySelection, func(i int) bool {
return 0 <= i && i < s.KeypadSize.NumbOfKeys
})
if !validKeySelection {
return nil, errors.New(fmt.Sprintf("one or key selection is out of range 0-%d", s.KeypadSize.NumbOfKeys-1))
}
s.SetKeyEntry = keySelection
s.Username = username
setInterface := UserInterface{IdxInterface: s.SetInterface, KeypadSize: s.KeypadSize}
err := setInterface.DisperseInterface()
if err != nil {
return nil, err
}
s.ConfirmInterface = setInterface.IdxInterface
return s.ConfirmInterface, nil
}
func (s *UserSignSession) getSelectedKeyVals(keySelections []int, userInterface []int) ([][]int, error) {
keypadInterface, err := util.ListToMatrix(userInterface, s.KeypadSize.AttrsPerKey)
if err != nil {
return nil, err
}
keyVals := make([][]int, len(keySelections))
for idx, keyIdx := range keySelections {
keyVals[idx] = keypadInterface[keyIdx]
}
return keyVals, nil
}
func signupInterface(baseUserInterface UserInterface) (*UserInterface, error) {
if baseUserInterface.KeypadSize.IsDispersable() {
return nil, errors.New("keypad is dispersable, can't use signupInterface")
}
err := baseUserInterface.RandomShuffle()
if err != nil {
return nil, err
}
interfaceMatrix, err := baseUserInterface.InterfaceMatrix()
if err != nil {
return nil, err
}
attrSetView, err := util.MatrixTranspose(interfaceMatrix)
if err != nil {
return nil, err
}
err = util.FisherYatesShuffle[[]int](&attrSetView)
if err != nil {
return nil, err
}
numbOfKeys := baseUserInterface.KeypadSize.NumbOfKeys
attrSetView = attrSetView[:numbOfKeys]
attrSetView, err = util.MatrixTranspose(attrSetView)
if err != nil {
return nil, err
}
signupUserInterface := UserInterface{
IdxInterface: util.MatrixToList(attrSetView),
KeypadSize: models.KeypadSize{
AttrsPerKey: numbOfKeys,
NumbOfKeys: numbOfKeys,
},
}
return &signupUserInterface, nil
}

View File

@@ -1,119 +0,0 @@
package api
import (
"github.com/stretchr/testify/assert"
"go-nkode/models"
py_builtin "go-nkode/py-builtin"
"testing"
)
func TestUserCipherKeys_EncipherSaltHashCode(t *testing.T) {
keypadSize := models.KeypadSize{AttrsPerKey: 10, NumbOfKeys: 5}
maxNKodeLen := 10
customerAttrs, err := NewCustomerAttributes(keypadSize)
assert.NoError(t, err)
newUser, err := NewUserCipherKeys(keypadSize, customerAttrs.SetVals, maxNKodeLen)
assert.NoError(t, err)
passcodeIdx := []int{0, 1, 2, 3}
encipher0, err := newUser.EncipherSaltHashCode(passcodeIdx, *customerAttrs)
assert.NoError(t, err)
err = newUser.ValidPassword(encipher0, passcodeIdx, *customerAttrs)
assert.NoError(t, err)
}
func TestUserCipherKeys_EncipherDecipherMask(t *testing.T) {
keypadSize := models.KeypadSize{AttrsPerKey: 10, NumbOfKeys: 5}
maxNKodeLen := 10
customerAttrs, err := NewCustomerAttributes(keypadSize)
assert.NoError(t, err)
newUser, err := NewUserCipherKeys(keypadSize, customerAttrs.SetVals, maxNKodeLen)
assert.NoError(t, err)
passcodeIdx := []int{0, 1, 2, 3}
originalSetVals := make([]uint64, len(passcodeIdx))
for idx, val := range passcodeIdx {
attr := customerAttrs.AttrVals[val]
originalSetVals[idx], err = customerAttrs.GetAttrSetVal(attr)
assert.NoError(t, err)
}
encipheredCode, err := newUser.EncipherNKode(passcodeIdx, *customerAttrs)
assert.NoError(t, err)
passcodeSetVals, err := newUser.DecipherMask(encipheredCode.Mask, customerAttrs.SetVals, len(passcodeIdx))
assert.NoError(t, err)
for idx, setVal := range passcodeSetVals {
assert.Equal(t, setVal, originalSetVals[idx])
}
}
func TestUserInterface_RandomShuffle(t *testing.T) {
keypadSize := models.KeypadSize{
AttrsPerKey: 10,
NumbOfKeys: 5,
}
userInterface, err := NewUserInterface(keypadSize)
assert.NoError(t, err)
userInterfaceCopy := make([]int, len(userInterface.IdxInterface))
copy(userInterfaceCopy, userInterface.IdxInterface)
err = userInterface.RandomShuffle()
assert.NoError(t, err)
assert.Equal(t, len(userInterface.IdxInterface), len(userInterfaceCopy))
equalCount := 0
for idx, val := range userInterface.IdxInterface {
if val == userInterfaceCopy[idx] {
equalCount++
}
}
assert.NotEqual(t, equalCount, len(userInterface.IdxInterface))
}
func TestUserInterface_DisperseInterface(t *testing.T) {
for idx := 0; idx < 10000; idx++ {
keypadSize := models.KeypadSize{AttrsPerKey: 7, NumbOfKeys: 10}
userInterface, err := NewUserInterface(keypadSize)
assert.NoError(t, err)
preDispersion, err := userInterface.AttributeAdjacencyGraph()
assert.NoError(t, err)
err = userInterface.DisperseInterface()
assert.NoError(t, err)
postDispersion, err := userInterface.AttributeAdjacencyGraph()
assert.Equal(t, len(postDispersion), len(preDispersion))
for attr, adjAttrs := range preDispersion {
postAdjAttrs := postDispersion[attr]
assert.Equal(t, adjAttrs.Size(), postAdjAttrs.Size())
assert.True(t, adjAttrs.IsDisjoint(postAdjAttrs))
}
}
}
func TestUserInterface_PartialInterfaceShuffle(t *testing.T) {
keypadSize := models.KeypadSize{AttrsPerKey: 7, NumbOfKeys: 10}
userInterface, err := NewUserInterface(keypadSize)
assert.NoError(t, err)
preShuffle := userInterface.IdxInterface
err = userInterface.PartialInterfaceShuffle()
assert.NoError(t, err)
postShuffle := userInterface.IdxInterface
shuffleCompare := make([]bool, len(postShuffle))
for idx, val := range preShuffle {
shuffleCompare[idx] = val == postShuffle[idx]
}
allTrue := py_builtin.All[bool](shuffleCompare, func(n bool) bool {
return n == true
})
assert.False(t, allTrue)
allFalse := py_builtin.All[bool](shuffleCompare, func(n bool) bool {
return n == false
})
assert.False(t, allFalse)
}