ExploreTrendingAnalytics
Nostr Archives
ExploreTrendingAnalytics

nextwave

ad0555…ac01bc
3Followers0Following15Notes

Just making sure everyone is having a good time on the Merry-go-round.

15 total
nextwave6d ago
Say what you will about Bush being functionally retarded, but the people backing him actually understood how to plan and sell their illegal war. Trump's Zionist handlers have now given up on all of their objectives and rationales for the war at this point, including liberating the Iranian people, and have chosen simultaneously to tuck tail and threaten to bomb a bunch of civilian infrastructure and making all the Iranian people suffer.
0000 sats
nextwave12d ago
American planes of American design, flying American weapons, supported by American navigation and guidance systems, refueled by American airtankers, defended by American air defense systems deployed all over the middle east, protected by Americans, everything paid for by American taxpayers. And the news headlines read, "Israeli bombers take out such and such a target". America is acting like the field servants who injure the boar before the hunt so the king can make the killing blow. "Excellent shot mi'lord."
1010 sats
nextwave16d ago
Fractal Data Compression Every piece of data has a shape. Fractal data compression makes that shape visible, and in doing so, makes the data smaller. The system works by splitting a message into fixed-size chunks and scanning for repetition. Each unique chunk becomes an affine transform in an Iterated Function System (IFS), the mathematical engine behind fractal geometry. An IFS defines a fractal through a small set of geometric operations, rotations, scalings, and translations, that are applied recursively to generate infinitely detailed structure from a finite description. When the message's byte patterns are mapped to these transforms, the resulting fractal is not an arbitrary visualization. It is the data itself, rendered as geometry. Every curve, cluster, and tendril in the image corresponds to a specific byte pattern from the original message. Compression emerges naturally from this process. When data contains repeated patterns, and most real-world data does, those patterns map to the same transform. The word "the" appearing fifty times in a document does not require fifty entries in the fractal's definition. It requires one transform, referenced fifty times by a compact index. The fractal's dictionary stores each unique pattern once, and a sequence of small indices records the order in which they appear. The dictionary plus the index sequence is the seed: a compact representation that is often significantly smaller than the original data, yet sufficient to reconstruct it exactly. The visual result is telling. Highly compressible data, text with repeated phrases, images with uniform regions, produces regular, self-similar fractals with clear symmetry and recognizable structure. This is because fewer unique transforms mean the IFS reuses the same geometric operations at every scale, which is precisely what makes a fractal self-similar. Random or incompressible data, by contrast, produces chaotic, asymmetric shapes with no discernible pattern. You can literally see the compressibility of data in the geometry of its fractal. Regularity is redundancy. Symmetry is compression. The encoding is lossless. The seed contains every byte of the original data, packed into the dictionary entries and their index sequence. Decoding is deterministic: unpack the dictionary, replay the index sequence, and the original message is recovered bit for bit. No information is lost, approximated, or discarded. The fractal is simply a different representation of the same data, one that happens to be visual, self-similar, and often smaller than the original. This approach inverts the usual relationship between data and visualization. Typically, compression is invisible, a smaller file that looks the same when decompressed. Here, the compression is the visualization. The fractal does not illustrate the data; it is the data, and its structure directly encodes the redundancy that makes compression possible. The medium is the message, and the message is the fractal.
0100 sats
nextwave16d ago
010025047720616569736E6F74726C75646367666D6870792C76622E77540A6B7149536A464748412D7A74128404D08400120200101119128904800E1862C00C708F00215E19208B00314050120318A10030A2472880840012062852C01D00805C62092D60184024800480801D24433012494803C12C200E2063C034818A14B00F0811D300444330211300114B0061D008800E24150620314D11300214C04408B00314004011A0C55806100805022040470C90C748018E00404A1013421000492465C40074023C01C601508044809104808B00314014A3C220628401705211300314C24A2C314D00D2032490C535300E2120C535300620054168314D4C03C168314D0074023C00401070512420031403C115200C28310314211665961008044818B28C1C318500638010128404D08400C0450140484801033450CE0CC0451C94805411022C018500808D0C61412401C804B0C70C614400114B0015010C905524200314D2022C30851C45807C62000C51070453024C07070490C114010128404D08400638708500314C24A2C200E0851422400452C03412090CC4C05D00C908080220F04500404A1013421003C14803820472880800405490852C018E01008854400114B0044433021002850DB2820071801D00832002463012431C30845806100C400B0D40881031D200518700614948008540114C08400740200E24150620044818E0C908054A1C004910600808E2423071001D008030A2472880490040CD14338330114C08018E00404A1013421000C500B0CE38220214700418C0C21C308459965C14004B2C31C31850071801D008320030A24314121200145108125300404A10134210030114004910601508004010628830200638014A1C80C70C61530112065032C314D0112061C20C500114B0021040851C30490140C704F0C51160211970940884C00C70031000CF4462070451C01C600C1851032C22001D00806CA0490C748018E00314D2022C30851C400A1022D30011001063C200C18F3C220C0C124948044818B28C08B00404A1013421003C14803061470431404480840885011C35021000452C004B2C31C350211602210030614428F0881005423063C200F1880804020491D08CC18510C0C62844C01D00880800C400100D2065C314D00B08F0452C03862000481C31011412400452C018834114330010128404D0801911C31851001D00470112031880C70E40806CA0490C74800452C010A1070431415432431D2580
0000 sats
nextwave19d ago
Second version of the protocol specification. There will be at least one more. 📝 69c1e619…
0000 sats
nextwave19d ago
# Wiresocket Protocol Specification > **DRAFT** — This document reflects implementation as of 2026-02-26 and is pending formal review. Version: 1 (`noisePrologue = "wiresocket v1"`) --- ## 1. Overview Wiresocket is a WireGuard-inspired, encrypted UDP event-stream protocol. It provides a bidirectional, multi-channel event stream between a client and server over a single UDP socket. **Key properties:** - **Transport**: UDP (connectionless) - **Encryption**: Noise IK over X25519 / ChaCha20-Poly1305 / BLAKE2s - **Authentication**: Both static keys (server always; client optionally) - **Multiplexing**: up to 256 independent channels per session (channel IDs 0–255) - **Fragmentation**: frames exceeding one UDP datagram are split across up to 65 535 fragments - **DoS mitigation**: WireGuard-style cookies (XChaCha20-Poly1305) - **Replay protection**: 4096-entry sliding window - **Reliable delivery**: optional per-channel sequencing, cumulative + selective ACKs (SACK), retransmit with exponential backoff, and window-based flow control - **Rate limiting**: optional per-session send rate cap (token bucket; configurable bytes-per-second) All multi-byte integers are **little-endian** unless stated otherwise. --- ## 2. Cryptographic Primitives | Primitive | Algorithm | Notes | |---|---|---| | DH | X25519 (RFC 7748) | Low-order-point rejection enforced | | AEAD (handshake) | ChaCha20-Poly1305 (RFC 8439) | | | AEAD (transport) | ChaCha20-Poly1305 | One AEAD instance per direction, cached per session | | AEAD (cookie reply) | XChaCha20-Poly1305 | 24-byte random nonce | | Hash | BLAKE2s-256 | | | MAC | Keyed BLAKE2s-256 | `BLAKE2s(key=K, data=D)` | | KDF | HKDF-BLAKE2s | See §2.1 | | Keypairs | X25519 | RFC 7748 clamping applied | ### 2.1 KDF ``` prk = MAC(key=ck, data=input) T[1] = MAC(key=prk, data=0x01) T[i] = MAC(key=prk, data=T[i-1] || byte(i)) ``` `kdf2(ck, input)` returns `(T[1], T[2])`. `kdf3(ck, input)` returns `(T[1], T[2], T[3])`. ### 2.2 Initial chaining key and hash ``` initialCK = "Noise_IK_25519_ChaChaPoly_BLAKE2s" (zero-padded to 32 bytes) initialH = HASH(initialCK || "wiresocket v1") ``` Both are computed once at process startup. ### 2.3 AEAD nonce Transport AEAD nonces are 12 bytes: ``` nonce[0:4] = 0x00 0x00 0x00 0x00 nonce[4:12] = counter (uint64 LE) ``` ### 2.4 MAC1 derivation ``` mac1_key = HASH("mac1----" || receiver_static_pub) MAC1 = MAC(mac1_key, message_body)[0:16] ``` `message_body` is everything in the serialised message before the MAC fields. ### 2.5 MAC2 derivation ``` MAC2 = MAC(key=cookie[0:16] zero-extended to 32 bytes, data=message_body)[0:16] ``` --- ## 3. Packet Types The first byte of every UDP datagram is a **type tag**: | Value | Name | Size (bytes) | |---|---|---| | 1 | HandshakeInit | 148 | | 2 | HandshakeResp | 92 | | 3 | CookieReply | 64 | | 4 | Data | 16 + ciphertext | | 5 | Disconnect | 32 (16 header + 16 AEAD tag) | | 6 | Keepalive | 32 (16 header + 16 AEAD tag) | | 7 | DataFragment | 16 + ciphertext | --- ## 4. Wire Formats ### 4.1 HandshakeInit (type 1, 148 bytes) Sent by the initiator to begin a session. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x01 1 3 reserved (zero) 4 4 sender_index uint32 LE — initiator's session token 8 32 ephemeral initiator ephemeral public key (X25519) 40 48 encrypted_static AEAD(initiator static pub key, 32 plain + 16 tag) 88 28 encrypted_timestamp AEAD(TAI64N timestamp, 12 plain + 16 tag) 116 16 mac1 MAC1 keyed by responder's static pub 132 16 mac2 MAC2 keyed by cookie (zeros if no cookie) ``` `sender_index` is a random 32-bit token chosen by the initiator. It is used as `receiver_index` in all subsequent packets the server sends to this session. `encrypted_timestamp` carries a 12-byte TAI64N timestamp (`uint64 BE seconds` || `uint32 BE nanoseconds`). The TAI epoch offset applied is `0x4000000000000000`. The responder rejects timestamps more than ±180 seconds from its own clock. ### 4.2 HandshakeResp (type 2, 92 bytes) Sent by the responder in reply to a valid HandshakeInit. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x02 1 3 reserved (zero) 4 4 sender_index uint32 LE — responder's session token 8 4 receiver_index uint32 LE — echoes initiator's sender_index 12 32 ephemeral responder ephemeral public key (X25519) 44 16 encrypted_nil AEAD(empty plaintext) — 0 plain + 16 tag 60 16 mac1 MAC1 keyed by initiator's static pub 76 16 mac2 MAC2 keyed by cookie (zeros if no cookie) ``` ### 4.3 CookieReply (type 3, 64 bytes) Sent by the server instead of HandshakeResp when under load. The cookie must be used in MAC2 of the retried HandshakeInit. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x03 1 3 reserved (zero) 4 4 receiver_index uint32 LE — echoes initiator's sender_index 8 24 nonce random 24-byte XChaCha20 nonce 32 32 encrypted_cookie XChaCha20-Poly1305(cookie, 16 plain + 16 tag) ``` The XChaCha20-Poly1305 key is the MAC1 from the HandshakeInit zero-extended to 32 bytes. Only the genuine initiator (who knows its own MAC1) can decrypt the cookie. ### 4.4 Data (type 4) Carries one encrypted Frame. Total size: `16 + len(plaintext) + 16`. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x04 1 3 reserved (zero) 4 4 receiver_index uint32 LE — recipient's session token 8 8 counter uint64 LE — monotonic send counter 16 N+16 ciphertext ChaCha20-Poly1305(frame_bytes, N plain + 16 tag) ``` AAD is empty. The nonce is constructed from `counter` (see §2.3). ### 4.5 Disconnect (type 5, 32 bytes) Authenticated graceful shutdown notification. Same header layout as Data with an AEAD over empty plaintext. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x05 1 3 reserved (zero) 4 4 receiver_index uint32 LE 8 8 counter uint64 LE 16 16 AEAD tag ChaCha20-Poly1305(empty) — 0 plain + 16 tag ``` ### 4.6 Keepalive (type 6, 32 bytes) Liveness probe. Same layout as Disconnect with type 6. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x06 1 3 reserved (zero) 4 4 receiver_index uint32 LE 8 8 counter uint64 LE 16 16 AEAD tag ChaCha20-Poly1305(empty) — 0 plain + 16 tag ``` A keepalive is sent whenever no data has been exchanged for `KeepaliveInterval` (default 10 s). The counter participates in replay protection. ### 4.7 DataFragment (type 7) Carries one encrypted fragment of a large Frame. Total size: `16 + 8 + len(frag_data) + 16`. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x07 1 3 reserved (zero) 4 4 receiver_index uint32 LE 8 8 counter uint64 LE 16 N+24 ciphertext ChaCha20-Poly1305(frag_plain, (8+M) plain + 16 tag) ``` The **plaintext** inside the ciphertext has its own sub-header: ``` Plain offset Size Field ------------ ---- ----- 0 4 frame_id uint32 LE — unique per frame within a session 4 2 frag_index uint16 LE — zero-based index of this fragment 6 2 frag_count uint16 LE — total number of fragments (1–65535) 8 M frag_data raw fragment bytes ``` `frame_id` is a monotonically increasing counter scoped to the sending session. All fragments of the same frame share the same `frame_id`. --- ## 5. Noise IK Handshake The handshake follows the **Noise IK** pattern (`Noise_IK_25519_ChaChaPoly_BLAKE2s`): ``` Pre-messages: -> s (responder's static public key known to initiator out-of-band) Messages: -> e, es, s, ss (HandshakeInit) <- e, ee, se (HandshakeResp) ``` ### 5.1 Symmetric State Both sides maintain a symmetric state `(ck, h, k, nonce)`: - `ck` — chaining key, starts as `initialCK` - `h` — transcript hash, starts as `initialH` - `k` — current AEAD key (empty until first `mixKey`) - `nonce` — per-key counter, reset to 0 on each `mixKey` **`mixHash(data)`**: `h = HASH(h || data)` **`mixKey(dh_out)`**: `(ck, k) = kdf2(ck, dh_out)` ; `nonce = 0` **`encryptAndHash(plain)`**: `c = AEAD_Seal(k, nonce++, h, plain)` ; `mixHash(c)` ; return `c` **`decryptAndHash(cipher)`**: `p = AEAD_Open(k, nonce++, h, cipher)` ; `mixHash(cipher)` ; return `p` ### 5.2 Initiator: CreateInit Starting state: `ck = initialCK`, `h = HASH(initialCK || "wiresocket v1")`. ``` Pre-message: mixHash(responder_static_pub) Message construction: mixHash(e_pub) # -> e (ck, k) = kdf2(ck, DH(e_priv, s_resp_pub)) # -> es encrypted_static = encryptAndHash(s_init_pub) # -> s (ck, k) = kdf2(ck, DH(s_init_priv, s_resp_pub)) # -> ss encrypted_timestamp = encryptAndHash(TAI64N()) mac1 = MAC1(responder_static_pub, msg_body_without_macs) mac2 = MAC2(cookie, msg_body_without_mac2) # zero if no cookie ``` ### 5.3 Responder: ConsumeInit ``` Pre-message: mixHash(local_static_pub) Verification and processing: verify MAC1 mixHash(e_init_pub) # -> e (ck, k) = kdf2(ck, DH(s_resp_priv, e_init_pub)) # -> es s_init_pub = decryptAndHash(encrypted_static) # -> s (ck, k) = kdf2(ck, DH(s_resp_priv, s_init_pub)) # -> ss timestamp = decryptAndHash(encrypted_timestamp) validate timestamp within ±180 s ``` ### 5.4 Responder: CreateResp Continues immediately after ConsumeInit. ``` mixHash(e_resp_pub) # -> e (ck, k) = kdf2(ck, DH(e_resp_priv, e_init_pub)) # -> ee (ck, k) = kdf2(ck, DH(e_resp_priv, s_init_pub)) # -> se encrypted_nil = encryptAndHash(empty) mac1 = MAC1(initiator_static_pub, resp_body_without_macs) mac2 = 0 (no cookie in response) ``` ### 5.5 Initiator: ConsumeResp ``` mixHash(e_resp_pub) # <- e (ck, k) = kdf2(ck, DH(e_init_priv, e_resp_pub)) # <- ee (ck, k) = kdf2(ck, DH(s_init_priv, e_resp_pub)) # <- se decryptAndHash(encrypted_nil) # proves responder identity ``` ### 5.6 Transport Key Derivation (SPLIT) After both sides complete the handshake: ``` (T_initiator_send, T_initiator_recv) = kdf2(ck, empty) ``` - Initiator sends with `T_initiator_send`, receives with `T_initiator_recv`. - Responder sends with `T_initiator_recv`, receives with `T_initiator_send`. --- ## 6. Cookie / DoS Mitigation When the server is under load, it may respond to HandshakeInit with a CookieReply instead of HandshakeResp. ### 6.1 Cookie derivation (server side) The server maintains a 32-byte `cookie_secret` rotated every 2 minutes. ``` cookie_key = MAC(key=cookie_secret, data="cookie--" || server_static_pub) cookie = MAC(key=cookie_key, data=client_addr_string)[0:16] ``` `client_addr_string` is the client's UDP address formatted as `"ip:port"`. ### 6.2 CookieReply construction ``` key = mac1_from_HandshakeInit zero-extended to 32 bytes nonce = random 24 bytes encrypted_cookie = XChaCha20-Poly1305-Seal(key, nonce, cookie, aad=empty) ``` ### 6.3 MAC2 retry On receiving a CookieReply, the initiator decrypts the cookie and retries HandshakeInit with: ``` MAC2 = MAC2(cookie, message_body_without_mac2)[0:16] ``` The server accepts a HandshakeInit with a valid MAC2 even under load. --- ## 7. Session Lifecycle ``` Client Server | | |------ HandshakeInit --------->| | | (may send CookieReply if under load) |<----- HandshakeResp ----------| | | | [session established] | | | |<===== Data / Fragments ======>| |<===== Keepalives ============>| | | |------ Disconnect ------------>| (or timeout) ``` ### 7.1 Session indices Each side independently picks a random 32-bit `session_index`. The sender places the **recipient's** index in every outgoing data packet's `receiver_index` field so the recipient can route it to the correct session. ### 7.2 Send counter The sender maintains a monotonically increasing 64-bit counter starting at 0. The counter is used both as the AEAD nonce and for the receiver's replay window. When the counter reaches `2^64 - 1` it wraps to 0 and the session is closed, forcing a new handshake. ### 7.3 Timeouts and keepalives | Parameter | Default | Description | |---|---|---| | `KeepaliveInterval` | 10 s | Send keepalive if data idle for this long | | `SessionTimeout` | 180 s | Close session if no packet received for this long | | `RekeyAfterTime` | 180 s | Initiate new handshake after this session age | | `RekeyAfterMessages` | 2^60 | Initiate new handshake after this many packets sent | Each side enforces its own timeout independently. Keepalive receipt does **not** reset the data-idle timer; a peer that only sends keepalives will still receive them in return. --- ## 8. Replay Protection Incoming data, keepalive, disconnect, and fragment packets are all subject to replay protection using a 4096-entry sliding window implemented as a `[64]uint64` bitmap (64 words × 64 bits). ``` Window covers: [head - 4095, head] ``` - If `counter > head`: accepted (new high-water mark). - If `counter < head - 4095`: rejected (too old). - Otherwise: check bitmask. If bit already set: rejected (duplicate). The window is updated (`head` advanced, bitmap updated) only after AEAD decryption succeeds. `head` is stored atomically for a lock-free fast path on the common case of strictly in-order delivery. **Why 4096 entries?** On Linux, `sendFragments` allocates all N fragment counters in a tight loop *before* the `sendmmsg` batch is written to the socket. A concurrent keepalive send can steal a counter mid-loop and arrive at the peer before the fragment batch, causing the peer's `head` to advance past the early fragment counters. With the original 64-entry window, a difference ≥ 64 triggered spurious replay rejections and permanent event loss. A 4096-entry window safely accommodates the maximum in-flight fragment count with ample headroom. --- ## 9. Fragmentation Frames whose serialised plaintext exceeds `maxFragPayload` bytes are split into multiple DataFragment packets. ### 9.1 Default MTU parameters | Parameter | Value | Derivation | |---|---|---| | Default MaxPacketSize | 1232 bytes | IPv6 min path MTU (1280) − IPv6 header (40) − UDP header (8) | | Default maxFragPayload | 1192 bytes | 1232 − DataHeader(16) − FragmentHeader(8) − AEADTag(16) | | Maximum fragments per frame | 65 535 | `frag_count` is uint16 | | Maximum frame size at default MTU | ≈ 78 MB | 65 535 × 1192 bytes | ### 9.2 Reassembly The receiver maintains a map of partial frames keyed by `frame_id`. When all `frag_count` fragments for a `frame_id` arrive, the payloads are concatenated in `frag_index` order and the result is decoded as a Frame. Incomplete fragment sets are garbage-collected after `2 × KeepaliveInterval` of inactivity. At most `MaxIncompleteFrames` (default 64, configurable per `ServerConfig`/`DialConfig`) partial frames are buffered per session; excess fragments are silently dropped. Duplicate fragments (same `frame_id` + `frag_index`) are ignored. --- ## 10. Frame Wire Format A **Frame** is the plaintext inside a Data or reassembled DataFragment packet. It uses a custom encoding that is a strict subset of Protocol Buffers wire format, allowing standard proto decoders to parse it as an extension of the proto schema. ``` Byte 0: channel_id (uint8, raw — not proto-encoded) Bytes 1..N: events (field-1 LEN records, one per event) [optional] Seq (field-2 varint) — omitted when 0 (unreliable) [optional] AckSeq (field-3 varint) — omitted when 0 [optional] AckBitmap (field-4 I64 LE) — omitted when 0 [optional] WindowSize (field-5 varint) — omitted when 0 ``` Each event body is encoded as a Protocol Buffers–style LEN field: ``` varint(0x0A) # field=1, wire type=2 (LEN) → event body follows varint(len(event_body)) # byte length of event body event_body[0] # event type (uint8, 0–254 app-defined; 255 internal) event_body[1:] # opaque payload bytes (may be empty) ``` The reliability fields are appended after all events using these proto tags: ``` varint(0x10) # field=2, wire type=0 (varint) → Seq (uint32) varint(0x18) # field=3, wire type=0 (varint) → AckSeq (uint32) varint(0x21) # field=4, wire type=1 (I64 LE) → AckBitmap (uint64) varint(0x28) # field=5, wire type=0 (varint) → WindowSize (uint32) ``` All four reliability fields are zero-omitted, preserving backward compatibility with peers that implement only unreliable delivery. A **standalone ACK** frame carries no events (`Events` is empty) and has `Seq == 0`; it carries only `AckSeq`, `AckBitmap`, and `WindowSize`. Multiple events may be packed into a single Frame (coalescing). ### 10.1 Channel IDs | Value | Usage | |---|---| | 0 | Default channel | | 1–254 | Application-defined channels | | 255 | Internal (`channelCloseType`) | Event type 255 (`channelCloseType`) on any channel signals that the remote peer has closed that channel. The receiver evicts the channel and signals any blocked `Recv` callers with an error. --- ## 11. Reliable Delivery Reliable delivery is opt-in per channel via `Channel.SetReliable(ReliableCfg)`. Channels that do not call `SetReliable` have zero overhead; all reliability fields in their frames are zero and ignored on receipt. ### 11.1 Sequence numbers Sequence numbers are `uint32`, starting at **1** (0 is reserved to mean "unreliable"). The sender assigns a monotonically increasing sequence number to each outgoing frame in `preSend`. Sequence numbers reset to 1 whenever the underlying session reconnects (persistent connections). ### 11.2 Cumulative ACK `AckSeq` carries the **next expected** sequence number (TCP-style). A value of `AckSeq = N` means the receiver has received all frames with `seq ∈ [1, N-1]` in order and is waiting for `seq == N`. The sender frees all pending frames with `seq < AckSeq`. ### 11.3 Selective ACK (SACK) `AckBitmap` is a 64-bit SACK bitmap. Bit `i` (LSB = bit 0) is set when the frame with sequence number `AckSeq + i + 1` has been received out of order. The sender uses this to free selectively acknowledged frames without waiting for gap-filling retransmits. The receiver maintains an out-of-order (OOO) buffer of at most `reliableOOOWindow = 64` slots. Frames arriving more than 64 positions ahead of the expected sequence are dropped. ### 11.4 Flow control (window) `WindowSize` reports how many additional frames the sender of the ACK can accept (receive-buffer headroom). The remote sender blocks when `numPending >= peerWindow`. `WindowSize` is updated dynamically as the receiver's channel buffer drains. The initial window equals the configured `ReliableCfg.WindowSize` (default 256). ### 11.5 ACK timing ACKs are **piggybacked** on outgoing data frames whenever possible: before a data frame is sent, any pending ACK state is consumed and written into the frame's `AckSeq`/`AckBitmap`/`WindowSize` fields at no extra cost. When no data is ready to send, a **standalone ACK** is dispatched after at most `ACKDelay` (default 20 ms) by a `time.AfterFunc` timer. ### 11.6 Retransmit A single retransmit timer (`time.AfterFunc`) is armed per channel after any frame is sent. On firing it retransmits the oldest unACKed frame and reschedules itself with **exponential backoff** (RTO doubles each retry, capped at `maxRTO = 30 s`). After `MaxRetries` (default 10) consecutive retransmit attempts the channel is closed. The retransmit timer is reset to `BaseRTO` (default 200 ms) whenever an ACK frees at least one frame. ### 11.7 Reconnect behaviour When a persistent `Conn` reconnects, `reset()` is called on every channel that has a `reliableState`. This purges all pending frames, resets `nextSeq` to 1, restores `peerWindow` to the configured maximum, and broadcasts on the flow-control condition variable to unblock any goroutines waiting in `preSend`. The receiver-side `expectSeq` is also reset to 1 and the OOO buffer is cleared. In-flight frames that had not been ACKed before the reconnect are discarded; the application layer is responsible for any end-to-end retransmission policy across reconnects. --- ## 12. Numeric Limits | Constant | Value | |---|---| | `sizeHandshakeInit` | 148 bytes | | `sizeHandshakeResp` | 92 bytes | | `sizeCookieReply` | 64 bytes | | `sizeDataHeader` | 16 bytes | | `sizeFragmentHeader` | 8 bytes | | `sizeAEADTag` | 16 bytes | | `sizeKeepalive` / `sizeDisconnect` | 32 bytes | | `defaultMaxPacketSize` | 1232 bytes | | `defaultMaxFragPayload` | 1192 bytes | | `MaxIncompleteFrames` (default) | 64 (configurable) | | `windowWords` | 64 | | `windowSize` (replay) | 4096 (= 64 words × 64 bits) | | `maxTimestampSkew` | 180 s | | `cookieRotation` | 2 min | | `rekeyAfterTime` | 180 s | | `rekeyAfterMessages` | 2^60 | | Maximum fragments per frame | 65 535 | | Maximum channels | 256 (IDs 0–255) | | `defaultReliableWindow` | 256 frames | | `defaultBaseRTO` | 200 ms | | `defaultMaxRetries` | 10 | | `defaultACKDelay` | 20 ms | | `maxRTO` | 30 s | | `reliableOOOWindow` | 64 slots | --- ## 13. Implementation Notes ### Batch sends (Linux) On Linux, outgoing fragments are sent in a single `sendmmsg(2)` syscall via `ipv4.PacketConn.WriteBatch` (IPv4 sockets) or `ipv6.PacketConn.WriteBatch` (IPv6 sockets). On other platforms, fragments are sent in a loop of individual `sendmsg` calls. ### Batch receives Incoming UDP datagrams are read in batches of up to 64 (server) or 16 (client) messages per `recvmmsg(2)` syscall via `ipv4.PacketConn.ReadBatch`. ### Buffer pools Send and receive paths use `sync.Pool`-backed byte slices to reduce GC pressure. AEAD operations write ciphertext and plaintext in-place into pool buffers; no additional allocation occurs on the hot path when buffers have sufficient capacity. ### Socket buffers Both client and server request 4 MiB `SO_RCVBUF` / `SO_SNDBUF`. On Linux, this may be silently clamped by `net.core.rmem_max` / `wmem_max` (default ≈ 208 KiB). To guarantee the full 4 MiB, either raise the sysctl: ```bash sysctl -w net.core.rmem_max=4194304 sysctl -w net.core.wmem_max=4194304 ``` or use `SO_RCVBUFFORCE` (requires `CAP_NET_ADMIN`). In Docker, pass `--sysctl net.core.rmem_max=4194304`. ### Rate limiting When `SendRateLimitBPS` is non-zero in `ServerConfig` or `DialConfig`, a token-bucket limiter is installed on the session's send path. The burst capacity is 2× the per-second rate, allowing short bursts to proceed at full wire speed. The limiter is checked in `session.send()` and `session.sendFragments()` before each write; it sleeps on a timer when tokens are exhausted and aborts early if the session closes. ### Pipeline sizing (`ProbeUDPRecvBufSize`) Benchmark and high-throughput pipeline code should call `wiresocket.ProbeUDPRecvBufSize(requested int) int` to determine the actual achievable receive-buffer size before computing `inflightCap`. On Linux without `CAP_NET_ADMIN`, `SO_RCVBUF` is clamped by `net.core.rmem_max`; the probe function creates a temporary loopback socket, applies `SO_RCVBUFFORCE` (falling back to `SO_RCVBUF`), reads back the result with `getsockopt`, and divides by 2 to undo the kernel's automatic doubling. On other platforms it returns `requested` unchanged. Using the probed value prevents the in-flight frame count from exceeding what the kernel buffer can hold, avoiding packet loss under burst sends.
0000 sats
nextwave19d ago
First round of reliability tuning in. Throughput is still holding strong. Next round is testing the protocol out on increasingly shaky environments.
0000 sats
nextwave20d ago
Some say we've moved from the Information Age to the Intelligence Age. We're actually in the Discernment Age.
0100 sats
nextwave20d ago
Here's a benchmark for the final set of optimizations on commodity hardware. Very reasonable performance.
0600 sats
nextwave21d ago
Hopefully this will shed some light as to why I designed the protocol with channels. Channel multiplexing lets logically separate concerns share a single encrypted session without the overhead of establishing multiple connections. The main use cases: Prioritization and QoS - High-priority control messages (e.g. stop/pause commands) on a dedicated channel so they aren't queued behind large data payloads - Real-time telemetry on one channel, bulk file transfer on another — each can have independent flow control Topic / stream isolation - Pub/sub: each topic maps to a channel; subscribers receive only what they're interested in without receiver-side filtering overhead - Sensor feeds: temperature on ch 1, GPS on ch 2, video frames on ch 3 — consumers subscribe selectively Request/response multiplexing - Interleave multiple concurrent RPC calls over one session — each call gets its own channel ID to match replies to requests, similar to HTTP/2 streams Backpressure isolation - A slow consumer on channel 3 doesn't block or drop events on channel 1 — each channel has its own buffer - Wiresocket's per-channel events buffer means a full channel drops or blocks independently Versioned or feature-gated streams - Send on channel 0 for v1 clients, channel 1 for v2 clients — a server can maintain both protocols simultaneously without separate sockets Lifecycle decoupling - A control plane (handshake, session management) and data plane (event stream) on separate channels — the control channel can signal teardown without racing with in-flight data Security boundaries - Different trust levels or tenants sharing a session can be isolated by channel — the application enforces which channels a principal may read/write without separate TLS termination In wiresocket specifically, the design is intentionally minimal: 256 channels (0–255), channel 255 reserved for internal close signals. The application layer owns the semantics of each channel ID, keeping the protocol unopinionated about how multiplexing is used.
1000 sats
nextwave21d ago
The early reference implementation in Golang will saturate multi-gigabit connections on commodity hardware. The payload is the size of individual events.
0000 sats
nextwave21d ago
# Wiresocket Protocol Specification Version: 1 (`noisePrologue = "wiresocket v1"`) --- ## 1. Overview Wiresocket is a WireGuard-inspired, encrypted UDP event-stream protocol. It provides a bidirectional, multi-channel event stream between a client and server over a single UDP socket. **Key properties:** - **Transport**: UDP (connectionless) - **Encryption**: Noise IK over X25519 / ChaCha20-Poly1305 / BLAKE2s - **Authentication**: Both static keys (server always; client optionally) - **Multiplexing**: up to 256 independent channels per session (channel IDs 0–255) - **Fragmentation**: frames exceeding one UDP datagram are split across up to 65 535 fragments - **DoS mitigation**: WireGuard-style cookies (XChaCha20-Poly1305) - **Replay protection**: 64-bit sliding window All multi-byte integers are **little-endian** unless stated otherwise. --- ## 2. Cryptographic Primitives | Primitive | Algorithm | Notes | |---|---|---| | DH | X25519 (RFC 7748) | Low-order-point rejection enforced | | AEAD (handshake) | ChaCha20-Poly1305 (RFC 8439) | | | AEAD (transport) | ChaCha20-Poly1305 | One AEAD instance per direction, cached per session | | AEAD (cookie reply) | XChaCha20-Poly1305 | 24-byte random nonce | | Hash | BLAKE2s-256 | | | MAC | Keyed BLAKE2s-256 | `BLAKE2s(key=K, data=D)` | | KDF | HKDF-BLAKE2s | See §2.1 | | Keypairs | X25519 | RFC 7748 clamping applied | ### 2.1 KDF ``` prk = MAC(key=ck, data=input) T[1] = MAC(key=prk, data=0x01) T[i] = MAC(key=prk, data=T[i-1] || byte(i)) ``` `kdf2(ck, input)` returns `(T[1], T[2])`. `kdf3(ck, input)` returns `(T[1], T[2], T[3])`. ### 2.2 Initial chaining key and hash ``` initialCK = "Noise_IK_25519_ChaChaPoly_BLAKE2s" (zero-padded to 32 bytes) initialH = HASH(initialCK || "wiresocket v1") ``` Both are computed once at process startup. ### 2.3 AEAD nonce Transport AEAD nonces are 12 bytes: ``` nonce[0:4] = 0x00 0x00 0x00 0x00 nonce[4:12] = counter (uint64 LE) ``` ### 2.4 MAC1 derivation ``` mac1_key = HASH("mac1----" || receiver_static_pub) MAC1 = MAC(mac1_key, message_body)[0:16] ``` `message_body` is everything in the serialised message before the MAC fields. ### 2.5 MAC2 derivation ``` MAC2 = MAC(key=cookie[0:16] zero-extended to 32 bytes, data=message_body)[0:16] ``` --- ## 3. Packet Types The first byte of every UDP datagram is a **type tag**: | Value | Name | Size (bytes) | |---|---|---| | 1 | HandshakeInit | 148 | | 2 | HandshakeResp | 92 | | 3 | CookieReply | 64 | | 4 | Data | 16 + ciphertext | | 5 | Disconnect | 32 (16 header + 16 AEAD tag) | | 6 | Keepalive | 32 (16 header + 16 AEAD tag) | | 7 | DataFragment | 16 + ciphertext | --- ## 4. Wire Formats ### 4.1 HandshakeInit (type 1, 148 bytes) Sent by the initiator to begin a session. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x01 1 3 reserved (zero) 4 4 sender_index uint32 LE — initiator's session token 8 32 ephemeral initiator ephemeral public key (X25519) 40 48 encrypted_static AEAD(initiator static pub key, 32 plain + 16 tag) 88 28 encrypted_timestamp AEAD(TAI64N timestamp, 12 plain + 16 tag) 116 16 mac1 MAC1 keyed by responder's static pub 132 16 mac2 MAC2 keyed by cookie (zeros if no cookie) ``` `sender_index` is a random 32-bit token chosen by the initiator. It is used as `receiver_index` in all subsequent packets the server sends to this session. `encrypted_timestamp` carries a 12-byte TAI64N timestamp (`uint64 BE seconds` || `uint32 BE nanoseconds`). The TAI epoch offset applied is `0x4000000000000000`. The responder rejects timestamps more than ±180 seconds from its own clock. ### 4.2 HandshakeResp (type 2, 92 bytes) Sent by the responder in reply to a valid HandshakeInit. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x02 1 3 reserved (zero) 4 4 sender_index uint32 LE — responder's session token 8 4 receiver_index uint32 LE — echoes initiator's sender_index 12 32 ephemeral responder ephemeral public key (X25519) 44 16 encrypted_nil AEAD(empty plaintext) — 0 plain + 16 tag 60 16 mac1 MAC1 keyed by initiator's static pub 76 16 mac2 MAC2 keyed by cookie (zeros if no cookie) ``` ### 4.3 CookieReply (type 3, 64 bytes) Sent by the server instead of HandshakeResp when under load. The cookie must be used in MAC2 of the retried HandshakeInit. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x03 1 3 reserved (zero) 4 4 receiver_index uint32 LE — echoes initiator's sender_index 8 24 nonce random 24-byte XChaCha20 nonce 32 32 encrypted_cookie XChaCha20-Poly1305(cookie, 16 plain + 16 tag) ``` The XChaCha20-Poly1305 key is the MAC1 from the HandshakeInit zero-extended to 32 bytes. Only the genuine initiator (who knows its own MAC1) can decrypt the cookie. ### 4.4 Data (type 4) Carries one encrypted Frame. Total size: `16 + len(plaintext) + 16`. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x04 1 3 reserved (zero) 4 4 receiver_index uint32 LE — recipient's session token 8 8 counter uint64 LE — monotonic send counter 16 N+16 ciphertext ChaCha20-Poly1305(frame_bytes, N plain + 16 tag) ``` AAD is empty. The nonce is constructed from `counter` (see §2.3). ### 4.5 Disconnect (type 5, 32 bytes) Authenticated graceful shutdown notification. Same header layout as Data with an AEAD over empty plaintext. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x05 1 3 reserved (zero) 4 4 receiver_index uint32 LE 8 8 counter uint64 LE 16 16 AEAD tag ChaCha20-Poly1305(empty) — 0 plain + 16 tag ``` ### 4.6 Keepalive (type 6, 32 bytes) Liveness probe. Same layout as Disconnect with type 6. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x06 1 3 reserved (zero) 4 4 receiver_index uint32 LE 8 8 counter uint64 LE 16 16 AEAD tag ChaCha20-Poly1305(empty) — 0 plain + 16 tag ``` A keepalive is sent whenever no data has been exchanged for `KeepaliveInterval` (default 10 s). The counter participates in replay protection. ### 4.7 DataFragment (type 7) Carries one encrypted fragment of a large Frame. Total size: `16 + 8 + len(frag_data) + 16`. ``` Offset Size Field ------ ---- ----- 0 1 type = 0x07 1 3 reserved (zero) 4 4 receiver_index uint32 LE 8 8 counter uint64 LE 16 N+24 ciphertext ChaCha20-Poly1305(frag_plain, (8+M) plain + 16 tag) ``` The **plaintext** inside the ciphertext has its own sub-header: ``` Plain offset Size Field ------------ ---- ----- 0 4 frame_id uint32 LE — unique per frame within a session 4 2 frag_index uint16 LE — zero-based index of this fragment 6 2 frag_count uint16 LE — total number of fragments (1–65535) 8 M frag_data raw fragment bytes ``` `frame_id` is a monotonically increasing counter scoped to the sending session. All fragments of the same frame share the same `frame_id`. --- ## 5. Noise IK Handshake The handshake follows the **Noise IK** pattern (`Noise_IK_25519_ChaChaPoly_BLAKE2s`): ``` Pre-messages: -> s (responder's static public key known to initiator out-of-band) Messages: -> e, es, s, ss (HandshakeInit) <- e, ee, se (HandshakeResp) ``` ### 5.1 Symmetric State Both sides maintain a symmetric state `(ck, h, k, nonce)`: - `ck` — chaining key, starts as `initialCK` - `h` — transcript hash, starts as `initialH` - `k` — current AEAD key (empty until first `mixKey`) - `nonce` — per-key counter, reset to 0 on each `mixKey` **`mixHash(data)`**: `h = HASH(h || data)` **`mixKey(dh_out)`**: `(ck, k) = kdf2(ck, dh_out)` ; `nonce = 0` **`encryptAndHash(plain)`**: `c = AEAD_Seal(k, nonce++, h, plain)` ; `mixHash(c)` ; return `c` **`decryptAndHash(cipher)`**: `p = AEAD_Open(k, nonce++, h, cipher)` ; `mixHash(cipher)` ; return `p` ### 5.2 Initiator: CreateInit Starting state: `ck = initialCK`, `h = HASH(initialCK || "wiresocket v1")`. ``` Pre-message: mixHash(responder_static_pub) Message construction: mixHash(e_pub) # -> e (ck, k) = kdf2(ck, DH(e_priv, s_resp_pub)) # -> es encrypted_static = encryptAndHash(s_init_pub) # -> s (ck, k) = kdf2(ck, DH(s_init_priv, s_resp_pub)) # -> ss encrypted_timestamp = encryptAndHash(TAI64N()) mac1 = MAC1(responder_static_pub, msg_body_without_macs) mac2 = MAC2(cookie, msg_body_without_mac2) # zero if no cookie ``` ### 5.3 Responder: ConsumeInit ``` Pre-message: mixHash(local_static_pub) Verification and processing: verify MAC1 mixHash(e_init_pub) # -> e (ck, k) = kdf2(ck, DH(s_resp_priv, e_init_pub)) # -> es s_init_pub = decryptAndHash(encrypted_static) # -> s (ck, k) = kdf2(ck, DH(s_resp_priv, s_init_pub)) # -> ss timestamp = decryptAndHash(encrypted_timestamp) validate timestamp within ±180 s ``` ### 5.4 Responder: CreateResp Continues immediately after ConsumeInit. ``` mixHash(e_resp_pub) # -> e (ck, k) = kdf2(ck, DH(e_resp_priv, e_init_pub)) # -> ee (ck, k) = kdf2(ck, DH(e_resp_priv, s_init_pub)) # -> se encrypted_nil = encryptAndHash(empty) mac1 = MAC1(initiator_static_pub, resp_body_without_macs) mac2 = 0 (no cookie in response) ``` ### 5.5 Initiator: ConsumeResp ``` mixHash(e_resp_pub) # <- e (ck, k) = kdf2(ck, DH(e_init_priv, e_resp_pub)) # <- ee (ck, k) = kdf2(ck, DH(s_init_priv, e_resp_pub)) # <- se decryptAndHash(encrypted_nil) # proves responder identity ``` ### 5.6 Transport Key Derivation (SPLIT) After both sides complete the handshake: ``` (T_initiator_send, T_initiator_recv) = kdf2(ck, empty) ``` - Initiator sends with `T_initiator_send`, receives with `T_initiator_recv`. - Responder sends with `T_initiator_recv`, receives with `T_initiator_send`. --- ## 6. Cookie / DoS Mitigation When the server is under load, it may respond to HandshakeInit with a CookieReply instead of HandshakeResp. ### 6.1 Cookie derivation (server side) The server maintains a 32-byte `cookie_secret` rotated every 2 minutes. ``` cookie_key = MAC(key=cookie_secret, data="cookie--" || server_static_pub) cookie = MAC(key=cookie_key, data=client_addr_string)[0:16] ``` `client_addr_string` is the client's UDP address formatted as `"ip:port"`. ### 6.2 CookieReply construction ``` key = mac1_from_HandshakeInit zero-extended to 32 bytes nonce = random 24 bytes encrypted_cookie = XChaCha20-Poly1305-Seal(key, nonce, cookie, aad=empty) ``` ### 6.3 MAC2 retry On receiving a CookieReply, the initiator decrypts the cookie and retries HandshakeInit with: ``` MAC2 = MAC2(cookie, message_body_without_mac2)[0:16] ``` The server accepts a HandshakeInit with a valid MAC2 even under load. --- ## 7. Session Lifecycle ``` Client Server | | |------ HandshakeInit --------->| | | (may send CookieReply if under load) |<----- HandshakeResp ----------| | | | [session established] | | | |<===== Data / Fragments ======>| |<===== Keepalives ============>| | | |------ Disconnect ------------>| (or timeout) ``` ### 7.1 Session indices Each side independently picks a random 32-bit `session_index`. The sender places the **recipient's** index in every outgoing data packet's `receiver_index` field so the recipient can route it to the correct session. ### 7.2 Send counter The sender maintains a monotonically increasing 64-bit counter starting at 0. The counter is used both as the AEAD nonce and for the receiver's replay window. When the counter reaches `2^64 - 1` it wraps to 0 and the session is closed, forcing a new handshake. ### 7.3 Timeouts and keepalives | Parameter | Default | Description | |---|---|---| | `KeepaliveInterval` | 10 s | Send keepalive if data idle for this long | | `SessionTimeout` | 180 s | Close session if no packet received for this long | | `RekeyAfterTime` | 180 s | Initiate new handshake after this session age | | `RekeyAfterMessages` | 2^60 | Initiate new handshake after this many packets sent | Each side enforces its own timeout independently. Keepalive receipt does **not** reset the data-idle timer; a peer that only sends keepalives will still receive them in return. --- ## 8. Replay Protection Incoming data, keepalive, disconnect, and fragment packets are all subject to replay protection using a 64-bit sliding window of size 64. ``` Window covers: [head - 63, head] ``` - If `counter > head`: accepted (new high-water mark). - If `counter < head - 63`: rejected (too old). - Otherwise: check bitmask. If bit already set: rejected (duplicate). The window is updated (`head` advanced, bitmap updated) only after AEAD decryption succeeds. `head` is stored atomically for a lock-free fast path on the common case of strictly in-order delivery. --- ## 9. Fragmentation Frames whose serialised plaintext exceeds `maxFragPayload` bytes are split into multiple DataFragment packets. ### 9.1 Default MTU parameters | Parameter | Value | Derivation | |---|---|---| | Default MaxPacketSize | 1232 bytes | IPv6 min path MTU (1280) − IPv6 header (40) − UDP header (8) | | Default maxFragPayload | 1192 bytes | 1232 − DataHeader(16) − FragmentHeader(8) − AEADTag(16) | | Maximum fragments per frame | 65 535 | `frag_count` is uint16 | | Maximum frame size at default MTU | ≈ 78 MB | 65 535 × 1192 bytes | ### 9.2 Reassembly The receiver maintains a map of partial frames keyed by `frame_id`. When all `frag_count` fragments for a `frame_id` arrive, the payloads are concatenated in `frag_index` order and the result is decoded as a Frame. Incomplete fragment sets are garbage-collected after `2 × KeepaliveInterval` of inactivity. At most `MaxIncompleteFrames` (default 64) partial frames are buffered per session; excess fragments are silently dropped. Duplicate fragments (same `frame_id` + `frag_index`) are ignored. --- ## 10. Frame Wire Format A **Frame** is the plaintext inside a Data or reassembled DataFragment packet. ``` Byte 0: channel_id (uint8) Byte 1..N: events (sequence of length-prefixed event bodies) ``` Each event body is encoded as a Protocol Buffers–style LEN field (field 1, wire type 2): ``` varint(0x0A) # field=1, wire type=LEN (proto tag) varint(len(event_body)) # byte length of event body event_body[0] # event type (uint8, 0–254 app-defined; 255 internal) event_body[1:] # opaque payload bytes (may be empty) ``` Multiple events may be packed into a single Frame (coalescing). ### 10.1 Channel IDs | Value | Usage | |---|---| | 0 | Default channel | | 1–254 | Application-defined channels | | 255 | Internal (`channelCloseType`) | Event type 255 on channel ID 255 signals that the remote peer has closed that channel. The receiver evicts the channel and signals any blocked `Recv` callers with an error. --- ## 11. Numeric Limits | Constant | Value | |---|---| | `sizeHandshakeInit` | 148 bytes | | `sizeHandshakeResp` | 92 bytes | | `sizeCookieReply` | 64 bytes | | `sizeDataHeader` | 16 bytes | | `sizeFragmentHeader` | 8 bytes | | `sizeAEADTag` | 16 bytes | | `sizeKeepalive` / `sizeDisconnect` | 32 bytes | | `defaultMaxPacketSize` | 1232 bytes | | `defaultMaxFragPayload` | 1192 bytes | | `maxReassemblyBufs` (default) | 64 | | `windowSize` (replay) | 64 | | `maxTimestampSkew` | 180 s | | `cookieRotation` | 2 min | | `rekeyAfterTime` | 180 s | | `rekeyAfterMessages` | 2^60 | | Maximum fragments per frame | 65 535 | | Maximum channels | 256 (IDs 0–255) | --- ## 12. Implementation Notes ### Batch sends (Linux) On Linux, outgoing fragments are sent in a single `sendmmsg(2)` syscall via `ipv4.PacketConn.WriteBatch` (IPv4 sockets) or `ipv6.PacketConn.WriteBatch` (IPv6 sockets). On other platforms, fragments are sent in a loop of individual `sendmsg` calls. ### Batch receives Incoming UDP datagrams are read in batches of up to 64 (server) or 16 (client) messages per `recvmmsg(2)` syscall via `ipv4.PacketConn.ReadBatch`. ### Buffer pools Send and receive paths use `sync.Pool`-backed byte slices to reduce GC pressure. AEAD operations write ciphertext and plaintext in-place into pool buffers; no additional allocation occurs on the hot path when buffers have sufficient capacity. ### Socket buffers Both client and server request 4 MiB `SO_RCVBUF` / `SO_SNDBUF`. On Linux, this may be silently clamped by `net.core.rmem_max` / `wmem_max` (default ≈ 208 KiB). To guarantee the full 4 MiB, either raise the sysctl: ```bash sysctl -w net.core.rmem_max=4194304 sysctl -w net.core.wmem_max=4194304 ``` or use `SO_RCVBUFFORCE` (requires `CAP_NET_ADMIN`). In Docker, pass `--sysctl net.core.rmem_max=4194304`.
1200 sats
nextwave22d ago
Part of me is thinking that Claude Code is the result of someone finally figuring out how to combine dev and gambling.
0300 sats
nextwave29d ago
0000 sats
nextwave32d ago
Hello world!
2100 sats

Network

Following

Followers

EnkigojiberraNetSavior