Skip to main content

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

Release files for shorkin 1.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for shorkin 1.1.1
File Size Uploaded
shorkin-1.1.1.tar.gz 52.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for shorkin 1.1.1
File Interpreter ABI Platform
shorkin-1.1.1-py3-none-any.whl Python 3 none any Details

Total release size:109.5 kB

Release files / shorkin-1.1.1.tar.gz

Download URL shorkin-1.1.1.tar.gz
Size 52.5 kB
Tags Source
SHA-256 checksum
How to use checksums
b557ab82f734702cf2ba95c495606908227a968c6efda5c6e0e984223a6182f4
BLAKE2b-256 checksum
How to use checksums
85961b4fd4907673e7e0bd41430f95067c26da89be8d53d2f9899ff2918ce5c9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 1, 2026.

Transparency log

Release files / shorkin-1.1.1-py3-none-any.whl

Download URL shorkin-1.1.1-py3-none-any.whl
Size 57.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0a9ccd797c941d418abda1f704cf8f8e2dc517b46db1f6ee4e9b200ecc18fb67
BLAKE2b-256 checksum
How to use checksums
e7920fd8dbe5733f4e75ed9df6667e851d0a2499c614c2a41d87c538d628b173
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.1 This release

2 release files

1.0.0

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page