# Post-Quantum Cryptography

URL: https://docs.hanzo.ai/docs/zap/advanced/post-quantum

> ML-KEM, ML-DSA, and hybrid key exchange in ZAP

ZAP implements NIST-approved post-quantum algorithms to protect against future quantum computer attacks.

## Why Post-Quantum?

Current encryption (RSA, ECDSA, ECDH) will be broken by large-scale quantum computers. "Harvest now, decrypt later" attacks mean sensitive data encrypted today could be exposed in the future.

ZAP uses:

- **ML-KEM-768** (NIST FIPS 203) for key encapsulation
- **ML-DSA-65** (NIST FIPS 204) for digital signatures
- **Hybrid handshake** combining X25519 + ML-KEM for transitional security

## Key Types

### ML-KEM (Kyber)

Key encapsulation mechanism for secure key exchange:

```c
struct MLKEMPublicKey {
  # ML-KEM-768 public key (1184 bytes)
  data @0 :Data;
}

struct MLKEMCiphertext {
  # ML-KEM-768 ciphertext (1088 bytes)
  data @0 :Data;
}
```

### ML-DSA (Dilithium)

Digital signature scheme for authentication:

```c
struct MLDSAPublicKey {
  # ML-DSA-65 public key (1952 bytes)
  data @0 :Data;
}

struct MLDSASignature {
  # ML-DSA-65 detached signature (3293 bytes)
  data @0 :Data;
}
```

## Hybrid Handshake

ZAP uses a hybrid handshake combining classical and post-quantum algorithms:

### Handshake Flow

```text
Client                                     Server
  |                                           |
  |  PQHandshakeInit                          |
  |  - X25519 ephemeral public key (32B)      |
  |  - ML-KEM-768 public key (1184B)          |
  |  - Nonce (32B)                            |
  |  - Version                                |
  |  - Optional: identity key + signature     |
  |------------------------------------------>|
  |                                           |
  |  PQHandshakeResponse                      |
  |  - X25519 ephemeral public key (32B)      |
  |  - ML-KEM ciphertext (1088B)              |
  |  - Client nonce echo                      |
  |  - Server nonce (32B)                     |
  |  - Optional: identity key + signature     |
  |<------------------------------------------|
  |                                           |
  |  [Both derive shared secret]              |
  |  ss = HKDF(X25519_DH || ML-KEM_decap)     |
  |                                           |
  |  PQChannelMessage (encrypted RPC)         |
  |<==========================================>|
```

### Init Message

```c
struct PQHandshakeInit {
  # Client's X25519 ephemeral public key (32 bytes)
  x25519PublicKey @0 :Data;

  # Client's ML-KEM-768 public key for key encapsulation
  mlkemPublicKey @1 :MLKEMPublicKey;

  # Optional: Client's ML-DSA identity public key for authentication
  identityKey @2 :MLDSAPublicKey;

  # Optional: signature over (x25519PublicKey || mlkemPublicKey)
  identitySignature @3 :MLDSASignature;

  # Random nonce to prevent replay attacks
  nonce @4 :Data;

  # Protocol version
  version @5 :UInt16;
}
```

### Response Message

```c
struct PQHandshakeResponse {
  # Server's X25519 ephemeral public key (32 bytes)
  x25519PublicKey @0 :Data;

  # ML-KEM ciphertext containing encapsulated shared secret
  mlkemCiphertext @1 :MLKEMCiphertext;

  # Optional: Server's ML-DSA identity public key
  identityKey @2 :MLDSAPublicKey;

  # Optional: signature over (clientNonce || x25519PublicKey || mlkemCiphertext)
  identitySignature @3 :MLDSASignature;

  # Echo client nonce to bind response to request
  clientNonce @4 :Data;

  # Server nonce for session binding
  serverNonce @5 :Data;
}
```

## Key Derivation

The shared secret combines both classical and post-quantum sources:

```text
X25519_DH = X25519(client_sk, server_pk)
ML_KEM_SS = ML-KEM.Decapsulate(client_sk, ciphertext)

shared_secret = HKDF-SHA256(
  IKM = X25519_DH || ML_KEM_SS,
  salt = client_nonce || server_nonce,
  info = "ZAP-PQ-1"
)
```

This ensures security even if one algorithm is broken.

## Channel Encryption

After handshake, all messages are encrypted:

```c
struct PQChannelMessage {
  # Sequence number for replay protection
  sequence @0 :UInt64;

  # AEAD-encrypted payload (ChaCha20-Poly1305 or AES-256-GCM)
  ciphertext @1 :Data;

  # AEAD authentication tag
  tag @2 :Data;

  # Associated data (plaintext, authenticated but not encrypted)
  associatedData @3 :Data;
}
```

## Key Rotation

For long-lived sessions, keys can be rotated:

```c
struct PQKeyRotation {
  # New ML-KEM public key for next epoch
  newMlkemPublicKey @0 :MLKEMPublicKey;

  # ML-KEM ciphertext for the new key
  mlkemCiphertext @1 :MLKEMCiphertext;

  # Signature over (epoch || newMlkemPublicKey) with identity key
  signature @2 :MLDSASignature;

  # Epoch number (monotonically increasing)
  epoch @3 :UInt64;
}
```

## Usage Examples

### Rust

```rust
use zap_protocol::pq::{Identity, connect_pq};

// Generate identity
let identity = Identity::generate()?;
identity.save("./identity.key")?;

// Connect with PQ-TLS
let client = connect_pq("zap+pq://localhost:9000", identity).await?;
```

### Go

```go
import "github.com/zap-proto/go/pq"

// Generate identity
identity, _ := pq.GenerateIdentity()
identity.Save("./identity.key")

// Connect with PQ-TLS
client, _ := zap.Connect(ctx, "zap+pq://localhost:9000",
    zap.WithPQIdentity(identity))
```

### Python

```python
from zap_protocol.pq import Identity, connect_pq

# Generate identity
identity = Identity.generate()
identity.save("./identity.key")

# Connect with PQ-TLS
client = await connect_pq("zap+pq://localhost:9000", identity)
```

## Security Considerations

1. **Key Storage**: ML-DSA private keys are large (\~4KB). Use secure storage.
2. **Memory Safety**: Zeroize key material after use.
3. **Side Channels**: Use constant-time implementations.
4. **Hybrid Security**: Security relies on at least one algorithm being secure.

## Performance

| Operation      | Time (ms) | Size (bytes)        |
| -------------- | --------- | ------------------- |
| ML-KEM keygen  | 0.1       | 1184 pub, 2400 priv |
| ML-KEM encap   | 0.15      | 1088 ct, 32 ss      |
| ML-KEM decap   | 0.15      | 32 ss               |
| ML-DSA keygen  | 0.5       | 1952 pub, 4032 priv |
| ML-DSA sign    | 1.5       | 3293 sig            |
| ML-DSA verify  | 0.3       | -                   |
| Full handshake | \~5       | \~4KB total         |

## References

- [NIST FIPS 203: ML-KEM](https://csrc.nist.gov/pubs/fips/203/final)
- [NIST FIPS 204: ML-DSA](https://csrc.nist.gov/pubs/fips/204/final)
- [RFC 9180: HPKE](https://www.rfc-editor.org/rfc/rfc9180.html)
