ñü.vœîð

a file leaves
with no name.

Eight copies, each with its own key. The wrong key opens nothing.

stealth

a node holds ciphertext.
it cannot name the file.

Elliott first built this shape in 2010. nu.void is that design on this network. It is a bag, not a vault. What you put in it lives as nameless 64 KiB pieces. Only the map on your phone knows how they go back together.

  • One node65,536 bytes of ciphertext and an address. Not the name, the length of the file, the owner, or the other seven copies.
  • One relayA fixed-size mixnet packet, the same shape as the cover. The next chunk takes a different set of relays. No relay from the previous chunk is reused.
  • One wrong keyThe AES-256-GCM tag fails. That chunk returns no bytes, so the file cannot be pieced together from it. Measured: 200 of 200 wrong keys rejected.
  • One right keyThat one chunk. The footer says where its bytes sit. It does not open the rest of the file, and it does not point at the next chunk.
  • A different map per personA private send re-seals every chunk under new keys. Their addresses are not yours. View once deletes their map after it opens.
  • A camera in the roomView once draws on a surface the screenshot buffer does not include. A second camera still sees the screen.

An unlocked phone opens the map, because the map is meant to open for the person who can unlock it. Someone who watches every link still learns that a device is sending cover. The mixnet already assumes that. There is no claim that a file is impossible to read, and no claim that traffic is untraceable.

speed · benchmark

the cipher is not the wait.
the mixnet is.

  • 10.9 µs: To seal one 64 KiB chunk
  • 6.00 GB/s: AES-256-GCM seal throughput
  • 11.7 µs: To open that chunk
  • 1.8 ms: Cipher time for a 10 MiB file, 161 seals

Seal and open were measured on 12 October 2026 on a MacBook Pro (MacBookPro18,3, M1 Pro, macOS 26.4) with Python cryptography, 5,000 rounds of a 65,520-byte plaintext. Seal was 10.9 µs, 6.00 GB/s. Open was 11.7 µs, 5.62 GB/s. A wrong key was rejected on 200 of 200 opens, in 12.4 µs, and produced no plaintext. 161 × 10.9 µs is 1.8 ms, calculated from that seal time. This is that machine. It is not a phone, and it is not the network. Each chunk takes its own mixnet route. That wait was not measured here.

on the wire

sixteen bytes of tag.
the name stays on the phone.

A sealed chunk is 65,536 bytes, every time. The 48-byte nu.feet footer is inside the encryption, so the wire does not grow by a header a node can read. The only bytes outside the padded plaintext are the 16-byte tag.

File, then zeros65,472 bytesñü.fêět48 bytes, insidetag16 bytes
A node sees one block of 64 KiB. The footer is in the ciphertext. The address is a hash of that block, not a file name.

stays on the phone

  • The name you gave the file
  • The type, and any note you wrote
  • Who it belongs to
  • The order of the chunks
  • The key for each chunk

crosses the mixnet

  • 65,536 bytes of ciphertext
  • An address derived from those bytes
  • Eight separate puts, on eight routes
  • No session to a storage node
  • No filename, type, length or owner

a 10 MiB file, counted

The file10 MiB
One sealed copy10.1 MiB
Eight copies80.5 MiB

10,485,760 file bytes divided by 65,472 is 160.15, so the file is 161 chunks. One copy is 161 × 65,536 = 10,551,296 bytes, which is 65,536 bytes more than the file: the padding, the footer and the tag, together the size of one chunk. Eight copies are 80.5 MiB. The ratio is 8.01. Almost all of that is the eight copies. The tag is 16 bytes in each 64 KiB, and the name is not among the bytes at all.

Cover traffic on the mixnet is extra and is not in these figures. A node that has run~node void off is not in the set of eight. This is not a smaller file. It is a file whose name, type and owner never leave the phone, stored eight times at one fixed size.

format

the chunk, written out.

This is the wire format. An implementation can follow it. It has not been submitted to the IETF.

struct {
  opaque body[65472];     // file bytes, then zeros
  uint32 magic;           // 0x74656566, the bytes of "feet"
  uint32 used;            // file bytes in body, 0..65472
  uint32 index;           // this chunk, from 0
  uint32 count;           // chunks in the file
  opaque object_id[32];
} ChunkPlain;             // 65,520 bytes

k_chunk    = random 32
sealed     = AES-256-GCM(k_chunk, zero_nonce,
               ChunkPlain, aad = object_id || uint32(index))
chunk_addr = H256(Label("nv chunk addr") || sealed)
// sealed is 65,536 bytes
  • Zero nonceOne key encrypts one chunk, once. The key is never reused, so the zero nonce is safe.
  • No convergent encryptionThe same file stored twice, or by two people, gets unrelated addresses.
  • Mixnet onlyEach put and each get is its own mixnet message. nu.void does not open a session to a storage node.
  • The mapFor each chunk: the used length, the 32-byte key, the 32-byte address. The map is wrapped by the Secure Enclave. It is not on a node.

A map handed to one person is sealed to their identity key with ML-KEM-1024, inside an ordinary MLS message. Their chunks are sealed again under new keys. Deleting theirs does not touch yours.

patents

published. not filed.

Nothing on this page is patent pending. A filing has not been made. The design is public so it can be built. Prior systems a later filing would have to stand beside: Tahoe-LAFS, IPFS, Cryptomator, age, Signal attachments, and Padmé padding.