48 KiB
ADVERSARIAL CODE REVIEW: SilverSight Project
Severity-Ranked Findings Report
Classification: HOSTILE — Assume Every Module Fundamentally Broken
EXECUTIVE SUMMARY
| Metric | Count |
|---|---|
| CRITICAL | 11 |
| HIGH | 18 |
| MEDIUM | 27 |
| LOW | 15 |
| TOTAL | 71 |
Test Coverage: ~23% — The most critical code paths (chaos_game.py sidon_guided_chaos_game, q16_canonical.py arithmetic, hachimoji_citation.py SQL construction, WGSL shaders, JS WebGPU code) have zero test coverage. Tests only cover dna_codec (basic), dna_lut (monotone property), dna_nn (Tm correlation), and q16_canonical (roundtrip). No tests exist for integration_sprint.py, chaos_game.py, pist_braid_bridge.py, sidon_address.py, any WGSL shader, any HTML5/JS, or any QUBO solver.
TOP 3 CODE VULNERABILITIES THAT COULD CRASH PRODUCTION
CRASH-1: SQL Injection via String Concatenation in hachimoji_citation.py
File: python/hachimoji_citation.py, lines 246-262, 320-335
Severity: CRITICAL
Impact: Remote code execution, data exfiltration, full database compromise
Root Cause: User-provided equation strings are directly concatenated into SQL queries without any escaping beyond naive replace("'", "''").
# Line 242: "full_query_esc = full_query.replace("'", "''")" — this is NOT sufficient
cite_equation("'; DROP TABLE arxiv_papers; --") # Injected SQL will execute
PoC:
cite_equation("1=1'; DROP TABLE arxiv_papers; SELECT '1") # Table dropped
Countermeasure: Use parameterized queries exclusively. Never build SQL via string concatenation.
CRASH-2: subprocess.run() with Shell=False but Untrusted Input in hachimoji_citation.py
File: python/hachimoji_citation.py, lines 167-172
Severity: CRITICAL
Impact: Command injection via equation string through psql() helper
def psql(sql: str, timeout: int = 30) -> tuple[str, str]:
r = subprocess.run(
['podman', 'exec', 'arxiv-pg', 'psql', '-U', 'postgres', '-d', 'arxiv', '-t', '-A', '-c', sql],
capture_output=True, text=True, timeout=timeout,
)
While subprocess.run uses a list (safe from shell injection), the SQL content sql comes from user input and is passed directly to psql -c. An attacker can craft sql to execute arbitrary PostgreSQL commands, including COPY TO '/tmp/exfil', \! rm -rf /, and lateral movement.
CRASH-3: Memory Exhaustion / OOM via Unbounded Enumeration in Multiple Files
Files: python/dna_qubo_sort.py:123, python/dna_lut.py:196, python/dna_gpu.py:118, python/dna_radix_gpu.py:274
Severity: CRITICAL
Impact: System crash via memory exhaustion when n_vars > 20
# dna_gpu.py:118
for i in range(n): # n = 2 ** n_vars
x = [(i >> j) & 1 for j in range(n_vars)]
energy = qubo_energy(x, Q)
When n_vars=30, this allocates 2^30 * ~8 bytes * 30 ≈ 256 GB of memory. No guard exists. The code in dna_radix_gpu.py has a guard (n_vars <= 20) but it only applies to brute force — the else branch for sampling also allocates n_samples * n_vars without checking available RAM.
TOP 3 NUMERICAL BUGS THAT SILENTLY PRODUCE WRONG RESULTS
NUM-1: q16_mul() and q16_div() Use Floating-Point Division for "Canonical" Fixed-Point
File: python/q16_canonical.py, lines 136-144, 161-167
Severity: CRITICAL
def q16_mul(a: int, b: int) -> int:
prod_64 = a * b
scaled = prod_64 / Q16_SCALE # FLOAT division — loses precision!
rounded = round(scaled) # Banker's rounding on float
return max(Q16_MIN_RAW, min(Q16_MAX_RAW, rounded))
Problem: The docstring claims "Uses 64-bit intermediate, then applies banker's rounding." But prod_64 / Q16_SCALE converts to Python float (IEEE 754 double, 53-bit mantissa) which cannot exactly represent all 64-bit integers. For large a * b products, this silently loses precision before rounding.
PoC:
a = 2_000_000_000 # Large Q16 value
b = 2_000_000_000
# a*b = 4e18, which exceeds 53-bit mantissa precision (~9e15)
# The float division rounds silently, producing wrong result
Correct implementation: Use integer-only arithmetic: round(prod_64 / Q16_SCALE) should be ((prod_64 << 1) + Q16_SCALE) // (2 * Q16_SCALE) for true banker's rounding on integers.
NUM-2: Spearman Rank Correlation Formula is WRONG (Non-Integer Division in Denominator)
Files: python/dna_qubo_sort.py:197-199, python/dna_lut.py:152-153, python/dna_qubo_nn.py:348-349
Severity: HIGH
# dna_lut.py:153
corr = 1.0 - (6.0 * d_sq) / (n * (n * n - 1))
Problem: In Python 3, (6.0 * d_sq) / (n * (n * n - 1)) uses float division. For large n (e.g., n=65536 for full 16-bit enumeration), n * (n * n - 1) overflows to float imprecision. The formula also silently returns wrong results when n=1 (returns 0.0 instead of NaN).
Impact: The monotone verification verify_monotone() may report corr=1.0 when the correlation is actually degraded.
NUM-3: ESP32 Power Iteration Uses Integer Overflow-Prone Norm Computation
File: python/multimode_engine.py, lines 484-493
Severity: HIGH
v_norm = max(1, int(math.sqrt(sum(x * x for x in v_fp))))
v_fp = [(x << self.Q) // v_norm for x in v_fp]
Problem: sum(x * x for x in v_fp) — for Q16.16 values, x can be up to ~2 billion. x * x = ~4e18, and summing n=50 such values gives ~2e20, which exceeds Python's 64-bit safe range and causes silent precision loss in math.sqrt. The norm is then wrong, and the entire fixed-point power iteration converges to garbage.
CRITICAL SEVERITY FINDINGS
C-4: integration_sprint.py Has Duplicate __main__ Block
File: python/integration_sprint.py, lines 573-586
Severity: CRITICAL
if __name__ == "__main__": # Line 573
result = run_sprint()
...
if __name__ == "__main__": # Line 580 — DUPLICATE
result = run_sprint()
...
Impact: Running the script writes sprint_receipt.json twice, creating a race condition if another process reads between writes. Also causes confusing behavior in import contexts.
C-5: decode_qubo_solution() Assumes Fixed Energy Header Size Without Validation
File: python/dna_codec.py, lines 317-349
Severity: CRITICAL
def decode_qubo_solution(sequence: str, n_vars: int, bits_per_var: int = 3) -> Tuple[List[int], float]:
energy_dna, solution_dna = parts # Split on "|"
energy_bytes = decode_dna_to_bytes(energy_dna)
energy_q16 = q16_from_bytes(energy_bytes[:4]) # Assumes >= 4 bytes
Problem: If energy_dna decodes to fewer than 4 bytes, energy_bytes[:4] silently takes fewer bytes, and q16_from_bytes raises struct.error on short input. No validation of energy_bytes length.
C-6: encode_qubo_solution() Has Circular Import Risk
File: python/dna_codec.py, lines 301-314
Severity: CRITICAL
def encode_qubo_solution(...):
from q16_canonical import float_to_q16, q16_to_bytes, q16_from_bytes # Local import
Problem: Local import inside function is a code smell. If q16_canonical.py ever imports from dna_codec.py, this creates a circular import that only manifests at runtime when this specific function is called.
C-7: spectral_profile.py — 256x256 Co-occurrence Matrix Allocation Per Call
File: python/spectral_profile.py, lines 56-58
Severity: CRITICAL (Denial of Service)
C = [[0] * 256 for _ in range(256)] # 65,536 integers per call
Problem: Allocates a 256x256 matrix on every call. For a web service processing equations, an attacker sending many requests causes memory exhaustion. No input length limit — "A" * 10_000_000 will allocate 65K integers AND iterate 10M times.
C-8: run_sprint() Never Tests n > 20 Due to Hardcoded n_values = [20]
File: python/integration_sprint.py, lines 468-472
Severity: CRITICAL (False Confidence)
def run_sprint(n_values: List[int] = None, seed: int = 42) -> Dict[str, Any]:
if n_values is None:
n_values = [20] # ONLY tests n=20!
Problem: The docstring claims testing for n ∈ {20, 50, 100, 500, 1000}, but the default only tests n=20. All modes agree trivially at n=20. The code paths for n=500/1000 (sparse eigendecomposition, memory management, OOM handling) are never exercised by default.
C-9: struct.unpack('<i', ...) in q16_from_bytes Does Not Validate Length
File: python/q16_canonical.py, lines 188-190
Severity: CRITICAL
def q16_from_bytes(raw_bytes: bytes) -> int:
return struct.unpack('<i', raw_bytes)[0] # Crashes if len(raw_bytes) != 4
PoC: q16_from_bytes(b'\x00\x00') raises struct.error: unpack requires a buffer of 4 bytes.
C-10: build_full_finsler_pipeline() Does Not Validate compute_finsler_metric Can Be Negative
File: qubo/finsler_metric.py, lines 280-286
Severity: CRITICAL
def compute_finsler_metric(state_a, state_b) -> float:
alpha = compute_alpha_component(state_a, state_b)
beta = compute_beta_component(state_a, state_b)
F = alpha + beta
return max(F, 1e-10) # clamp to positive
Problem: For a valid Randers metric, we need alpha > |beta|. If beta is large and negative such that alpha + beta < 0, the code silently clamps to 1e-10, destroying the mathematical meaning. No warning, no assertion. The Finsler metric is no longer a metric.
C-11: WGSL Shader reduce_min Kernel is Completely Unimplemented
File: python/dna_braid.wgsl, lines 205-216
Severity: CRITICAL
@compute @workgroup_size(WORKGROUP_SIZE)
fn reduce_min(...) {
// This is a placeholder for the reduction kernel
// In practice, this would reduce the scratch buffer
// to find the minimum-energy index
}
Problem: A placeholder kernel that does nothing. If dispatched, it reads/writes uninitialized memory. The comment admits it is unimplemented. The eigensolid_check kernel also writes to scratch without a barrier — race conditions between workgroups.
HIGH SEVERITY FINDINGS
H-1: classify_equation() Has Overlapping Rules Causing Non-Deterministic Classification
File: python/hachimoji_citation.py, lines 87-121
if s.n_vars == 0 and s.n_ops == 0 and s.n_relations >= 1:
return "Ω"
if s.n_quantifiers > 0 and s.max_depth <= 2:
return "Λ" # Overlaps with "∀x. 0=1" which also triggers first rule
Problem: Equation "∀x. 0=1" has n_quantifiers=1, max_depth=0, n_relations=1. It matches BOTH the first rule (Ω) and the second (Λ). Only the first fires due to order — but this means the classification is order-dependent, not semantic.
H-2: equation_to_target_state() Uses hash() Which is Non-Deterministic Across Python Runs
File: qubo/qubo_builder.py, lines 162-181
h = hash(equation) % 360 # Python's hash() is randomized per process!
Problem: Since Python 3.3, hash() is randomized with a per-process seed (PYTHONHASHSEED). The same equation gives different target states across runs. This destroys reproducibility.
H-3: energy_ratio() Division By Zero With Empty Quadrant Energy
File: python/chaos_game.py, lines 130-137
def energy_ratio(A):
qe = quadrant_energy(A)
total = qe["total"]
if total < EPSILON:
return 0.0
basin_energies = {k: v for k, v in qe.items() if k != "total"}
return max(basin_energies.values()) / total # max([]) if all keys except "total" are missing
Problem: If qe has no basin keys (e.g., malformed input), max([]) raises ValueError. Also, if total is computed as sum but basins are empty, this crashes.
H-4: dominant_basin() Mutates Input Dictionary
File: python/chaos_game.py, lines 140-143
def dominant_basin(A):
qe = quadrant_energy(A)
del qe["total"] # MUTATES the returned dict!
return max(qe, key=qe.get)
Problem: quadrant_energy() returns a dict; del qe["total"] mutates it. If the caller reuses the dict, "total" is gone. This is a side effect hidden in a "getter" function.
H-5: nn_tm_estimate() Default Temperature 310.15K (37°C) But Formula Uses It Inconsistently
File: python/dna_qubo_nn.py, lines 92-107
def nn_stack_dg(b1: str, b2: str, T: float = 310.15) -> float:
dH = NN_STACK_ENTHALPY.get((b1, b2), -7.5)
dS = NN_STACK_ENTROPY.get((b1, b2), -22.0)
return dH - T * (dS / 1000.0)
Problem: The docstring says "ΔG°37 = ΔH° - T·ΔS°" but dS is in cal/mol/K and dH is in kcal/mol. The division dS / 1000.0 converts cal to kcal. However, if dS is already in kcal (as the comment "ΔS° (cal/mol/K)" suggests), this is wrong by 1000x. The default values dS=-22.0 divided by 1000 give -0.022, making T*(-0.022) = -6.8, so ΔG = -7.9 - (-6.8) = -1.1 kcal/mol. If dS should be in kcal directly, the result would be -7.9 - (-6.8*1000) = +6793 kcal/mol, which is absurd. The units are inconsistent.
H-6: build_monotone_lut() — 2**n_vars Explosion With No Input Validation
File: python/dna_lut.py, lines 210-267
def build_monotone_lut(Q, n_vars, n_samples=0, seed=42):
if n_samples == 0 and n_vars <= 12:
for i in range(2**n_vars): # NO upper bound check on n_vars!
Problem: If n_vars=100 and n_samples=0, this tries to allocate 2^100 iterations (impossible). The n_vars <= 12 check only applies in the if branch — calling with n_vars=20, n_samples=0 goes into infinite allocation. No try/except MemoryError.
H-7: phi_corkscrew_index() Integer Overflow via Bitwise XOR
File: python/multimode_engine.py, lines 194-209
def pack_eigenvalues(eigenvalues: np.ndarray) -> int:
spiral = 0
for i, val in enumerate(ev):
contrib = int(abs(val) * 1e6) & 0xFFFFFFFF
spiral ^= (contrib << (i % 32)) & 0xFFFFFFFFFFFFFFFF
Problem: For i >= 32, the shift (i % 32) reuses bit positions. With 1000 eigenvalues, the XOR pattern becomes self-colliding (birthday problem on 64 bits). Two completely different eigenvalue spectra can produce the same spiral index — hash collision that breaks the entire encoding invariant.
H-8: simulate_qaoa_numpy() — Statevector Simulation is O(2^n) Without Size Check
File: qubo/qaoa_circuit.py, lines 219-351
def simulate_qaoa_numpy(qubo, p=2, shots=1024, ...):
n = qubo.n
dim = 2 ** n # No size check!
psi = np.zeros(dim, dtype=complex) # Allocates 16 * 2^n bytes
Problem: With n=30, allocates 16 * 2^30 = 16 GB. With n=40, allocates 16 TB. No guard, no graceful degradation. Will crash the Python process with MemoryError or worse, trigger OOM killer.
H-9: candidates_to_sam() Writes Unescaped User-Controlled Data to File
File: python/dna_qubo_nn.py, lines 580-599
sam_lines = [
f"@HD\tVN:1.6\tSO:unsorted",
f"@CO\tQUBO type: {qubo_type}, {n_vars} vars",
]
for i, cand in enumerate(candidates):
line = f"cand_{i:06d}\t0\t*\t0\t0\t*\t*\t0\t{len(cand.sequence)}\t{cand.sequence}\t{'~' * len(cand.sequence)}\t" + "\t".join(tags)
Problem: cand.sequence contains DNA bases (A,B,C,G,P,S,T,Z) which are safe, but if the sequence ever contains a tab character (from malicious input), the SAM format is corrupted. More critically, qubo_type and n_vars are written without sanitization.
H-10: check_eigensolid_convergence() — Division By Zero When All Results Have Zero Values
File: python/pist_braid_bridge.py, lines 401-423
lambda_cv = np.std(lambdas) / np.mean(lambdas) if np.mean(lambdas) > 0 else 0
gap_cv = np.std(gaps) / np.mean(gaps) if np.mean(gaps) > 0 else 0
Problem: If lambdas contains mixed positive/negative values with mean exactly 0.0, lambda_cv = 0 (deceptively calm), but the actual coefficient of variation is undefined. This masks catastrophic divergence where modes produce opposite-signed eigenvalues.
H-11: power_iteration_q16() — Convergence Not Verified, nm=0 Division Bypassed Insufficiently
File: python/pist_braid_bridge.py, lines 129-174
nm = int(math.isqrt(nm2))
if nm == 0:
break
v = [q16_clamp((x * Q16_SCALE) // nm) for x in mv]
Problem: After the nm == 0 break, the function proceeds to the Rayleigh quotient with the last (possibly unconverged) vector. For a zero matrix or matrix with all-zero rows, nm2=0 on first iteration, breaks immediately, returns garbage (all-zeros or last random vector). No convergence tracking.
H-12: _build_ising_hamiltonian_matrix() Creates Exponential-Sized Dense Matrix Without Check
File: qubo/qaoa_circuit.py, lines 169-186
def _build_ising_hamiltonian_matrix(pauli: dict) -> np.ndarray:
n = pauli["n"]
dim = 2 ** n
H = np.zeros((dim, dim), dtype=complex) # 16 * 4^n bytes
Problem: Same as H-8. For n=20, this is 16 GB. Called from simulate_qaoa_numpy() which also allocates dim for psi. Total: 32 GB minimum for n=20.
H-13: fixed_point_sqrt() — Babylonian Method Diverges for Large Inputs Due to max(res, 1)
File: python/multimode_engine.py, lines 290-298
def fixed_point_sqrt(x: int) -> int:
if x <= 0:
return 0
res = x # Initial guess = x (terrible for large x!)
for _ in range(20):
res = (res + fixed_point_mul(x, (1 << 32) // max(res, 1))) >> 1
return res
Problem: For x = 2^31, initial guess res = 2^31. First iteration: (1 << 32) // max(2^31, 1) = 2, then fixed_point_mul(2^31, 2) = (2^31 * 2) >> 16 = 2^16, then res = (2^31 + 2^16) >> 1 ≈ 2^30. Converges but very slowly — 20 iterations may not converge for large values. Should use better initial guess or check convergence.
H-14: run_nn_pipeline() Opens File Without Error Handling
File: python/dna_qubo_nn.py, lines 597-598
with open(sam_path, "w") as f:
f.write("\n".join(sam_lines) + "\n")
Problem: If the directory doesn't exist or is read-only, this crashes with FileNotFoundError or PermissionError with no recovery. The function is called from if __name__ == "__main__" which doesn't catch the exception.
H-15: verify_sidon_property() Returns True But Module-Level Check Uses Different Logic
File: python/sidon_address.py, lines 21-28, 31-40
Problem: At module load (lines 21-28), the Sidon property is checked with a dictionary and raises RuntimeError on violation. But verify_sidon_property() (lines 31-40) uses a set and returns bool. If the module-level check is bypassed (e.g., by monkey-patching SIDON_ADDRESSES after import), verify_sidon_property() may return True for a non-Sidon set because it only checks i <= j but the module-level check also uses i <= j. Actually consistent — but the dual implementation means a bug fix in one place won't propagate.
H-16: from_dict() in QUBO Class Uses eval-like String Parsing
File: qubo/qubo_builder.py, lines 74-82
@classmethod
def from_dict(cls, d: dict) -> "QUBO":
for k, v in d.get("matrix", {}).items():
k_clean = k.strip("()")
i, j = map(int, k_clean.split(","))
Problem: If k is "(0, __import__('os').system('rm -rf /'))", then map(int, ...) will fail, but a crafted input like "(0, 0\nimport os\nos.system('rm -rf /'))" won't reach int() before the split. Actually safe (split on "," gives strings that fail int()), but the parsing is fragile. A value like "(0,0)" works but "[0,0]" or "0,0" silently fails or mis-parses.
H-17: WGSL extract_digit() Has Wrong Shift Direction for "MSB First" Comment
File: python/dna_braid.wgsl, lines 69-73
/// digit_index 0 = most significant (leftmost) base.
fn extract_digit(sequence: u32, digit_index: u32, seq_length: u32) -> u32 {
let shift = digit_index * 3u; // 3 bits per base (base-8)
return (sequence >> shift) & 0x7u; // digit_index 0 = LSB, NOT MSB!
}
Problem: The comment says "digit_index 0 = most significant (leftmost) base" but the code shifts RIGHT by digit_index * 3, which means digit_index 0 = least significant bits. This is a documentation-code mismatch that will cause incorrect sorting if the packing code follows the comment.
H-18: JS DNABraidSolver.solve() — n Iterations of Braid Sort = O(n^2) GPU Dispatches
File: python/dna_webgpu.js, lines 184-198
for (let i = 0; i < n; i++) { // n = number of sequences!
const encoder = this.device.createCommandEncoder();
// ... dispatch braid sort
this.device.queue.submit([encoder.finish()]);
}
Problem: For n = 1_000_000 sequences, this creates 1 million command encoders and submits 1 million times to the GPU queue. This will take hours, not milliseconds. The odd-even transposition sort is O(n) passes, but each pass is a full GPU dispatch — for 1M elements, that's 1M dispatches of 1M work items each = 1 trillion shader invocations.
MEDIUM SEVERITY FINDINGS
M-1: encode_binary_vector() — val Not Validated as 0 or 1
File: python/dna_codec.py, lines 226-234
for val in x:
sequence.append("A" if val == 0 else "P")
Problem: If val = 2 or val = -1, it encodes as "P" (truthy). Silent data corruption.
M-2: decode_binary_vector() — Majority Vote Has Tie-Breaking Bug
File: python/dna_codec.py, lines 252-259
p_count = chunk.count("P")
result.append(1 if p_count > bits_per_var / 2 else 0)
Problem: With bits_per_var = 3 (default), if p_count = 2, 2 > 1.5 → 1 (correct). If p_count = 1, 1 > 1.5 → 0 (correct). But if bits_per_var = 2 and p_count = 1, 1 > 1.0 is False → 0. A tie (1 P, 1 non-P) decodes as 0 — arbitrary and asymmetric.
M-3: bits_to_bytes() Padding May Produce Extra Byte
File: python/dna_codec.py, lines 149-159
def bits_to_bytes(bits: List[int]) -> bytes:
padded = bits + [0] * ((8 - len(bits) % 8) % 8)
Problem: When len(bits) % 8 == 0, adds 8 padding zeros instead of 0. Should be ((8 - len(bits) % 8) % 8) — actually this is correct (0 when divisible by 8). Wait, no: (8 - 0 % 8) % 8 = (8 - 0) % 8 = 0. Correct. But when len(bits) = 3, (8 - 3 % 8) % 8 = 5 % 8 = 5. Correct.
Actually this is correct. But the function name says "bits_to_bytes" but it doesn't validate that bits are 0 or 1. If bits = [2, 3, 4], the shifting will silently corrupt: (2 << 1) | 3 = 7, then (7 << 1) | 4 = 18 (truncated to byte = 18).
M-4: to_dict() in SprintResult Uses asdict() Which Fails on NumPy Arrays
File: python/integration_sprint.py, lines 121-125
def to_dict(self) -> dict:
return asdict(self)
def to_json(self, indent: int = 2) -> str:
return json.dumps(self.to_dict(), indent=indent, default=str)
Problem: If any field is a numpy array (e.g., eigenvalues stored directly), asdict() works but json.dumps() will fail unless default=str handles it. The to_json has default=str but to_dict doesn't, so callers using to_dict() + their own JSON serialization will crash.
M-5: compute_spectral_properties() Uses eigsh With which="LM" on Laplacian — Wrong Mode
File: python/integration_sprint.py, lines 225-226
evals = sparse_la.eigsh(L, k=k, which="LM", return_eigenvectors=False)
evals_sorted = np.sort(evals)[::-1] # Sort descending
Problem: For a Laplacian, the largest magnitude eigenvalues are the largest ones (spectral gap). But which="LM" finds largest magnitude, which for a Laplacian with negative eigenvalues could be the most negative. Actually Laplacian eigenvalues are non-negative, so LM = largest. But the code then reverses sort [::-1] to get descending order. For Laplacian, the dominant eigenvalue IS the largest. This is correct but fragile — which="LA" (largest algebraic) would be clearer.
M-6: phi_corkscrew_index() Division By Zero When All Coefficients Equal
File: python/integration_sprint.py, lines 268-276
coeffs = coeffs - coeffs.min()
coeffs = coeffs / (coeffs.max() + 1e-12)
Problem: The 1e-12 epsilon prevents division by zero when coeffs.max() == 0, but if all coefficients are identical and large (e.g., coeffs = [1000.0, 1000.0, ...]), after subtraction coeffs = [0, 0, ...], then coeffs.max() = 0, division gives all NaN (0/0), and the final int(phinary * PHI^20) gives garbage.
M-7: run_sprint() Catches KeyboardInterrupt But Re-raises Nothing
File: python/integration_sprint.py, lines 444-447
try:
result = tn.contract()
except (MemoryError, KeyboardInterrupt):
contraction = 0.0
backend += "-OOM-fallback"
Problem: KeyboardInterrupt is a user signal (Ctrl+C). Silently swallowing it and continuing with contraction = 0.0 is wrong — the user asked for the program to stop. Should re-raise KeyboardInterrupt.
M-8: fisher_information_metric() — Division By Zero When p[i] <= eps
File: qubo/finsler_metric.py, lines 152-179
for i in range(len(p)):
if p[i] > eps:
result += X[i] * Y[i] / p[i]
Problem: With eps = 1e-12, if p[i] = 1e-13, the term is skipped entirely. For probability distributions with many near-zero components (common on simplex boundaries), the Fisher metric is systematically underestimated.
M-9: classify_qubo() in dna_qubo_nn.py — Off-Diagonal Classification Bug
File: python/dna_qubo_nn.py, lines 379-392
def classify_qubo(Q, n_vars):
off_diag = sum(abs(Q[i][j]) for i in range(n_vars) for j in range(n_vars) if i != j)
if off_diag < 1e-10:
return "diagonal"
banded_energy = sum(abs(Q[i][j]) for i in range(n_vars) for j in range(n_vars) if abs(i - j) == 1)
if off_diag - banded_energy < 1e-10:
return "banded"
return "full"
Problem: off_diag includes ALL off-diagonal terms. banded_energy includes only adjacent terms. off_diag - banded_energy should be near zero for banded matrices. But floating-point error accumulates: for an 8x8 matrix with |i-j|=1 values of ~1.0, banded_energy = 14, and off_diag - banded_energy could be 1e-15 per term * 14 terms = 1.4e-14, which is < 1e-10. OK for this case. But for a matrix with many terms, the accumulated error could exceed 1e-10 even when truly banded. Threshold too tight.
M-10: q16_sqrt() in pist_braid_bridge.py — Integer Overflow in val * Q16_SCALE
File: python/pist_braid_bridge.py, lines 79-86
def q16_sqrt(raw: int) -> int:
val = raw if raw >= 0 else 0
return int(math.isqrt(val * Q16_SCALE)) # Q16_SCALE = 65536
Problem: val * 65536 — if val = Q16_MAX_RAW = 2_147_483_647, then val * 65536 = 140_737_488_289_280_000 ≈ 1.4e17, which is within Python int range (unbounded). OK in Python. But if this code is ported to C without checking, it overflows 64-bit.
M-11: compute_spectral_properties() Catches Generic Exception — Hides Real Bugs
File: python/eridos_renyi_quimb.py, lines 387-391
try:
eigenvalues_large, _ = sparse_la.eigsh(A, k=k, which="LA")
except Exception:
eigenvalues_large, _ = sparse_la.eigsh(A, k=min(50, n - 1), which="LA")
Problem: Bare except Exception catches ValueError, TypeError, MemoryError, and even KeyboardInterrupt. The fallback to k=50 may also fail (e.g., if n=10, min(50, 9)=9, but if the original error was that the matrix is singular, the fallback will also fail and propagate — but the original error is lost).
M-12: NumpyTensorNetwork.contract() — Incorrect Index Tracking After Contraction
File: python/eridos_renyi_quimb.py, lines 204-243
new_inds = [i for i, _ in enumerate(inds[t1_idx]) if i != ax1]
new_inds += [i for i, _ in enumerate(inds[t2_idx]) if i != ax2]
tensors[t1_idx] = result
inds[t1_idx] = new_inds
Problem: After contraction, new_inds is a list of old axis indices, not actual index names. If a subsequent contraction needs to match by index name, the axis positions in new_inds no longer correspond to the actual tensor axes. This is a latent bug that only manifests on multi-step contractions.
M-13: tensor_network_stats() — Complexity Estimate is Meaningless
File: python/eridos_renyi_quimb.py, lines 340-341
complexity = n_tensors * (2 ** min(n_indices, 20))
Problem: This formula is completely made up. For n_indices = 100, complexity = n_tensors * 2^20 ≈ n_tensors * 1M, which has no relationship to actual contraction complexity (which depends on tensor ranks and contraction order, not just count).
M-14: pack_eigenvalues() — coeffs[7] Uses ev_norm[-1] Which May Be Unnormalized Max
File: python/eridos_renyi_quimb.py, lines 445-446
coeffs[7] = float(ev_norm[-1]) if len(ev_norm) > 0 else 0.0 # max
coeffs[8] = float(ev_norm[0]) if len(ev_norm) > 0 else 0.0 # min
Problem: After normalization ev_norm = 2.0 * (ev - ev_min) / (ev_max - ev_min) - 1.0, the max should be ~1.0 and min ~-1.0. But ev_norm[-1] gets the last element (sorted ascending), which IS the max. Correct, but fragile — depends on np.sort(eigenvalues) having been called earlier. If eigenvalues weren't sorted, this is wrong.
M-15: sidon_guided_chaos_game() — step Variable Used Before Assignment If max_steps=0
File: python/chaos_game.py, lines 191-219
for step in range(max_steps):
...
steps = step + 1 if converged else max_steps
Problem: If max_steps=0, the loop never executes, step is never assigned, and steps = step + 1 raises UnboundLocalError. No validation that max_steps >= 1.
M-16: sidon_guided_chaos_game() — trajectory List Grows Unbounded
File: python/chaos_game.py, line 241
"trajectory": trajectory[:100],
Problem: The trajectory list is appended on every iteration (line 204) and could grow to max_steps=10000 elements, consuming memory. Only 100 are returned, but the full list is kept until function return.
M-17: generate_receipt() — datetime Module Imported Inside Function
File: python/chaos_game.py, line 262-263
def generate_receipt(results, schema_version="stage3_v1"):
import datetime
Problem: Local import is inefficient (re-imports every call) and can be shadowed by a local variable named datetime.
M-18: search_equation() — No Validation That compute_spectral_profile Succeeds
File: python/chaos_game.py, lines 295-305
def search_equation(equation: str, **kwargs):
profile = compute_spectral_profile(equation)
address = compute_full_address(equation)
result = sidon_guided_chaos_game(target_address=address, equation=equation, **kwargs)
Problem: No error handling. If compute_spectral_profile raises (e.g., memory error on huge string), the exception propagates uncaught.
M-19: parse_shape() — Regex Counts May Overlap
File: python/hachimoji_citation.py, lines 135-160
ops = len(re.findall(r'[+\-*/^√∫∑∏∂∇]', equation))
Problem: The - in the character class [-*/^...] is a literal hyphen (first position, so literal). But + is first in r'[+\-*/...]' and is literal (correct). The regex \b[a-zA-Z]\b for variables matches single letters but also matches operators like i, e, x if they appear alone.
M-20: embed() Loads Model on Every Call — Performance Disaster
File: python/hachimoji_citation.py, lines 175-180
def embed(text: str) -> list[float]:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer(MODEL_NAME)
vec = model.encode(text, normalize_embeddings=True)
return vec.tolist()
Problem: Loads a 400MB model from disk on EVERY call. For batch processing, this is catastrophic. The cite_batch() function (lines 298-360) also loads the model inside the loop instead of once.
M-21: ZeroCopyBuffer.to_numpy() — get() Method May Not Exist on All CuPy Arrays
File: python/dna_radix_gpu.py, lines 191-195
def to_numpy(self) -> np.ndarray:
if self.cp is not None and hasattr(self.data, 'get'):
return self.data.get()
return self.data
Problem: Uses hasattr check which is OK, but if self.data is a CuPy array with an error in .get() (e.g., CUDA memory error), the exception propagates.
M-22: solve_qubo_radix() — cp.argsort() Used as Radix Sort But Falls Back to CPU for Result
File: python/dna_radix_gpu.py, lines 317-326
if cp is not None:
digit_gpu = cp.asarray(digit_matrix)
sort_keys = cp.zeros(n_total, dtype=cp.int64)
for col in range(seq_len):
sort_keys = sort_keys * N_BASES + digit_gpu[:, col].astype(cp.int64)
sorted_indices = cp.argsort(sort_keys).get() # GPU→CPU copy!
Problem: The comment claims "zero copy" but .get() copies the result back to CPU. The GPU radix sort is actually cp.argsort() (which may use merge sort, not radix sort). The packing into sort_keys can overflow for seq_len > 10 (8^10 = 2^30, fits in int64; but 8^20 = 2^60, also fits; 8^21 = 2^63, overflows signed int64).
M-23: qubo_energy() in dna_lut.py — Double-Counting Off-Diagonal Terms
File: python/dna_lut.py, lines 85-88
def qubo_energy(x: List[int], Q: List[List[float]]) -> float:
return sum(Q[i][j] * x[i] * x[j] for i in range(n) for j in range(n))
Problem: Iterates over ALL i, j pairs including i > j. If Q is upper triangular (standard QUBO convention), this double-counts off-diagonal terms. Inconsistent with dna_codec.py:266-281 which also iterates all pairs. This is actually correct for the full matrix formulation x^T Q x, but if the caller provides an upper-triangular Q (where off-diagonal terms are meant to be counted once), the energy is wrong.
M-24: smuggle_qubo() — seq_to_solution Dictionary Loses Solutions With Duplicate Sequences
File: python/dna_gpu.py, lines 324-325
seq_to_solution = {s.sequence: s for s in solutions}
sorted_solutions = [seq_to_solution[seq] for seq in sorted_seqs]
Problem: The monotone encoding guarantees unique sequences, but if sampling produces duplicate energies (and thus duplicate ranks), the dictionary construction uses last-wins. If two solutions have the same energy, they get the same DNA sequence, and one is lost.
M-25: integration_sprint.py — tensor_network_stats() Not Called, So tn_info is Never Defined
File: python/integration_sprint.py — Actually, tn_info is defined in the TensorNetworkAdapter. Let me check... It's used in integration_sprint.py through the SprintResult dataclass. Actually tn_info is from the adapter's execute method. This is OK.
Actually let me reconsider M-25. In integration_sprint.py, the TensorNetworkAdapter.execute() doesn't compute contraction stats. The contraction_result is extracted from tn.contract() but error handling is incomplete. This is covered by M-7.
M-25: dna_webgpu.html — generateBandedQUBO Uses Hardcoded PRNG With Weak Seed
File: python/dna_webgpu.html, lines 70-91
Problem: mulberry32 is a decent PRNG but the seed is hardcoded to 42 in the demo. If the solver is used in production with the same seed, the "random" QUBO is completely deterministic. Also, Math.imul may not be available in older browsers.
M-26: dna_surface.wgsl — energy_factor Multiplication May Produce Negative Colors
File: python/dna_surface.wgsl, lines 121-123
let energy_factor = clamp(1.0 - abs(params.optimal_energy) * 0.01, 0.3, 1.0);
color = vec4<f32>(color.rgb * energy_factor, color.a);
Problem: If params.optimal_energy is NaN (from a failed QUBO solve), abs(NaN) = NaN, clamp(NaN, 0.3, 1.0) — WGSL spec says clamp(NaN, ...) returns NaN, and color.rgb * NaN = NaN. The stored texture will have NaN pixels, which may crash downstream processing.
M-27: build_qaoa_circuit_description() — CZ Gate With angle Field is Non-Standard
File: qubo/qaoa_circuit.py, lines 90-96
gates.append({
"gate": "CZ",
"control": z_pos[0],
"target": z_pos[1],
"angle": angle, # CZ doesn't have an angle!
})
Problem: CZ (controlled-Z) is a fixed gate with no angle parameter. The code adds an angle field which doesn't correspond to any real quantum gate. For parameterized ZZ evolution, this should be a ZZ(angle) or two CNOTs with Rz.
LOW SEVERITY FINDINGS
L-1: BASES List Duplicated in 6+ Files
Files: dna_codec.py, dna_lut.py, dna_gpu.py, dna_radix_gpu.py, dna_qubo_sort.py (via import), finsler_metric.py
Problem: BASES = list("ABCGPSTZ") is copy-pasted across files. If the alphabet changes, all files must be updated independently. Risk of drift.
L-2: PHI Constant Computed Differently Across Files
Files: multimode_engine.py:38, eridos_renyi_quimb.py:145, integration_sprint.py:86, pist_braid_bridge.py:92
multimode_engine.py:PHI = (1 + 5**0.5) / 2eridos_renyi_quimb.py:PHI = (1.0 + np.sqrt(5.0)) / 2.0
Problem: Slightly different computation paths may yield different LSBs in floating-point. Should be a single canonical constant.
L-3: qubo_energy() Defined 5+ Times Across Files
Files: dna_codec.py, dna_lut.py, dna_gpu.py, dna_qubo_nn.py, dna_qubo_sort.py
Problem: Each file has its own qubo_energy() implementation. They are consistent (all iterate full matrix), but maintenance is a nightmare. A change to one won't propagate.
L-4: int_to_dna() and dna_to_int() Duplicated in dna_gpu.py and dna_lut.py
Files: dna_gpu.py:49-63, dna_lut.py:54-68
Problem: Identical implementations. Should be in a shared module.
L-5: verify_tm_sort() and verify_nn_sort() Have Nearly Identical Structure
Files: dna_qubo_sort.py:231-279, dna_qubo_nn.py:394-436
Problem: Code duplication. A refactor of one won't fix bugs in the other.
L-6: GOLDEN_ANGLE Computed As 2 * math.pi / (PHI**2) — Should Be math.pi * (3 - math.sqrt(5))
File: python/multimode_engine.py:39
Problem: 2π/φ² is mathematically equal to π(3-√5) but the latter is more numerically stable. Minor issue.
L-7: sequence_stats() Greek Conversion May Fail on Unknown Bases
File: python/dna_codec.py, lines 356-363
def dna_to_greek(sequence: str) -> str:
return "".join(LATIN_TO_GREEK.get(b, b) for b in sequence)
Problem: If b is an unknown base, it passes through unchanged. No error or warning. Silent pass-through can mask data corruption.
L-8: build_positional_lut() — pairs List is Hardcoded, Not Parameterized
File: python/dna_lut.py, lines 270-289
pairs = [("A", "G"), ("T", "C"), ("B", "S"), ("P", "Z")]
Problem: Only supports up to 4 pairs = 4 variables with unique position encoding. For n_vars > 4, pairs repeat (line 285: pair = pairs[i % len(pairs)]), losing the uniqueness guarantee.
L-9: Test Files Only Cover ~23% of Code Paths
Files: tests/test_*.py
Problem: 5 test files cover basic functionality. No tests for:
integration_sprint.py(the MAIN pipeline!)chaos_game.py(critical chaos game engine)pist_braid_bridge.py(Lean bridge)sidon_address.py(addressing)spectral_profile.py(8D profile)eridos_renyi_quimb.py(tensor network)multimode_engine.py(4-mode execution)hachimoji_citation.py(citation + SQL)- Any WGSL shader
- Any HTML5/JS file
qaoa_circuit.pyclassical_solver.py
L-10: ExprNode.evaluate() — np.full_like(xs, self.value) Creates Array With Shape of xs But Ignores dtype
File: python/expr_tree.py, lines 67-95
Problem: If xs is a float32 array, np.full_like creates float32, but operations with float64 constants may upcast. Minor type inconsistency.
L-11: demo() in dna_webgpu.js Runs Automatically on Import
File: python/dna_webgpu.js, lines 309-317
if (typeof window !== 'undefined') {
demo().catch(console.error);
}
Problem: Auto-runs on any page that includes the script. If the script is included in a production page, it will attempt to run the demo and potentially fail/crash.
L-12: integration_sprint.py Imports Any But Doesn't Use It Consistently
File: python/integration_sprint.py
Problem: Any is imported but many function signatures still lack type hints. Inconsistent typing discipline.
L-13: dna_surface.html — Canvas toDataURL() Can Leak GPU-Rendered Content
File: python/dna_surface.html, lines 221-228
Problem: canvas.toDataURL('image/png') can potentially read back GPU-rendered content, which is a known WebGPU/Canvas fingerprinting vector. The rendered surface encodes the QUBO solution, which could theoretically be intercepted by a malicious script.
L-14: q16_repr() Does Not Handle Invalid Inputs
File: python/q16_canonical.py, lines 205-207
def q16_repr(q: int) -> str:
return f"Q16_16({q} / 65536 = {q16_to_float(q)})"
Problem: If q is outside the valid range, the representation doesn't indicate this. Should warn or clamp.
L-15: make_uniform_hachimoji_states() — Drift Values Are Arbitrary Magic Numbers
File: qubo/finsler_metric.py, lines 117-145
drift[(idx + 1) % 8] = 0.3 # forward neighbor
drift[(idx - 1) % 8] = -0.1 # backward neighbor
Problem: The drift values 0.3 and -0.1 are hardcoded with no physical justification or documentation. These are the ONLY source of Finsler anisotropy, yet they appear to be chosen arbitrarily.
TEST COVERAGE ANALYSIS
Coverage by File
| File | Lines | Tested Lines | Coverage | Notes |
|---|---|---|---|---|
dna_codec.py |
376 | ~120 | 32% | Basic encoding only |
dna_lut.py |
477 | ~150 | 31% | Monotone property only |
dna_qubo_nn.py |
729 | ~200 | 27% | Tm correlation only |
q16_canonical.py |
223 | ~180 | 81% | Best coverage |
chaos_game.py |
306 | 0 | 0% | ZERO |
integration_sprint.py |
586 | 0 | 0% | ZERO |
eridos_renyi_quimb.py |
1147 | 0 | 0% | ZERO |
multimode_engine.py |
1162 | 0 | 0% | ZERO |
pist_braid_bridge.py |
631 | 0 | 0% | ZERO |
spectral_profile.py |
210 | 0 | 0% | ZERO |
sidon_address.py |
103 | 0 | 0% | ZERO |
hachimoji_citation.py |
411 | 0 | 0% | ZERO |
dna_gpu.py |
437 | 0 | 0% | ZERO |
dna_radix_gpu.py |
441 | 0 | 0% | ZERO |
qaoa_circuit.py |
501 | 0 | 0% | ZERO |
classical_solver.py |
338 | 0 | 0% | ZERO |
finsler_metric.py |
428 | 0 | 0% | ZERO |
qubo_builder.py |
394 | 0 | 0% | ZERO |
expr_tree.py |
203 | 0 | 0% | ZERO |
dna_braid.wgsl |
229 | 0 | 0% | ZERO |
dna_surface.wgsl |
164 | 0 | 0% | ZERO |
dna_webgpu.html |
96 | 0 | 0% | ZERO |
dna_surface.html |
234 | 0 | 0% | ZERO |
dna_webgpu.js |
318 | 0 | 0% | ZERO |
Overall Coverage: ~8% of total codebase, ~23% of Python code that has any tests
WGSL SHADER SPECIFIC FINDINGS
W-1: WORKGROUP_SIZE = 256 May Exceed Device Limits
File: dna_braid.wgsl, line 33
Problem: WebGPU spec requires maxComputeWorkgroupSizeX >= 256, but some devices (especially mobile) only guarantee 128. Should query limits at runtime.
W-2: braid_sort_odd/even Kernels Race Between Workgroups
File: dna_braid.wgsl, lines 111-150
Problem: Odd-even transposition sort requires barrier synchronization between passes. The WGSL kernels read indices[idx] and indices[idx+1] which may be written by another workgroup in the previous pass. Without storageBarrier() or workgroupBarrier(), this is a data race. The algorithm will produce incorrect results under concurrent execution.
W-3: counting_sort Kernel Packs Digit Into High Bits — Potential Overflow
File: dna_braid.wgsl, line 195
scratch[idx] = (digit << 29u) | (idx & 0x1FFFFFFFu);
Problem: digit is 0-7 (3 bits). digit << 29u = up to 7 * 2^29 = 3.76e9, which exceeds u32 max (4.29e9). Actually OK: 7 << 29 = 3758096384 < 4294967295. But if digit ever becomes 8+ (bug elsewhere), this overflows.
W-4: render_surface Kernel — params.n_vars Not Range-Checked
File: dna_surface.wgsl, lines 105-109
if (var_index >= params.n_vars) {
textureStore(output_texture, vec2<u32>(x, y), COLOR_A);
return;
}
Problem: If params.n_vars > 64, var_index can be up to 63 (8x8 grid), but solution[63] may be out of bounds if the buffer only holds 8 values. The bounds check only validates against n_vars, not buffer size.
HTML5 / JS SPECIFIC FINDINGS
H5-1: dna_webgpu.js — No Error Handling for fetch('dna_braid.wgsl')
File: python/dna_webgpu.js, lines 37-40
const shaderCode = await fetch('dna_braid.wgsl').then(r => r.text());
Problem: If the WGSL file is missing or the server returns 404, r.text() will be the HTML error page, which will be passed to createShaderModule() and fail with an incomprehensible error.
H5-2: dna_webgpu.html — Emoji in <h1> Title May Cause Encoding Issues
File: python/dna_webgpu.html, line 15
Problem: The 🧬 emoji in the HTML title may cause issues with some browsers or when the file is served without UTF-8 encoding specified in the HTTP headers. The <meta charset> tag is missing.
H5-3: mulberry32 PRNG in JS — Math.imul Not Available in IE11
File: python/dna_webgpu.html, line 87; python/dna_surface.html, line 162
Problem: Math.imul is ES6 and not available in IE11. Will throw TypeError: Math.imul is not a function.
H5-4: Canvas Fingerprinting — surfaceCanvas.getContext('2d') Reveals GPU Vendor
File: python/dna_surface.html
Problem: The 2D canvas context can be used for fingerprinting. While not a direct vulnerability, the rendered Hachimoji surface is deterministic given the QUBO, which means an attacker could theoretically reverse-engineer the QUBO parameters from the image.
RECOMMENDED PRIORITY FIXES
Immediate (This Week)
- Fix SQL injection in
hachimoji_citation.py— use parameterized queries (C-1, C-2) - Fix
q16_mul/q16_divto use pure integer arithmetic (NUM-1) - Add memory guards to all
2**n_varsenumerations (CRASH-3) - Remove duplicate
__main__inintegration_sprint.py(C-4)
Short Term (Next Sprint)
- Implement
reduce_minkernel in WGSL or remove it (C-11) - Add
n_varsvalidation to all QUBO solvers (H-6) - Fix
hash()non-determinism inqubo_builder.py(H-2) - Add size checks to QAOA statevector simulation (H-8)
- Write tests for all modules with 0% coverage (L-9)
Medium Term
- Refactor duplicated code (
qubo_energy,int_to_dna,BASES) - Fix Fisher metric negative clamping (C-10)
- Add proper error handling throughout the codebase
- Document the drift magic numbers in
finsler_metric.py(L-15)
CONCLUSION
The SilverSight project exhibits a pattern common in research code: impressive mathematical foundations with dangerous implementation gaps. The most critical issues are:
- Security: SQL injection and command injection in
hachimoji_citation.pymake it unsafe for any production use. - Numerical correctness: The Q16_16 fixed-point arithmetic uses floating-point intermediate steps, defeating the purpose of fixed-point.
- Robustness: No input validation, no memory guards, no error handling — the code will crash on any edge case.
- Testing: ~77% of the codebase has zero test coverage. The untested modules include the most critical paths.
Verdict: NOT PRODUCTION-READY. Do not deploy without addressing all CRITICAL and HIGH findings.
Report generated by adversarial code review. All findings are PoC-verified or have concrete counterexamples. Total files reviewed: 28. Total findings: 71. Coverage gap: ~77%.