Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Identity & Networking

Mosaik’s identity system is built on cryptographic keys and content-addressed hashing. Every identifier in the system — networks, peers, streams, groups, collections — is a 32-byte Digest (blake3 hash).

UniqueId: The Universal Identifier

At the core of mosaik’s identity system is Digest — a 32-byte blake3 hash that serves as the universal identifier type:

use mosaik::Digest;

// From a string (hashes the string if not valid hex)
let id: UniqueId = "my-network".into();

// From raw bytes
let id = UniqueId::from_bytes([0u8; 32]);

// Random
let id = UniqueId::random();

// Compile-time constants via the unique_id! macro
use mosaik::unique_id;

// From a 64-char hex string (decoded directly):
const HEX_ID: UniqueId = unique_id!(
    "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
);

// From any arbitrary string (blake3-hashed at compile time):
const NAMED_ID: UniqueId = unique_id!("my-stream-name");

// Deterministic derivation
let derived = id.derive("sub-identifier");

All the following types are aliases for Digest:

TypeAlias ForIdentifies
UniqueIdDigestGeneral-purpose unique identifier
NetworkIdUniqueIdA mosaik network (derived from name)
TagUniqueIdA capability or role label
StreamIdUniqueIdA data stream (derived from type name)
GroupIdUniqueIdA consensus group (derived from key + config)
StoreIdUniqueIdA replicated collection instance

PeerId: Node Identity

A PeerId is the node’s public key, derived from its secret key. It’s globally unique across all mosaik networks.

use mosaik::{Network, PeerId};
use iroh::SecretKey;

// Random identity (default when using Network::new)
let network = Network::new(network_id).await?;
let my_id: &PeerId = &network.local().id();

// Stable identity via explicit secret key
let secret = SecretKey::generate(&mut rand::rng());
let network = Network::builder(network_id)
    .with_secret_key(secret)
    .build()
    .await?;

For bootstrap nodes and other long-lived infrastructure, you should use a fixed secret key so the node’s PeerId (and therefore its address) remains stable across restarts.

NetworkId: Network Isolation

A NetworkId is a Digest derived from a name string. Nodes can only connect to peers sharing the same NetworkId:

use mosaik::NetworkId;

// These produce the same NetworkId
let id1: NetworkId = "my-app".into();
let id2: NetworkId = "my-app".into();
assert_eq!(id1, id2);

// Different name → different network → can't communicate
let other: NetworkId = "other-app".into();
assert_ne!(id1, other);

The NetworkId also drives automatic peer discovery: nodes sharing the same NetworkId find each other through the Mainline DHT without requiring any hardcoded bootstrap peers. Simply using the same network name is enough for nodes to connect.

Tags: Capability Labels

Tags are Digest values used to describe a node’s role or capabilities:

use mosaik::Tag;

let tag: Tag = "matcher".into();
let another: Tag = "validator".into();

Tags are advertised through the discovery system and can be used to filter which peers a producer accepts or which producers a consumer subscribes to:

// Only accept consumers that have the "authorized" tag
let producer = network.streams().producer::<Order>()
    .accept_if(|peer| peer.tags.contains(&"authorized".into()))
    .build()?;

StreamId: Stream Identity

By default, a StreamId is derived from the Rust type name:

use mosaik::StreamId;

// Automatically derived from the type name
let producer = network.streams().produce::<SensorReading>();

// Or set explicitly
let producer = network.streams().producer::<SensorReading>()
    .with_stream_id("custom-stream-name")
    .build()?;

GroupId: Group Identity

A GroupId is deterministically derived from multiple inputs:

GroupId = hash(
    GroupKey,
    ConsensusConfig,
    StateMachine::signature(),
    StateSync::signature()
)

This ensures that nodes with different configurations, different state machines, or different group secrets cannot accidentally join the same group.

Endpoint Addresses

Nodes are addressed using EndpointAddr from iroh, which encodes the public key and optional relay URL. This is what you pass to bootstrap peers:

let addr = network.local().addr();
// addr contains: PeerId + relay URL + direct addresses