Skip to content

Commit b88ada8

Browse files
Enhance kha256 with quantum random bytes support
Updated version to 0.3.7 and added quantum random byte generation functionality.
1 parent df3ca0b commit b88ada8

1 file changed

Lines changed: 199 additions & 11 deletions

File tree

kha256/kha256.py

Lines changed: 199 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,23 @@
2222
# pip install -U bcrypt kececinumbers blake3 pycryptodome xxhash argon2-cffi pandas numpy cryptography ipywidgets ipython scipy
2323
# conda install -c conda-forge kececinumbers bcrypt blake3 pycryptodome xxhash argon2-cffi pandas numpy cryptography pandas ipywidgets ipython scipy
2424
# pip install xxhash: # xxh32 collision riski yüksek (64-bit için ~yüz milyonlarda %0.03)
25+
26+
* 0.3.7. qKHA256: quantum random
27+
2528
"""
2629

2730
from __future__ import annotations
2831

2932
import argon2 # pip install argon2-cffi # conda install conda-forge::argon2-cffi
3033
import bcrypt
3134
from blake3 import blake3
35+
from collections import defaultdict
36+
from contextlib import contextmanager
37+
from dataclasses import dataclass
38+
from datetime import datetime
39+
from decimal import getcontext
40+
from functools import lru_cache
41+
from hmac import compare_digest # , compare_digicmp
3242
from Crypto.Cipher import ChaCha20 # pip install -U pycryptodome # conda install conda-forge::pycryptodome
3343
from Crypto.Hash import SHAKE256
3444
from cryptography.hazmat.primitives import hashes
@@ -49,6 +59,7 @@
4959
import platform
5060
import random
5161
import re
62+
import requests
5263
from scipy.stats import chi2, norm
5364
import secrets
5465
import sqlite3
@@ -59,17 +70,13 @@
5970
import time
6071
import traceback
6172
import uuid
62-
from collections import defaultdict
63-
from contextlib import contextmanager
64-
from dataclasses import dataclass
65-
from datetime import datetime
66-
from decimal import getcontext
67-
from functools import lru_cache
68-
from hmac import compare_digest # , compare_digicmp
6973
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, List, Literal, NamedTuple, Optional, overload, Tuple, Union, cast
7074
# pip install xxhash: # xxh32 collision riski yüksek (64-bit için ~yüzmilyonlarda %0.03)
7175
import xxhash
7276

77+
from . import __version__ # paket __init__.py'de tanımlı
78+
79+
7380

7481

7582
def silent_kn():
@@ -248,7 +255,7 @@ def is_jupyter():
248255
from . import __version__
249256
except ImportError:
250257
# Dosya doğrudan çalıştırıldığında (Örn: python kha256.py) fallback
251-
__version__ = "0.2.9"
258+
__version__ = "0.3.7"
252259

253260

254261
# Version information
@@ -257,7 +264,7 @@ def is_jupyter():
257264
__license__ = "AGPL-3.0-or-later"
258265
__status__ = "Pre-Production"
259266
__certificate__ = "KHA256-PA-2025-001"
260-
req_kececinumbers = "1.0.1"
267+
req_kececinumbers = "1.0.5"
261268

262269
# KeçeciNumbers check - made API compatible
263270
KHA_AVAILABLE = True
@@ -1444,7 +1451,8 @@ class KHA256:
14441451
def __init__(self):
14451452
self._salt_length = 32
14461453
self._metrics = {"hash_count": 0, "total_time_ms": 0.0, "memory_hard_count": 0}
1447-
self._version = "2.5.0"
1454+
#self._version = "0.3.7"
1455+
self._version = __version__ # __init__.py'den al
14481456

14491457
def hash(
14501458
self,
@@ -1542,9 +1550,189 @@ def version(self) -> str:
15421550
def metrics(self) -> Dict[str, Any]:
15431551
return self._metrics.copy()
15441552

1553+
def get_quantum_bytes(length: int, verbose: bool = False) -> Tuple[bytes, str]:
1554+
"""
1555+
ANU kuantum rastgele sayı API'sinden 'length' byte üretir.
1556+
Ham uint16 değerlerini big-endian 2 byte olarak birleştirir.
1557+
"""
1558+
CHUNK_SIZE = 1000 # API maksimum 1000 öğe döner
1559+
needed_u16 = (length + 1) // 2 # kaç uint16 gerektiği
1560+
all_bytes = bytearray()
1561+
1562+
for i in range(0, needed_u16, CHUNK_SIZE):
1563+
chunk = min(CHUNK_SIZE, needed_u16 - i)
1564+
url = f"https://qrng.anu.edu.au/API/jsonI.php?length={chunk}&type=uint16"
1565+
try:
1566+
resp = requests.get(url, timeout=15)
1567+
if resp.status_code == 200:
1568+
data = resp.json().get("data", [])
1569+
if len(data) >= chunk:
1570+
for val in data[:chunk]:
1571+
all_bytes.extend(val.to_bytes(2, 'big'))
1572+
if verbose:
1573+
print(f"✅ Kuantum API: {len(data[:chunk])*2} byte alındı")
1574+
else:
1575+
if verbose:
1576+
print("⚠️ API yetersiz veri döndü, fallback'e geçiliyor.")
1577+
return _fallback_bytes(length, verbose), "fallback"
1578+
else:
1579+
if verbose:
1580+
print(f"⚠️ API hatası {resp.status_code}")
1581+
return _fallback_bytes(length, verbose), "fallback"
1582+
except Exception as e:
1583+
if verbose:
1584+
print(f"⚠️ API bağlantı hatası: {e}")
1585+
return _fallback_bytes(length, verbose), "fallback"
1586+
1587+
# Tam olarak length byte döndür (fazlalık varsa kes)
1588+
return bytes(all_bytes[:length]), "api"
1589+
1590+
def _fallback_bytes(length: int, verbose: bool = False) -> bytes:
1591+
if verbose:
1592+
print("↳ secrets.token_bytes ile devam ediliyor.")
1593+
return secrets.token_bytes(length)
1594+
1595+
class qKHA256:
1596+
"""
1597+
qKHA-256 - Quantum KHA-256
1598+
==========================================
1599+
✓ Hiçbir standart hash'ten kod alınmamıştır
1600+
✓ Tüm sabitler matematiksel irrasyonellerden üretilmiştir
1601+
✓ Perfect avalanche hedefi: 128.00/128.00
1602+
✓ HMAC desteği
1603+
✓ real quantum random
1604+
==========================================
1605+
"""
1606+
1607+
__slots__ = ("_salt_length", "_metrics", "_version")
1608+
1609+
def __init__(self):
1610+
self._salt_length = 32
1611+
self._metrics = {"hash_count": 0, "total_time_ms": 0.0, "memory_hard_count": 0}
1612+
self._version = __version__ # __init__.py'den al
1613+
1614+
def _generate_salt(self, quantum: bool = True, verbose: bool = False) -> bytes:
1615+
"""Kuantum (varsa) ya da sistem random ile salt üret."""
1616+
if quantum:
1617+
salt_bytes, source = get_quantum_bytes(self._salt_length, verbose=verbose)
1618+
if source == "api":
1619+
return salt_bytes
1620+
# fallback olmuşsa da döner, yukarıda fallback zaten secrets ile yapılıyor
1621+
# quantum False ise ya da üretim başarısız olup fallback döndüyse
1622+
return secrets.token_bytes(self._salt_length)
1623+
1624+
def hash(
1625+
self,
1626+
data: Union[str, bytes],
1627+
salt: Optional[bytes] = None,
1628+
*,
1629+
deterministic: bool = False,
1630+
memory_hard: bool = False,
1631+
memory_mb: int = 1,
1632+
quantum: bool = True, # yeni parametre
1633+
verbose: bool = False # kuantum API durumunu görmek için
1634+
) -> str:
1635+
start = time.perf_counter()
1636+
data_bytes = data.encode("utf-8") if isinstance(data, str) else data
1637+
1638+
if deterministic:
1639+
if salt is None:
1640+
raise ValueError("Deterministic modda salt gerekli!")
1641+
result = DeterministicHash.hash(data_bytes + salt).hex()
1642+
self._update_metrics(start)
1643+
return result
1644+
1645+
if memory_hard:
1646+
if salt is None:
1647+
salt = self._generate_salt(quantum=quantum, verbose=verbose)
1648+
result = MemoryHardHash(memory_mb).hash(data_bytes, salt)
1649+
self._update_metrics(start)
1650+
self._metrics["memory_hard_count"] += 1
1651+
return result
1652+
1653+
if salt is None:
1654+
salt = self._generate_salt(quantum=quantum, verbose=verbose)
1655+
1656+
# Pre-processing
1657+
prepared = bytearray(data_bytes)
1658+
for i in range(len(prepared)):
1659+
prepared[i] ^= salt[i % len(salt)]
1660+
prepared[i] = KHAUtils.rotl8(prepared[i], ROT_PRE)
1661+
prepared[i] ^= (i * int(PI)) & 0xFF
1662+
1663+
result = CoreHash.hash(bytes(prepared), salt)
1664+
1665+
final = bytearray(result)
1666+
for i in range(len(final)):
1667+
final[i] ^= salt[i % len(salt)]
1668+
final[i] ^= data_bytes[i % len(data_bytes)]
1669+
final[i] = KHAUtils.rotl8(final[i], ROT_POST)
1670+
final[i] ^= TransformFunctions.chaos(i) & 0xFF
1671+
1672+
self._update_metrics(start)
1673+
return bytes(final).hex()
1674+
1675+
def hmac(self, key: bytes, message: Union[str, bytes]) -> str:
1676+
"""
1677+
KHA-256 HMAC (Hash-based Message Authentication Code)
1678+
"""
1679+
msg_bytes = message.encode("utf-8") if isinstance(message, str) else message
1680+
1681+
# Key padding - HMAC standardı
1682+
if len(key) > 64:
1683+
key = DeterministicHash.hash(key)
1684+
if len(key) < 64:
1685+
key = key + b"\x00" * (64 - len(key))
1686+
1687+
# HMAC: hash(o_key_pad || hash(i_key_pad || message))
1688+
o_key_pad = bytes(x ^ 0x5C for x in key[:64])
1689+
i_key_pad = bytes(x ^ 0x36 for x in key[:64])
1690+
1691+
# Deterministic mod kullan (salt yok)
1692+
inner_hash = self.hash(i_key_pad + msg_bytes, b"", deterministic=True)
1693+
outer_hash = self.hash(
1694+
o_key_pad + bytes.fromhex(inner_hash), b"", deterministic=True
1695+
)
1696+
1697+
return outer_hash
1698+
1699+
def verify(
1700+
self, data: Union[str, bytes], hash_str: str, salt: bytes, **kwargs
1701+
) -> bool:
1702+
"""Hash doğrulama"""
1703+
computed = self.hash(data, salt, **kwargs)
1704+
return compare_digest(computed.encode(), hash_str.encode())
1705+
1706+
def _update_metrics(self, start: float):
1707+
elapsed = (time.perf_counter() - start) * 1000
1708+
self._metrics["hash_count"] += 1
1709+
self._metrics["total_time_ms"] += elapsed
1710+
1711+
@property
1712+
def version(self) -> str:
1713+
return self._version
1714+
1715+
@property
1716+
def metrics(self) -> Dict[str, Any]:
1717+
return self._metrics.copy()
1718+
1719+
## 3. Kullanım örneği
1720+
qhasher = qKHA256()
1721+
1722+
# Kuantum salt ile hash (varsayılan)
1723+
h1 = qhasher.hash("merhaba dünya", verbose=True)
1724+
1725+
# Klasik güvenli random ile hash
1726+
h2 = qhasher.hash("merhaba dünya", quantum=False)
1727+
1728+
# Doğrulama
1729+
salt = secrets.token_bytes(32)
1730+
h3 = qhasher.hash("veri", salt=salt, quantum=True)
1731+
assert qhasher.verify("veri", h3, salt, quantum=True)
1732+
15451733

15461734
# ============================================================================
1547-
# 8. STREAMING HASH SINIFI - KESİN ÇÖZÜM (ARTIK ÇALIŞIYOR!)
1735+
# 8. STREAMING HASH SINIFI
15481736
# ============================================================================
15491737

15501738

0 commit comments

Comments
 (0)