Inspiration

Post-quantum cryptography is coming whether or not most Java teams are ready for it, and the teams with the most riding on it — regulated shops in finance and insurance — are also the ones least able to gamble on a rewrite. There's a lot of PQC benchmarking floating around, but very little of it is measured on the hardware an increasing share of production and AI infrastructure actually runs on: Arm64 (Graviton, Azure Cobalt 100, Ampere). We wanted a real, working migration, not a proof of concept, benchmarked on real Arm64 silicon, honest about what actually got faster and what didn't.

What it does

Latticejack migrates a Java mTLS reference service from classical TLS 1.3 (ECDSA P-256 + X25519) to hybrid post-quantum TLS 1.3 (X25519MLKEM768) — self-verifying, asserting a HelloRetryRequest occurred so "success" can't be a silent fallback to classical. Then it tries eight concrete ways to claw back the latency hybrid PQC costs, all measured on real Azure Cobalt 100 (Neoverse-N2) hardware: session resumption, JVM tuning, JDK 25's built-in ML-KEM intrinsics, GraalVM native-image, hand-tuned NEON assembly (mlkem-native) via Java's Foreign Function & Memory API, Java's Vector API, and two Rust comparisons. Two levers came back null — reported as findings, not hidden. Two produced real wins: GraalVM native-image (~7.9x faster cold start) and mlkem-native via FFM (~4.0x faster end-to-end), the latter now wired directly into the real handshake behind an opt-in flag.

Behind the PQC handshake sits a real AI workload too: a quantized LLM served by llama.cpp with Arm's KleidiAI backend, positively verified engaged — not just linked-and-hoping. And judges don't have to take any of this on faith: latticejack.itinerario.io boots a real Azure Cobalt 100 VM on demand, streams its actual output to the browser — classical TLS, hybrid PQC, native ML-KEM, a real AI reply — then deallocates itself. Not a recording.

How we built it

Component A is a raw-JSSE Java service running BouncyCastle 1.85's BCJSSE provider for the hybrid group. Component B1/B2 is a from-scratch benchmark harness (no HdrHistogram, no framework) that measured all eight optimization levers on the same real 2-vCPU Azure Cobalt 100 VM, three-run averaged for levers 3 through 8. Component C is a Claude Code Skill (skills/pqc-authoring/) that reviews TLS code for regressions back to classical crypto — demonstrated and executed live against fresh input — plus a CycloneDX 1.6 CBOM validated against the real published schema with a committed, re-runnable validator.

The live demo is a Cloudflare Worker + Durable Object orchestrating a real Azure VM lifecycle (provision, run, stream, deallocate) behind a Cloudflare Turnstile gate, with a Playwright-recorded, narrated demo video built entirely from real captured footage.

Challenges we ran into

Almost everything we assumed going in needed correcting once we actually measured. A local (Apple Silicon) signal for JVM tuning flags completely evaporated on real Arm64 hardware; a "near-guaranteed win" for session resumption measured at under 2%, and a later independent audit found even that number wasn't confirmed by the harness's own resumption-detection logic. We found that our fastest optimization — the native ML-KEM integration — was deriving real TLS session secrets from deterministic, non-cryptographic key material: a genuine security bug in our own code. After fixing it, verified two keygens now produce different keys where before they were identical, and re-measured on real hardware to see what the fix actually cost (it erased a small performance edge that had never been real). Getting the live demo working end-to-end on real Azure infrastructure had its own gauntlet: Azure AD client-secret propagation delays, a missing environment variable found by SSHing into a live VM, and a Cloudflare Workers config bug that silently swallowed our account_id.

What we learned

Measure, don't assume — in both directions. Some effects that looked real locally vanished on real target hardware, and some effects too small to trust on a fast laptop turned out to be real and repeatable on the actual chip. It is also important to check for real security bug in fastest optimization. And "AI solution on Arm" is stronger as a working, verified artifact (a real LLM behind a real PQC handshake, a real Skill executed against fresh input) than as an argument about what TLS is generally used for.

What's next

Wiring GraalVM native-image and the native ML-KEM path together, an x86-vs-Arm64 cross-reference (flagged in our own write-up as not yet done), and ML-DSA post-quantum certificate authentication once it stabilizes upstream in BouncyCastle.

Built With

  • arm64
  • azure
  • bouncycastle
  • claude-code
  • claude-code-skills
  • cloudflare-turnstile
  • cloudflare-workers
  • cobalt-100
  • durable-objects
  • ffm
  • graalvm
  • java
  • jdk21
  • kleidiai
  • kyber
  • llama-cpp
  • maven
  • ml-kem
  • native-image
  • neon
  • neoverse-n2
  • post-quantum-cryptography
  • rust
  • tls-1-3
  • x25519
Share this project:

Updates