NAME
Net::Nostr::Negentropy - NIP-77 negentropy set reconciliation
SYNOPSIS
use Net::Nostr::Negentropy;
# Client side
my $client = Net::Nostr::Negentropy->new;
$client->add_item(1000, '01' x 32);
$client->add_item(2000, '02' x 32);
$client->seal;
my $q = $client->initiate;
# Send $q in NEG-OPEN message
# Server side
my $server = Net::Nostr::Negentropy->new;
$server->add_item(1000, '01' x 32);
$server->add_item(3000, '03' x 32);
$server->seal;
my ($response, $s_have, $s_need) = $server->reconcile($q);
# Send $response in NEG-MSG
# Client processes response
my ($next, $c_have, $c_need) = $client->reconcile($response);
# $c_have = ['02' x 32] -- client has, server doesn't
# $c_need = ['03' x 32] -- server has, client doesn't
# If $next is defined, send as NEG-MSG and continue
DESCRIPTION
Implements the Negentropy set reconciliation protocol as specified in NIP-77. This protocol efficiently determines the symmetric difference between two sets of events by exchanging fingerprints and progressively narrowing mismatched ranges.
The protocol uses a binary message format with varint encoding, range-based fingerprints (SHA-256 of modular ID sums), and ID lists. Messages are hex-encoded for transmission over the Nostr WebSocket protocol.
Typical flow:
- 1. Both sides create a Negentropy instance, add their local events via "add_item", and call "seal".
- 2. The client (initiator) calls "initiate" to produce the initial message.
- 3. The server calls "reconcile" with the client's message and returns a response.
- 4. The client calls "reconcile" with the server's response. If the return message is
undef, the protocol is complete. Otherwise, send the message and repeat from step 3.
After reconciliation, the client knows which IDs it has that the server lacks (have) and which IDs the server has that it lacks (need). It can then use EVENT to upload and REQ to download.
CONSTRUCTOR
new
my $ne = Net::Nostr::Negentropy->new;
my $ne = Net::Nostr::Negentropy->new(frame_size_limit => 4096);
Creates a new Negentropy instance. Croaks on unknown arguments.
Options:
frame_size_limit-- maximum byte size for encoded protocol messages. When set, "initiate" and "reconcile" croak if an incoming or outgoing binary negentropy frame would exceed the configured limit. Defaults to0(unlimited).
METHODS
add_item
$ne->add_item($timestamp, $id_hex);
Adds an event to the local set. $timestamp must be a non-negative integer (the event's created_at). The maximum uint64 value (2**64 - 1) is reserved as the protocol's infinity timestamp and is rejected. $id_hex must be a 64-character lowercase hex string (the event ID). Croaks if called after "seal".
seal
$ne->seal;
Sorts the items and finalizes the set. Must be called before "initiate" or "reconcile". After sealing, "add_item" is no longer allowed.
initiate
my $hex_msg = $ne->initiate;
Creates the initial reconciliation message. Returns a hex-encoded binary message string. This marks the instance as the initiator (client side). Croaks if not sealed.
reconcile
my ($hex_response, $have_ids, $need_ids) = $ne->reconcile($hex_msg);
Processes a reconciliation message from the other side. Returns:
$hex_response-- the response message (hex string), orundefif the protocol is complete$have_ids-- arrayref of hex ID strings that we have and they don't$need_ids-- arrayref of hex ID strings that they have and we don't
Croaks if not sealed.