from typing import ClassVar from pydantic import BaseModel, model_validator from src.models import KeypadSize from src.utils import generate_random_nonrepeating_list class CustomerAttributes(BaseModel): attr_vals: list[int] set_vals: list[int] keypad_size: KeypadSize MAX_KEYS: ClassVar[int] = 256 MAX_ATTRS_PER_KEY: ClassVar[int] = 256 @model_validator(mode='after') def check_keys_vs_attrs(self) -> 'CustomerAttributes': if self.keypad_size.is_dispersable: raise ValueError("number of keys must be less than the number of " "attributes per key to be dispersion resistant") return self @classmethod def create(cls, keypad_size: KeypadSize) -> 'CustomerAttributes': if keypad_size.numb_of_keys > cls.MAX_KEYS or keypad_size.attrs_per_key > cls.MAX_ATTRS_PER_KEY: raise ValueError(f"Keys and attributes per key must not exceed {cls.MAX_KEYS}") return cls( 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(self): 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.keypad_size.attrs_per_key return self.set_vals[set_idx] def get_set_index(self, set_val: int) -> int: if set_val not in self.set_vals: raise ValueError(f"Set value {set_val} not found in set values") return self.set_vals.index(set_val)