A maintainable, extensible BitTorrent client (C11, Linux/io_uring) targeting 10 GbE saturation. All torrent functionality is built from scratch; liburing is the only linked third-party dependency on the data path. Implements Phases 1-7 of the roadmap: - core: page-aligned buffer pool, MPMC/Treiber queues, bitfields, worker pool - crypto: SHA-1/256 (SHA-NI + scalar), Merkle (BEP-52), RC4 (MSE) - bencode/metainfo: zero-copy parser, v1/v2/hybrid .torrent + magnet - peer: sans-IO wire codec, MSE/PE handshake state machine, BEP-10, ut_metadata, PEX - piece/storage: block-level multi-peer engine, rarest-first + endgame, per-file completion events + single-file relocate (move-as-you-finish) - tracker/dht: HTTP + UDP (BEP-15) trackers, BEP-5 KRPC iterative lookup - platform: io_uring reactor (SQPOLL, registered buffers, SEND_ZC) - surface: versioned RPC, native plugin ABI, sandboxed Lua scripting, nautd/nautctl Verified against libtorrent (single/multi/hybrid, MSE, magnet-via-DHT, swarm); unit + interop tests green; ASan/UBSan/TSan clean. Scripting reference in docs/scripting.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
94 lines
3.5 KiB
C
94 lines
3.5 KiB
C
#include "naut/hash.h"
|
|
#include "naut/rc4.h"
|
|
#include "naut/merkle.h"
|
|
#include "test.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
static int hexeq(const uint8_t *got, const char *hex, size_t n) {
|
|
for (size_t i = 0; i < n; i++) {
|
|
unsigned b;
|
|
sscanf(hex + i*2, "%2x", &b);
|
|
if (got[i] != (uint8_t)b) return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int main(void) {
|
|
uint8_t d[32];
|
|
|
|
/* --- SHA-1 (FIPS) --- */
|
|
naut_sha1("abc", 3, d);
|
|
CHECK(hexeq(d, "a9993e364706816aba3e25717850c26c9cd0d89d", 20));
|
|
naut_sha1("", 0, d);
|
|
CHECK(hexeq(d, "da39a3ee5e6b4b0d3255bfef95601890afd80709", 20));
|
|
|
|
/* --- SHA-256 (FIPS) --- */
|
|
fprintf(stderr, "sha256 backend: %s\n", naut_sha256_backend());
|
|
naut_sha256("abc", 3, d);
|
|
CHECK(hexeq(d, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", 32));
|
|
naut_sha256("", 0, d);
|
|
CHECK(hexeq(d, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 32));
|
|
|
|
/* multi-block + streaming: 1,000,000 'a' fed in odd-sized chunks */
|
|
{
|
|
naut_sha256_ctx c; naut_sha256_init(&c);
|
|
char chunk[7]; memset(chunk, 'a', sizeof chunk);
|
|
size_t left = 1000000;
|
|
while (left) { size_t n = left < sizeof chunk ? left : sizeof chunk;
|
|
naut_sha256_update(&c, chunk, n); left -= n; }
|
|
naut_sha256_final(&c, d);
|
|
CHECK(hexeq(d, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0", 32));
|
|
}
|
|
|
|
/* --- RC4 (Wikipedia test vectors, drop=0) --- */
|
|
{
|
|
naut_rc4 c; uint8_t buf[16];
|
|
memcpy(buf, "Plaintext", 9);
|
|
naut_rc4_init(&c, "Key", 3, 0); naut_rc4_xor(&c, buf, 9);
|
|
CHECK(hexeq(buf, "bbf316e8d940af0ad3", 9));
|
|
|
|
memcpy(buf, "pedia", 5);
|
|
naut_rc4_init(&c, "Wiki", 4, 0); naut_rc4_xor(&c, buf, 5);
|
|
CHECK(hexeq(buf, "1021bf0420", 5));
|
|
|
|
/* round-trip with MSE-style drop=1024 */
|
|
uint8_t msg[64], orig[64];
|
|
for (int i = 0; i < 64; i++) orig[i] = msg[i] = (uint8_t)(i * 7);
|
|
naut_rc4_init(&c, "secretkey", 9, 1024); naut_rc4_xor(&c, msg, 64);
|
|
CHECK(memcmp(msg, orig, 64) != 0); /* actually encrypted */
|
|
naut_rc4_init(&c, "secretkey", 9, 1024); naut_rc4_xor(&c, msg, 64);
|
|
CHECK(memcmp(msg, orig, 64) == 0); /* decrypts back */
|
|
}
|
|
|
|
/* --- Merkle (BEP-52 structure) --- */
|
|
{
|
|
/* 3 leaf hashes -> pad to 4 with a zero leaf */
|
|
uint8_t leaves[3*32];
|
|
for (int i = 0; i < 3; i++) { char s[2] = { (char)('a'+i), 0 };
|
|
naut_sha256(s, 1, leaves + i*32); }
|
|
|
|
uint8_t root[32], expect[32];
|
|
CHECK(naut_merkle_root(leaves, 3, root) == NAUT_OK);
|
|
|
|
/* recompute by hand: n0=H(l0||l1), n1=H(l2||zero), root=H(n0||n1) */
|
|
uint8_t zero[32] = {0}, n0[32], n1[32], cat[64];
|
|
memcpy(cat, leaves+0, 32); memcpy(cat+32, leaves+32, 32); naut_sha256(cat, 64, n0);
|
|
memcpy(cat, leaves+64, 32); memcpy(cat+32, zero, 32); naut_sha256(cat, 64, n1);
|
|
memcpy(cat, n0, 32); memcpy(cat+32, n1, 32); naut_sha256(cat, 64, expect);
|
|
CHECK(memcmp(root, expect, 32) == 0);
|
|
|
|
/* single leaf: root == leaf */
|
|
CHECK(naut_merkle_root(leaves, 1, root) == NAUT_OK);
|
|
CHECK(memcmp(root, leaves, 32) == 0);
|
|
|
|
/* leaves from a 40 KiB buffer -> 3 leaves (16K,16K,8K) */
|
|
size_t len = 40*1024;
|
|
uint8_t *blob = malloc(len); memset(blob, 0x5a, len);
|
|
uint8_t lv[3*32];
|
|
CHECK_EQ(naut_merkle_leaves(blob, len, lv), 3);
|
|
free(blob);
|
|
}
|
|
|
|
TEST_MAIN_END();
|
|
}
|