Skip to content

Commit fb28221

Browse files
Merge pull request #2 from rwilliamspbg-ops/feat/devcontainer-oqs
Add liboqs devcontainer + telemetry and scaling harness
2 parents d3cbe3e + 0bdbced commit fb28221

26 files changed

Lines changed: 1411 additions & 0 deletions

.devcontainer/Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM ubuntu:24.04
2+
3+
ENV DEBIAN_FRONTEND=noninteractive
4+
5+
RUN apt-get update && apt-get install -y --no-install-recommends \
6+
build-essential cmake git ca-certificates wget curl pkg-config \
7+
python3 python3-pip python3-venv python3-dev ca-certificates \
8+
libssl-dev libffi-dev && \
9+
rm -rf /var/lib/apt/lists/*
10+
11+
# Install liboqs from source
12+
WORKDIR /opt
13+
RUN git clone --depth 1 https://github.com/open-quantum-safe/liboqs.git && \
14+
mkdir -p liboqs/build && cd liboqs/build && \
15+
cmake -DCMAKE_BUILD_TYPE=Release .. && \
16+
make -j"$(nproc)" && make install
17+
18+
# Ensure pip is upgraded and install Python oqs wrapper
19+
RUN python3 -m pip install --upgrade pip setuptools wheel && \
20+
python3 -m pip install oqs
21+
22+
WORKDIR /workspace

.devcontainer/devcontainer.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "Mohawk Inference Devcontainer",
3+
"build": {
4+
"dockerfile": "Dockerfile"
5+
},
6+
"workspaceFolder": "/workspace",
7+
"settings": {},
8+
"extensions": [],
9+
"forwardPorts": [8003],
10+
"postCreateCommand": "./.devcontainer/post_create.sh"
11+
}

.devcontainer/post_create.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
echo "Running devcontainer post-create: install build deps and liboqs"
5+
# install system deps (attempt apt, then apk)
6+
if command -v apt-get >/dev/null 2>&1; then
7+
sudo apt-get update
8+
sudo apt-get install -y build-essential cmake git python3-dev python3-pip pkg-config
9+
elif command -v apk >/dev/null 2>&1; then
10+
sudo apk add --no-cache build-base cmake git python3 python3-dev py3-pip pkgconfig
11+
else
12+
echo "Unknown package manager; please install build tools (cmake, make, git, python3-dev) manually"
13+
fi
14+
15+
CACHE_DIR="$HOME/.cache/liboqs"
16+
mkdir -p "$CACHE_DIR"
17+
if [ ! -d "$CACHE_DIR/liboqs" ]; then
18+
git clone --depth 1 https://github.com/open-quantum-safe/liboqs.git "$CACHE_DIR/liboqs"
19+
fi
20+
21+
pushd "$CACHE_DIR/liboqs"
22+
mkdir -p build && cd build
23+
cmake -DCMAKE_BUILD_TYPE=Release ..
24+
make -j"$(nproc)"
25+
if command -v sudo >/dev/null 2>&1; then
26+
sudo make install
27+
else
28+
make install
29+
fi
30+
popd
31+
32+
# ensure pip and install oqs python package
33+
python3 -m pip install --upgrade pip || true
34+
python3 -m pip install oqs || true
35+
36+
echo "post-create complete"

.github/workflows/ci.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, feat/* ]
6+
pull_request:
7+
branches: [ main ]
8+
workflow_dispatch:
9+
inputs:
10+
build_liboqs:
11+
description: Build liboqs from source before running tests
12+
required: false
13+
default: false
14+
type: boolean
15+
16+
jobs:
17+
test:
18+
runs-on: ubuntu-latest
19+
env:
20+
OQS_INSTALL_PATH: /usr/local
21+
steps:
22+
- uses: actions/checkout@v4
23+
- name: Set up Python
24+
uses: actions/setup-python@v4
25+
with:
26+
python-version: '3.12'
27+
- name: Install system deps
28+
run: |
29+
sudo apt-get update
30+
sudo apt-get install -y build-essential cmake libssl-dev pkg-config
31+
- name: Optionally build liboqs
32+
if: github.event_name == 'workflow_dispatch' && inputs.build_liboqs || vars.BUILD_LIBOQS == 'true'
33+
run: |
34+
git clone --depth 1 https://github.com/open-quantum-safe/liboqs.git /tmp/liboqs
35+
mkdir -p /tmp/liboqs/build && cd /tmp/liboqs/build
36+
cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=/usr/local ..
37+
make -j$(nproc)
38+
sudo make install
39+
sudo ldconfig
40+
python -m pip install liboqs-python
41+
- name: Install Python deps
42+
run: |
43+
python -m pip install --upgrade pip
44+
pip install -r prototype/requirements.txt
45+
- name: Run tests
46+
run: |
47+
pytest -q

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.venv/
2+
__pycache__/
3+
*.pyc
4+
.pytest_cache/
5+
.vscode/
6+
.env
7+
dist/
8+
build/
9+
/.pytest_cache/
10+
*.egg-info/

docs/ARCHITECTURE.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
Mohawk Inference Engine — Architecture Spec
2+
3+
Overview
4+
5+
Goal: provide a production-grade inference engine that enables capabilities LM Studio does not: multi-device layer splitting, PQC-secured edge offload, and high-concurrency session management. This document describes the core subsystems, dataflows, APIs, security model, and implementation priorities for an MVP.
6+
7+
1. Core concepts
8+
9+
- Layer-splitting: partitioning a neural network at layer boundaries (or sub-layer blocks) so different partitions (slices) execute on different devices (GPU/NPU/CPU/edge). Each slice exposes a small runtime ABI for input/output activation tensors and metadata.
10+
- Offload: the act of sending one or more slices to a remote device for execution. Offloads must preserve confidentiality/integrity of model IP (weights) and activations as required by policy.
11+
- PQC-secured channel: post-quantum cryptography handshake + authenticated encryption for slice packages and RPC traffic.
12+
- Session manager: long-lived controller that maps client sessions to slice placements, manages QoS, adaptive batching, autoscaling, and failure recovery.
13+
14+
2. High-level architecture
15+
16+
Components:
17+
- Controller (central or local): plans partitioning, placement, and routes requests to workers.
18+
- Worker runtime: lightweight process on each device that accepts slice packages, registers capabilities (memory, device type), and executes slices.
19+
- Offload transport: secure RPC over TCP/QUIC with PQC handshake and integrity checks.
20+
- Session Manager: receives client requests, handles session state, batching, and QoS rules.
21+
- Scheduler: maps slices to workers, performs placement decisions using cost model and current telemetry.
22+
- Persistence: key/value store for slice metadata, session state, and logs (can be local filesystem or etcd for distributed setups).
23+
24+
3. Layer-splitting design
25+
26+
3.1 Partitioning model
27+
- Static split: for MVP, support deterministic splits at transformer block or attention/MLP block granularity. Input: model graph (ONNX, TorchScript), cost model, device inventory. Output: ordered list of slices with boundary tensor shapes and serialization descriptors.
28+
- Dynamic split (future): runtime re-partitioning based on latency/throughput signals.
29+
30+
3.2 Slice format
31+
- Metadata: slice id, inputs/outputs shapes, parameter size, expected memory footprint, device hints, version, policy tags (private/public).
32+
- Artifact: serialized weights in compact format (FP16/int8 quantized optional) + small runtime glue to map tensor ops.
33+
- Transport container: authenticated envelope (PQC AEAD) + optional compression.
34+
35+
3.3 Runtime ABI
36+
- Execute(slice_id, input_tensor, trace_id) -> output_tensor, metrics
37+
- Health(check) -> status
38+
- Preload(slice_id) -> ack
39+
40+
3.4 Scheduling and placement
41+
- Cost model inputs: parameter size, compute FLOPs per-token, estimated activation sizes, device throughput and free memory, network latency.
42+
- Heuristics for MVP: place compute-heavy contiguous slices on GPU if available; place small parameter slices on CPU to lower memory duplication; prefer colocated slices to reduce network hops.
43+
- Backpressure: if a worker is loaded, controller routes slice to alternate worker or falls back to local execution.
44+
45+
4. PQC-secured edge offload
46+
47+
4.1 Security goals
48+
- Confidentiality of slice weights when policy requires (IP protection).
49+
- Integrity of slice artifacts and runtime RPCs.
50+
- Forward-secure key exchange resistant to quantum-capable adversaries.
51+
52+
4.2 Keyflows and handshakes
53+
- Root authority: operator provides long-term signing key (classical/ECDSA) for worker identity; optionally use hardware TPM for key storage.
54+
- Session handshake: use a PQC KEM (e.g., Kyber or later NIST standard) to establish ephemeral symmetric AEAD keys per connection. Steps:
55+
1. Controller/worker exchange identity-signed certificates (classical) and PQC KEM public values.
56+
2. Both sides derive AEAD keys via HKDF over KEM shared secret and transcript.
57+
3. Optionally request remote attestation token before accepting slices (attestation hooks, e.g., Intel SGX/SEV or MDS attestation APIs).
58+
59+
4.3 Slice packaging & integrity
60+
- Each slice package: {manifest, weights.blob, signature, version}
61+
- Manifest contains policy tags; controller encrypts package with AEAD key and includes HMAC/signature for extra assurance.
62+
- Workers verify signature + AEAD before load.
63+
64+
4.4 Performance considerations
65+
- PQC KEM handshake cost is paid per long-lived connection; reuse AEAD keys for multiple RPCs.
66+
- For high-throughput edge fleets, pre-provision slice packages to workers via provisioning channel to avoid repeated KEM costs.
67+
68+
5. Session manager
69+
70+
5.1 API (gRPC/HTTP)
71+
- StartSession(request {model, routingHints, qos, tenant}) -> session_id
72+
- Infer(session_id, input, options {sync|async}) -> response stream or token
73+
- EndSession(session_id)
74+
- GetSessionStats(session_id) -> metrics
75+
76+
5.2 Session lifecycle
77+
- Session creation: controller allocates slices, populates placement plan, preloads prioritized slices on workers, returns session token.
78+
- Execution path: client -> session manager -> controller splits request across slices -> workers execute in pipeline -> session manager aggregates outputs.
79+
- Adaptive batching: session manager groups small inferences into micro-batches per slice based on configured latency budgets.
80+
81+
5.3 QoS and isolation
82+
- Per-session resource caps (max concurrency, token rate).
83+
- Tenant isolation: per-tenant slice caching and optional model duplication flags.
84+
- Fair queuing or priority queues for low-latency sessions.
85+
86+
6. Telemetry & metrics
87+
- Per-slice metrics: exec latency, memory usage, throughput, error rate.
88+
- Per-worker metrics: GPU util, free memory, network RTT, connection counts.
89+
- Per-session metrics: p50/p95/p99 latencies, batch sizes, tokens/sec.
90+
- Emit via Prometheus metrics endpoint and structured traces (OpenTelemetry) for tracing across slices.
91+
92+
7. Failure modes and fallbacks
93+
- Worker failure: controller reroutes to alternate worker or triggers local fallback (single-node execution). Evict/restore policy for preloaded slices.
94+
- Network partition: fall back to local execution when possible; if offload required, return graceful degradation messages to client.
95+
- Mismatched versions: use manifest version checks to prevent executing incompatible slices.
96+
97+
8. Interfaces & data formats
98+
- Model ingestion: accept ONNX and TorchScript (MVP) with translator that enumerates layer boundaries.
99+
- Slice artifact: gzipped protobuf or tar with manifest.json and weights.bin.
100+
- RPC: gRPC over QUIC (preferred) or HTTP/2 with AEAD wrapper.
101+
102+
9. Testing & benchmarks
103+
- Unit tests: correctness of slice outputs vs baseline single-node for a suite of models.
104+
- Integration tests: end-to-end run across two devices (GPU + CPU) validating activations and outputs.
105+
- Load tests: simulate 1k concurrent sessions with synthetic clients, measure p95 latency and throughput.
106+
- Security tests: verify PQC handshake, replay protection, and attestation flows.
107+
108+
10. MVP milestones and deliverables
109+
- Week 0–1: architecture doc, slice format, and prototype plan. (this doc)
110+
- Week 1–2: implement controller + worker minimal runtime and static partitioner that accepts a small transformer and emits slices.
111+
- Week 2–3: add PQC handshake, encrypted slice transport, and pre-provisioning flow.
112+
- Week 3–4: session manager with adaptive batching and basic QoS; run 1k simulated sessions.
113+
- Week 4–5: integration tests, telemetry dashboard, readme hero docs, and release prep.
114+
115+
11. Open questions
116+
- Target PQC primitives (Kyber, CRYSTALS-Kyber; choose current NIST-recommended variant). Decide whether to include hybrid classical+PQC key exchange.
117+
- Attestation strategy for diverse edge hardware — what minimal attestation APIs should we support for MVP?
118+
- Benchmark targets: supply representative hardware profiles to set realistic throughput/latency goals.
119+
120+
Appendix: quick dataflow
121+
1. `StartSession` -> controller computes split plan -> preloads slices to assigned workers (encrypted transfer).
122+
2. Client sends `Infer` -> session manager pipelines activations across workers over secure channels.
123+
3. Workers return outputs and metrics -> session manager aggregates and returns response.
124+
125+
Next steps: implement the static partitioner and minimal worker runtime (Week 1 task).

docs/PQC_INTEGRATION.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
liboqs (pyOQS) integration notes
2+
3+
Goal: Replace the placeholder X25519-only `PQCAdapter` with a hybrid KEM based on liboqs (e.g., Kyber) + X25519.
4+
5+
High level steps:
6+
7+
1. Install native liboqs and Python bindings (pyOQS).
8+
- On Ubuntu (example):
9+
```bash
10+
sudo apt-get update
11+
sudo apt-get install -y build-essential cmake libssl-dev pkg-config
12+
# Build and install liboqs from source (follow liboqs README)
13+
git clone --branch main https://github.com/open-quantum-safe/liboqs.git
14+
cd liboqs
15+
mkdir build && cd build
16+
cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
17+
make -j$(nproc)
18+
sudo make install
19+
20+
# Install the Python bindings that import as `oqs`
21+
pip install liboqs-python
22+
```
23+
- Alternatively use your distribution's packages or a prepared devcontainer that installs liboqs.
24+
- Set `OQS_INSTALL_PATH=/usr/local` when using a local source install so the binding can find the shared library.
25+
26+
2. Update `prototype/crypto.py` to perform a proper KEM exchange during handshake:
27+
- Controller: send X25519 pub + OQS pub to worker.
28+
- Worker: encapsulate to controller's OQS pub -> return encapsulation ciphertext + worker OQS pub.
29+
- Controller: decapsulate ciphertext to obtain OQS shared secret.
30+
- Final symmetric AEAD key = HKDF(X25519_shared || OQS_shared)
31+
- The current binding in this workspace exposes `oqs.KeyEncapsulation`, `generate_keypair()`, `encap_secret()`, and `decap_secret()`.
32+
33+
3. Tests & validation:
34+
- Run `pytest -q prototype/test_oqs_hybrid.py prototype/test_secure_hybrid_integration.py prototype/test_concurrency_smoke.py`.
35+
- Use `prototype/test_secure_run.py` as a quick smoke script when you want a single-session end-to-end check.
36+
- Ensure the worker `/handshake` returns `worker_oqs_pub_b64` and `worker_pub_b64` when liboqs is available.
37+
38+
Notes:
39+
- The repository already contains scaffolding in `prototype/crypto.py` to detect pyOQS at runtime and expose `get_oqs_public()`; complete integration requires invoking `kem.encapsulate()` and `kem.decapsulate()` where appropriate.
40+
- Building liboqs on CI requires adding native build steps in the pipeline; consider a GitHub Actions matrix job with a prebuilt liboqs artifact or using a self-hosted runner.
41+
- The CI workflow includes a manual `workflow_dispatch` trigger that can build liboqs from source when `build_liboqs` is enabled.
42+
43+
If you want, I can:
44+
- Implement the full handshake KEM flow (controller encapsulate/decapsulate and worker encapsulate) once you confirm installing `pyOQS` in the devcontainer/CI is acceptable, or
45+
- Prepare a PR that adds devcontainer Dockerfile steps to install liboqs so we can run the full integration here.

docs/SCOPE.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Scope & Success Criteria
2+
3+
Target: platform and infrastructure engineers, MLOps teams, and edge fleet operators who need production-grade inference beyond single-node setups.
4+
5+
MVP capabilities:
6+
- Multi-device layer splitting: demonstrate partitioning a medium-sized transformer across GPU and CPU with deterministic correctness and end-to-end inference.
7+
- Secure edge offload: implement PQC-based encryption and integrity checks for offloaded model slices and communications.
8+
- High-concurrency session management: support 1k+ concurrent lightweight sessions with per-session QoS and adaptive batching.
9+
10+
Success metrics:
11+
- Correctness: identical outputs (within numerical tolerance) compared to single-node baseline for partitioned runs.
12+
- Performance: 2× throughput improvement for target hardware when split across devices (measured on prototype hardware), and median p95 latency within target SLA for 95% of sessions.
13+
- Security: PQC handshake and slice integrity checks complete within acceptable overhead (<20% added latency in offload path) and keys/telemetry never expose raw weights.
14+
15+
Out of scope for MVP:
16+
- Full production orchestration (K8s operators) and UI consoles — focus is on core engine, APIs, and integrations.
17+
18+
Next: architecture spec covering layer-splitting algorithm, PQC keyflows, and session manager APIs.

prototype/README_PROTOTYPE.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
Prototype demo
2+
3+
This prototype demonstrates a minimal multi-device layer-splitting demo using a toy model. It simulates two workers (FastAPI) that accept slice preload and execution.
4+
5+
Quickstart:
6+
7+
1. Install dependencies:
8+
9+
```bash
10+
python -m pip install -r prototype/requirements.txt
11+
```
12+
13+
2. Start two workers in separate terminals (secure worker available):
14+
15+
```bash
16+
# insecure worker (no encryption)
17+
python prototype/worker.py --port 8001
18+
# secure worker (handshake + AEAD) listens on a separate port
19+
python prototype/worker_secure.py --port 8003
20+
```
21+
22+
3. Run the demo:
23+
24+
```bash
25+
python prototype/run_demo.py
26+
```
27+
28+
Notes:
29+
- This is a functional prototype illustrating partitioning, preload, and remote execution. It uses pickle-serialized weights and inputs for simplicity.
30+
- A secure path using X25519 + optional liboqs hybrid KEM is scaffolded in [prototype/crypto.py](prototype/crypto.py) and [prototype/worker_secure.py](prototype/worker_secure.py). To enable full hybrid PQC tests, install native liboqs plus the Python binding and set `OQS_INSTALL_PATH=/usr/local` (see [docs/PQC_INTEGRATION.md](docs/PQC_INTEGRATION.md)).
31+
- The in-process integration tests can be run with `pytest -q prototype/test_secure_hybrid_integration.py prototype/test_concurrency_smoke.py` once the environment is prepared.

prototype/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)