Skip to main content

Noise and synchronization

The SDK implements the exact deployed Noise_NK_25519_ChaChaPoly_SHA256 profile and bounded NIP-77 Negentropy state. It never opens a socket or owns a database.

Noise handshake and transport

Create one handshake with the relay’s authenticated static public key. Send messageOne as one binary WebSocket frame, pass the relay’s complete message two to complete, then use the returned transport for ordered binary frames.

let handshake = NoiseClientHandshake::new(relay_static_key, true)?;
socket.send_binary(handshake.message_one());
let transport = handshake.complete(message_two)?;

for frame in transport.encrypt(application_bytes)? {
socket.send_binary(frame);
}
if let Some(message) = transport.decrypt(received_frame)? {
handle_complete_message(message);
}
transport.shutdown();

Authentication failure closes this session. Never retry with the same handshake state, reveal detailed cryptographic errors, or concatenate transport frames outside the negotiated chunking rules.

Negentropy

Take one bounded, sorted snapshot of (createdAt, eventId) pairs from the host database, then construct a client. Send initiate(). For each relay response, apply the have/need IDs to host queries, send outgoing when present, and finish when complete is true.

let client = NegentropyClient::new(items, 60_000)?;
send(client.initiate()?);
let step = client.reconcile(response)?;

The snapshot and frame limits are denial-of-service boundaries. Split the application’s sync scope instead of raising them without a measured, interoperable protocol decision.