| Crates.io | korium |
| lib.rs | korium |
| version | 0.6.23 |
| created_at | 2025-12-20 19:38:19.872287+00 |
| updated_at | 2026-01-25 23:40:42.96343+00 |
| description | Batteries-included adaptive networking fabric |
| homepage | https://korium.io |
| repository | https://github.com/magikrun/korium |
| max_upload_size | |
| id | 1996891 |
| size | 1,370,884 |
Batteries-included adaptive networking fabric
Korium is a high-performance, secure, and adaptive networking library written in Rust. It provides a robust foundation for building decentralized applications, scale-out fabrics, and distributed services with built-in NAT traversal, efficient PubSub, and a cryptographic identity system.
Add Korium to your Cargo.toml:
[dependencies]
korium = "0.6.20"
tokio = { version = "1", features = ["full"] }
use korium::Node;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Bind to any available port
let node = Node::bind("0.0.0.0:0").await?;
println!("Node identity: {}", node.identity());
println!("Listening on: {}", node.local_addr()?);
// Option 1: Bootstrap from public Korium network (DNS-based discovery)
node.bootstrap_public().await?;
// Option 2: Bootstrap from a specific peer
// node.bootstrap("peer_identity_hex", &["192.168.1.100:4433".into()]).await?;
Ok(())
}
// Subscribe to a topic
node.subscribe("events/alerts").await?;
// Publish messages (signed with your identity)
node.publish("events/alerts", b"System update available".to_vec()).await?;
// Receive messages
let mut rx = node.messages().await?;
while let Some(msg) = rx.recv().await {
println!("[{}] from {}: {:?}", msg.topic, &msg.from[..16], msg.data);
}
// Set up a request handler (echo server)
node.set_request_handler(|from, request| {
println!("Request from {}: {:?}", &from[..16], request);
request // Echo back the request as response
}).await?;
// Send a request and get a response
let response = node.send("peer_identity_hex", b"Hello!".to_vec()).await?;
println!("Response: {:?}", response);
// Or use the low-level API for async handling
let mut requests = node.incoming_requests().await?;
while let Some((from, request, response_tx)) = requests.recv().await {
// Process request asynchronously
let response = process_request(request);
response_tx.send(response).ok();
}
For custom protocols, tunneling, or file transfers, use raw bidirectional streams:
// Receiver: Accept incoming streams
let mut incoming = node.incoming_streams().await?;
tokio::spawn(async move {
while let Some((from_identity, mut send, mut recv)) = incoming.recv().await {
println!("Stream from: {}", &from_identity[..16]);
// Read data (using quinn's RecvStream API)
let data = recv.read_to_end(1024 * 1024).await?;
// Send response
send.write_all(b"ACK").await?;
send.finish()?;
}
});
// Sender: Open a stream to a peer
let (mut send, mut recv) = node.open_stream("peer_identity_hex").await?;
// Send data (no framing - raw bytes)
send.write_all(b"Hello via raw stream!").await?;
send.finish()?;
// Read response
let response = recv.read_to_end(1024).await?;
Raw streams differ from request-response:
// Get all known peers from DHT routing table
let peers = node.get_peers().await;
// Resolve a peer's published contact record
let contact = node.resolve(&peer_identity).await?;
// Publish your address for others to discover
node.publish_address(vec!["192.168.1.100:4433".to_string()]).await?;
// Automatic NAT configuration (helper is a known peer identity in the DHT)
let helper_identity = "abc123..."; // hex-encoded peer identity
let (is_public, relay, incoming_rx) = node.configure_nat(helper_identity, addresses).await?;
if is_public {
println!("Publicly reachable - can serve as relay");
} else {
println!("Behind NAT - using relay: {:?}", relay);
// Handle incoming relay connections via mesh signaling
if let Some(mut rx) = incoming_rx {
while let Some(incoming) = rx.recv().await {
node.accept_incoming(&incoming).await?;
}
}
}
// Alternative: Enable mesh-mediated signaling (no dedicated relay connection)
let mut rx = node.enable_mesh_signaling().await;
while let Some(incoming) = rx.recv().await {
node.accept_incoming(&incoming).await?;
}
┌─────────────────────────────────────────────────────────────────────┐
│ Node │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ │
│ │ GossipSub │ │ Crypto │ │ DHT │ │ Relay │ │
│ │ (PubSub) │ │ (Identity) │ │ (Discovery) │ │ (Client) │ │
│ └──────┬──────┘ └─────────────┘ └──────┬──────┘ └─────┬──────┘ │
│ │ │ │ │
│ ┌──────┴─────────────────────────────────┴────────────────┴──────┐ │
│ │ RpcNode │ │
│ │ (Connection pooling, request routing) │ │
│ └────────────────────────────┬───────────────────────────────────┘ │
│ ┌────────────────────────────┴───────────────────────────────────┐ │
│ │ SmartSock │ │
│ │ (Path probing, relay tunnels, virtual addressing, QUIC mux) │ │
│ └────────────────────────────┬───────────────────────────────────┘ │
│ ┌────────────────────────────┴───────────────────────────────────┐ │
│ │ QUIC (Quinn) │ │
│ └────────────────────────────┬───────────────────────────────────┘ │
│ ┌────────────────────────────┴───────────────────────────────────┐ │
│ │ UDP Socket + Relay Server │ │
│ └────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
| Module | Description |
|---|---|
node |
High-level facade exposing the complete public API |
transport |
SmartSock with path probing, relay tunnels, and virtual addresses |
rpc |
Connection pooling, RPC dispatch, raw streams, and actor-based state management |
dht |
Kademlia-style DHT with latency tiering, adaptive parameters, and peer discovery |
gossipsub |
GossipSub v1.1/v1.2 epidemic broadcast with peer scoring |
relay |
UDP relay server and client with mesh-mediated signaling for NAT traversal |
fabric |
Shared peer registry for cross-protocol coordination (single source of truth) |
connections |
Connection manager with LRU caching and lifecycle management |
streams |
Raw bidirectional stream handling with lifecycle guards |
network |
Network utilities for address validation and routable address discovery |
crypto |
Ed25519 certificates, identity verification, custom TLS |
identity |
Keypairs, endpoint records, and signed address publication |
protocols |
Protocol trait definitions (DhtNodeRpc, GossipSubRpc, RelayRpc, PlainRpc) |
messages |
Protocol message types and bounded serialization |
thresholdca |
FROST threshold CA (K-of-N signing) |
ffi |
UniFFI bindings for mobile platforms (Kotlin/Swift) |
Every node has a cryptographic identity derived from an Ed25519 keypair:
let node = Node::bind("0.0.0.0:0").await?;
let identity: String = node.identity(); // 64 hex characters (32 bytes)
let keypair = node.keypair(); // Access for signing
Identities are:
A Contact represents a reachable peer:
pub struct Contact {
pub identity: Identity, // Ed25519 public key
pub addrs: Vec<String>, // List of addresses (IP:port)
}
SmartSock maps identities to virtual IPv6 addresses in the fd00:c0f1::/32 range:
Identity (32 bytes) → blake3 hash → fd00:c0f1:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
This enables:
Automatic connection establishment with fallback:
// send() and open_stream() handle connection automatically (with relay fallback)
let response = node.send("target_identity_hex", request).await?;
// For raw streams:
let (send, recv) = node.open_stream("target_identity_hex").await?;
// For explicit connection (primarily for debugging/testing):
let conn = node.connect("target_identity_hex").await?;
Korium uses a mesh-first relay model where any reachable mesh peer can act as a relay:
SmartSock implements transparent NAT traversal:
Path Probe (SMPR)
┌──────────┬──────────┬──────────┬──────────────┐
│ Magic │ Type │ Tx ID │ Timestamp │
│ 4 bytes │ 1 byte │ 8 bytes │ 8 bytes │
└──────────┴──────────┴──────────┴──────────────┘
Relay Frame (CRLY)
┌──────────┬──────────────┬──────────────────────┐
│ Magic │ Session ID │ QUIC Payload │
│ 4 bytes │ 16 bytes │ (variable) │
└──────────┴──────────────┴──────────────────────┘
if direct_path.rtt + 10ms < current_path.rtt:
switch to direct_path
elif relay_path.rtt + 50ms < direct_path.rtt:
switch to relay_path (relay gets 50ms handicap)
The DHT is used internally for peer discovery and address publication:
// Get all known peers from routing table
let peers = node.get_peers().await;
// Resolve peer's published contact record
let contact = node.resolve(&peer_id).await?;
// Publish your address for discovery
node.publish_address(vec!["192.168.1.100:4433".to_string()]).await?;
The DHT implements Coral-inspired latency tiering:
Korium is designed to scale to millions of concurrent peers. Key design decisions enable efficient operation at scale:
Each node uses constant memory regardless of network size:
| Component | Memory | Design |
|---|---|---|
| Routing table | ~640 KB | 256 buckets × 20 contacts |
| RTT tiering | ~1 MB | /16 prefix-based (not per-peer) |
| Passive view | ~13 KB | 100 recovery candidates |
| Connection cache | ~200 KB | 1,000 LRU connections |
| Peer scoring | ~1 MB | 10K active peers scored |
| Message dedup | ~2 MB | 10K source sequence windows |
| Total | ~5 MB | Bounded, scales to 10M+ nodes |
| Metric | Value | Notes |
|---|---|---|
| Lookup hops | O(log₂ N) ≈ 23 | Standard Kademlia complexity |
| Parallel queries (α) | 2-5 adaptive | Reduces under congestion |
| Bucket size (k) | 10-30 adaptive | Increases with churn |
| Routing contacts | ~5,120 max | 256 buckets × 20 |
| Feature | Standard Kademlia | Korium | Benefit |
|---|---|---|---|
| Bucket size | Fixed k=20 | Adaptive 10-30 | Handles churn spikes |
| Concurrency | Fixed α=3 | Adaptive 2-5 | Load shedding |
| RTT optimization | ❌ None | /16 prefix tiering | Lower latency paths |
| Sybil protection | ❌ Basic | S/Kademlia PoW + per-peer limits | Eclipse resistant |
| Gossip layer | ❌ None | GossipSub v1.1/v1.2 | Fast broadcast, scoring |
| NAT traversal | ❌ None | SmartSock + mesh relays | Works behind NAT |
| Identity | SHA-1 node IDs | Ed25519 + PoW | Self-certifying, Sybil-resistant |
These limits are per-node, not network-wide. With 10M nodes, the network's aggregate capacity scales linearly:
| Parameter | Per-Node Limit | At 10M Nodes | Notes |
|---|---|---|---|
| Routing contacts | ~5,120 | N/A | O(log N) = 23 hops at 10M |
| Contact records | 100K entries | 1 trillion | Distributed across DHT |
| Scored peers | 10,000 | 100 billion | Per-node active peer set |
| PubSub topics | 10,000 | 100 billion | Topics span multiple nodes |
| Peers per topic | 1,000 | N/A | Gossip efficiency bound |
| Relay tunnels/peer | 8 | 80 billion | Connection-based routing |
Prefix-based RTT — Tracking RTT per /16 IP prefix instead of per-peer reduces memory from O(N) to O(65K) while maintaining routing quality through statistical sampling.
Adaptive parameters — k and α automatically adjust based on observed churn rate, preventing cascade failures during network instability.
Bounded data structures — All caches use LRU eviction with fixed caps, ensuring memory stays constant regardless of network size.
Korium implements the full GossipSub v1.1 specification with v1.2 extensions:
GossipSub implements efficient topic-based publish/subscribe:
Publisher → Mesh Push → Subscribers
↓
Gossip (IHave)
↓
IWant requests
↓
Message delivery
All published messages include Ed25519 signatures:
// Messages are signed with publisher's keypair
node.publish("topic", data).await?;
// Signatures verified on receipt (invalid messages rejected)
let msg = rx.recv().await?; // msg.from is verified sender
| Limit | Value |
|---|---|
| Publish rate | 100/sec |
| Per-peer receive rate | 50/sec |
| Max message size | 64 KB |
| Max topics | 10,000 |
| Max peers per topic | 1,000 |
| Layer | Protection |
|---|---|
| Identity | Ed25519 keypairs, identity = public key |
| Transport | Mutual TLS on all QUIC connections |
| RPC | Identity verification on every request |
| Storage | Per-peer quotas, rate limiting, content validation |
| Routing | Rate-limited insertions, ping verification, S/Kademlia PoW |
| PubSub | Message signatures, replay detection, peer scoring (P1-P7), IP colocation (P6) |
| Constant | Value | Purpose |
|---|---|---|
MAX_VALUE_SIZE |
1 MB | DHT value limit |
MAX_RESPONSE_SIZE |
1 MB | RPC response limit |
MAX_RELAY_FRAME_SIZE |
1,400 | Relay frame size limit |
MAX_RELAY_TUNNELS_PER_PEER |
8 | Relay tunnels per peer |
PER_PEER_STORAGE_QUOTA |
1 MB | DHT storage per peer |
PER_PEER_ENTRY_LIMIT |
100 | DHT entries per peer |
MAX_CONCURRENT_STREAMS |
64 | QUIC streams per connection |
POW_DIFFICULTY |
24 bits | Identity PoW (Sybil resistance) |
Korium supports namespace-based isolation for multi-tenant deployments. Namespaces create cryptographically isolated overlays on top of the global mesh infrastructure.
┌─────────────────────────────────────────────────────────────────────┐
│ Global Infrastructure │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ DHT │ │ Relay │ │ Bootstrap │ │
│ │ (Discovery) │ │ (NAT Trav) │ │ (Routing) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ↑ ↑ ↑ │
│ │ │ │ All nodes share infrastructure │
│ ───────────────────────┼──┼──┼────────────────────────────────── │
│ │ │ │ │
│ ┌───────────────────────┴──┴──┴─────────────────────────────────┐ │
│ │ Namespace Gating Layer │ │
│ │ Challenge-Response + Payload Encryption │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ ↓ ↓ ↓ │
│ ┌────────────────┴──┴──┴────────────────┐ │
│ │ Isolated Application Traffic │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ GossipSub │ │ Plain │ │ │
│ │ │ (PubSub) │ │ (Req/Res) │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Key Properties:
use korium::{Node, NamespaceConfig};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Shared secret for the namespace (must be identical across all nodes in namespace)
let master_secret: [u8; 32] = derive_from_your_key_management_system();
let node = Node::builder("0.0.0.0:0")
.namespace_config(NamespaceConfig::new(master_secret))
.build()
.await?;
// This node can:
// ✓ Participate in global DHT (peer discovery)
// ✓ Use global relay infrastructure (NAT traversal)
// ✓ Only exchange GossipSub/Plain with peers that know master_secret
Ok(())
}
// Default: 1-hour epochs, 2-epoch grace period
let config = NamespaceConfig::new(master_secret);
// Custom epoch duration and grace period
let config = NamespaceConfig::new_with_params(
master_secret,
Duration::from_secs(3600), // Epoch duration (key rotation interval)
3, // Grace epochs (tolerance for clock skew)
);
Before accepting GossipSub or Plain streams, peers verify namespace membership:
Initiator Responder
│ │
│──── Connect (QUIC mTLS) ───────────────────│
│ │
│──── Open Stream (GossipSub/Plain) ─────────│
│ │
│◄─── Challenge(nonce) ──────────────────────│
│ │
│──── Response(BLAKE3(session_secret ║ │
│ nonce ║ pubkeys)) ────────────│
│ │
│ ✓ Verified: Accept stream │
│ ✗ Failed: Reject stream │
The challenge response is bound to:
All GossipSub and Plain payloads are encrypted:
Encryption Key = BLAKE3("korium-ns-encrypt-v1:" ║ master_secret ║ epoch)
Ciphertext = nonce (12 bytes) ║ encrypted_data ║ auth_tag (16 bytes)
Properties:
| Traffic Type | Namespaced Node Behavior |
|---|---|
| DHT | Global — Discovers all peers, serves routing |
| Relay | Global — Uses/provides relay for all peers |
| GossipSub | Isolated — Only sends/receives with namespace peers |
| Plain (Req/Res) | Isolated — Only sends/receives with namespace peers |
For additional Sybil resistance within namespaces, bind PoW to the namespace:
// Generate keypair with PoW bound to namespace hash
let (keypair, proof) = Keypair::generate_with_pow_for_namespace("my-namespace")?;
// Build node with namespace-bound identity
let node = Node::builder("0.0.0.0:0")
.with_keypair(keypair, proof)
.namespace_config(NamespaceConfig::new(master_secret))
.build()
.await?;
This ensures:
namespace_hash is hidden from serialized contacts (prevents namespace enumeration)| Scenario | Configuration |
|---|---|
| Multi-tenant SaaS | Each tenant gets a unique master_secret |
| Private networks | Namespace acts as a VPN overlay on public infrastructure |
| Regulatory compliance | Isolate data flows while sharing routing infrastructure |
| Development/staging | Separate environments on shared mesh |
Korium supports SPIFFE (Secure Production Identity Framework for Everyone) as an interoperability layer. This enables Korium nodes to present SPIFFE-compliant X.509 certificates for integration with enterprise service meshes and identity-aware proxies.
SPIFFE support includes:
Important: SPIFFE compatibility is additive—it does NOT replace Korium's native Ed25519 self-certifying identity model. The SPIFFE ID is embedded as a URI SAN (Subject Alternative Name) in X.509 certificates and is cryptographically bound to the node's identity.
SPIFFE ID Format:
spiffe://{trust_domain}/{identity_hex}[/{workload_path}]
Example:
spiffe://production.example.com/d4f5a6b7c8.../api-gateway
use korium::Node;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let node = Node::builder("0.0.0.0:0")
.spiffe_trust_domain("production.example.com")
.spiffe_workload_path("api-gateway")
.build()
.await?;
println!("Node identity: {}", node.identity());
// Certificate now contains URI SAN: spiffe://production.example.com/{identity}/api-gateway
Ok(())
}
| Method | Description |
|---|---|
NodeBuilder::spiffe_trust_domain(domain) |
Set the SPIFFE trust domain |
NodeBuilder::spiffe_workload_path(path) |
Set optional workload path suffix |
Certificates with SPIFFE URI SANs are generated automatically when building a node with spiffe_trust_domain() set.
Korium does not use a central Certificate Authority. Instead, verification relies on the self-certifying property of Ed25519 identities:
Standard SPIFFE:
SPIRE CA signs SVID → Verifier trusts CA → Trusts workload identity
Korium (Self-Certifying):
TLS handshake proves key possession → Public key IS the identity
→ SPIFFE ID is metadata bound to verified key
Verification Flow:
// Verification pseudocode
let cert_pubkey = extract_pubkey_from_cert(&peer_cert); // From TLS handshake
let expected_identity = Identity(cert_pubkey); // Identity = Public Key
if let Some(spiffe_id) = extract_spiffe_id_from_cert(&peer_cert)? {
// Validate SPIFFE ID is bound to the same identity
let spiffe_identity = validate_spiffe_id(&spiffe_id, "my-trust-domain")?;
assert_eq!(spiffe_identity, expected_identity); // Cryptographic binding
}
Why This Works:
| Property | Standard SPIFFE | Korium |
|---|---|---|
| Trust anchor | CA certificate | None (self-certifying) |
| Identity proof | CA signature | TLS key possession |
| Revocation | CA-managed | Peer scoring / DHT expiry |
| SPIFFE ID role | Primary identity | Interoperability metadata |
For enterprise integrations requiring CA-backed certificates, Korium includes a distributed threshold CA using FROST (Flexible Round-Optimized Schnorr Threshold) signatures. This enables K-of-N signing without any single party holding the complete CA private key.
┌─────────────────────────────────────────────────────────────────────┐
│ Threshold CA Architecture │
│ │
│ 1. DKG (one-time setup, external): │
│ - N signers run 3-round protocol │
│ - Each signer gets KeyPackage (private share) │
│ - All get combined CA public key │
│ │
│ 2. Signing (per certificate): │
│ - Requester broadcasts CSR to signers │
│ - K signers validate and produce partial signatures │
│ - Requester combines into valid FROST signature │
│ │
│ Trust Model: │
│ - Verifier trusts CA_pubkey (32 bytes) │
│ - CA_pubkey created by committee via DKG │
│ - Any K honest signers can produce valid signatures │
└─────────────────────────────────────────────────────────────────────┘
Note: DKG (Distributed Key Generation) is performed externally using the Korium CLI or custom tooling. The internal DKG protocol types are not part of the public API—nodes receive pre-generated
SignerStatefrom the ceremony.
For automatic signing, configure nodes as signers using NodeBuilder:
use korium::{Node, CaRequestConfig, SignerState};
// === Signer Node ===
// Load signer state from encrypted storage (from DKG ceremony)
let signer_state = SignerState::deserialize(&encrypted_state)?;
let signer_node = Node::builder("0.0.0.0:4433")
.spiffe_trust_domain("example.org")
.as_ca_signer(signer_state)
.build()
.await?;
// Node now automatically responds to CSR requests:
// 1. Listens on GossipSub `csr` topic for CSR broadcasts
// 2. Sends commitment via RPC to requester
// 3. Receives sign-request via RPC with all commitments
// 4. Responds with signature share via RPC
// === Requesting Node ===
let node = Node::builder("0.0.0.0:4433")
.spiffe_trust_domain("example.org")
.build()
.await?;
// First bootstrap into the mesh
node.bootstrap(&bootstrap_identity, &[bootstrap_addr]).await?;
// Then request CA certificate
let config = CaRequestConfig {
signer_identities: vec![signer1, signer2, signer3],
min_signers: 2,
ca_public_key,
timeout: Duration::from_secs(30),
};
let cert_der = node.request_ca_certificate_from_mesh("example.org", Some("api-gw"), &config).await?;
// cert_der is a valid X.509 certificate signed by the threshold CA
┌─────────────┐ GossipSub: csr ┌─────────────┐
│ Requester │ ─────────────────▶ │ Signers │
│ │ │ (K of N) │
│ │ ◀───────────────── │ │
│ │ RPC: commitment └─────────────┘
│ │ │
│ │ ─────────────────▶ │
│ │ RPC: sign-request │
│ │ (all commitments) │
│ │ ◀───────────────── │
│ │ RPC: signature share │
└─────────────┘ │
│ aggregate K shares │
▼ │
[CA-signed X.509 cert] │
| Type/Function | Description |
|---|---|
SignerState |
Holds private key share (generated externally, serialize for persistence) |
CaPublicKey |
Distributable CA public key |
CaRequestConfig |
Configuration for requesting CA-signed certificates |
ThresholdCaConfig |
Configuration (N signers, K threshold, trust domain) |
ThresholdCaError |
Error type for threshold CA operations |
NodeBuilder::as_ca_signer() |
Configure node as CA signer |
Node::request_ca_certificate_from_mesh() |
Request CA-signed certificate |
| Property | Value |
|---|---|
| Byzantine Tolerance | Survives up to N-K malicious signers |
| No Trusted Dealer | DKG ensures no party sees complete key |
| Identifiable Aborts | Misbehaving signers can be detected |
| Key Shares | Must be stored encrypted at rest |
| Signature Algorithm | FROST (RFC 9591) over Ed25519 |
| Topic | Purpose |
|---|---|
csr |
Certificate signing request broadcast |
Note: Commitments and signature shares are exchanged via RPC (point-to-point), not GossipSub, for privacy and efficiency.
Korium provides native mobile bindings via UniFFI, enabling seamless integration with Kotlin (Android) and Swift (iOS) applications.
# Install Android NDK and set environment variables
export ANDROID_NDK_HOME=/path/to/ndk
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin:$PATH
# Add Android targets
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android
# Build for ARM64 (most common)
cargo build --release --target aarch64-linux-android
# Generate Kotlin bindings
cargo run --bin uniffi-bindgen generate \
--library target/aarch64-linux-android/release/libkorium.so \
--language kotlin \
--out-dir bindings/kotlin
# Add iOS targets
rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios
# Build for iOS device
cargo build --release --target aarch64-apple-ios
# Generate Swift bindings
cargo run --bin uniffi-bindgen generate \
--library target/aarch64-apple-ios/release/libkorium.dylib \
--language swift \
--out-dir bindings/swift
The FFI layer exposes a safe subset of Korium's functionality:
| Type/Function | Description |
|---|---|
FfiNode |
Main node wrapper with async operations |
IdentityBundle |
Keypair with hex-encoded identity and secret key |
PubSubMessage |
Received message with topic, sender, and data |
PeerContact |
Peer identity and addresses |
Telemetry |
Node statistics and metrics |
generate_identity() |
Create new keypair with PoW |
sign() / verify() |
Ed25519 signature operations |
import korium.*
suspend fun main() {
val identity = generateIdentity()
val node = FfiNode.bind("0.0.0.0:0")
node.bootstrap(peerIdentity, listOf("192.168.1.100:4433"))
node.subscribe("events")
node.publish("events", "Hello from Android!".toByteArray())
val messages = node.messages()
for (msg in messages) {
println("${msg.topic}: ${msg.data.decodeToString()}")
}
}
# Start a node on a random port
cargo run
# Start with specific bind address
cargo run -- --bind 0.0.0.0:4433
# Bootstrap from existing peer
cargo run -- --bootstrap 192.168.1.100:4433/abc123...def456
# With debug logging
RUST_LOG=debug cargo run
# Terminal 1: Start first node
cargo run --example chatroom -- --name Alice --room dev
# Terminal 2: Join with bootstrap (copy the bootstrap string from Terminal 1)
cargo run --example chatroom -- --name Bob --room dev --bootstrap <bootstrap_string>
The chatroom demonstrates:
/room messages)/dm <identity> <message>)/peers)# Run all tests
cargo test
# Run with logging
RUST_LOG=debug cargo test
# Run specific test
cargo test test_smart_addr
# Run integration tests
cargo test --test node_public_api
cargo test --test gossipsub_integration
cargo test --test gossipsub_public
cargo test --test scaled_mesh
# Run Threshold CA tests
cargo test --features test-pow thresholdca
# Spawn local cluster (7 nodes)
./scripts/spawn_cluster.sh
| Crate | Purpose |
|---|---|
quinn |
QUIC implementation |
tokio |
Async runtime |
ed25519-dalek |
Ed25519 signatures |
blake3 |
Fast cryptographic hashing |
rustls |
TLS implementation |
bincode |
Binary serialization |
lru |
LRU caches |
tracing |
Structured logging |
rcgen |
X.509 certificate generation (URI SAN for SPIFFE) |
x509-parser |
Certificate parsing (SPIFFE ID extraction) |
frost-ed25519 |
FROST threshold signatures (RFC 9591) |
dashmap |
Concurrent hash maps |
chacha20poly1305 |
Authenticated encryption for namespaces |
hickory-resolver |
DNS resolution for public bootstrap |
uniffi |
FFI bindings for Kotlin/Swift |
subtle |
Constant-time comparison (timing attack prevention) |
Liang, J., et al. (2024). Implementing NAT Hole Punching with QUIC. VTC2024-Fall. arXiv:2408.01791
Demonstrates QUIC hole punching advantages and connection migration saving 2 RTTs.
Freedman, M. J., et al. (2004). Democratizing Content Publication with Coral. NSDI '04. PDF
Introduced "sloppy" DHT with latency-based clustering—inspiration for Korium's tiering system.
Baumgart, I. & Mies, S. (2007). S/Kademlia: A Practicable Approach Towards Secure Key-Based Routing. ICPP '07.
The S/Kademlia specification that Korium implements for Sybil-resistant identity generation via Proof-of-Work.
Vyzovitis, D., et al. (2020). GossipSub: Attack-Resilient Message Propagation in the Filecoin and ETH2.0 Networks.
The GossipSub v1.1 specification that Korium's PubSub implementation follows, including peer scoring (P1-P7), Adaptive Gossip, and mesh management.
Leitão, J., Pereira, J., & Rodrigues, L. (2007). Epidemic Broadcast Trees. SRDS '07.
The PlumTree paper that influenced GossipSub's design, combining gossip reliability with efficient message propagation.
Korium delivers a complete networking stack in a compact binary:
| Build | Binary | Size |
|---|---|---|
| Debug | korium |
~34 MB |
| Release | korium |
~9 MB |
| Release (optimized) | korium |
~3 MB |
The release profile in Cargo.toml is configured for size optimization:
[profile.release]
opt-level = "z" # Optimize for size
lto = true # Link-time optimization
codegen-units = 1 # Single codegen unit for better optimization
panic = "abort" # Smaller binary, no unwinding
strip = true # Strip symbols
~3 MB includes: DHT, GossipSub, Relay, mTLS, Proof-of-Work, Threshold CA, and FFI bindings.
Korium is a general-purpose networking library designed for legitimate decentralized applications. Like any powerful tool, it could potentially be misused.
| Protection | Description |
|---|---|
| Proof-of-Work Identity | Each node must compute PoW to generate an identity, making large-scale Sybil attacks computationally expensive |
| SSPL License | Server Side Public License creates legal friction for malware-as-a-service operations |
| Binary Size (~3 MB) | Larger than typical malware implants (<500 KB), making it conspicuous |
| Distinctive Signatures | Protocol magic bytes (CRLY, SMPR) and QUIC patterns are detectable by network monitoring |
For defenders and threat hunters:
Protocol: QUIC over UDP
ALPN: "korium"
Probe Magic: 0x534D5052 ("SMPR")
Relay Magic: 0x43524C59 ("CRLY")
DHT Records: 32-byte keys with Ed25519 signed Contact blobs
If you observe Korium being used for malicious purposes (C2, botnets, etc.), please report to:
We take abuse seriously and will work with security researchers and law enforcement as appropriate.
Server Side Public License (SSPL-1.0) - see LICENSE for details.