PostQuantum.Hybrid 1.1.1

dotnet add package PostQuantum.Hybrid --version 1.1.1
                    
NuGet\Install-Package PostQuantum.Hybrid -Version 1.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PostQuantum.Hybrid" Version="1.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PostQuantum.Hybrid" Version="1.1.1" />
                    
Directory.Packages.props
<PackageReference Include="PostQuantum.Hybrid" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PostQuantum.Hybrid --version 1.1.1
                    
#r "nuget: PostQuantum.Hybrid, 1.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PostQuantum.Hybrid@1.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PostQuantum.Hybrid&version=1.1.1
                    
Install as a Cake Addin
#tool nuget:?package=PostQuantum.Hybrid&version=1.1.1
                    
Install as a Cake Tool

PostQuantum.Hybrid

CI CodeQL codecov Docs NuGet License: MIT

High-level hybrid post-quantum cryptography for .NET. Combines a battle-tested classical primitive with a NIST-standardized post-quantum algorithm so your shared secrets and signatures remain secure as long as either primitive holds — defense in depth against both today's attackers and tomorrow's quantum adversaries.

For .NET developers who need quantum-resistant key exchange and signatures without becoming cryptography experts.

  • Targets: .NET 8 and .NET 10
  • Backends: native System.Security.Cryptography.MLKem / MLDsa on .NET 10; BouncyCastle on .NET 8. Wire-compatible across both.
  • Dependencies: BouncyCastle.Cryptography only.

▶ Live demo — https://demo.pqhybrid.systemslibrarian.dev — Swagger UI at the root. Fetch the server's hybrid KEM and signature public keys, POST /seal a plaintext to round-trip an X25519 + ML-KEM-768 + AES-256-GCM envelope, or POST /sign to get an Ed25519 + ML-DSA-65 hybrid signature — all in the browser, no install. Runs on Azure Container Apps with the native .NET 10 ML-KEM / ML-DSA path (OpenSSL 3.6 baked into the image). Hosted scale-to-zero to keep costs near nothing — the first request after idle can take up to a minute to wake; reload if needed. Source: samples/WebApiDemo.

Why PostQuantum.Hybrid?

  • Safe by default. Every private-key and encapsulation type is IDisposable and zeros its buffers on dispose. Roslyn analyzers PQH001–PQH005 catch the common misuses — undisposed sensitive types, raw shared secrets used as keys, decapsulating before verifying, ignored Verify results, AEAD without KEM-ciphertext binding — at build time, with code-fixes for the mechanical ones.
  • Honest about limits. KNOWN-GAPS.md, docs/THREAT-MODEL.md, and docs/adr/ state exactly what the library does, does not do, and why.
  • Versioned wire format. Algorithm-id byte + fixed sizes means new combinations can be added later without breaking existing artifacts (see docs/SPEC.md).
  • Same blob on .NET 8 and .NET 10. Native BCL primitives on .NET 10, BouncyCastle fallback on .NET 8 — wire-compatible either direction.
  • One library, one ecosystem. Envelopes for Seal/Open, AspNetCore for DI + key rotation + IDataProtector, TestingSupport for downstream test suites, Templates for dotnet new scaffolds, a VS Code snippets extension for analyzer-clean starter code, and a downstream hardening audit script that scans consumer .csproj files for missing best-practice references.

Algorithms

Use case Default combination Standards
Key encapsulation X25519 + ML-KEM-768 RFC 7748 + FIPS 203
Digital signatures Ed25519 + ML-DSA-65 RFC 8032 + FIPS 204

Packages

Package Purpose
PostQuantum.Hybrid The library. Hybrid KEM and hybrid signatures.
PostQuantum.Hybrid.Envelopes Opinionated Seal/Open wrappers combining KEM + HKDF + AES-GCM in one call. Anonymous and signed variants.
PostQuantum.Hybrid.AspNetCore DI extensions: AddPostQuantumHybrid(...), rotating key providers (AddRotatingHybridKemKeys(...)).
PostQuantum.Hybrid.Analyzers Roslyn analyzers PQH001–PQH005 + code-fix providers that catch common misuse at build time.
PostQuantum.Hybrid.TestingSupport Cached test keys, tamper-injection helpers, fake key providers for consumers' test suites.
PostQuantum.Hybrid.Templates dotnet new pqhybrid-app / pqhybrid-webapi / pqhybrid-envelope scaffolds.

Install

dotnet add package PostQuantum.Hybrid
dotnet add package PostQuantum.Hybrid.Analyzers      # strongly recommended — catches misuse at build time
dotnet add package PostQuantum.Hybrid.Envelopes      # if you want one-call seal/open
dotnet add package PostQuantum.Hybrid.AspNetCore     # if you're in ASP.NET Core

Install the analyzers. PostQuantum.Hybrid.Analyzers is technically optional but turns five of the most-common cryptographic foot-guns into build-time errors. Skipping it is a hostile choice for your future self.

Or start a new project from a template:

dotnet new install PostQuantum.Hybrid.Templates

dotnet new pqhybrid-app      -n MyApp        # console KEM + signature demo
dotnet new pqhybrid-webapi   -n MyApi        # ASP.NET Core Minimal API starter
dotnet new pqhybrid-envelope -n MyEncryptor  # file-encryption CLI

Quick start — Hybrid KEM

using PostQuantum.Hybrid;

// Recipient: generate a key pair, publish the public key.
using var recipient = HybridKem.GenerateKeyPair();
byte[] publicKeyBytes = recipient.PublicKey.Export();

// Sender: encapsulate against the recipient's public key.
var publicKey = HybridKemPublicKey.Import(publicKeyBytes);
using var encapsulation = HybridKem.Encapsulate(publicKey);

byte[] ciphertext = encapsulation.Ciphertext.ToBytes();   // send to recipient
byte[] sharedSecret = encapsulation.SharedSecret;          // use locally (32 bytes)

// Recipient: decapsulate to recover the same shared secret.
byte[] recoveredSecret = HybridKem.Decapsulate(recipient.PrivateKey, ciphertext);
// recoveredSecret == sharedSecret

Quick start — Hybrid signatures

using PostQuantum.Hybrid;

using var signer = HybridSignature.GenerateKeyPair();

byte[] message = "Hello, post-quantum world!"u8.ToArray();
byte[] signature = HybridSignature.Sign(signer.PrivateKey, message);

bool valid = HybridSignature.Verify(signer.PublicKey, message, signature);

Samples

The samples/ folder has nine focused demos. See samples/README.md for the recommended reading order.

Sample What it shows
BasicDemo The shortest possible KEM + signature round trip.
EnvelopesDemo Recommended starting point. One-call HybridEnvelope.Seal/Open and SignedHybridEnvelope.Seal/Open — replaces the whole KEM → HKDF → AES-GCM pipeline.
KemEncryption The same encryption flow wired by hand — see what Envelopes does for you.
SignedDocument Detached document signature with publish/verify split.
KeyPersistence Save and load PEM keys with TryImportPem at the trust boundary.
SecureMessenger End-to-end signed-and-encrypted messaging (Alice → Bob).
LargeFileEncryption Chunked AES-GCM encryption of multi-GB files with one hybrid KEM exchange.
WebApiDemo ASP.NET Core Minimal API exercising the AspNetCore package's DI. Live at https://demo.pqhybrid.systemslibrarian.dev with Swagger UI at the root — no install needed.
KeyRotationDemo ASP.NET Core + AddRotatingHybridKemKeys + a sidecar that rewrites the on-disk PEM files every 15 s. Proves zero-downtime rotation.

Run any sample with:

dotnet run --project samples/EnvelopesDemo --framework net10.0

To exercise every sample on every TFM and assert each one's happy path, tamper detection, and analyzer-cleanness in one pass:

pwsh tools/run-all-samples.ps1

That script also runs the solution-wide build with TreatWarningsAsErrors=true first, so any analyzer regression in a sample fails the run before the samples even start.

Serialization

Every key/ciphertext/signature is a versioned, fixed-size byte blob. Both raw and PEM encodings are supported.

// Raw bytes
byte[] pubBytes = signer.PublicKey.Export();
var pubFromBytes = HybridSignaturePublicKey.Import(pubBytes);

// PEM
string pubPem = signer.PublicKey.ExportPem();
var pubFromPem = HybridSignaturePublicKey.ImportPem(pubPem);
Artifact Size (bytes) PEM label
Hybrid KEM public key 1217 PQH HYBRID KEM PUBLIC KEY
Hybrid KEM private key 2433 PQH HYBRID KEM PRIVATE KEY
Hybrid KEM ciphertext 1121 (raw only)
Hybrid signature public key 1985 PQH HYBRID SIG PUBLIC KEY
Hybrid signature private key 4065 PQH HYBRID SIG PRIVATE KEY
Hybrid signature 3374 (raw only)
Shared secret 32 (raw only)

For the full normative wire-format spec, see docs/SPEC.md.

X.509 SPKI / PKCS#8 envelopes (preview)

For embedding hybrid keys inside an X.509 certificate template or a PKCS#8-aware key store, the v1 wire format also rides inside a standard DER envelope:

byte[] spki  = signer.PublicKey.ExportSubjectPublicKeyInfo();
byte[] pkcs8 = signer.PrivateKey.ExportPkcs8PrivateKey();

var pubFromSpki  = HybridSignaturePublicKey.ImportSubjectPublicKeyInfo(spki);
using var privFromPkcs8 = HybridSignaturePrivateKey.ImportPkcs8PrivateKey(pkcs8);

The algorithm OIDs are placeholders under RFC 5612's IANA Example PEN (1.3.6.1.4.1.32473) until the IETF LAMPS WG finalizes composite OIDs. The framing is standard X.509 SPKI / PKCS#8 v1, so third-party DER tooling parses the structure; only the OID lookup will need updating when LAMPS ships. See ADR 0014.

Alternative combiner: X-Wing (preview)

Algorithm-id 0x02 swaps the v1 HKDF-SHA256 combiner for an X-Wing-style SHA3-256 combiner (per draft-connolly-cfrg-xwing-kem) over the same component sizes:

using var pair = HybridKem.GenerateKeyPair(HybridKemAlgorithm.X25519MlKem768XWing);

Opt-in only; HybridKem.Default stays on the v1 HKDF combiner. The v1 component layout is preserved, so the resulting blobs are not byte-compatible with the IETF X-Wing wire format (PQ-first ordering); for that, use HybridKemAlgorithm.XWing below. See ADR 0013.

Strict IETF X-Wing (preview)

Algorithm-id 0x03 is byte-for-byte IETF X-Wing per draft-connolly-cfrg-xwing-kem-10: PQ-first wire order (pk_M || pk_X, ct_M || ct_X) and a 32-byte seed as the entire private key, validated against the draft's official test vectors on both target frameworks.

using var pair = HybridKem.GenerateKeyPair(HybridKemAlgorithm.XWing);

Strip the 1-byte algorithm-id prefix from any exported blob and you have genuine X-Wing bytes for other stacks (CIRCL, libcrux, …); prepend 0x03 to foreign X-Wing material to import it. The SPKI / PKCS#8 exports use the draft's real id-XWing OID (1.3.6.1.4.1.62253.25722) with raw IETF inner bytes — no prefix — and re-encode Cloudflare CIRCL's published fixtures byte-for-byte. Preview until the draft becomes an RFC. See ADR 0015.

Performance

Pinned baselines from a BenchmarkDotNet run on Windows 11 + Intel Core Ultra 7 256V @ 2.20 GHz (see benchmarks/). The weekly Benchmarks workflow re-runs these on every push to track regressions; the tools/compare-benchmarks.ps1 script gates PRs at +25% over baseline.

.NET 10 (native MLKem / MLDsa):

Operation Mean Allocated
HybridKem.GenerateKeyPair 277 µs 6.3 KB
HybridKem.Encapsulate 503 µs 6.2 KB
HybridKem.Decapsulate 322 µs 3.1 KB
HybridSignature.GenerateKeyPair 1.80 ms 9.5 KB
HybridSignature.Sign (64 B msg) 1.63 ms 11.4 KB
HybridSignature.Sign (64 KB msg) 3.23 ms 139 KB
HybridSignature.Verify (64 B msg) 583 µs 7.1 KB
HybridSignature.Verify (64 KB msg) 1.56 ms 135 KB

.NET 8 (BouncyCastle backend):

Operation Mean Allocated
HybridKem.GenerateKeyPair 591 µs 29 KB
HybridKem.Encapsulate 978 µs 36 KB
HybridKem.Decapsulate 861 µs 40 KB
HybridSignature.Sign (64 B msg) 4.17 ms 640 KB
HybridSignature.Verify (64 B msg) 1.14 ms 189 KB

The native net10.0 backend is roughly 2–3× faster and 10–60× less allocation-heavy than the net8.0 BouncyCastle fallback, depending on the operation. Both wire-compatibly produce the same 1217 / 2433 / 1121 / 1985 / 4065 / 3374 byte artifacts.

How it works

Hybrid KEM combiner

The two component shared secrets are combined with HKDF-SHA256, with both ciphertexts bound into the info parameter so the derived secret depends on the full transcript:

sharedSecret = HKDF-SHA256(
    ikm  = ss_x25519 ‖ ss_mlkem,
    info = "PostQuantum.Hybrid v1 KEM X25519-MLKEM768" ‖ ct_x25519 ‖ ct_mlkem,
    len  = 32 )

See ADR 0003 for rationale.

Hybrid signature combiner

Both schemes independently sign the message bytes (each does its own internal hashing). The signatures are concatenated; verification requires both to verify. See ADR 0004.

Security

  • Algorithm agility: wire format begins with a 1-byte algorithm identifier so future combinations can be added without breaking existing artifacts.
  • Implicit rejection: ML-KEM uses FIPS 203's implicit rejection — malformed ciphertexts yield pseudorandom secrets rather than throwing.
  • Sensitive material: every private-key type implements IDisposable and zeros its buffers on dispose.
  • Build-time misuse checks: PostQuantum.Hybrid.Analyzers ships five rules with code-fixes — PQH001 (undisposed sensitive types), PQH002 (raw SharedSecret used as a symmetric key without HKDF), PQH003 (decapsulate before verify), PQH004 (ignored HybridSignature.Verify result), and PQH005 (AEAD without KEM-ciphertext binding as associatedData).
  • Signature randomization: ML-DSA signing is randomized by default — two signatures over the same data will differ. This is expected.

Detailed security guidance:

Consumer self-check:

pwsh scripts/audit-pqh.ps1 -Path path/to/your/solution

The audit script walks consumer .csproj files, flags projects that reference PostQuantum.Hybrid without also referencing PostQuantum.Hybrid.Analyzers, and prints a punch list. See scripts/README.md.

Documentation

Doc Audience
README.md Everyone — entry point
DocFX site Browsable API reference + handwritten guides (auto-deploys on push to main)
docs/SPEC.md Implementers porting to another language
docs/design.md Reviewers, anyone asking "why these choices?"
docs/THREAT-MODEL.md Security reviewers
docs/adr/ Architecture decision records (currently 14)
HARDENING-CHECKLIST.md Operators deploying to production
SECURITY.md Vulnerability reporters
CONTRIBUTING.md Contributors
CLAUDE.md AI coding assistants working in this repo
src/LLM-USAGE.md AI coding assistants generating user code
src/SECURE-USAGE.md Developers writing application code
samples/README.md Walking the 9 sample demos in order
scripts/README.md Consumer audit script
vscode-extension/README.md VS Code snippets extension
KNOWN-GAPS.md Anyone asking "does it do X?"
CHANGELOG.md Version history

Repo layout

src/PostQuantum.Hybrid/                       the library
src/PostQuantum.Hybrid.Envelopes/             Seal/Open opinionated wrappers
src/PostQuantum.Hybrid.AspNetCore/            DI + key rotation for ASP.NET Core
src/PostQuantum.Hybrid.Analyzers/             Roslyn analyzers + code-fixes (PQH001-005)
src/PostQuantum.Hybrid.TestingSupport/        test helpers for consumers
tests/PostQuantum.Hybrid.Tests/               xUnit tests (run on net8.0 and net10.0)
tests/PostQuantum.Hybrid.Envelopes.Tests/     Envelopes tests
tests/PostQuantum.Hybrid.AspNetCore.Tests/    DI + rotation tests
tests/PostQuantum.Hybrid.Analyzers.Tests/     analyzer tests
tests/PostQuantum.Hybrid.TestingSupport.Tests/ test-helpers tests
fuzz/PostQuantum.Hybrid.Fuzz/                 property-style fuzz tests
benchmarks/PostQuantum.Hybrid.Benchmarks/     BenchmarkDotNet suite
samples/                                      9 focused demos (BasicDemo .. KeyRotationDemo)
templates/                                    3 dotnet new templates
docs/                                         spec, design, ADRs (1-14), threat model, perf
docs-site/                                    DocFX config + landing pages (deploys to GH Pages)
scripts/                                      consumer preflight tools (see scripts/README.md)
tools/                                        repo maintenance scripts (incl. run-all-samples.ps1)
vscode-extension/                             PostQuantum.Hybrid Snippets (VS Code Marketplace)
.github/                                      CI, CodeQL, release, SBOM, mutation, bench, docs

Development

# Build everything
dotnet build PostQuantum.Hybrid.slnx

# Run all tests on all TFMs (340+ tests across 5 suites)
dotnet test PostQuantum.Hybrid.slnx

# Run every sample on every TFM (18 runs) with stricter checks than the test
# suite alone — exit codes, expected output, stack-trace scanning, end-to-end
# HTTP for the web samples, SHA-256 diff for LargeFileEncryption, full
# zero-downtime rotation flow for KeyRotationDemo
pwsh tools/run-all-samples.ps1

# Run the broader "is everything green?" wrapper
pwsh tools/run-all.ps1

# Run benchmarks (Release only)
dotnet run --project benchmarks/PostQuantum.Hybrid.Benchmarks --framework net10.0 --configuration Release

# Build the DocFX site locally
docfx docs-site/docfx.json --serve

License

MIT. See LICENSE.


To God be the glory — 1 Corinthians 10:31.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on PostQuantum.Hybrid:

Package Downloads
PostQuantum.Hybrid.AspNetCore

ASP.NET Core extensions for PostQuantum.Hybrid: dependency-injection helpers for loading hybrid KEM and signature keys from configuration, plus opinionated IHybridKeyProvider abstractions.

PostQuantum.Hybrid.TestingSupport

Test helpers for projects that consume PostQuantum.Hybrid. Cached deterministic test keys (HybridTestKeys), fake KemKeyProvider / SignatureKeyProvider, and tamper-injection helpers for negative-path tests.

PostQuantum.Hybrid.Envelopes

Opinionated, misuse-resistant message envelopes for PostQuantum.Hybrid. HybridEnvelope.Seal / Open wrap KEM + HKDF + AES-GCM into one call; SignedHybridEnvelope.Seal / Open add hybrid authentication on top.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.1 75 6/10/2026
1.1.0 72 6/10/2026
1.0.1 151 6/8/2026
1.0.0 140 6/7/2026