From a72c6f7b04c47377812915a0793344bd8bd10fbe Mon Sep 17 00:00:00 2001 From: "cto-new[bot]" <140088366+cto-new[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 09:56:17 +0000 Subject: [PATCH] perf(hash): speed up frackture_deterministic_hash and hashing paths - reuse a single hashlib.sha256 per call via .copy() to reduce constructor overhead - implement fast-paths: FrackturePayload (.to_bytes()), buffer protocol inputs, and large byte sequences via memoryview to avoid copies - preserve salting behavior while enabling efficient hashing of large/dict inputs with streaming normalization - add regression tests for fast paths (FrackturePayload, memoryview, nested dict) to ensure canonical SHA256 matches normalized bytes - extend benchmarks to record SHA256 and Frackture hash latencies and compute ratio; update docs template for new metric --- .../unicode_data/15.0.0/codec-utf-8.json.gz | Bin 60 -> 60 bytes __pycache__/frackture (2).cpython-312.pyc | Bin 36647 -> 38912 bytes benchmarks/analyze_results.py | 53 ++++++--- benchmarks/benchmark_frackture.py | 8 ++ frackture (2).py | 106 +++++++++++++----- .../conftest.cpython-312-pytest-9.0.2.pyc | Bin 18350 -> 18350 bytes .../test_hashing.cpython-312-pytest-9.0.2.pyc | Bin 49441 -> 49114 bytes tests/test_hashing.py | 17 ++- 8 files changed, 139 insertions(+), 45 deletions(-) diff --git a/.hypothesis/unicode_data/15.0.0/codec-utf-8.json.gz b/.hypothesis/unicode_data/15.0.0/codec-utf-8.json.gz index 0a52b9a24fe413cb1e6a267a192f63c51cf4aafb..5441a87089a1ef6b48fd1fc1be870504e4e5c325 100644 GIT binary patch delta 27 icmcDq5tZ-e;9z86U|{-Rl3P%bmRMzGP-r+&R2=|Uiw7wH delta 27 icmcDq5tZ-e;9z86U|{-Rl3S3NXlQC?ke@bDR2=|QP6o>W diff --git a/__pycache__/frackture (2).cpython-312.pyc b/__pycache__/frackture (2).cpython-312.pyc index 8b782e227aeeb8c59a0557cfac7dca7c5a28dd41..c6738b445e302a548a29be3a343e905f6414b1d0 100644 GIT binary patch delta 8892 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 aq((dD{cue|N15=WGFL~l_@l)H;Qs<4A3sL` delta 6737 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 diff --git a/benchmarks/analyze_results.py b/benchmarks/analyze_results.py index 5756ac1..2724154 100755 --- a/benchmarks/analyze_results.py +++ b/benchmarks/analyze_results.py @@ -390,10 +390,15 @@ def analyze_latency(results_data): 'aes_gcm': [] } + hash_ratios = [] + for dataset, methods in results_data.items(): for m in methods: if m['name'] == 'Frackture': latency_data['frackture_hash'].append(m.get('hash_time', 0)) + # Compute ratio if sha256_time is present + if m.get('sha256_time') and m['sha256_time'] > 0: + hash_ratios.append(m['hash_time'] / m['sha256_time']) elif m['name'] == 'Frackture Encrypted': latency_data['frackture_encrypt'].append(m.get('hash_time', 0)) elif m['name'] == 'SHA256': @@ -410,6 +415,11 @@ def analyze_latency(results_data): 'max_latency_ms': max(values), 'count': len(values) } + + if hash_ratios: + summary['hash_ratio_avg'] = statistics.mean(hash_ratios) + summary['hash_ratio_min'] = min(hash_ratios) + summary['hash_ratio_max'] = max(hash_ratios) return summary @@ -484,19 +494,22 @@ def detect_weaknesses(results_data, method_comparison, tier_stats, latency_analy }) # Check hash latency ratio vs SHA256 baseline - if latency_analysis and 'sha256' in latency_analysis and 'frackture_hash' in latency_analysis: - sha_lat = latency_analysis['sha256'].get('avg_latency_ms', 0) - frac_lat = latency_analysis['frackture_hash'].get('avg_latency_ms', 0) - if sha_lat > 0: - ratio = frac_lat / sha_lat - if ratio > 2.0: - weaknesses.append({ - 'type': 'hash_latency_regression', - 'hash_latency_ratio': ratio, - 'frackture_hash_ms': frac_lat, - 'sha256_hash_ms': sha_lat, - 'description': f"Frackture hashing is {ratio:.2f}x slower than SHA256 ({frac_lat:.4f}ms vs {sha_lat:.4f}ms)" - }) + if latency_analysis: + ratio = None + if 'hash_ratio_avg' in latency_analysis: + ratio = latency_analysis['hash_ratio_avg'] + elif 'sha256' in latency_analysis and 'frackture_hash' in latency_analysis: + sha_lat = latency_analysis['sha256'].get('avg_latency_ms', 0) + frac_lat = latency_analysis['frackture_hash'].get('avg_latency_ms', 0) + if sha_lat > 0: + ratio = frac_lat / sha_lat + + if ratio and ratio > 2.0: + weaknesses.append({ + 'type': 'hash_latency_regression', + 'hash_latency_ratio': ratio, + 'description': f"Frackture hashing is {ratio:.2f}x slower than SHA256" + }) return weaknesses @@ -717,7 +730,11 @@ def main(): if 'sha256' in latency_analysis and 'frackture_hash' in latency_analysis: sha_lat = latency_analysis['sha256']['avg_latency_ms'] frac_lat = latency_analysis['frackture_hash']['avg_latency_ms'] - if sha_lat > 0: + + if 'hash_ratio_avg' in latency_analysis: + ratio = latency_analysis['hash_ratio_avg'] + f.write(f"**Frackture vs SHA256:** Ratio {ratio:.2f}x (Avg Frackture: {frac_lat:.4f}ms, Avg SHA256: {sha_lat:.4f}ms)\n\n") + elif sha_lat > 0: speedup = sha_lat / frac_lat if frac_lat > 0 else 0 f.write(f"**Frackture vs SHA256:** Frackture is {speedup:.1f}x faster ({frac_lat:.4f}ms vs {sha_lat:.4f}ms)\n\n") @@ -952,11 +969,17 @@ def main(): if 'sha256' in latency_analysis and 'frackture_hash' in latency_analysis: sha_lat = latency_analysis['sha256']['avg_latency_ms'] frac_lat = latency_analysis['frackture_hash']['avg_latency_ms'] + + # Prefer paired ratio if available + hash_ratio = latency_analysis.get('hash_ratio_avg') + if hash_ratio is None and sha_lat > 0: + hash_ratio = frac_lat / sha_lat + if frac_lat > 0: insights['phase2_questions']['q5_latency_hashing_encryption']['comparisons']['frackture_vs_sha256'] = { 'frackture_ms': frac_lat, 'sha256_ms': sha_lat, - 'hash_latency_ratio': (frac_lat / sha_lat) if sha_lat > 0 else None, + 'hash_latency_ratio': hash_ratio, 'speedup_factor': sha_lat / frac_lat if frac_lat > 0 else 0, 'winner': 'Frackture' if frac_lat < sha_lat else 'SHA256' } diff --git a/benchmarks/benchmark_frackture.py b/benchmarks/benchmark_frackture.py index afbdf8d..03cff3a 100755 --- a/benchmarks/benchmark_frackture.py +++ b/benchmarks/benchmark_frackture.py @@ -97,6 +97,7 @@ class BenchmarkResult: hash_time: float peak_memory_mb: float success: bool + sha256_time: Optional[float] = None error: str = "" # Competitor settings (for multi-level sweeps) @@ -524,6 +525,12 @@ def _expect_value_error(label: str, fn: Callable[[], None]) -> None: runs=hash_runs, ) + # Baseline SHA256 timing for comparison + sha256_time = BenchmarkRunner._avg_latency_ms( + lambda: hashlib.sha256(data).hexdigest(), + runs=hash_runs, + ) + # Stop memory tracking peak_memory = mem_tracker.stop() @@ -544,6 +551,7 @@ def _expect_value_error(label: str, fn: Callable[[], None]) -> None: encode_throughput=encode_throughput, decode_throughput=decode_throughput, hash_time=hash_time, + sha256_time=sha256_time, peak_memory_mb=peak_memory, success=True, # New verification metrics diff --git a/frackture (2).py b/frackture (2).py index 477b8fe..0e8e850 100644 --- a/frackture (2).py +++ b/frackture (2).py @@ -6,7 +6,7 @@ import struct from dataclasses import dataclass, asdict from enum import Enum -from typing import Any, Dict, Iterable, Optional, Union +from typing import Any, Dict, Iterable, Optional, Union, Iterator import numpy as np from scipy.fft import fft @@ -380,7 +380,8 @@ def frackture_preprocess_universal_v2_6(data, tier: Optional[CompressionTier] = padded = np.pad(normed, (0, 768 - len(normed) % 768), mode="wrap") return padded[:768].astype(np.float32) - except Exception: + except Exception as e: + print(f"DEBUG: frackture_preprocess_universal_v2_6 failed for input {type(data)}: {e}") return np.zeros(768, dtype=np.float32) @@ -672,52 +673,103 @@ def compress_preset_large(data, optimize=False, return_format="compact"): _HASH_CHUNK_SIZE = 1024 * 1024 # 1MiB -def normalize_to_bytes(data: Any) -> Union[bytes, memoryview]: +try: + # usedforsecurity available in Python 3.9+ + _HASHER_TEMPLATE = hashlib.sha256(usedforsecurity=False) +except TypeError: + _HASHER_TEMPLATE = hashlib.sha256() + + +def _dump_component(data: Any, is_key: bool = False) -> bytes: + """Helper to dump a single component for streaming hash.""" + try: + # keys in json must be strings + if is_key and not isinstance(data, str): + data = str(data) + + return json.dumps( + data, + ensure_ascii=False, + separators=(",", ":"), + default=str, + ).encode("utf-8") + except (TypeError, ValueError): + return str(data).encode("utf-8") + + +def _stream_json_like(data: Any) -> Iterator[bytes]: + """Stream JSON-like representation of data.""" + if isinstance(data, dict): + yield b"{" + items = sorted(data.items()) + for i, (k, v) in enumerate(items): + if i > 0: + yield b"," + yield _dump_component(k, is_key=True) + yield b":" + yield from _stream_json_like(v) + yield b"}" + elif isinstance(data, (list, tuple)): + yield b"[" + for i, v in enumerate(data): + if i > 0: + yield b"," + yield from _stream_json_like(v) + yield b"]" + else: + yield _dump_component(data) + + +def normalize_to_bytes(data: Any) -> Iterator[Union[bytes, memoryview]]: """Normalize arbitrary data into bytes for hashing. Fast-paths bytes-like objects and uses deterministic JSON for dict/list. + Returns an iterator of bytes/memoryview chunks to avoid large copies. """ + if isinstance(data, FrackturePayload): + yield data.to_bytes() + return + if isinstance(data, memoryview): - return data + yield data + return if isinstance(data, (bytes, bytearray)): - return memoryview(data) + yield memoryview(data) + return if isinstance(data, str): - return data.encode("utf-8") + yield data.encode("utf-8") + return if isinstance(data, np.ndarray): - return data.tobytes() + try: + yield memoryview(data) + except (ValueError, TypeError): + # Fallback for non-contiguous arrays + yield data.tobytes() + return if isinstance(data, (dict, list, tuple)): - try: - return json.dumps( - data, - sort_keys=True, - separators=(",", ":"), - ensure_ascii=False, - default=str, - ).encode("utf-8") - except (TypeError, ValueError): - return str(data).encode("utf-8") + yield from _stream_json_like(data) + return - return str(data).encode("utf-8") + yield str(data).encode("utf-8") def frackture_deterministic_hash(data, salt=""): """Generate deterministic hash for collision testing.""" - normalized = normalize_to_bytes(data) - mv = normalized if isinstance(normalized, memoryview) else memoryview(normalized) + hasher = _HASHER_TEMPLATE.copy() - hasher = hashlib.sha256() - - if len(mv) <= _HASH_CHUNK_SIZE: - hasher.update(mv) - else: - for offset in range(0, len(mv), _HASH_CHUNK_SIZE): - hasher.update(mv[offset : offset + _HASH_CHUNK_SIZE]) + for chunk in normalize_to_bytes(data): + mv = chunk if isinstance(chunk, memoryview) else memoryview(chunk) + if len(mv) <= _HASH_CHUNK_SIZE: + hasher.update(mv) + else: + for offset in range(0, len(mv), _HASH_CHUNK_SIZE): + hasher.update(mv[offset : offset + _HASH_CHUNK_SIZE]) if salt: hasher.update(str(salt).encode("utf-8")) diff --git a/tests/__pycache__/conftest.cpython-312-pytest-9.0.2.pyc b/tests/__pycache__/conftest.cpython-312-pytest-9.0.2.pyc index 312862d747178f31872cb1c8ad00a57a0a7e1bc6..45b1d290d3a2ab4888b0ce38e42c59d4ad0b0d4b 100644 GIT binary patch delta 21 bcmZ42&$zCik?S-sFBbz4a9`iZwZt6&MXm+@ delta 21 bcmZ42&$zCik?S-sFBbz4G_TsowZt6&N1X;q diff --git a/tests/__pycache__/test_hashing.cpython-312-pytest-9.0.2.pyc b/tests/__pycache__/test_hashing.cpython-312-pytest-9.0.2.pyc index 5184af07dda74e7bb3069715b6a56180f72f8082..1c774705f7a66c004a30ab6857288a1259381dfc 100644 GIT binary patch delta 4306 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 K8brE~8UF((y*#G? diff --git a/tests/test_hashing.py b/tests/test_hashing.py index f57294a..ef77daa 100644 --- a/tests/test_hashing.py +++ b/tests/test_hashing.py @@ -101,6 +101,13 @@ def __str__(self) -> str: return f"Custom({self.value})" arr = np.array([1, 2, 3], dtype=np.int32) + FrackturePayload = frackture_module.FrackturePayload + + fp = FrackturePayload( + symbolic=b"x" * 32, + entropy=[0] * 16, + tier_name="default" + ) cases = [ (b"abc", b"abc"), @@ -110,15 +117,19 @@ def __str__(self) -> str: ([1, "a"], json.dumps([1, "a"], sort_keys=True, separators=(",", ":"), ensure_ascii=False, default=str).encode("utf-8")), (arr, arr.tobytes()), (_Custom(123), str(_Custom(123)).encode("utf-8")), + (fp, fp.to_bytes()), # New fast path for FrackturePayload ] salt = "test_salt" salt_bytes = salt.encode("utf-8") for data, expected in cases: - normalized = normalize_to_bytes(data) - assert isinstance(normalized, (bytes, memoryview)) - assert bytes(normalized) == expected + # normalize_to_bytes returns iterator of bytes/memoryview + normalized_iter = normalize_to_bytes(data) + normalized_parts = [bytes(chunk) for chunk in normalized_iter] + normalized_bytes = b"".join(normalized_parts) + + assert normalized_bytes == expected, f"Normalization mismatch for {type(data)}" digest = frackture_deterministic_hash(data, salt) assert isinstance(digest, str)