# ant-quic
**Pure Post-Quantum QUIC** transport with NAT traversal for P2P networks. Every node is symmetric - can connect AND accept connections.
[](https://docs.rs/ant-quic/)
[](https://crates.io/crates/ant-quic)
[](LICENSE-MIT)
[](LICENSE-APACHE)
[](https://github.com/dirvine/ant-quic/actions/workflows/ci.yml)
[](https://github.com/dirvine/ant-quic/actions/workflows/security.yml)
## Key Features
- **🔐 Pure Post-Quantum Cryptography (v0.2)** - ML-KEM-768 + ML-DSA-65 ONLY - no classical fallback
- **Symmetric P2P Nodes** - Every node is identical: connect, accept, coordinate
- **Automatic NAT Traversal** - Per [draft-seemann-quic-nat-traversal-02](docs/rfcs/draft-seemann-quic-nat-traversal-02.txt)
- **External Address Discovery** - Per [draft-ietf-quic-address-discovery-00](docs/rfcs/draft-ietf-quic-address-discovery-00.txt)
- **Default-On Local Discovery** - First-party scoped mDNS is built in and enabled by default on non-loopback endpoints
- **Router-Assisted Reachability** - UPnP IGD is part of the implemented connectivity stack as a best-effort local-router port-mapping assist layer (enabled by default, disable with `--no-port-mapping`)
- **Assist Capability Hints** - Nodes advertise relay/bootstrap/coordinator willingness by default; peers still decide whether to use them
- **Pure PQC Raw Public Keys** - ML-DSA-65 authentication per [our specification](docs/rfcs/ant-quic-pqc-authentication.md)
- **Zero Configuration Required** - Sensible defaults, just create and connect
- **Powered by [saorsa-pqc](https://crates.io/crates/saorsa-pqc)** - NIST FIPS 203/204 compliant implementations
## Quick Start
```rust
use ant_quic::{P2pEndpoint, P2pConfig};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Create a P2P endpoint - PQC is always on
let config = P2pConfig::builder()
.known_peer("peer.example.com:9000".parse()?)
.build()?;
let endpoint = P2pEndpoint::new(config).await?;
println!("Peer ID: {:?}", endpoint.peer_id());
// Seed connectivity and address discovery through the unified path
endpoint.connect_known_peers().await?;
// Your external address may become known after seeded peer observation
if let Some(addr) = endpoint.external_addr() {
println!("External address: {}", addr);
}
// Best-effort router port mapping contributes an additional candidate when available
if let Some(mapped) = endpoint.port_mapping_addr() {
println!("Router-mapped address: {}", mapped);
}
Ok(())
}
```
## Architecture
ant-quic uses a **symmetric P2P model** where every node has identical capabilities:
```
┌─────────────┐ ┌─────────────┐
│ Node A │◄───────►│ Node B │
│ (peer) │ QUIC │ (peer) │
│ │ PQC │ │
└─────────────┘ └─────────────┘
│ │
│ OBSERVED_ADDRESS │
│◄──────────────────────┤
│ │
├──────────────────────►│
│ ADD_ADDRESS │
└───────────────────────┘
```
### No Roles - All Nodes Are Equal
In v0.13.0, we removed all role distinctions:
- No `EndpointRole::Client/Server/Bootstrap`
- No `NatTraversalRole` enum
- **Any peer can coordinate** NAT traversal for other peers
- **Any peer can report** your external address via OBSERVED_ADDRESS frames
The term "known_peers" replaces "bootstrap_nodes" - they're just addresses to connect to first. In practice, seeded known peers and refreshed runtime peers provide the initial address-observation context.
**PeerId vs SocketAddr**: `PeerId` is the durable peer identity. `SocketAddr`
is only a routing/contact hint and may change across NAT rebinding,
reconnects, or path migration. Persist coordinator/bootstrap knowledge by
`PeerId`, then update the latest known `SocketAddr` as reachability changes.
**Measure, don't trust**: capability hints are treated as unverified signals.
Peers are selected based on observed reachability and success rates, not
self-asserted roles.
### Three-Layer Design
1. **Protocol Layer**: QUIC + NAT traversal extension frames
2. **Integration APIs**: `P2pEndpoint`, `P2pConfig`
3. **Applications**: Binary, examples
## Pure Post-Quantum Cryptography (v0.2)
**ant-quic v0.2 uses PURE post-quantum cryptography** - no classical algorithms, no hybrid modes, no fallback.
This is a greenfield network with no legacy compatibility requirements.
### Algorithms
| **ML-KEM-768** | FIPS 203 | Key Exchange | NIST Level 3 (192-bit) | 0x0201 |
| **ML-DSA-65** | FIPS 204 | Digital Signatures | NIST Level 3 (192-bit) | 0x0905 |
### Powered by saorsa-pqc
ant-quic uses [saorsa-pqc](https://crates.io/crates/saorsa-pqc) for all PQC operations:
- **NIST FIPS 203/204 compliant** implementations
- **AVX2/AVX-512/NEON** hardware acceleration
- **Constant-time operations** for side-channel resistance
- **Extensively tested** against NIST Known Answer Tests (KATs)
```rust
use ant_quic::crypto::pqc::PqcConfig;
let pqc = PqcConfig::builder()
.ml_kem(true) // ML-KEM-768 key exchange
.ml_dsa(true) // ML-DSA-65 signatures
.memory_pool_size(10) // Memory pool for crypto ops
.handshake_timeout_multiplier(2.0) // PQC handshakes are larger
.build()?;
```
### Why Pure PQC (No Hybrid)?
- **Greenfield Network** - No legacy systems to maintain compatibility with
- **Maximum Security** - No weak classical algorithms in the chain
- **Simpler Implementation** - One cryptographic path, fewer edge cases
- **Future-Proof** - All connections quantum-resistant from day one
- **NIST Standardized** - ML-KEM and ML-DSA are FIPS 203/204 standards
### Identity Model
- **32-byte PeerId** - SHA-256 hash of ML-DSA-65 public key (compact identifier for durable peer identity)
- **SocketAddr is not identity** - addresses are ephemeral reachability hints and must be treated as mutable contact metadata
- **ML-DSA-65 Authentication** - All TLS handshake signatures use pure PQC
- **ML-KEM-768 Key Exchange** - All key agreement uses pure PQC
See [docs/guides/pqc-security.md](docs/guides/pqc-security.md) for security analysis.
## NAT Traversal
NAT traversal is built into the QUIC protocol via extension frames, not STUN/TURN.
In addition, the connectivity architecture now treats **UPnP IGD** as a
best-effort local-router assist layer on compatible home networks. This is
additive: it can improve inbound reachability and yield a better external
candidate address, but native QUIC address discovery, hole punching, and MASQUE
relay fallback remain the core connectivity path.
### Connectivity Stack
1. **Router assist (UPnP IGD)** — best-effort local gateway port mapping on compatible home routers
2. **Native QUIC NAT traversal** — OBSERVED_ADDRESS + ADD_ADDRESS + PUNCH_ME_NOW
3. **MASQUE relay fallback** — last-resort reachability when direct paths still fail
### How It Works
1. **Connect to one or more known/runtime peers**
2. **A connected peer may observe your external address** from incoming packets
3. **That peer can send an OBSERVED_ADDRESS frame** back to you
4. **You may learn a public address candidate** and use it for later coordination
5. **Direct P2P connection may then be established** through NAT
### Extension Frames
| `ADD_ADDRESS` | 0x3d7e90 (IPv4), 0x3d7e91 (IPv6) | Advertise candidate addresses |
| `PUNCH_ME_NOW` | 0x3d7e92 (IPv4), 0x3d7e93 (IPv6) | Coordinate hole punching timing |
| `REMOVE_ADDRESS` | 0x3d7e94 | Remove stale address |
| `OBSERVED_ADDRESS` | 0x9f81a6 (IPv4), 0x9f81a7 (IPv6) | Report external address to peer |
### Transport Parameters
| NAT Traversal Capability | 0x3d7e9f0bca12fea6 | Negotiates NAT traversal support |
| RFC-Compliant Frames | 0x3d7e9f0bca12fea8 | Enables RFC frame format |
| Address Discovery | 0x9f81a176 | Configures address observation |
### NAT Type Support
| Full Cone | >95% | Direct connection |
| Restricted Cone | 80-90% | Coordinated punch |
| Port Restricted | 70-85% | Port-specific coordination |
| Symmetric | 60-80% | Prediction algorithms |
| CGNAT | 50-70% | Relay fallback may be needed |
See [docs/NAT_TRAVERSAL_GUIDE.md](docs/NAT_TRAVERSAL_GUIDE.md) for detailed information.
## Raw Public Key Identity (v0.2)
Each node has a single ML-DSA-65 key pair for both identity and authentication:
```rust
// ML-DSA-65 keypair - used for everything
let (ml_dsa_pub, ml_dsa_sec) = generate_ml_dsa_65_keypair();
// PeerId = SHA-256(ML-DSA-65 public key) = 32 bytes
// Compact identifier for addressing and peer tracking
let peer_id = derive_peer_id_from_public_key(&ml_dsa_pub);
```
This follows our [Pure PQC Authentication specification](docs/rfcs/ant-quic-pqc-authentication.md).
### v0.2 Changes
- **Pure PQC Identity**: Single ML-DSA-65 key pair, no classical keys
- **32-byte PeerId**: SHA-256 hash of ML-DSA-65 public key (1952 bytes → 32 bytes)
- **ML-DSA-65 Authentication**: ALL TLS handshake signatures use pure PQC
- **No Classical Keys**: Ed25519 completely removed, pure ML-DSA-65 only
### Trust Model
- **TOFU (Trust On First Use)**: First contact stores ML-DSA-65 public key fingerprint
- **Rotation**: New keys must be signed by old key (continuity)
- **Channel Binding**: TLS exporter signed with ML-DSA-65 (pure PQC)
- **NAT/Path Changes**: Token binding uses (PeerId || CID || nonce)
## Installation
### From Crates.io
```bash
cargo add ant-quic
```
### Pre-built Binaries
Download from [GitHub Releases](https://github.com/dirvine/ant-quic/releases):
- Linux: `ant-quic-linux-x86_64`, `ant-quic-linux-aarch64`
- Windows: `ant-quic-windows-x86_64.exe`
- macOS: `ant-quic-macos-x86_64`, `ant-quic-macos-aarch64`
### From Source
```bash
git clone https://github.com/dirvine/ant-quic
cd ant-quic
cargo build --release
```
## Binary Usage
```bash
# Run as a symmetric peer (auto-seeds from default known peers if none are provided)
ant-quic --listen 0.0.0.0:9000
# Provide explicit known peers for initial connectivity and address discovery
ant-quic --listen 0.0.0.0:9000 --known-peers 1.2.3.4:9000 --known-peers 5.6.7.8:9000
# Connect to a specific address through the unified outbound connectivity path
ant-quic --listen 0.0.0.0:9000 --connect 5.6.7.8:9001
# Disable best-effort router port mapping on demand
ant-quic --listen 0.0.0.0:9000 --no-port-mapping
# Show your external address (discovered via connected peers)
ant-quic --listen 0.0.0.0:9000
# Output: External address: YOUR.PUBLIC.IP:PORT
```
`--connect` does **not** force a "direct-only" attempt. It uses the canonical address-based connect entrypoint, so the endpoint still applies its normal routing/orchestration behavior such as connection reuse, direct dialing, and fallback handling when applicable. Richer peer-oriented discovery behavior comes from `connect_known_peers()` and `connect_peer()`.
### Default Known Peers
If no `--known-peers` are specified, ant-quic automatically seeds connectivity from the default Saorsa Labs known peers:
- `saorsa-1.saorsalabs.com:9000`
- `saorsa-2.saorsalabs.com:9000`
These are ordinary symmetric peers running the same ant-quic software as everyone else. They are useful starting points for initial discovery, but they are not special protocol roles.
### Peer Cache
ant-quic maintains a local cache of discovered peers to improve startup time and resilience. The cache is stored under the platform cache directory:
| **macOS** | `~/Library/Caches/ant-quic/` |
| **Linux** | `~/.cache/ant-quic/` |
| **Windows** | `%LOCALAPPDATA%\\ant-quic\\` |
The runtime manages the exact cache filename and format within that directory.
The cache includes:
- Peer IDs and socket addresses
- Connection quality scores (RTT, success rate)
- NAT type hints for traversal optimization
- Last-seen timestamps for freshness
The cache is automatically managed - stale entries are pruned and high-quality peers are prioritized for reconnection.
## API Reference
### Primary Types
| `P2pEndpoint` | Main entry point for P2P networking |
| `P2pConfig` | Configuration builder |
| `P2pEvent` | Events from the endpoint |
| `PeerId` | 32-byte peer identifier |
| `PqcConfig` | Post-quantum crypto tuning |
| `NatConfig` | NAT traversal tuning |
### P2pEndpoint Methods
```rust
impl P2pEndpoint {
// Creation
async fn new(config: P2pConfig) -> Result<Self>;
// Identity
fn peer_id(&self) -> PeerId;
fn local_addr(&self) -> Option<SocketAddr>;
fn external_addr(&self) -> Option<SocketAddr>;
fn all_external_addrs(&self) -> Vec<SocketAddr>;
fn port_mapping_active(&self) -> bool;
fn port_mapping_addr(&self) -> Option<SocketAddr>;
// Connections
async fn connect_known_peers(&self) -> Result<usize>;
async fn connect_addr(&self, addr: SocketAddr) -> Result<PeerConnection>;
async fn connect_peer(&self, peer: PeerId) -> Result<PeerConnection>;
async fn connected_peers(&self) -> Vec<PeerConnection>;
async fn accept(&self) -> Option<PeerConnection>;
// Events
fn subscribe(&self) -> broadcast::Receiver<P2pEvent>;
// Statistics
async fn stats(&self) -> EndpointStats;
}
```
`connect_addr()` is the canonical address-based connect entrypoint. It goes through the endpoint's normal routing/orchestration path, including connection reuse, direct dialing, and fallback handling when applicable. Richer peer-oriented discovery and identity-driven behavior comes from `connect_known_peers()` and `connect_peer()`.
### P2pConfig Builder
```rust
let config = P2pConfig::builder()
.bind_addr("0.0.0.0:9000".parse()?) // Local address
.known_peer(addr1) // Add known peer
.known_peers(vec![addr2, addr3]) // Add multiple
.max_connections(100) // Connection limit
.pqc(pqc_config) // PQC tuning
.nat(nat_config) // NAT tuning
.mtu(MtuConfig::pqc_optimized()) // MTU for PQC
.build()?;
```
See [docs/API_GUIDE.md](docs/API_GUIDE.md) for the complete API reference.
## RFC Compliance
ant-quic implements these specifications:
| [RFC 9000](docs/rfcs/rfc9000.txt) | Full | QUIC Transport Protocol |
| [RFC 9001](docs/rfcs/rfc9001.txt) | Full | QUIC TLS |
| [Pure PQC Auth](docs/rfcs/ant-quic-pqc-authentication.md) | Full | Raw Public Keys + Pure PQC (v0.2) |
| [draft-seemann-quic-nat-traversal-02](docs/rfcs/draft-seemann-quic-nat-traversal-02.txt) | Full | NAT Traversal |
| [draft-ietf-quic-address-discovery-00](docs/rfcs/draft-ietf-quic-address-discovery-00.txt) | Full | Address Discovery |
| [FIPS 203](docs/rfcs/fips-203-ml-kem.pdf) | Full | ML-KEM (via saorsa-pqc) |
| [FIPS 204](docs/rfcs/fips-204-ml-dsa.pdf) | Full | ML-DSA (via saorsa-pqc) |
See [docs/review.md](docs/review.md) for detailed RFC compliance analysis.
## Performance
### Connection Establishment
| Handshake (PQC) | ~50ms typical |
| Address Discovery | <100ms |
| NAT Traversal | 200-500ms |
| PQC Overhead | ~8.7% |
### Data Transfer (localhost)
| Send Throughput | 267 Mbps |
| Protocol Efficiency | 96.5% |
| Protocol Overhead | 3.5% |
### Scalability
| 100 | 56 KB | Minimal |
| 1,000 | 547 KB | Minimal |
| 5,000 | 2.7 MB | Linear |
## System Requirements
- **Rust**: 1.88.0+ (Edition 2024)
- **OS**: Linux 3.10+, Windows 10+, macOS 10.15+
- **Memory**: 64MB minimum, 256MB recommended
- **Network**: UDP traffic on chosen port
## Documentation
- [API Guide](docs/API_GUIDE.md) - Complete API reference
- [Symmetric P2P](docs/SYMMETRIC_P2P.md) - Architecture explanation
- [NAT Traversal Guide](docs/NAT_TRAVERSAL_GUIDE.md) - NAT traversal details
- [PQC Configuration](docs/guides/pqc-configuration.md) - PQC tuning
- [Architecture](docs/architecture/ARCHITECTURE.md) - System design
- [Troubleshooting](docs/TROUBLESHOOTING.md) - Common issues
## Examples
```bash
# Simple chat application
cargo run --example simple_chat -- --listen 0.0.0.0:9000
# Chat with peer discovery
cargo run --example chat_demo -- --known-peers peer.example.com:9000
# Statistics dashboard
cargo run --example dashboard_demo
```
## Testing
```bash
# Run all tests
cargo test
# Run with verbose output
cargo test -- --nocapture
# Specific test categories
cargo test nat_traversal
cargo test pqc
cargo test address_discovery
# Run benchmarks
cargo bench
```
## Contributing
Contributions welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md).
```bash
# Development setup
git clone https://github.com/dirvine/ant-quic
cd ant-quic
cargo fmt --all
cargo clippy --all-targets -- -D warnings
cargo test
```
## License
Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))
at your option.
## Acknowledgments
- Built on [Quinn](https://github.com/quinn-rs/quinn) QUIC implementation
- **Pure PQC powered by [saorsa-pqc](https://crates.io/crates/saorsa-pqc)** - NIST FIPS 203/204 compliant ML-KEM and ML-DSA
- NAT traversal per [draft-seemann-quic-nat-traversal-02](https://datatracker.ietf.org/doc/draft-seemann-quic-nat-traversal/)
- Developed for the [Autonomi](https://autonomi.com) decentralized network
## Security
For security vulnerabilities, please email security@autonomi.com rather than filing a public issue.