1. Choose parameters and define the modular space
Choose a small toy modulus of the form
N = 2^n, n = 5 -> N = 32.
All arithmetic on the registers a and b is interpreted modulo 32.
Choose:
the true secret k (what we ultimately want to hide),
a mask r (classical offset),
and the cipher-slope:
k′ ≡ k + r (mod 32).
In the concrete run:
k = 13, r = 6, k′ = 13 + 6 = 19 (mod 32).
Note: This is a toy-scale primitive intended to study information geometry, not a secure encryption scheme.
2. Enforce invertibility for decoding from correlations
Later, to recover a slope from measured pairs, we need to divide by b (multiply by its modular inverse). In modulus 2^n, only odd numbers are invertible, so restrict attention to outcomes where:
gcd(b,2^n) = 1 (b is odd)
Separately, choose k′ to be odd so that multiplication by k′ is bijective over Z_(2^n). This ensures that the map:
B ↦ a = k' b (mod 2^n)
is a permutation, helping keep the marginals high-entropy and approximately uniform.
In the concrete run, k′ = 19 is odd, satisfying this design choice.
3. Define the quantum registers and the intended nonlocal relation
Allocate two n-qubit registers:
b: 5 qubits (the input share),
a: 5 qubits (the output share),
so the total quantum system is 10 qubits.
The target functional relation we want embedded into the joint quantum state is:
a ≡ k′ b (mod 32).
This relation is the ridge, outcomes lie on a modular line in the discrete (a,b) grid.
4. Prepare b in a uniform superposition
Initialize the system in ∣0⟩^(⊗10).
Apply Hadamards to all qubits of register b, producing:
∣b⟩ -> 1/√32 (∑_b=0)^31 ∣b⟩.
So the joint state becomes:
∣a = 0⟩ ⊗ 1/√32 (∑_b=0)^31 ∣b⟩.
5. Compute the modular multiplication a <- k′ b (mod 32)
Now implement a reversible arithmetic computation that maps:
∣a⟩ ∣b⟩ -> ∣a + k′ b (mod 32)⟩ ∣b⟩.
Since a starts at 0, this produces:
∣0⟩ ⊗ 1/√32 (∑_b=0)^31 ∣b⟩ -> 1/√32 (∑_b=0)^31 ∣k′ b mod 32⟩ ∣b⟩.
This is the key nonlocal encoding, no single register contains the secret slope by itself, it is expressed in the correlation between them.
The arithmetic identity used:
Write b in binary:
b = (∑_j=0)^(n−1) b_j 2^j, 𝑏_𝑗 ∈ {0, 1}
Then:
k′ b ≡ (∑_j=0)^(n−1) b_j (k′ 2^j) (mod 2^n).
So modular multiplication can be built from a sequence of controlled modular adds of constants k′ 2^j.
6. Implement modular adds using the Quantum Fourier Transform (QFT)
To make modular addition efficient in gate form, add in Fourier space.
Apply QFT on register a:
The Quantum Fourier Transform over 2^n is:
QFT ∣x⟩ = 1/√2^n (∑_y=0)^(2^n-1) e^(2πixy/2^n) ∣y⟩.
Apply QFT to a so that additions to a can be performed by phase rotations.
Add constants with controlled phase rotations:
Adding a constant c to a register in Fourier space corresponds to applying phase shifts whose angles are proportional to c.
Conceptually, “a -> a + c” becomes:
∣a⟩ --QFT--> (∑_y)^(2^n-1) e^(2πiay/2^n) ∣y⟩ --Phases--> (∑_y)^(2^n-1) e^(2πi(a+c)y/2^n) ∣y⟩.
So the constant addition is encoded in the phase:
e^(2πicy/2^n).
In the circuit, these phases are implemented by controlled-phase gates CP(θ) with angles derived from c and the Fourier-bit index (denominator 2^(k+1)).
Sum the controlled constants for each bit of b:
For each bit b_j, conditionally add:
c_j = k′ 2^j (mod 2^n).
So the total effect is:
a -> a + (∑_j=0)^(n-1) b_j c_j ≡ a + k′ b (mod 2^n).
Apply inverse QFT on register a:
After all phase additions, apply QFT^-1 to map a back to the computational basis, finishing the multiplication.
At this point, the joint quantum state is:
1/√32 (∑_b=0)^31 ∣k′ b mod 32⟩ ∣b⟩.
7. Measure both registers locally
Measure every qubit in both registers in the computational basis.
Each shot yields a classical pair (a,b) with probability determined by the final joint state.
In the ideal noiseless case, only outcomes satisfying a ≡ k′ b (mod 32) appear (up to the fact that b is uniformly distributed). That set is the ridge line in the 32 x 32 grid.
With hardware noise, probability mass spreads off the line, but the ridge is still statistically detectable by aggregating counts.
8. The nonlocal ciphertext interpretation
The distribution of a alone looks approximately uniform.
The distribution of b alone looks approximately uniform.
The secret structure is in the joint distribution P(a,b), where a ridge forms along the constraint.
So the ciphertext is not a string stored in a or b, but a correlation structure across them.
This assumes an attacker with full access to the measured joint samples (a,b), no circuit access beyond those samples, and no knowledge of the classical mask r. The security goal of this toy construction is not computational secrecy, but controlled leakage, while the masked scalar k′ is recoverable from global joint structure, the true secret k remains hidden without knowledge of r.
9. Classical post-processing: recover k′ from the joint samples
For each measured pair (a,b), whenever b is invertible mod 32 (b is odd), the ridge equation implies:
a ≡ k′ b (mod 32) -> k′ ≡ ab^−1 (mod 32).
Restrict to invertible b.
Discard even b because b^-1 does not exist mod 2^n for even numbers:
gcd(b,32) = 1 ⟺ b odd.
Compute modular inverse b^-1 (mod 32)
Compute an inverse using an iterative method (Newton-style lifting), which produces the inverse modulo 2^n for odd b:
b^-1 (mod 2^n).
Vote on candidates for k′.
For every valid sample (a,b), compute:
k̂'= ab^-1 (mod 32),
and add that shot’s count as a vote for k̂'.
The most frequent candidate (highest vote total) is taken as:
k̂' = argmax_{x in {0,...,31}} votes(x).
In the ideal case:
k̂' = k'.
10. Unblinding to recover the true secret k using the mask r
The experiment purposely hides k behind a mask r:
k′ ≡ k + r (mod 32).
So after recovering k′, the legitimate receiver who knows r computes:
k ≡ k′ - r (mod 32).
Thus the estimated secret is:
k̂ ≡ k̂' - r (mod 32).
Without r, an attacker can at best recover k′, not k.
11. Calibration-based qubit selection
Before running on the QPU, we select the best physical qubits using the most recent calibration CSV.
Load the CSV and sort qubits by:
minimizing single-qubit error,
maximizing T_1,
maximizing T_2.
Formally, we pick the top 2N qubits by lexicographic ranking:
smallest ϵ_sx,
largest T_1,
largest T_2.
This yields a list of 10 physical qubit indices:
PHYSICAL = [q_0, q_1, …, q_9],
used as the initial layout so the logical qubits map onto the best hardware qubits.
12. Transpilation and execution on IBM Runtime
Transpile the circuit:
backend: ibm_fez
shots: 8192
The output is a count dictionary counts_raw over 10-bit measurement strings.
All measurement bitstrings are parsed in little-endian order, with the least significant bit corresponding to the lowest-index qubit, and the joint distribution C[a,b] is constructed such that ridge tests evaluate the relation a ≡ k′ b (mod 2^n) consistently under this convention.
13. Save result to JSON
Save a single JSON file containing:
experiment name,
backend name,
chosen physical qubits,
shot count,
calibration CSV path,
all parameters n, N, k, r, k′,
recovered estimates k̂′, k̂,
marginals for a and b,
the top vote list for k′,
and the full raw counts.
Code:
# Main circuit
# Imports
import os, json, logging, math
from datetime import datetime
from collections import Counter
import pandas as pd
from qiskit import QuantumCircuit, transpile
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
# Logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s | %(levelname)s | %(message)s")
log = logging.getLogger(__name__)
# IBMQ
TOKEN = "YOUR_IBMQ_API_KEY"
INSTANCE = "YOUR_IBMQ_CRN"
BACKEND_NAME = "ibm_fez"
CAL_CSV = "MOST_RECENT_ibm_fez_calibrations.csv"
SHOTS = 8192
# Parameters (toy nonlocal ridge encryption. Ciphertext slope k' = k + r mod 2^n)
N_BITS = 5
N_MOD = 1 << N_BITS
K_SECRET = 13
R_MASK = 6
K_PRIME = (K_SECRET + R_MASK) % N_MOD
if K_PRIME % 2 == 0:
raise ValueError("K_PRIME must be odd (invertible mod 2^n). Pick different K_SECRET/R_MASK.")
log.info(f"n={N_BITS} | k={K_SECRET} | r={R_MASK} | k'={K_PRIME}")
# QFT/iQFT (little-endian qubit order. Qubits[0] = LSB)
def qft(qc: QuantumCircuit, qubits: list[int]) -> None:
n = len(qubits)
for j in range(n):
qc.h(qubits[j])
for k in range(j + 1, n):
angle = math.pi / (1 << (k - j))
qc.cp(angle, qubits[k], qubits[j])
for i in range(n // 2):
qc.swap(qubits[i], qubits[n - 1 - i])
def iqft(qc: QuantumCircuit, qubits: list[int]) -> None:
n = len(qubits)
for i in range(n // 2):
qc.swap(qubits[i], qubits[n - 1 - i])
for j in reversed(range(n)):
for k in reversed(range(j + 1, n)):
angle = -math.pi / (1 << (k - j))
qc.cp(angle, qubits[k], qubits[j])
qc.h(qubits[j])
# Constant multiply a = (k * b) mod 2^n using QFT adder (b in computational basis, a in Fourier basis)
def const_mul_mod_2n(qc: QuantumCircuit, a: list[int], b: list[int], k: int) -> None:
n = len(a)
qft(qc, a)
for bj in range(n):
c = (k << bj) % (1 << n)
if c == 0:
continue
for ak in range(n):
angle = (2.0 * math.pi * c) / (1 << (ak + 1))
qc.cp(angle, b[bj], a[ak])
iqft(qc, a)
# Circuit (ciphertext lives in joint (a,b) correlation: a = k' * b mod 2^n)
a = list(range(N_BITS))
b = list(range(N_BITS, 2 * N_BITS))
qc = QuantumCircuit(2 * N_BITS, 2 * N_BITS)
qc.h(b)
const_mul_mod_2n(qc, a, b, K_PRIME)
qc.measure(range(2 * N_BITS), range(2 * N_BITS))
# Calibration based qubit pick
def best_qubits(csv_path: str, n: int) -> list[int]:
df = pd.read_csv(csv_path)
df.columns = df.columns.str.strip()
winners = (
df.sort_values(["√x (sx) error", "T1 (us)", "T2 (us)"],
ascending=[True, False, False])
["Qubit"].head(n).tolist()
)
log.info("Best physical qubits: %s", winners)
return winners
PHYSICAL = best_qubits(CAL_CSV, 2 * N_BITS)
# IBM Runtime
service = QiskitRuntimeService(channel="ibm_cloud", token=TOKEN, instance=INSTANCE)
backend = service.backend(BACKEND_NAME)
log.info("Backend → %s", backend.name)
trans = transpile(qc,
backend=backend,
initial_layout=PHYSICAL,
optimization_level=3)
log.info("Circuit depth %d, gate counts %s", trans.depth(), trans.count_ops())
# SamplerV2
sampler = Sampler(mode=backend)
job = sampler.run([trans], shots=SHOTS)
result = job.result()
# Classical post processing (recover k' from joint stats and unblind k with r)
creg_name = trans.cregs[0].name
counts_raw = result[0].data.__getattribute__(creg_name).get_counts()
def _split_ab(bs: str, nbits: int) -> tuple[int, int]:
s = bs.replace(" ", "")[::-1]
aval = int(s[0:nbits][::-1], 2)
bval = int(s[nbits:2*nbits][::-1], 2)
return aval, bval
def invert_mod_2n_odd(x: int, nbits: int) -> int:
if x % 2 == 0:
raise ValueError("No inverse for even numbers mod 2^n.")
mod = 1 << nbits
inv = 1
for _ in range(nbits):
inv = (inv * (2 - x * inv)) % mod
return inv
A = Counter()
B = Counter()
votes = Counter()
for bs, cts in counts_raw.items():
aval, bval = _split_ab(bs, N_BITS)
A[aval] += cts
B[bval] += cts
if bval % 2 == 1:
invb = invert_mod_2n_odd(bval, N_BITS)
votes[(aval * invb) % N_MOD] += cts
k_prime_hat = votes.most_common(1)[0][0] if votes else None
k_secret_hat = (k_prime_hat - R_MASK) % N_MOD if k_prime_hat is not None else None
log.info("Marginals | A_unique=%d B_unique=%d (expect near %d)", len(A), len(B), N_MOD)
log.info("Recovered k' (attacker sees) = %s (true %d)", str(k_prime_hat), K_PRIME)
log.info("Unblinded k (needs r) = %s (true %d)", str(k_secret_hat), K_SECRET)
# Save JSON
out = {
"experiment": "Nonlocal_Ridge_Encryption_n5",
"backend": backend.name,
"physical_qubits": PHYSICAL,
"shots": SHOTS,
"calibration_csv": CAL_CSV,
"n_bits": N_BITS,
"modulus": N_MOD,
"k_secret": K_SECRET,
"r_mask": R_MASK,
"k_prime_cipher": K_PRIME,
"k_prime_hat": k_prime_hat,
"k_secret_hat": k_secret_hat,
"marginals": {"A_counts": dict(A), "B_counts": dict(B)},
"k_prime_votes_top10": votes.most_common(10),
"counts": counts_raw
}
JSON_PATH = "FILE_PATH_TO_SAVE_BACKEND_RESULT_JSON.json"
with open(JSON_PATH, "w") as fp:
json.dump(out, fp, indent=4)
log.info("Results saved → %s", JSON_PATH)
# End
# Code for all visuals from experiment JSON
# Imports
import json
from collections import Counter
from math import gcd, log2
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Load Run data
FILE_PATH = "FILE_PATH_TO_IMPORT_BACKEND_RESULT_JSON.json"
with open(FILE_PATH, "r") as f:
data = json.load(f)
counts_raw = data["counts"]
N = int(data["n_bits"])
MOD = int(data["modulus"])
shots = int(data["shots"])
# Handle naming differences safely
k_prime = int(data.get("k_prime_hat", data.get("k_prime_cipher")))
# Parse bitstrings -> (a, b)
def parse_ab(bitstring: str):
s = bitstring.replace(" ", "")[::-1]
a = int(s[0:N][::-1], 2)
b = int(s[N:2 * N][::-1], 2)
return a, b
# Build counters and joint count matrix
joint = Counter()
A = Counter()
B = Counter()
total = 0
for bitstring, c in counts_raw.items():
a, b = parse_ab(bitstring)
joint[(a, b)] += c
A[a] += c
B[b] += c
total += c
assert total == shots
C = np.zeros((MOD, MOD), dtype=np.int64)
for (a, b), c in joint.items():
C[a, b] = c
P = C / max(total, 1)
pA = P.sum(axis=1)
pB = P.sum(axis=0)
bb = np.arange(MOD)
aa = (k_prime * bb) % MOD
# Joint heatmap and ridge overlay
plt.figure()
plt.imshow(C)
plt.title(f"Joint Count Heatmap | n={N}, k'={k_prime}")
plt.xlabel("b")
plt.ylabel("a")
plt.colorbar(label="counts")
plt.scatter(bb, aa, s=18)
plt.show()
# k' vote histogram from invertible b
votes = Counter()
invertible_mass = 0
for (a, b), c in joint.items():
if gcd(b, MOD) == 1:
inv_b = pow(b, -1, MOD)
k_cand = (a * inv_b) % MOD
votes[k_cand] += c
invertible_mass += c
plt.figure()
plt.bar(range(MOD), [votes[k] for k in range(MOD)])
plt.title("Recovered k′ Votes (invertible b only)")
plt.xlabel("k′ candidate")
plt.ylabel("counts")
plt.show()
# Line-score spectrum
line_mass = []
for k in range(MOD):
m = 0
for (a, b), c in joint.items():
if (a - k * b) % MOD == 0:
m += c
line_mass.append(m)
plt.figure()
plt.bar(range(MOD), line_mass)
plt.title("Line-Score Spectrum: mass on a ≡ k' b (mod 32)")
plt.xlabel("k")
plt.ylabel("counts on line")
plt.show()
# Residual histogram and mutual information
residual = [0] * MOD
for (a, b), c in joint.items():
r = (a - k_prime * b) % MOD
residual[r] += c
mi = 0.0
for (a, b), c in joint.items():
p_ab = c / total
mi += p_ab * log2(p_ab / ((A[a] / total) * (B[b] / total)))
plt.figure()
plt.bar(range(MOD), residual)
plt.title(f"Residuals res=(a−k′b) mod 32 | MI(a;b)≈{mi:.3f} bits")
plt.xlabel("residual res")
plt.ylabel("counts")
plt.show()
# SVD spectrum
U, S, Vt = np.linalg.svd(P, full_matrices=False)
energy = (S**2) / np.sum(S**2)
cum_energy = np.cumsum(energy)
plt.figure()
plt.plot(np.arange(1, len(S) + 1), S, marker="o")
plt.title("SVD Spectrum of P(a,b)")
plt.xlabel("index")
plt.ylabel("singular value")
plt.show()
plt.figure()
plt.plot(np.arange(1, len(S) + 1), cum_energy, marker="o")
plt.title("Cumulative SVD Energy")
plt.xlabel("modes")
plt.ylabel("energy fraction")
plt.ylim(0, 1.02)
plt.show()
# 2D FFT magnitude
F = np.fft.fftshift(np.fft.fft2(P))
plt.figure()
plt.imshow(np.abs(F), origin="lower")
plt.colorbar(label="|FFT(P)|")
plt.title("2D FFT Magnitude of Joint Distribution")
plt.xlabel("freq b")
plt.ylabel("freq a")
plt.show()
# Conditional entropy H(A|b)
eps = 1e-15
H_A_given_b = np.zeros(MOD)
for b in range(MOD):
if pB[b] > 0:
col = P[:, b] / pB[b]
H_A_given_b[b] = -np.sum(col * np.log2(np.maximum(col, eps)))
plt.figure()
plt.bar(range(MOD), H_A_given_b)
plt.title("Conditional Entropy H(A | B=b)")
plt.xlabel("b")
plt.ylabel("bits")
plt.show()
# KL divergence D(P(A|b) || P(A))
KL_col = np.zeros(MOD)
for b in range(MOD):
if pB[b] > 0:
pA_given_b = P[:, b] / pB[b]
KL_col[b] = np.sum(
pA_given_b * np.log2(np.maximum(pA_given_b / np.maximum(pA, eps), eps))
)
plt.figure()
plt.bar(range(MOD), KL_col)
plt.title("Information Gain per b-column")
plt.xlabel("b")
plt.ylabel("bits")
plt.show()
# Top-mass constellation and ridge overlays
flat = [(C[a, b], a, b) for a in range(MOD) for b in range(MOD) if C[a, b] > 0]
flat.sort(reverse=True)
TOPN = min(120, len(flat))
top = flat[:TOPN]
sizes = 20 + 180 * (np.array([x[0] for x in top]) / top[0][0])**0.8
a_top = [x[1] for x in top]
b_top = [x[2] for x in top]
plt.figure()
plt.scatter(b_top, a_top, s=sizes, alpha=0.7)
plt.scatter(bb, aa, s=12, label=f"a=k′b (k′={k_prime})")
plt.gca().invert_yaxis()
plt.title(f"Top-{TOPN} Joint Outcomes with Ridge Overlay")
plt.xlabel("b")
plt.ylabel("a")
plt.legend()
plt.show()
# Controls and Significance
def mutual_information_from_C(Cmat: np.ndarray) -> float:
"""MI(A;B) in bits from count matrix C[a,b]."""
total_local = int(np.sum(Cmat))
if total_local <= 0:
return 0.0
Pm = Cmat / total_local
pA_ = Pm.sum(axis=1, keepdims=True)
pB_ = Pm.sum(axis=0, keepdims=True)
eps_ = 1e-15
denom = np.maximum(pA_ * pB_, eps_)
ratio = Pm / denom
mask = Pm > 0
return float(np.sum(Pm[mask] * np.log2(np.maximum(ratio[mask], eps_))))
def line_mass_spectrum_from_C(Cmat: np.ndarray, mod: int) -> np.ndarray:
"""For each slope k, mass on line a ≡ k b (mod mod)."""
out = np.zeros(mod, dtype=np.int64)
for k in range(mod):
m = 0
for b in range(mod):
a = (k * b) % mod
m += int(Cmat[a, b])
out[k] = m
return out
def shuffle_columns(Cmat: np.ndarray, rng: np.random.Generator) -> np.ndarray:
"""Shuffle columns of C (permute b labels). Preserves row/col sums exactly."""
perm = rng.permutation(Cmat.shape[1])
return Cmat[:, perm]
def safe_hist(ax, x: np.ndarray, bins: int = 30):
"""
Histogram that won't crash if x has (near) zero range.
Falls back to a single bin/bar if needed.
"""
x = np.asarray(x, dtype=float)
xmin, xmax = float(np.min(x)), float(np.max(x))
if np.isclose(xmin, xmax):
ax.bar([xmin], [len(x)], width=0.0001 if xmin != 0 else 0.0001)
ax.set_xlim(xmin - 0.001, xmax + 0.001)
return
rng = xmax - xmin
if rng < 1e-6:
bins = 5
ax.hist(x, bins=bins)
# Product baseline P(A)P(B) turned into a counts-like matrix
C_prod = np.outer(pA, pB) * total # expected counts under independence
C_prod = np.rint(C_prod).astype(np.int64)
# Ridge alignment control
rng = np.random.default_rng(7)
C_shuf_example = shuffle_columns(C, rng)
# Line-score comparison real vs shuffled vs product
line_real = line_mass_spectrum_from_C(C, MOD)
line_shuf = line_mass_spectrum_from_C(C_shuf_example, MOD)
line_prod = line_mass_spectrum_from_C(C_prod, MOD)
plt.figure()
plt.plot(range(MOD), line_real, marker="o", label="real")
plt.plot(range(MOD), line_shuf, marker="o", label="shuffled columns (alignment null)")
plt.plot(range(MOD), line_prod, marker="o", label="P(A)P(B) baseline")
plt.title("Line-Score Comparison (real vs null controls)")
plt.xlabel("k")
plt.ylabel("counts on a ≡ k' b (mod 32)")
plt.legend()
plt.show()
def fft_mag(Pmat: np.ndarray) -> np.ndarray:
Fm = np.fft.fftshift(np.fft.fft2(Pmat))
return np.abs(Fm)
P_real = C / max(total, 1)
P_shuf = C_shuf_example / max(total, 1)
P_prod = C_prod / max(total, 1)
F_real = fft_mag(P_real)
F_shuf = fft_mag(P_shuf)
F_prod = fft_mag(P_prod)
# Remove DC for visualization
center = MOD // 2
F_real_vis = F_real.copy()
F_real_vis[center, center] = 0
F_shuf_vis = F_shuf.copy()
F_shuf_vis[center, center] = 0
F_prod_vis = F_prod.copy()
F_prod_vis[center, center] = 0
plt.figure()
plt.imshow(F_real_vis, origin="lower")
plt.colorbar(label="|FFT| (DC removed)")
plt.title("FFT Magnitude | real P(a,b)")
plt.xlabel("freq b")
plt.ylabel("freq a")
plt.show()
plt.figure()
plt.imshow(F_shuf_vis, origin="lower")
plt.colorbar(label="|FFT| (DC removed)")
plt.title("FFT Magnitude | shuffled-column null")
plt.xlabel("freq b")
plt.ylabel("freq a")
plt.show()
plt.figure()
plt.imshow(F_prod_vis, origin="lower")
plt.colorbar(label="|FFT| (DC removed)")
plt.title("FFT Magnitude | P(A)P(B) baseline")
plt.xlabel("freq b")
plt.ylabel("freq a")
plt.show()
# Significance tests
NUM_PERM = 300
k0 = int(k_prime) % MOD
peak_real = float(line_real[k0])
mi_real = mutual_information_from_C(C)
# Ridge-line null via column shuffles
peak_null = np.zeros(NUM_PERM, dtype=float)
rng = np.random.default_rng(123)
for i in range(NUM_PERM):
C_sh = shuffle_columns(C, rng)
line_sh = line_mass_spectrum_from_C(C_sh, MOD)
peak_null[i] = float(line_sh[k0])
# MI null via independent resampling from marginals
mi_null = np.zeros(NUM_PERM, dtype=float)
pA_norm = pA / max(np.sum(pA), 1e-15)
pB_norm = pB / max(np.sum(pB), 1e-15)
rng_mi = np.random.default_rng(999)
for i in range(NUM_PERM):
a_samp = rng_mi.choice(MOD, size=total, p=pA_norm)
b_samp = rng_mi.choice(MOD, size=total, p=pB_norm)
C_ind = np.zeros((MOD, MOD), dtype=np.int64)
np.add.at(C_ind, (a_samp, b_samp), 1)
mi_null[i] = mutual_information_from_C(C_ind)
# p-values
p_peak = (np.sum(peak_null >= peak_real) + 1) / (NUM_PERM + 1)
p_mi = (np.sum(mi_null >= mi_real) + 1) / (NUM_PERM + 1)
# z-scores
pk_mu, pk_sig = float(np.mean(peak_null)), float(np.std(peak_null) + 1e-12)
mi_mu, mi_sig = float(np.mean(mi_null)), float(np.std(mi_null) + 1e-12)
z_peak = (peak_real - pk_mu) / pk_sig
z_mi = (mi_real - mi_mu) / mi_sig
print("\nSignificance Tests")
print(
f"Peak line-mass at k'={k0}: real={peak_real:.1f} | null mean={pk_mu:.1f} std={pk_sig:.1f} "
f"| z={z_peak:.2f} | p≈{p_peak:.4f}"
)
print(
f"MI(A;B): real={mi_real:.4f} bits | indep-null mean={mi_mu:.4f} std={mi_sig:.4f} "
f"| z={z_mi:.2f} | p≈{p_mi:.4f}"
)
# Visualize null distributions
fig, ax = plt.subplots()
safe_hist(ax, mi_null, bins=30)
ax.axvline(mi_real, linestyle="--", linewidth=2, label="real MI")
ax.set_title("MI Null (independence resampling from P(A)P(B))")
ax.set_xlabel("MI (bits)")
ax.set_ylabel("count")
ax.legend()
plt.show()
fig, ax = plt.subplots()
safe_hist(ax, peak_null, bins=30)
ax.axvline(peak_real, linestyle="--", linewidth=2, label=f"real peak at k'={k0}")
ax.set_title("Peak Line-Mass Null (column-shuffle alignment test)")
ax.set_xlabel("counts on ridge line")
ax.set_ylabel("count")
ax.legend()
plt.show()
# Bar-spectrum of P(A=a)
cmap = plt.cm.viridis
x_a = np.arange(MOD)
norm_a = plt.Normalize(vmin=np.min(pA), vmax=np.max(pA))
colors_a = cmap(norm_a(pA))
fig, ax = plt.subplots()
ax.bar(x_a, pA, color=colors_a, width=0.9)
sm_a = plt.cm.ScalarMappable(cmap=cmap, norm=norm_a)
sm_a.set_array([])
fig.colorbar(sm_a, ax=ax, label="P(A=a)")
ax.set_title(f"P(A=a) Marginal Spectrum | MOD={MOD}, shots={shots}")
ax.set_xlabel("a")
ax.set_ylabel("probability")
plt.tight_layout()
plt.show()
# Bar-spectrum of P(B=b)
x_b = np.arange(MOD)
norm_b = plt.Normalize(vmin=np.min(pB), vmax=np.max(pB))
colors_b = cmap(norm_b(pB))
fig, ax = plt.subplots()
ax.bar(x_b, pB, color=colors_b, width=0.9)
sm_b = plt.cm.ScalarMappable(cmap=cmap, norm=norm_b)
sm_b.set_array([])
fig.colorbar(sm_b, ax=ax, label="P(B=b)")
ax.set_title(f"P(B=b) Marginal Spectrum | MOD={MOD}, shots={shots}")
ax.set_xlabel("b")
ax.set_ylabel("probability")
plt.tight_layout()
plt.show()
# Shared mesh for 3D surfaces
Agrid, Bgrid = np.meshgrid(np.arange(MOD), np.arange(MOD), indexing="ij")
# 3D surface of the joint distribution P(a,b)
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
surf = ax.plot_surface(
Agrid, Bgrid, P,
rstride=1, cstride=1,
linewidth=0, antialiased=True,
cmap="viridis",
)
fig.colorbar(surf, ax=ax, shrink=0.6, pad=0.08, label="P(a,b)")
ax.set_title(f"3D Joint Surface P(a,b) | MOD={MOD}")
ax.set_xlabel("a")
ax.set_ylabel("b")
ax.set_zlabel("probability")
ax.view_init(elev=35, azim=-135)
plt.tight_layout()
plt.show()
# 3D surface of correlation lift
eps = 1e-15
pA_mat = pA[:, None]
pB_mat = pB[None, :]
indep = np.clip(pA_mat * pB_mat, eps, None)
ratio = np.clip(P / indep, eps, None)
lift = np.log2(ratio)
# Mask places where P is zero to avoid huge negative floors
lift_masked = np.where(P > 0, lift, np.nan)
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
surf = ax.plot_surface(
Agrid, Bgrid, lift_masked,
rstride=1, cstride=1,
linewidth=0, antialiased=True,
cmap="viridis",
)
fig.colorbar(surf, ax=ax, shrink=0.6, pad=0.08, label="lift (bits)")
ax.set_title("3D Correlation Lift: log_2(P(a,b)/(P(a)P(b)))")
ax.set_xlabel("a")
ax.set_ylabel("b")
ax.set_zlabel("lift (bits)")
ax.view_init(elev=35, azim=-135)
plt.tight_layout()
plt.show()
# 3D residual-conditioned ridge mass
R = np.zeros((MOD, MOD), dtype=np.float64) # rows=b, cols=r
for b in range(MOD):
for r in range(MOD):
a = (k_prime * b + r) % MOD
R[b, r] = P[a, b]
BB, RR = np.meshgrid(np.arange(MOD), np.arange(MOD), indexing="ij") # B x R
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
surf = ax.plot_surface(
BB, RR, R,
rstride=1, cstride=1,
linewidth=0, antialiased=True,
cmap="viridis",
)
fig.colorbar(surf, ax=ax, shrink=0.6, pad=0.08, label="P(a=k'b+res, b)")
ax.set_title(f"3D Residual Slice Mass | a=(k'·b+res) mod {MOD}, k'={k_prime}")
ax.set_xlabel("b")
ax.set_ylabel("residual res")
ax.set_zlabel("probability")
ax.view_init(elev=35, azim=-135)
plt.tight_layout()
plt.show()
# End
// Code for Three.js render of backend data
// Config
const HALF_BITS = 5; // 5 per axis
const TOTAL_BITS = 2 * HALF_BITS; // 10
const GRID = 1 << HALF_BITS; // 32
const MOD = GRID; // 32
// Nonlocal Ridge Encryption params
const K_PRIME = 19; // cipher slope (attacker sees) k'
const R_MASK = 6; // one-time mask r
const K_SECRET = ((K_PRIME - R_MASK) % MOD + MOD) % MOD; // 13
// Load JSON
async function loadQuantumData() {
const res = await fetch('Nonlocal_Ridge_Encryption_n5_0.json');
const data = await res.json();
return data.counts; // bitstring -> count
}
// Three.js setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Controls and lighting
const controls = new THREE.OrbitControls(camera, renderer.domElement);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(10, 10, 10);
scene.add(light);
// Camera
camera.position.set(0, 30, 60);
camera.lookAt(0, 0, 0);
// Globals
let mesh;
let dots = [];
let time = 0;
// Helpers
const padN = (s, n) => s.padStart(n, '0').slice(-n);
const rev = s => s.split('').reverse().join(''); // mirror Python's bs[::-1]
const mod = (x, m) => ((x % m) + m) % m;
// Parse into classical (a,b) matching Python bit ordering
function parseEntries(counts) {
const entries = [];
for (const [bit, cRaw] of Object.entries(counts)) {
const b10 = padN(String(bit).replace(/\s+/g, ""), TOTAL_BITS);
const left = b10.slice(0, HALF_BITS); // raw left 5
const right = b10.slice(HALF_BITS); // raw right 5
// Python mapping: a = int(right[::-1],2), b = int(left[::-1],2)
const a = parseInt(rev(right), 2);
const b = parseInt(rev(left), 2);
entries.push({ bit, a, b, count: Number(cRaw) });
}
return entries;
}
// Build matrix as heat[a][b] (rows=a, cols=b)
function buildHeat(entries) {
const heat = Array.from({ length: GRID }, () => Array(GRID).fill(0));
let maxCount = 0;
for (const e of entries) {
heat[e.a][e.b] = e.count;
if (e.count > maxCount) maxCount = e.count;
}
return { heat, maxCount };
}
// Build surface and dots
function createWaveSurface(heat, maxCount) {
const WIDTH = GRID * 2;
const SEGMENTS = WIDTH;
const STEP = WIDTH / (GRID - 1);
const geometry = new THREE.PlaneGeometry(WIDTH, WIDTH, SEGMENTS, SEGMENTS);
const colors = [];
const gridX = SEGMENTS + 1;
const gridY = SEGMENTS + 1;
for (let y = 0; y < gridY; y++) {
for (let x = 0; x < gridX; x++) {
// Map geometry samples -> discrete lattice. x-axis = b (cols), y-axis = a (rows)
const b = Math.min(GRID - 1, Math.floor(x / (gridX / GRID)));
const a = Math.min(GRID - 1, Math.floor(y / (gridY / GRID)));
const c = heat[a]?.[b] ?? 0;
const amp = maxCount > 0 ? (c / maxCount) : 0;
// Ridge: a ≡ k' * b (mod 32)
const isRidge = mod(a - (K_PRIME * b), MOD) === 0;
// Ridge lattice points
const color = isRidge
? new THREE.Color(0x0000ff) // ridge cells (blue)
: new THREE.Color(0x00ff00); // background (green)
colors.push(color.r, color.g, color.b);
}
}
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
const material = new THREE.MeshBasicMaterial({ vertexColors: true, wireframe: true });
mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = -Math.PI / 2;
// Store for animation
mesh.userData = { heat, maxCount, GRID, STEP, gridX, gridY };
scene.add(mesh);
// Red dots ONLY where count > 0
const dotMat = new THREE.MeshBasicMaterial({ color: 0xff0000 });
for (let a = 0; a < GRID; a++) {
for (let b = 0; b < GRID; b++) {
const c = heat[a][b];
if (!c || c <= 0) continue;
const amp = maxCount > 0 ? (c / maxCount) : 0;
const dot = new THREE.Mesh(new THREE.SphereGeometry(0.18, 10, 10), dotMat);
dot.userData = { a, b, amp };
// x=b, z=a
dot.position.set(
(b - (GRID - 1) / 2) * STEP,
amp * 20 + 0.6,
(a - (GRID - 1) / 2) * STEP
);
dots.push(dot);
scene.add(dot);
}
}
console.log(`Nonlocal Ridge Encryption: k'=${K_PRIME}, r=${R_MASK}, k=${K_SECRET}`);
}
// Animate
function animate() {
requestAnimationFrame(animate);
time += 0.2;
if (!mesh) return;
const { heat, maxCount, GRID, gridX, gridY } = mesh.userData;
const pos = mesh.geometry.attributes.position;
for (let i = 0; i < pos.count; i++) {
const x = i % gridX;
const y = Math.floor(i / gridX);
const b = Math.min(GRID - 1, Math.floor(x / (gridX / GRID)));
const a = Math.min(GRID - 1, Math.floor(y / (gridY / GRID)));
const c = heat[a]?.[b] ?? 0;
const amp = maxCount > 0 ? (c / maxCount) : 0;
// Wave motion
const wave = Math.sin((x + time) * 0.4) * Math.cos((y + time) * 0.4);
pos.setZ(i, amp * wave * 20);
}
// Keep dots floating at their amplitude height
dots.forEach(dot => {
dot.position.y = dot.userData.amp * 20 + 0.6;
});
pos.needsUpdate = true;
controls.update();
renderer.render(scene, camera);
}
// Main
loadQuantumData().then(counts => {
const entries = parseEntries(counts);
const { heat, maxCount } = buildHeat(entries);
createWaveSurface(heat, maxCount);
animate();
});
// End