Quantum computing toolkit: Shor's, Grover's, Deutsch-Jozsa, teleportation, gates, and QKD protocols
Project description
Shorkin
A quantum computing toolkit for Python. Implements Shor's algorithm for integer factorization, Deutsch-Jozsa for constant/balanced classification, Grover's algorithm for unstructured search, quantum teleportation, and Quantum Key Distribution (QKD) protocols with HTTP and gRPC transport integrations.
Quantum simulation is powered by Google Cirq. QKD-derived keys are used for AES-256-GCM payload encryption.
Installation
# Core library (Shor's algorithm + QKD protocols)
pip install shorkin
# With a specific web framework
pip install shorkin[fastapi]
pip install shorkin[django]
pip install shorkin[starlette]
pip install shorkin[tornado]
# With gRPC support
pip install shorkin[grpc]
# Everything
pip install shorkin[all]
Requires Python 3.10+.
Shor's Algorithm
Factor composite integers using a quantum (simulated via Cirq) or classical order-finding backend.
CLI
# Factor an integer
shorkin factor 15
# 15 = 3 x 5
# Factor with a specific mode
shorkin factor 21 --mode classical
shorkin factor 15 --mode quantum --verbose
# Factor the modulus from an RSA public key
shorkin factor-key path/to/public.pem
Library
from shorkin.factor import factor
from shorkin.classical.order_finder import find_order
class ClassicalFinder:
method_name = "classical"
def find_order(self, x, n):
return find_order(x, n)
result = factor(15, ClassicalFinder())
print(result.factors) # [3, 5]
Deutsch-Jozsa Algorithm
Determine whether a Boolean function f: {0,1}^n -> {0,1} is constant or balanced with a single quantum query (classically requires up to 2^(n-1)+1 evaluations).
from shorkin.deutsch_jozsa import deutsch_jozsa
# Constant function (always returns 1)
result = deutsch_jozsa(lambda x: 1, n=3)
print(result.function_type) # "constant"
print(result.is_constant) # True
# Balanced function (returns 1 for odd inputs)
result = deutsch_jozsa(lambda x: x % 2, n=3)
print(result.function_type) # "balanced"
print(result.is_balanced) # True
Grover's Algorithm
Search an unstructured space of 2^n items in O(sqrt(N)) oracle queries (vs O(N) classically).
from shorkin.grover import grover
# Find item 5 in a space of 8
result = grover(lambda x: int(x == 5), n=3)
print(result.found) # 5
print(result.search_space_size) # 8
# Multiple marked items
marked = {3, 5}
result = grover(lambda x: int(x in marked), n=3, num_marked=2)
print(result.found) # 3 or 5
# Reproducible results with a seed
result = grover(lambda x: int(x == 5), n=3, seed=42)
Quantum Teleportation
Transfer an arbitrary single-qubit state using a shared Bell pair and two classical bits.
import math
from shorkin.teleportation import teleport
# Teleport |1> state (theta=pi)
result = teleport(theta=math.pi)
print(result.fidelity) # ~1.0
print(result.success) # True
print(result.alice_bits) # (0, 0), (0, 1), (1, 0), or (1, 1)
# Teleport |+> state (theta=pi/2)
result = teleport(theta=math.pi / 2)
print(result.fidelity) # ~1.0
Quantum Gates
Convenience wrappers around Cirq gates with a fluent GateChain builder.
import cirq
from shorkin.gates import H, CNOT, rotate_x, GateChain
q0, q1 = cirq.LineQubit.range(2)
# Gate aliases
circuit = cirq.Circuit()
circuit.append(H(q0))
circuit.append(CNOT(q0, q1))
# Fluent chaining
import math
chain = GateChain().h(q0).cnot(q0, q1).rz(q1, math.pi / 4)
circuit.append(chain.operations)
QKD Protocols
Three quantum key distribution protocols, all following a common QKDProtocol interface:
| Protocol | Description | Sifting Yield | QBER Threshold |
|---|---|---|---|
| BB84 | 2 bases, 4 states (Bennett-Brassard 1984) | ~50% | ~11% |
| B92 | 2 non-orthogonal states (Bennett 1992) | ~25% | ~5% |
| E91 | Entanglement-based with CHSH Bell test (Ekert 1991) | ~22% | ~11% |
Basic Usage
from shorkin.qkd import BB84, B92, E91, SimulatedChannel
# Create a simulated quantum channel
channel = SimulatedChannel(error_rate=0.02, seed=42)
# Generate a shared key using BB84
protocol = BB84(seed=42)
result = protocol.generate_key(num_qubits=4096, channel=channel)
print(f"Protocol: {result.protocol}")
print(f"QBER: {result.qber:.4f}")
print(f"Key: {result.final_key.hex()}")
print(f"Key bits: {result.key_length_bits}")
Choosing a Protocol
# BB84 -- the standard, good balance of efficiency and security
protocol = BB84(seed=42)
result = protocol.generate_key(num_qubits=4096, channel=channel)
# B92 -- simpler (2 states), lower yield, needs more qubits
protocol = B92(seed=42)
result = protocol.generate_key(num_qubits=8000, channel=channel)
# E91 -- entanglement-based, includes Bell inequality (CHSH) test
protocol = E91(seed=42)
result = protocol.generate_key(num_qubits=20000, channel=channel)
print(f"CHSH value: {result.metadata['chsh_value']:.3f}") # > 2.0 = secure
Encrypt / Decrypt with QKD Keys
from shorkin.qkd import BB84, SimulatedChannel, encrypt, decrypt
channel = SimulatedChannel(seed=42)
result = BB84(seed=42).generate_key(num_qubits=4096, channel=channel)
ciphertext = encrypt(b"secret payload", result.final_key)
plaintext = decrypt(ciphertext, result.final_key)
assert plaintext == b"secret payload"
Simulated Channel Options
from shorkin.qkd import SimulatedChannel
# Perfect channel (no errors, no loss)
channel = SimulatedChannel()
# Noisy channel (5% bit-flip error rate)
channel = SimulatedChannel(error_rate=0.05)
# Lossy channel (10% photon loss)
channel = SimulatedChannel(loss_rate=0.10)
# Both noise and loss
channel = SimulatedChannel(error_rate=0.03, loss_rate=0.05, seed=42)
The QuantumChannel is a typing.Protocol -- you can implement your own to connect to real quantum hardware.
HTTP Integration
QKD key exchange runs at /.well-known/qkd/initiate. Once a session is established, request and response bodies are AES-256-GCM encrypted using the QKD-derived key, identified by the X-QKD-Session-Id header.
FastAPI
from fastapi import Depends, FastAPI
from shorkin.transport.http.fastapi import QKDMiddleware, QKDSession, qkd_session
app = FastAPI()
# Option 1: Middleware (encrypts all responses for active sessions)
app.add_middleware(QKDMiddleware, protocol="bb84")
# Option 2: Dependency injection (per-route control)
@app.get("/secure")
async def secure_endpoint(qkd: QKDSession = Depends(qkd_session("bb84"))):
if qkd.is_active:
return {"encrypted": qkd.encrypt(b"secret").hex()}
return {"message": "no QKD session"}
Client usage with FastAPI
import httpx
# Step 1: Initiate key exchange
resp = httpx.post("http://localhost:8000/.well-known/qkd/initiate", json={
"protocol": "bb84",
"peer_id": "my-client",
})
session_id = resp.json()["session_id"]
# Step 2: Make requests with the session
resp = httpx.get("http://localhost:8000/secure", headers={
"X-QKD-Session-Id": session_id,
})
# Response body is AES-256-GCM encrypted
Starlette
from starlette.applications import Starlette
from shorkin.transport.http.starlette import QKDMiddleware
app = Starlette(routes=[...])
app.add_middleware(QKDMiddleware, protocol="bb84")
Django
# settings.py
MIDDLEWARE = [
# ...
"shorkin.transport.http.django.QKDMiddleware",
]
SHORKIN_QKD = {
"PROTOCOL": "bb84", # or "b92", "e91"
"NUM_QUBITS": 4096,
"TARGET_KEY_BITS": 256,
"STRICT": False, # True = reject requests without QKD session
}
Tornado
import tornado.web
from shorkin.transport.http.tornado import QKDRequestMixin, qkd_routes
class SecureHandler(QKDRequestMixin, tornado.web.RequestHandler):
def get(self):
self.write(b"encrypted if QKD session is active")
app = tornado.web.Application(
qkd_routes("bb84") + [
(r"/secure", SecureHandler, {"qkd_protocol": "bb84"}),
]
)
Strict Mode
All HTTP integrations support strict=True, which rejects any request without an active QKD session (returns 403). QKD negotiation endpoints are always accessible.
gRPC Integration
QKD key exchange is exposed as a QKDKeyExchange gRPC service. Client and server interceptors handle session metadata transparently.
Server
from concurrent import futures
import grpc
from shorkin.transport.grpc.servicer import QKDKeyExchangeServicer
from shorkin.transport.grpc.interceptor import QKDServerInterceptor
from shorkin.transport.grpc import qkd_pb2_grpc
interceptor = QKDServerInterceptor(protocol="bb84")
server = grpc.server(
futures.ThreadPoolExecutor(max_workers=10),
interceptors=[interceptor],
)
servicer = QKDKeyExchangeServicer(protocol="bb84")
qkd_pb2_grpc.add_QKDKeyExchangeServicer_to_server(servicer, server)
server.add_insecure_port("[::]:50051")
server.start()
server.wait_for_termination()
Client
import grpc
from shorkin.transport.grpc.interceptor import QKDClientInterceptor
from shorkin.transport.grpc import qkd_pb2, qkd_pb2_grpc
# Set up intercepted channel
interceptor = QKDClientInterceptor(protocol="bb84")
channel = grpc.intercept_channel(
grpc.insecure_channel("localhost:50051"),
interceptor,
)
stub = qkd_pb2_grpc.QKDKeyExchangeStub(channel)
# Initiate key exchange
response = stub.Initiate(qkd_pb2.KeyExchangeInitRequest(
protocol="bb84",
peer_id="my-service",
))
print(f"Session: {response.session_id}")
print(f"Status: {response.status}")
# Set session for subsequent calls
interceptor.session_id = response.session_id
Architecture
QKD and Classical Networks
True QKD requires a physical quantum channel (photon transmission over fiber optics). This library simulates the quantum channel using Cirq, making it suitable for:
- Education and prototyping -- learn and develop QKD-secured applications without quantum hardware
- Integration testing -- validate your application's encryption pipeline end-to-end
- Research -- experiment with protocol parameters, noise models, and error thresholds
The classical post-processing (basis reconciliation, error estimation, privacy amplification) runs over standard HTTP/gRPC and is protocol-accurate. The QuantumChannel abstraction is pluggable -- swap SimulatedChannel for a real hardware adapter without changing application code.
Package Structure
shorkin/
classical/ # Classical order finding (brute-force)
quantum/ # Quantum order finding (Cirq QPE)
factor.py # Shor's algorithm orchestration
deutsch_jozsa.py # Deutsch-Jozsa algorithm
grover.py # Grover's search algorithm
teleportation.py # Quantum teleportation protocol
gates.py # Gate aliases, helpers, and GateChain builder
cli.py # CLI entry point
qkd/ # QKD protocol engines
bb84.py # BB84 protocol
b92.py # B92 protocol
e91.py # E91 protocol
channel.py # QuantumChannel Protocol + SimulatedChannel
encryption.py # AES-256-GCM encrypt/decrypt
key_store.py # Session key storage with rotation/expiration
transport/ # HTTP & gRPC integrations
http/
fastapi.py # FastAPI middleware + Depends()
starlette.py
django.py
tornado.py
grpc/
servicer.py # QKDKeyExchange gRPC service
interceptor.py # Client + server interceptors
Key Types
from shorkin.qkd import QKDResult
result: QKDResult
result.final_key # bytes -- the usable symmetric key
result.raw_key # bytes -- key before privacy amplification
result.protocol # str -- "bb84", "b92", or "e91"
result.qber # float -- quantum bit error rate
result.key_length_bits # int -- final key length in bits
result.initial_qubit_count # int -- qubits transmitted
result.sifted_key_length # int -- bits after sifting
result.amplified # bool -- privacy amplification applied
result.metadata # dict -- protocol-specific (e.g., chsh_value for E91)
Development
# Clone and install in dev mode
git clone https://github.com/yourusername/shorkin.git
cd shorkin
pip install -e ".[all]"
# Run tests
pytest
# Run only QKD tests
pytest tests/qkd/
# Run only transport tests
pytest tests/transport/
# Run only the original Shor tests
pytest tests/test_*.py
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file shorkin-1.1.1.tar.gz.
File metadata
- Download URL: shorkin-1.1.1.tar.gz
- Upload date:
- Size: 52.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b557ab82f734702cf2ba95c495606908227a968c6efda5c6e0e984223a6182f4
|
|
| MD5 |
181cb8bfb8feb3fd3216fbda7ff7f375
|
|
| BLAKE2b-256 |
85961b4fd4907673e7e0bd41430f95067c26da89be8d53d2f9899ff2918ce5c9
|
Provenance
The following attestation bundles were made for shorkin-1.1.1.tar.gz:
Publisher:
publish.yml on bjornaer/shorkin
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shorkin-1.1.1.tar.gz -
Subject digest:
b557ab82f734702cf2ba95c495606908227a968c6efda5c6e0e984223a6182f4 - Sigstore transparency entry: 1207469955
- Sigstore integration time:
-
Permalink:
bjornaer/shorkin@4c605fccbadb399ddd98804db534fa808cc2465a -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/bjornaer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4c605fccbadb399ddd98804db534fa808cc2465a -
Trigger Event:
release
-
Statement type:
File details
Details for the file shorkin-1.1.1-py3-none-any.whl.
File metadata
- Download URL: shorkin-1.1.1-py3-none-any.whl
- Upload date:
- Size: 57.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a9ccd797c941d418abda1f704cf8f8e2dc517b46db1f6ee4e9b200ecc18fb67
|
|
| MD5 |
1f8173152157c83236a18250bdf81c42
|
|
| BLAKE2b-256 |
e7920fd8dbe5733f4e75ed9df6667e851d0a2499c614c2a41d87c538d628b173
|
Provenance
The following attestation bundles were made for shorkin-1.1.1-py3-none-any.whl:
Publisher:
publish.yml on bjornaer/shorkin
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shorkin-1.1.1-py3-none-any.whl -
Subject digest:
0a9ccd797c941d418abda1f704cf8f8e2dc517b46db1f6ee4e9b200ecc18fb67 - Sigstore transparency entry: 1207470066
- Sigstore integration time:
-
Permalink:
bjornaer/shorkin@4c605fccbadb399ddd98804db534fa808cc2465a -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/bjornaer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4c605fccbadb399ddd98804db534fa808cc2465a -
Trigger Event:
release
-
Statement type: