PQC Hypervisor Attestation
Sigstore for hypervisor memory attestation. When an AI workload runs inside a cloud VM, the hypervisor (KVM, QEMU, Hyper-V) is transparent: nothing cryptographically proves to the tenant that model weights in RAM have not been read or rewritten by a malicious host. This library is the post-quantum cryptographic envelope — MemoryRegion, AttestationClaim, AttestationReport, ML-DSA-signed, independently verifiable — that a hypervisor project, TEE runtime, or confidential-computing framework can plug its memory-reading primitives into. The library ships pluggable backends for AMD SEV-SNP and Intel TDX as stubs, plus a reference InMemoryBackend for tests.
The Problem
Cloud AI inference workloads place multi-hundred-megabyte model weights in guest memory. The hypervisor can read or rewrite every page. Today's tenants rely on contractual trust ("the cloud provider said they wouldn't") plus coarse platform-level attestation (MRTD, launch digest) that only covers VM boot — not the runtime state of the pages you actually care about. An attacker with host compromise, or a curious operator, can:
- Silently exfiltrate proprietary model weights.
- Swap in backdoored weights for a single request.
- Corrupt the KV cache to influence in-flight generations.
None of this is visible to the guest without a runtime memory attestation protocol. And any attestation that signs memory state with RSA or ECDSA today is retroactively forgeable once a CRQC exists — which is why the cryptographic envelope must be post-quantum from day one.
The Solution
Every attestation is a post-quantum signed, freshness-bounded claim about specific memory regions:
- SHA3-256 per-region content hashes — deterministic snapshot of what lives at those pages.
- ML-DSA (FIPS 204) signature over the canonical report bytes, by a known attester DID.
- Expiry and nonce for replay resistance.
- Expected-hash pinning so a remote verifier can detect drift from trusted state.
- Pluggable backends — the library never reads memory itself; backends do, using
/dev/sev-guest,/dev/tdx-guest, or whatever primitive the real TEE exposes.
Installation
pip install pqc-hypervisor-attestation
Development:
pip install -e ".[dev]"
Quick Start
from quantumshield.identity.agent import AgentIdentity
from pqc_hypervisor_attestation import (
AttestationVerifier,
Attester,
ContinuousAttester,
InMemoryBackend,
MemoryRegion,
RegionSnapshot,
)
# 1. Identity + signer.
identity = AgentIdentity.create("llama-host-attester", capabilities=["attest"])
attester = Attester(identity)
# 2. Backend with a pinned region.
backend = InMemoryBackend()
weights = MemoryRegion(
region_id="model-weights-0",
description="Llama weight shard 0",
address=0x1000,
size=128,
protection="RO",
)
content = b"\xaa" * 128
backend.register("model-serving-1", weights, content)
# 3. Continuous attester with pinned expected hash.
loop = ContinuousAttester(
attester=attester,
backend=backend,
workload_id="model-serving-1",
expected_hashes={weights.region_id: RegionSnapshot.hash_bytes(content)},
)
report = loop.attest_once()
result = AttestationVerifier.verify(report, strict=True)
assert result.valid
Architecture
+-----------------------------+ +------------------------------+
| AI workload (guest VM) | | Remote verifier |
| | | |
| ContinuousAttester | | AttestationVerifier |
| | | | | |
| v | | v |
| AttestationBackend | | - ML-DSA signature check |
| (SEV-SNP | TDX | memory) | | - expiry check |
| | | | - expected_hash pinning |
| v | | |
| MemoryRegion ---> RegionSnapshot -> AttestationClaim |
| | |
| v |
| AttestationReport (bundle) |
| | |
| v |
| ML-DSA sign (quantumshield) |
+-----------------------------+ +------------------------------+
| ^
| signed AttestationReport |
+---------------------------------+
Cryptography
| Primitive | Purpose | Algorithm |
|---|---|---|
| Region content hash | Fingerprint memory bytes | SHA3-256 |
| Report canonical digest | Input to signer | SHA3-256 |
| Attestation signature | Bind report to attester DID | ML-DSA-65 |
| Verifier trust anchor | Attester public key (from DID / keystore) | ML-DSA public |
All signing is delegated to quantumshield, which prefers real liboqs ML-DSA when available and falls back to transitional Ed25519.
Threat Model
| Adversary capability | Coverage |
|---|---|
| Forges an attestation report from scratch | Blocked — requires the attester's ML-DSA private key. |
| Replays an old valid report to hide drift | Blocked — expires_at bound + per-report nonce in each claim. |
| Rewrites model weights in guest memory | Detected — region snapshot hash diverges from expected_hash. |
| Substitutes a newer signed report from same key | Mitigated — verifier pins expected hashes independently. |
| Tampers with report fields in transit | Blocked — canonical-bytes + ML-DSA binds every field. |
| Q-day adversary with CRQC | Out of scope for ECDSA/RSA signers; covered here by ML-DSA. |
| Compromises the attester key via guest escape | Out of scope — mitigate with SEV-SNP / TDX sealed key storage. |
Backend Integration Guide
The library defines a single abstract interface:
class AttestationBackend(ABC):
name: str
platform: str
def list_regions(self, workload_id: str) -> list[MemoryRegion]: ...
def snapshot(self, region: MemoryRegion) -> RegionSnapshot: ...
Any backend that can enumerate memory ranges and hash their bytes can plug in.
AMD SEV-SNP (/dev/sev-guest)
The shipped AMDSEVSNPBackend is a stub that documents the expected behaviour. A real integration:
- Reads the SEV-SNP launch digest at VM start and stores per-region base/size in its workload manifest.
- For
list_regions, returnsMemoryRegionentries whoseaddressis the guest-physical base andsizeis the range length. - For
snapshot, issues theSNP_GET_REPORTioctl on/dev/sev-guest, reads the backing pages into a buffer, and returnsRegionSnapshot.create(region_id, buffer).
Intel TDX (/dev/tdx-guest)
IntelTDXBackend follows the same pattern using TDX_CMD_GET_REPORT0 and the TD's MRTD / RTMR measurements.
Your own backend
Subclass AttestationBackend, implement list_regions and snapshot, and pass an instance to ContinuousAttester. The library handles canonicalisation, signing, and verification uniformly.
API Reference
Data types
| Class | Description |
|---|---|
MemoryRegion |
Addressable range (region_id, address, size, protection). |
RegionSnapshot |
(region_id, content_hash, size, taken_at) SHA3-256 fingerprint. |
AttestationClaim |
One signed statement about one region at one point in time. |
AttestationReport |
Bundle of claims + ML-DSA envelope + expiry. |
VerificationResult |
Breakdown of signature / expiry / drift checks. |
Signers and verifiers
| Symbol | Purpose |
|---|---|
Attester |
Wraps an AgentIdentity; signs reports. |
AttestationVerifier |
Static verifier; returns VerificationResult. |
AttestationVerifier.verify_or_raise |
Raises RegionDriftError / AttestationVerificationError. |
ContinuousAttester |
Periodic loop: enumerate regions, snapshot, sign. |
Backends
| Class | Use |
|---|---|
InMemoryBackend |
Reference / tests / tutorials. |
AMDSEVSNPBackend |
Stub for AMD SEV-SNP (plug into /dev/sev-guest). |
IntelTDXBackend |
Stub for Intel TDX (plug into /dev/tdx-guest). |
Exceptions
HypervisorAttestationError -> InvalidRegionError, AttestationVerificationError (-> RegionDriftError), BackendError (-> UnknownBackendError).
Why PQC Matters for Hypervisor Attestation
Cloud confidential-computing deployments live for a decade or more. A VM image spun up in 2026 may still be attested by the same kind of signature in 2036 — long enough for a CRQC to exist. An attestation signed today with ECDSA or RSA can be retroactively forged by any adversary holding a recording of the public key and the signed payload: in 2035 they can manufacture a fresh, valid-looking "clean" attestation for a workload they actually tampered with in 2026, and no auditor can distinguish it from a real one. Post-quantum signatures break that chain: even with Shor's algorithm, ML-DSA remains unbroken, so historical attestations continue to bind the host to its claim. Hypervisor attestation is exactly the place that non-repudiation must survive the cryptographic transition.
Examples
examples/basic_attestation.py— end-to-end sign-and-verify over two in-memory regions.examples/detect_memory_tampering.py— mutate a region between attestations and watch drift surface.examples/continuous_loop_demo.py— run the periodic attestation loop and stream reports.
License
Apache 2.0. See LICENSE.
Release files for pqc-hypervisor-attestation 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pqc_hypervisor_attestation-0.1.0.tar.gz | 19.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pqc_hypervisor_attestation-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.9 kB
Release files / pqc_hypervisor_attestation-0.1.0.tar.gz
| Download URL | pqc_hypervisor_attestation-0.1.0.tar.gz |
|---|---|
| Size | 19.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
66e558995b52c4b51ba11b1dd9a5f5951d41ebc0a546cdf5fc50da1e6d6dfd2e
|
|
BLAKE2b-256 checksum How to use checksums |
dbecd084843f50ef8af579f0047d625900abad5962f4693dede707bdd27477ee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / pqc_hypervisor_attestation-0.1.0-py3-none-any.whl
| Download URL | pqc_hypervisor_attestation-0.1.0-py3-none-any.whl |
|---|---|
| Size | 19.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a3daf775f7d9bbbb70da2a6788ed693b69a1cfea395daead30c6f695c8fc757e
|
|
BLAKE2b-256 checksum How to use checksums |
c469193b1d37d7a99170b10464f6920dbb5c3db013696610eb7eabdf29abb7b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|