diff --git a/Python/AnyankaKeys.py b/Python/AnyankaKeys.py new file mode 100644 index 0000000..2ad6e31 --- /dev/null +++ b/Python/AnyankaKeys.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from typing import Any, Self, Callable, Optional, TypeVar, Iterable +from time import time +from re import compile as re_compile, Pattern as RePattern, I as RE_IgnoreCase + +T = TypeVar("T", int, float, str, bytes) + +class AnyankaKeys: + + __slots__:tuple[str] = ( + '__alphabet', '__dictionary', '__private_key', '__private_key_l', + '__multiplier', '__primes', '__primes_l', '__multiplier_jumps', + '__multiplier_jump', '__base', '__encrypt_i', '__password', '__password_l' + ) + + ALPHABET:tuple[str] = tuple("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") + PRIVATE_KEY:tuple[int] = tuple(range(1, 0x100)) + MULTIPLIER:int = 1 + MULTIPLIER_JUMPS:int = 3 + MULTIPLIER_JUMP:int = 7 + PRIMES:tuple[int] = ( + 0x3FFFFFFB, 0x3FFFFF29, 0x3FFFFF0B, + 0x2FFFFFFF, 0x2FFFFF5B, 0x1FFFFFFF, + 0x279DB13D, 0x279DB113, + 0x2AAAAAAB, 0x1555556B, 0x27D4EB2F, 0x165667B1, + 0x1000007F, 0x3B9ACA07, 0x01000193, 0x1EADBEEF, 0x0AFEBABE, 0x0BADC0DE, 0x3B9AC9C1, 0x1D295C4D, 0x990BF9F, 0x1CFAA2DB, + 0xDEADBEEF, 0xCAFEBABF, 0xBAADF00D + ) + + RE_KEY:RePattern = re_compile(r'^[a-z_][a-z0-9_]*$', RE_IgnoreCase) + + def __init__(self:Self, inputs:Optional[dict[str, Any|None]] = None) -> None: + + self.__alphabet:tuple[str] = tuple(self.unique(self.get_value("alphabet", inputs, self.ALPHABET))) + self.__dictionary:dict[str, int] = {value : index for index, value in enumerate(self.__alphabet)} + self.__private_key:tuple[int] = tuple(self.get_value("private_key", inputs, self.PRIVATE_KEY)) + self.__private_key_l:int = len(self.__private_key) + self.__multiplier:int = self.get_value("multiplier", inputs, self.MULTIPLIER) + self.__primes:tuple[int] = tuple(self.get_value("primes", inputs, self.PRIMES)) + self.__primes_l:int = len(self.__primes) + self.__multiplier_jumps:int = self.get_value("multiplier_jumps", inputs, self.MULTIPLIER_JUMPS) + self.__multiplier_jump:int = self.get_value("multiplier_jump", inputs, self.MULTIPLIER_JUMP) + l:int = len(self.__alphabet) + self.__base:int = self.get_value("base", inputs, l) + self.__encrypt_i:int = 0 + self.__password:tuple[int] = (0,) + self.__password_l:int = 1 + + self.set_password(self.get_value("password", inputs, "")) + + if self.__base > l: + self.__base = l + + def set_password(self:Self, password:str) -> None: + + if password: + + password_changed:list[int] = [] + + self.change_base(password, self.__base, input_handler = ord, output_handler = password_changed.append) + self.__password = tuple(password_changed) + + else: + self.__password = (0,) + + self.__password_l = len(self.__password) + + def __get_multiplier(self:Self, i:int) -> int: + + value:int = (i + self.__multiplier + self.__primes[ + i := (i + self.__multiplier_jump) % self.__primes_l + ]) & 0x3FFFFFFF + + for _ in range(self.__multiplier_jumps): + + shift:int = 13 + i % 8 + + value = ((value ^ ( + value >> shift if i & 1 else value << shift + )) + self.__primes[ + i := (i + self.__multiplier_jump) % self.__primes_l + ]) & 0x3FFFFFFF + + return value + + def encrypt(self:Self, data:str) -> str: + + i:int = self.__get_multiplier(self.__encrypt_i + len(data) + int(time() % 1 * 1000)) % self.__base + summatory:str = self.__alphabet[i] + encrypted:list[str] = [] + + self.__encrypt_i += i + i -= 1 + + def output_handler(value:int) -> None: + nonlocal encrypted, i + + multiplier:int = self.__get_multiplier(i := i + 1) + + encrypted.append(self.__alphabet[(multiplier + value + self.__private_key[ + multiplier // self.__base % self.__private_key_l + ] + self.__password[multiplier % self.__password_l]) % self.__base]) + + self.change_base(data, self.__base, 0x100, + input_handler = ord, + output_handler = output_handler + ) + + return summatory + "".join(reversed(encrypted)) + + def decrypt(self:Self, data:str) -> str: + + i:int = len(data[1:]) + self.__dictionary[data[0]] + decrypted:list[str] = [] + + def output_handler(value:int) -> None: + nonlocal decrypted + decrypted.append(chr(value)) + + def input_handler(value:str) -> int: + nonlocal i + + multiplier:int = self.__get_multiplier(i := i - 1) + + return (self.__dictionary[value] - self.__private_key[ + multiplier // self.__base % self.__private_key_l + ] - multiplier - self.__password[multiplier % self.__password_l]) % self.__base + + self.change_base(data[1:], 0x100, self.__base, + input_handler = input_handler, + output_handler = output_handler + ) + + return "".join(reversed(decrypted)) + + @classmethod + def get_keys(cls:type[Self], *inputs:Iterable[Any|None]) -> list[str]: + + keys:list[str] = [] + + for item in inputs: + if isinstance(item, str): + cls.RE_KEY.match(item) and item in keys or keys.append(item) + elif isinstance(item, (list, tuple)): + keys.extend(cls.get_keys(*item)) + + return keys + + @classmethod + def get_dictionaries(cls:type[Self], *inputs:Iterable[Any|None]) -> list[dict[str, Any|None]]: + + dictionaries:list[dict[str, Any|None]] = [] + + for item in inputs: + if isinstance(item, dict): + dictionaries.append(item) + elif isinstance(item, (list, tuple)): + dictionaries.extend(cls.get_dictionaries(*item)) + + return dictionaries + + @classmethod + def get_value( + cls:type[Self], + keys:str|list[str]|tuple[str, ...], + inputs:dict[str, Any|None]|Iterable[Any|None], + default:Optional[Any] = None + ) -> Any|None: + if len(keys := cls.get_keys(keys)): + for dictionary in cls.get_dictionaries(inputs): + for key in keys: + if key in dictionary: + return dictionary[key] + return default + + @staticmethod + def unique(items:Iterable[Any|None]) -> list[Any|None]: + return list(dict.fromkeys(items)) + + @staticmethod + def change_base( + data:Iterable[T], + to_base:int, + from_base:int = 0x100, + input_handler:Optional[Callable[[T], int]] = None, + output_handler:Optional[Callable[[int], None]] = None + ) -> None: + + stack:int = 0 + value:int + has:bool = False + + if input_handler is None:input_handler = lambda value:value + if output_handler is None:output_handler = lambda value:value + + for value in data: + stack = stack * from_base + input_handler(value) + while stack >= to_base: + has = True + stack, value = divmod(stack, to_base) + output_handler(value) + + (not has or stack) and output_handler(stack) \ No newline at end of file diff --git a/Python/gemini.01.benchmark.py b/Python/gemini.01.benchmark.py new file mode 100644 index 0000000..26295a4 --- /dev/null +++ b/Python/gemini.01.benchmark.py @@ -0,0 +1,81 @@ +import timeit +import secrets +import math + +primes = (0x3FFFFFFB, 0x3FFFFF29, 0x3FFFFF0B, 0x2FFFFFFF, 0x2FFFFF5B) + +# --- Lógica Actual (Bucle) --- +def get_multiplier_current(i, multiplier, primes, p_len, jumps, jump): + value = (i + multiplier + primes[(i + jump) % p_len]) & 0x3FFFFFFF + for _ in range(jumps): + shift = 13 + i % 8 + if i & 1: + value ^= (value >> shift) + else: + value ^= (value << shift) + value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF + return value + +# --- Lógica Optimizada (Unrolled) --- +def get_multiplier_fast(i, multiplier, primes, p_len, jump): + # Asumiendo que jumps siempre es 3 + value = (i + multiplier + primes[(i + jump) % p_len]) & 0x3FFFFFFF + + # Salto 1 + shift = 13 + i % 8 + value ^= (value >> shift if i & 1 else value << shift) + value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF + + # Salto 2 + shift = 13 + i % 8 + value ^= (value >> shift if i & 1 else value << shift) + value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF + + # Salto 3 + shift = 13 + i % 8 + value ^= (value >> shift if i & 1 else value << shift) + value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF + + return value + +# --- 2. Lógica con While --- +def get_multiplier_while(i, multiplier, primes, p_len, jumps, jump): + value = (i + multiplier + primes[(i + jump) % p_len]) & 0x3FFFFFFF + count = 0 + while count < jumps: + shift = 13 + i % 8 + if i & 1: + value ^= (value >> shift) + else: + value ^= (value << shift) + value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF + count += 1 + return value + +def get_multiplier_callback(multiplier, primes, p_len, jumps, jump, i = 0): + value = ((value ^ ( + value >> shift if i & 1 else value << shift + )) + self.__primes[ + i := (i + self.__multiplier_jump) % self.__primes_l + ]) & 0x3FFFFFFF + +# --- Configuración del Test --- +primes = (0x3FFFFFFB, 0x3FFFFF29, 0x3FFFFF0B, 0x2FFFFFFF, 0x2FFFFF5B) +setup_code = """ +from __main__ import get_multiplier_current, get_multiplier_fast, primes +import secrets +""" + +# Ejecución de 1 millón de iteraciones +n = 1_000_000 + +t_current = timeit.timeit(lambda: get_multiplier_current(5, 1, primes, 5, 3, 7), setup=setup_code, number=n) +t_fast = timeit.timeit(lambda: get_multiplier_fast(5, 1, primes, 5, 7), setup=setup_code, number=n) +t_secrets = timeit.timeit(lambda: secrets.token_bytes(4), setup=setup_code, number=n) +t_while = timeit.timeit(lambda: get_multiplier_while(5, 1, primes, 5, 3, 7), setup=setup_code, number=n) + +print(f"--- Resultados ({n} iteraciones) ---") +print(f"Anyanka (Bucle): {t_current:.4f} seg") +print(f"Anyanka (Unrolled): {t_fast:.4f} seg") +print(f"Secrets (Cripto): {t_secrets:.4f} seg") +print(f"Anyanka (While): {t_while:.4f} seg") \ No newline at end of file diff --git a/Python/test.py b/Python/test.py new file mode 100644 index 0000000..193c507 --- /dev/null +++ b/Python/test.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from AnyankaKeys import AnyankaKeys + +class Tests: + + @staticmethod + def change_base() -> None: + + for prueba in [ + [1, 2, 3], + [2, 5, 5], + [3, 2], + [0] + ]: + + ncripted:list[int] = [] + decripted:list[int] = [] + + def ncript(value:int) -> None: + ncripted.insert(0, value) + # ncripted.append(value) + + def decript(value:int) -> None: + decripted.insert(0, value) + # decripted.append(value) + + AnyankaKeys.change_base(prueba, 2, 16, None, ncript) + AnyankaKeys.change_base(ncripted, 16, 2, None, decript) + + print(["O", prueba]) + # print(["A", AnyankaKeys.to_base(prueba, 16, 10, lambda value:print(["C", value]))]) + # print(["B", list(AnyankaKeys.to_base_old(prueba, 16, 10))]) + print(["A", ncripted]) + print(["B", decripted]) + + @staticmethod + def basic_encript() -> None: + + anyanka:AnyankaKeys = AnyankaKeys({ + "password": "MiContraseñaSecreta123!@#", + }) + + for prueba in [ + "Hola Mundo", + "Hola Mundo", + "Iola Mundo", + "Hola Mundo1", + "AnyankaKeys", + "1234567890", + "!@#$%^&*()_+-=[]{}|;':\",./<>?" + ]: + encrypted:str = anyanka.encrypt(prueba) + decrypted:str = anyanka.decrypt(encrypted) + + print(["O", prueba]) + print(["A", encrypted]) + print(["B", decrypted]) + + @staticmethod + def get_hexadecimal() -> None: + print(["0x" + hex(value)[2:].upper() for value in ( + # -- Grupo 1: Constantes de Dispersión Máxima (Golden/Silver Ratios) -- + 2654435761, # 0x9E3779B1 (Knuth's Golden Ratio Prime) + 1865882353, # Cerca de 2^32 / sqrt(5) + 3339476533, # Alta entropía + + # -- Grupo 2: Primos "Sucios" (Mezcla perfecta de 0s y 1s) -- + # Estos números parecen ruido estático en binario. + 32416190071 & 0xFFFFFFFF, # (Nota: Ajustado a 32 bits si copias de 64) -> Usamos estos directos: + 2246822519, # Primo cercano a Murmur constant + 3266489917, + 668265263, + 374761393, + + # -- Grupo 3: Primos Grandes (Cercanos al límite de 32-bit signed) -- + 2147483647, # 2^31 - 1 (Mersenne Prime - Clásico) + 2147483629, # Un poco menos que el máximo + 2147483587, + + # -- Grupo 4: Primos de "Grano Fino" (Para variedad en rangos medios) -- + 160481183, + 486187739, + 999999937, # El primo más grande menor de mil millones + 1000000007 + )]) + +# Tests.change_base() +Tests.basic_encript() +# Tests.get_hexadecimal() \ No newline at end of file diff --git a/version b/version index 35e6837..e8f89e5 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.0.3.1 \ No newline at end of file +0.0.4.1 \ No newline at end of file