Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .hypothesis/unicode_data/15.0.0/codec-utf-8.json.gz
Binary file not shown.
Binary file modified __pycache__/frackture (2).cpython-312.pyc
Binary file not shown.
53 changes: 38 additions & 15 deletions benchmarks/analyze_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand All @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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")

Expand Down Expand Up @@ -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'
}
Expand Down
8 changes: 8 additions & 0 deletions benchmarks/benchmark_frackture.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()

Expand All @@ -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
Expand Down
106 changes: 79 additions & 27 deletions frackture (2).py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)


Expand Down Expand Up @@ -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"))
Expand Down
Binary file modified tests/__pycache__/conftest.cpython-312-pytest-9.0.2.pyc
Binary file not shown.
Binary file modified tests/__pycache__/test_hashing.cpython-312-pytest-9.0.2.pyc
Binary file not shown.
17 changes: 14 additions & 3 deletions tests/test_hashing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand All @@ -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)
Expand Down