Metadata-Version: 2.4
Name: pqc-hypervisor-attestation
Version: 0.1.0
Summary: PQC-signed hypervisor memory attestation framework for AI workloads. ML-DSA signed claims about memory region state, pluggable backends for AMD SEV-SNP and Intel TDX.
Author: Dyber PQC
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: attestation,confidential-computing,hypervisor,ml-dsa,pqc,sev-snp,tdx
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.10
Requires-Dist: quantumshield>=0.1.0
Provides-Extra: dev
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Description-Content-Type: text/markdown

# PQC Hypervisor Attestation

![PQC Native](https://img.shields.io/badge/PQC-Native-blue)
![ML-DSA-65](https://img.shields.io/badge/ML--DSA--65-FIPS%20204-green)
![Backends](https://img.shields.io/badge/backends-SEV--SNP%20%7C%20TDX%20ready-purple)
![License](https://img.shields.io/badge/License-Apache%202.0-orange)
![Version](https://img.shields.io/badge/version-0.1.0-lightgrey)

**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

```bash
pip install pqc-hypervisor-attestation
```

Development:

```bash
pip install -e ".[dev]"
```

## Quick Start

```python
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`](https://github.com/dyber-pqc/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:

```python
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:

1. Reads the SEV-SNP launch digest at VM start and stores per-region base/size in its workload manifest.
2. For `list_regions`, returns `MemoryRegion` entries whose `address` is the guest-physical base and `size` is the range length.
3. For `snapshot`, issues the `SNP_GET_REPORT` ioctl on `/dev/sev-guest`, reads the backing pages into a buffer, and returns `RegionSnapshot.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`](examples/basic_attestation.py) — end-to-end sign-and-verify over two in-memory regions.
* [`examples/detect_memory_tampering.py`](examples/detect_memory_tampering.py) — mutate a region between attestations and watch drift surface.
* [`examples/continuous_loop_demo.py`](examples/continuous_loop_demo.py) — run the periodic attestation loop and stream reports.

## License

Apache 2.0. See [LICENSE](LICENSE).
