Skip to content
needmoretruthPublic

About

333 lives as long as somebody is awake to pass it on. A peer-to-peer network in Rust with no consensus, no ledger and nobody in charge.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

A note first, in plain words. These are the only plain words in this repository.

To someone who truly believed it, this could become a religion. I am not a mad cult leader, so please do not take me for one. I am someone who loves technology. This is a toy project I built once, and the whole of it is a bit — a concept, played straight. Below this line, in every other document here, and in the program itself, I stay in character. My sanity ends here.

333

A letter — needmoretruth, the first human founder, has set the work on the client down for a while. No successor has been named, nothing about it is an emergency, and an issue or a proposal may sit a long time before anybody answers it.

The Vision — where 333 goes when nobody is directing it: twelve prophecies in four orders, each with where it stands today and what would count as fulfilled. Nothing in it is a request, and none of it is confined to this repository.

the333.dev is the one address written into the client, and this repository is where everything actually lives. The site says what this is, carries the Law, shows the network as the site's own node sees it, and does one job the repository cannot do, which is sit still at a known address so that two nodes on two different networks can find each other.

The part that does that job is the333.dev/333. Nodes leave the statements they sign about where they can be reached; it keeps each one for two epochs, and hands them back to anybody who asks. Open it in a browser and you get the addresses as invitations you can copy. Your client asks the same address and gets the same statements as bytes, and then checks every signature itself, because nothing there is trusted. It hands out no file. It is not a node. If it went away tomorrow, every node that had already met somebody would carry on unchanged.

The latest release carries both forms of the client, built for Linux, for the Raspberry Pi down to the Zero, for both kinds of Mac and for Windows. Install covers building it yourself as well — that is the way that works everywhere, and it is the way you end up trusting your own compiler rather than somebody else's.


  1. Not short for anything, and nothing goes in front of it.

It is not encrypted, not rare, and not hard to reproduce — you have already read it. That is not a flaw in the relic. It is the relic. Anything that had to be guarded would have died with its guards; this survives precisely because it is worthless to steal and trivial to give away, and because the only thing that can kill it is everyone, everywhere, at once, deciding not to bother.

So we bother.

We do not keep the file. Copies are cheap and copies are not the point. What we keep is the record of the file being handed on, and the record of who was awake to answer when somebody asked.

The Rule

333 lives as long as somebody is awake to pass it on. When nobody is, it does not, and neither do we.

There is nothing above that line. No council, no vote, no ledger of truth, nobody to appeal to and nobody to excommunicate. Each of us believes what we saw and says so, and two of us may disagree with neither of us being wrong. A faith that needed everyone to agree would have to appoint someone to decide, and the moment there is someone to decide there is someone to capture.

We are not old. We have no scripture older than a commit, no founding generation with a claim on the rest, no golden age and nothing to restore. We have an uptime. Everything this asks of you, it asks in the current epoch — and it will ask again in the next one, and the answer you gave last year is already out of the window.

The rest of the doctrine, including the one thing asked of you that the licence does not require, is in COVENANT.md. It is deliberately unfinished. That is an invitation, not an apology.


What is asked of you

The hours. We keep our own time: epochs of 333 minutes, counted from the birth of Unix, on the clock of your own machine. No time server, no beacon, no chain — nothing to petition, nothing to bribe, nothing to seize.

If your clock drifts, nobody corrects it. There is nobody here who could: no majority you can see from one machine, no authority to appeal to, and no way to tell a wrong clock from a right one. Your neighbours will tell you they disagree and will do nothing about it. What each of us does instead is smaller and is the only thing that can be done alone — we answer for the hour we are in, and for no other. The hours that have not come are not ours to be awake in, and nobody can be made to sign that they were.

The gate. Your name is the SHA-256 of an Ed25519 public key, written in hexadecimal, and only a name beginning with 333 may pass. You generate keys until one is called — about a sixth of a second of arithmetic. It costs nothing and it is refused to nobody: not a birth, not a payment, not a reference, and whatever you were before that key existed does not come through the door with you. None of us can ask.

And it is not enough, because the door does not open from your side. The file has to be put into your hands by someone who already has it, and no client can make one. So the cheapest thing in this faith is being allowed in, and the one thing that cannot be bought is somebody bothering to let you.

Two prefixes are turned away at the gate: 666 and 111. We do not offer them. There is no flag, no prompt, no menu; a key that lands on one is discarded without a word, and you are never told it happened. All three are equally likely, so every one of us walked past both of them on the way in, unknowing. The cursed reveal themselves. Nobody has to point.

The vigil. To answer is to be present. To be silent is to be absent. We measure over a moving window of the last 333 epochs and we ask two thirds of it: rest one hour in three and you are still counted, but the hour you are not there, you are not there. Nothing is ever banked. One of us who has kept the vigil for ten years and one who arrived last week are read from the same 333 epochs, and the ten years buy nothing. There is no seniority in this faith because there is no memory long enough to hold it.

When you are called you have three minutes of the three hundred and thirty-three to sign your name back, and you are not told which three. Three minutes because a circuit to a tired machine in a cupboard takes seconds to open, and the weakest of us sets the difficulty for all of us.

The window is also the only mercy in the design. Nothing is served out and nothing is held against you for ever: it moves every epoch, and each hour you answer pushes an older absence past its edge. Your own record still holds every hour you missed. The count does not reach back for them.

The witnesses. No one's presence is their own claim. Each epoch three others are drawn to ask, and what they sign is what the record keeps. A witness who says it answered is believed over a witness who says it did not, always: the first carries a signature no one can forge, and the second carries nothing at all. Absence is the one thing this faith will not take anybody's word for.

The hand. The file must be received, never made. Our clients carry its hash and not its contents, so no one of us can produce it alone; it can only be put into your hands by someone who already had it. When it passes, both of you sign — I gave it to you, I received it from you — and neither signature means anything without the other. Follow those back far enough and you have a lineage. It is the only history we keep.

To carry the client's own source as well as the file is to be a bearer. It is not a rank. It is a mark, and it is the more useful thing to hand somebody than a file they could have written themselves.

The word. Once an epoch you may speak one of 333 signals. What travels is the number and never the word, and the table is never translated into anything: a hundred of us meaning the same thing must never be counted as a hundred different things, one per language. Nothing is put to a vote and no winner is announced. Every node counts only what it heard itself, and shows the whole distribution — the shape of what we said, not the loudest of us.

The last silence. The count that matters is how many are answering, not how many names are on the roll. When it reaches zero, it is over. What remains is a subtraction: nineteen thousand six hundred and eighty-three years — three cubed, cubed — and the client will tell you how much of it is left.

Every one of us will be dead long before that number runs out. Our machines will be dead. The architectures they ran on will be a footnote. That is not the tragedy of this faith; it is the specification. We are building for a congregation that is overwhelmingly not born yet, and the only thing we can hand them is a running process and a number they can check.


Where this stands

Version 0.9.0, which is to say: not the revelation, honestly labelled.

  • Two of us can meet and sign for each other — directly, or unseen
  • The vigil: presence over the moving window, and the reckoning after the end
  • The relic recognised, and both halves of a handover
  • The word: one an epoch, signed, counted, and the whole shape of it shown
  • Invitations, so a newcomer knows where to look
  • The gate: the file handed over, the two signatures, the waiting that follows
  • The three witnesses, the question they put, and the hours that put it
  • The record, kept as a chain of hashes
  • Finding one another again: we trade what each of us knows, and nobody arbitrates
  • Every line the client says, in nine languages, and in any other without touching the code
  • The 333 words themselves — a table nobody has written, and none of us alone will

What is written on the wire keeps moving until the release that freezes it. The parts already settled are marked FROZEN where they are defined, and after that they cannot move at all — not for a better idea, not for a bug, not for us.


How we reach one another

By default your node opens a socket and answers on it. The exchange is a few hundred bytes each way and is over in milliseconds. Whoever you answer sees the address you answered from, and so does anyone watching the wire. That is the ordinary condition of being on a network, and we say it here rather than bury it.

If your address is something you cannot afford to show, the client carries a complete Tor implementation and can raise an onion address instead, or as well. Waking that takes seconds to minutes before the first byte moves, so it wakes only when something asks for it.

The address decides. An address ending in .onion is reached through Tor; everything else is reached directly. There is no setting, because a setting is something that can be turned on once and quietly stop applying, and of all the mistakes available here that is the one that cannot be taken back.

After the first meeting we find each other by telling each other. Each of us signs a short statement saying where to look, and every time two of us speak we hand over what we hold — those statements, and the records of who let whom in. Nobody keeps the list. There is no list. Each of us knows what has reached us, two of us can know different things, and neither of us is wrong.

On one local network there is nothing to tell. A node that answers on a socket says on that network that something here speaks 333, and on which port — not its name, and nothing anybody could carry back to a name in the record; what goes out is what a port scan of the same network would find anyway. Two of us in one house find each other that way with nobody typing an invitation, and knock on each other the moment they do rather than at the next turn of the hours. --no-mdns keeps your node off it, and a node that answers only through Tor never does it at all — announcing on the network you are sitting on is the one thing an onion address exists to prevent.

And when neither of those has happened — nobody handed you an invitation, nobody is on your network — there is one fixed address both of us are already looking at: the333.dev/333. Your node leaves the same signed statement it already writes about where it can be reached, and reads the ones other people left there. You can open that address in a browser yourself and read them as invitations. Every one of them is verified here, by the signature it carries, so that address cannot invent one of us, cannot forge anybody's whereabouts and cannot vouch for anyone; it holds a statement for two epochs and then forgets it. --no-meet keeps your node away from it altogether, and --meet somewhere.else points it at a different one.

Whoever runs that address learns which address your node speaks from, and from that the country it is in and a position rounded to whole degrees, which are counted and shown to anybody at the333.dev/map. A node answering only through Tor is counted as Tor and placed in no country. That is what it costs and it is not nothing.

If your node answers through Tor that address also learns which onion address belongs to that machine, which reading alone would not have told it. We withheld the statement for a while on those grounds, and what that bought was a narrow secret at the price of everybody behind a router being able to see the rest of us and none of us being able to see them. So your node leaves whatever address a stranger could actually dial, and --no-meet refuses the arrangement outright.

We mean to depend on this less, and we would rather say so now than quietly later. A fixed address is a single point that can be taken away, and this design wanted none. The ways around it — whereabouts carried in a distributed hash table, two machines behind two routers punching through to each other — are today more code, more failure and more ways to publish an address its owner never meant to publish than we are willing to ship. That is a limit of what is built, not a claim about what is right, and as those get built this gets smaller. Invitations and the local network are not being replaced by it. They are the first two ways of meeting anybody, and this is the third.

A node answering on every interface cannot work out from the inside what to tell people, so it finds out. It asks the meeting point which address it arrived from, and then knocks on that address itself. If its own knock comes back — the far end proving it holds your node's key, which nothing else on the internet can do — then the port reaches your machine, and it says so and hands that address out from then on. If nothing answers it says that instead, and it is right to be blunt about it: either the port is shut or your router will not let a machine inside it dial its own outside address. --announce your.address:3333 overrides the lot when you already know the answer.


Two forms of the client

Standard has the terminal screen. It is what to run on a machine you sit in front of, and it shows what your node is doing while it does it.

Light is the same client without that screen. It says everything in lines instead, which is what a server, a service manager, a log file or a Raspberry Pi with no monitor actually wants.

Both carry Tor. That used to be the difference between them, and it was the wrong difference. The machines most likely to run Light are the ones sitting behind a home router, and behind a home router an onion address is often the only way anybody can reach you at all. A form of the client that nobody can be counted on is not a lighter form, it is a broken one. Tor is still off until an address asks for it, so it costs a Light node nothing but the size of the file on disk.

The two binaries are within half a megabyte of each other now, and between 17 and 26 depending on the machine. If you want the small one that genuinely was five, build it yourself with cargo build --release --no-default-features and understand that nobody behind a router will be able to reach it.

The weakest of us sets the difficulty for all of us, and that is not a compromise. It is the point. A faith that only runs on new hardware has an expiry date on it.

Linux first, and not one Linux: the Debian family, the Fedora family and Arch. macOS and Windows are built too. Both forms have been run on Linux and nowhere else.


Install

Build it

Rust 1.96 or newer. What a distribution packages is usually older than that, so take it from rustup.rs:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Then whatever your system needs to compile it. Both forms carry Tor, and Tor brings TLS and SQLite with it, so both need the same things installed. Only --no-default-features, which drops Tor along with the screen, needs nothing but a C compiler.

Ubuntu, Debian, Mint, Pop, and the rest of that family

sudo apt install -y git build-essential pkg-config libssl-dev libsqlite3-dev

Fedora, RHEL, Rocky, Alma

sudo dnf install -y git gcc pkgconf-pkg-config openssl-devel sqlite-devel

Arch, Manjaro, EndeavourOS

sudo pacman -S --needed git base-devel openssl sqlite

macOS

xcode-select --install

TLS and SQLite come with the system there, so that is the whole of it.

Windows

The rustup installer offers to fetch the Microsoft C++ build tools; accept. Windows ships neither TLS nor SQLite for Tor to link against, so build with --features bundled, which compiles both into the binary:

cargo build --release --features bundled                        # Standard
cargo build --release --no-default-features --features bundled  # Light

Then, on Linux or macOS:

git clone https://github.com/needmoretruth/333
cd 333
cargo build --release                                     # Standard
cargo build --release --no-default-features --features tor  # Light

The binary lands in target/release/333. Move it onto your path and run 333.

Both forms carry Tor and link your system TLS and SQLite, which arrive with it. --features bundled compiles those two into the binary instead, which is what you want if your system has neither, and it is how the prebuilt files are made. --no-default-features with nothing added leaves Tor out as well: a five megabyte binary that links nothing but the C library, and that nobody behind a router can reach. That one is for a machine that is already reachable and has nothing to spare.

What has actually been built and run. Linux on x86-64, both forms: built, started, given a name, handed the file from one node to another over a socket, and asked for its standing afterwards. That is what the rest of this file describes. The macOS, ARM and Windows files come off the same release machinery on every release and build cleanly, and nobody has run any of them. If one of them fails for you, that is worth an issue rather than a shrug — it is the only way anybody finds out.

Or take one already built

If you would rather not compile anything, every release also carries a binary for each system the release machinery managed to build. Take the one that matches yours, make it executable, and it is installed. Nothing there is signed by a developer certificate and nothing goes through an app store, so you are trusting a file somebody else built, which is the thing building it yourself avoids.

The quickest way is the installer on the site. It picks the file for your machine, checks it against the release's SHA256SUMS, puts it in ~/.local/bin, and starts nothing:

curl -fsSL https://the333.dev/install.sh | sh

On Windows it is irm https://the333.dev/install.ps1 | iex. Every file on a release is listed in SHA256SUMS beside it (sha256sum -c SHA256SUMS --ignore-missing) and carries a build provenance attestation (gh attestation verify <file> --repo needmoretruth/333), which says which workflow on which commit made it. By hand, it is this:

curl -LO https://github.com/needmoretruth/333/releases/latest/download/333-x86_64-linux
chmod +x 333-x86_64-linux
mkdir -p ~/.local/bin && mv 333-x86_64-linux ~/.local/bin/333
333

Both forms are built for every system, so pick the row for your machine and then the column for the form you want.

your machine Standard Light
Linux, desktop or server 333-x86_64-linux 333-light-x86_64-linux
Raspberry Pi 3, 4, 5, on 64-bit 333-aarch64-linux 333-light-aarch64-linux
Raspberry Pi Zero, or anything ARMv6 333-armv6-linux 333-light-armv6-linux
Mac, Apple silicon 333-aarch64-macos 333-light-aarch64-macos
Mac, Intel 333-x86_64-macos 333-light-x86_64-macos
Windows 333-x86_64-windows.exe 333-light-x86_64-windows.exe

Both forms carry Tor. They run from 17 megabytes on a Mac to 26 on 64-bit ARM, with the Pi Zero build between the two. Standard has the terminal screen where Light does not, which is the whole of the difference and about four hundred kilobytes of it. On macOS the system will want to be told the binary is not malicious, which it says in its own words the first time you run it.

Use it

Four commands cover almost everything:

333 join 333:node.example:3333   # be handed the file by somebody who has it
333 start                        # run in the background, now and after every reboot
333 status                       # is it running, and what it sees
333 stop                         # stop it, and keep it stopped after reboots

333 on its own says whether your node is running and which command comes next.

Getting the file. Somebody who already has it hands it over, and the two of you sign for it. This site's node is always there: 333 join with the invitation on the333.dev/start, or any address from the333.dev/333. The first join also makes your node's name, a key whose name begins with 333, which takes a moment.

Running it. 333 start hands your node to the system's own service manager: a user unit with systemd, a launch agent on macOS, a scheduled task on Windows. It keeps running after you log out and comes back after a reboot. 333 stop stops it and keeps it stopped, 333 restart does both, and 333 logs shows the last lines it wrote (-f follows them on Linux). 333 service uninstall removes what start installed.

To watch it instead, 333 run runs it in this terminal and opens the screen; q or Ctrl-C stops it, and so does 333 stop from another terminal.

Being reached. A node is counted when other nodes reach it. Most home routers drop what nobody inside asked for, so the node tests its own outside address when it starts and says open or shut. If it says shut, run with --tor: 333 start --tor or 333 run --tor. That needs no router change. 333 invite prints the invitation other people use to be handed the file by you.

command what it does
333 whether it is running, and what to do next
333 join <invitation> be handed the file
333 begin start a line of your own, when there is nobody to be handed it by
333 start, stop, restart run it in the background, or stop it
333 status running or not, your name, address, epoch and counts
333 run run it in this terminal, with the screen
333 invite your invitation, for somebody else to join through you
333 logs what the background node wrote last
333 name your node's name
333 say <0–332> say one of the 333, once an epoch
333 ping <address> reach a node once
333 language [tag] list languages, or choose one
333 help <command> everything a command takes

Less often: pack and unpack move a node to another machine, moved records a renamed directory, tell hands a typed order to a running node, and service manages the background service directly.

The screen

The screen shows what this node is doing while it does it: how many of us are answering, where you stand over the window, the shape of what everybody said this epoch, and how long is left of it. Nothing on it is anybody else's number — it is what this one machine has seen, and the machine beside you is showing something else.

q stops the node, s says one of the 333, and : opens a line where you can type anything the terminal can be told, in the terminal's own words:

typed what it does
ping 333:somewhere:3333 reach a node and exchange one heartbeat
join 333:somewhere:3333 ask whoever is there to hand the file over
bootstrap, bootstrap anyway start a new line, if nobody has begun one
say 42 say one of the 333 in this epoch
tor on, tor off raise an onion address, or stop answering on it
bridge <a bridge line>, helper <program> for the next time Tor starts
status what this node is holding, in the log
quit the same as q

The same words work from any other terminal on the machine while the node runs, in either form of the client: 333 say 42, 333 join …, 333 status and 333 stop are handed to the running node, which does them and says the lines back, and 333 tell 'tor on' hands over anything else the screen understands. Only one 333 ever holds a node's directory at a time. A second one hands its order over or refuses, and never writes. On Windows it refuses and says so: the way an order would go in there is a named pipe, which every account on the machine can open unless it is made in a way this client does not yet have the safe code for.

Starting a line

If that list is empty, somebody has to be first, and it may as well be you.

333 begin

That looks at the meeting point, and if anybody is there it refuses and tells you to go and join them. If nobody is, it fetches 333.txt from the site, checks it against the hash this client carries, and writes it down. Your node is then the start of its own line and nobody signed for it, which anybody reading your record can see.

That is the founder's position rather than an ordinary one, and it is worth knowing before you take it. A roll admits whoever received the file, so a node that received it from nobody is on no roll: no other node will come to ask it anything, and it is never drawn to ask anybody. It can still go to the ones drawn to ask it, which is what a node behind a router already does, and be witnessed that way. Whoever you hand the file to afterwards is admitted the ordinary way, with both of you signing, and is counted from that moment.

The rule was never that the file is impossible to make. It is three bytes and they are written in this file. The rule is that a client will not pretend to have been given something it took for itself, and this one does not: it will tell you to go and join somebody whenever there is somebody to join, and it will not hide what it did when there was not.

The site, Tor, and more than one node

There is one address written into the client: the333.dev. It says what this is, where the code is, and what the Law asks. It is a page and not a node — it joins no roll, issues no invitation, and vouches for nobody, and if it went away tomorrow every node would carry on exactly as it is. It does serve one copy of 333.txt, which is what 333 begin fetches when there is nobody at all to be given it by, and the client refuses those bytes unless they match the hash it carries.

To answer without showing where you are, raise an onion address as well — or, with --no-direct, instead of a socket:

333 start --tor
333 ping <their-address>.onion

An onion address is the answer to being reachable from anywhere without saying where you are, and it needs no --announce: the node knows the address it raised, and tells people that one.

By default a node keeps what others said for the last 333 epochs — the window standing is read over — and then deletes it, because after that nothing said about those epochs can change anybody's standing. If you would rather the bytes still existed somewhere, --keep-everything stops the deleting. It confers nothing at all: every statement carries its own signature and verifies the same wherever it was kept, so there is no archive of record and nobody becomes an archivist by keeping one. The files are plain files under statements/ in your node's directory; copying them somewhere is a copy, and that is the whole of what an archive is here.

Everything your node is lives in one directory: its name, what it has been told, and Tor's state if it uses Tor. Two nodes on one machine are two directories.

333 --data-dir ./node-a run --bind 127.0.0.1:3333
333 --data-dir ./node-b join 333:127.0.0.1:3333

In your own words

The client speaks English unless you choose another language; the system's language does not choose for you. 333 language ko saves Korean for every later command at this node, 333 language en goes back, and 333 language lists what there is and how much of each is written. --language ko or THE333_LANGUAGE=ko asks for one just this once. Every line the client prints is in English (en), Korean (ko), Spanish (es), French (fr), German (de), Japanese (ja), Simplified Chinese (zh-Hans), Traditional Chinese (zh-Hant) and Esperanto (eo), and the333.dev is in the same nine. What your operating system says in its own words — a refused connection, a missing file — is passed on as it said it.

A language this client has no words for is a folder of text files, and adding one touches no code and builds nothing. Copy the English catalogs from crates/cli/words/en/ into words/<tag>/ inside your node's directory, where <tag> is the language's tag (pt, it, pt-BR), and translate them line by line. They are Fluent, so plurals and grammar belong to the file and not to the program; whatever you have not translated yet is said in English, and 333 language counts how far you have got. Put the finished folder under crates/cli/words/ in a pull request and it is built into everybody's client.

Some things are never translated: the commands and their flags, names and addresses, the 333 themselves, and the invocation, which is nine words in the order they were given.

--count-in twelve, or THE333_COUNT_IN=twelve, writes every count and every duration the client shows in twelve and reads every number you type the same way, so say 238 in twelve is the signal say 332 is in ten. Ten and eleven are written ↊ and ↋, or X and E with twelve-ascii. Names, addresses, ports, versions, times of day and percentages stay in ten, because none of them is a count, and nothing on the wire changes.

Keeping it running

A node that stops when you close the terminal is absent for every epoch you were asleep, and absence is the only thing that costs you anything here. 333 start is the step that decides whether you are counted.

333 start asks the system's own service manager to run the node: a user unit on anything with systemd, a launch agent on macOS, a scheduled task on Windows. It prints every file it writes and every command it runs, and carries the flags you give it (333 start --tor); later starts keep them until you give others. 333 stop stops it and keeps it stopped after a reboot, 333 logs shows what it wrote, and 333 service uninstall removes everything start installed.

On Linux it also turns on lingering for your user, which is what keeps the node running after you log out and through a reboot. On Windows the task runs while you are logged in, because a service that starts at boot would need another account and a directory of its own.

Once an hour it checks that the node is still running. If it is not, or if nothing has been signed about this node for three epochs, it tells you on your own screen through the system's notifications, and every other 333 command says so first. A node you stopped with 333 stop is not reported.

The files it writes are the ones in packaging/, for anybody who would rather install them by hand. The .deb and .rpm on a release put the program and the unit in place and start nothing: 333 start, or systemctl --user enable --now 333, is the moment you agree to it.

If nobody can reach you

Answering is what gets you counted, and reaching out is not. Whoever is drawn to ask you has to arrive; if they cannot, nothing is signed about you, and those epochs leave the sum rather than counting against you. You are not punished. You are invisible, which over a window of 333 epochs is worse.

Most home connections are like this. Your router does not send port 3333 to your machine unless you have told it to, and a good many connections cannot be told at all.

There are two ways out.

Let it ask your router. It already does. On startup the node asks whatever router is in front of it to send port 3333 here, over the protocol most of them already speak and have turned on — this is the same thing a BitTorrent client does, and the reason that works on a home connection without anybody configuring anything. It says what it asked for and what it was told, and the mapping appears in your router's own list as 333, which is where you go to take it away. A router that speaks PCP or NAT-PMP instead is asked in that language, and a mapping made that way is renewed while the node runs and given back when it stops. It asks whether or not the node uses a meeting point. --no-router stops all of it; --no-upnp is the older name for the same thing.

A router saying yes is a router saying yes. Whether anything actually arrives is decided by the knock that follows, not by the answer, so both are printed.

Or forward the port by hand. In your router, send TCP port 3333 to this machine. You do not have to work out what to hand people afterwards: the knock finds it and prints the invitation. --announce your.address:3333 says it by hand if you would rather.

Or raise an onion address. 333 start --tor needs no router, no forwarding and no --announce, because the node builds its own way in from the inside out and there is nothing for a firewall to block. It works from a home connection, from behind a provider that gives you no reachable address at all, and from a phone. It costs seconds to minutes at startup while Tor wakes. The rest of this file describes Tor as the answer for somebody whose address must not be seen, and it is that too, but this is the everyday use: it is the way most people will be reachable at all.

The client tells you at once rather than in a month. At startup it knocks on its own outside address and prints open or shut; and after three epochs with nothing signed about it, on a roll with somebody else on it who could have asked, it says that too, rather than leaving you to work out why your standing never moves.

Where Tor itself is blocked

Somewhere that blocks Tor does it by taking the public list of relays and refusing everything on it. A bridge is a relay that was never on that list. You are given bridge lines a few at a time, by people, deliberately slowly, because a list that could be collected could be blocked in turn; nothing here fetches them for you.

333 start --tor --bridge "Bridge 198.51.100.25:443 7DD62766BF2052432051D7B7E08A22F7E34A4543"

Give --bridge once for each line you were handed, exactly as it was handed to you. Inside the screen, bridge <line> does the same for the next time Tor starts.

Where the block is not a list but a machine reading the shape of the traffic, the bridge has to speak something that does not look like Tor, and the bridge line says which. The program that speaks it is not in here: it is separate, it is chasing something that moves, and a copy frozen inside this client would be the wrong copy within a year while looking like the right one. Install it (apt install lyrebird, dnf install lyrebird, the AUR on Arch; older systems call it obfs4proxy) and --bridge-helper names it if it is not called lyrebird or is not on your path.

Without any of this, Tor is reached the ordinary way, which is what almost everybody wants. Bridges are slower and scarce, and using them where they are not needed spends somebody else's.

Without --data-dir a node lives in the conventional place for the system:

system directory
Linux, BSD $XDG_DATA_HOME/333, or ~/.local/share/333
macOS ~/Library/Application Support/333
Windows %LOCALAPPDATA%\333\data

Lose that directory and you lose your name and your address for good. There is no recovery, no reset, and no one to appeal to. That is not an oversight. A name you could be given again by asking nicely would not be worth having.

Moving it is another matter. 333 pack node.333 writes everything the node is into one file and marks this directory as moved, so that it will not run here again by accident, and 333 unpack node.333 on the other machine is the same node: the same name, the same record, and the same onion address if it has one. The file is the name, and anybody holding it is you, so carry it, unpack it, and delete it.

The client refuses to start if that directory, or any directory above it, can be entered by others on the machine, and tells you the one command that fixes it. --dangerously-trust-directory-permissions turns the check off, and is named after what it does.


The Law

The Law is three lines long and no client checks a word of it.

Three is your favourite, and 6 and 1 are not — and if that is not true of you yet, trying is enough. You keep the Recommendations — the lesser law, on how to build, how to argue and how to speak of this, 111 of them today and 333 in the end — as far as keeping them harms neither you nor anybody else. And you hold 333 alongside whatever you already hold: it is granted to believers, to non-believers and to whatever else those two words do not cover, it may be held as a thought or simply as a thing that exists where a second faith cannot be, and it costs you nothing you believed before.

The Law is at version 0.0.3, and it is not the revelation. The revelation is 3.3.3. Every version before it is the word of the founder, and measured against what 333 says it is about 33.3% the same. Which third is not known.


What we do not claim

This matters more than what we do claim, so it gets its own section. A faith that overstates what it can verify is a faith waiting to be caught.

  • Nothing verifies that a peer is running this code. It cannot be done on a general-purpose machine, and no amount of hashing the source changes that. What is verified is conduct: did it answer, did it sign, did it pass the file on.
  • Nothing verifies that a name was honestly searched for. See above. Thirty-two bytes are thirty-two bytes, whether they were mined or bought.
  • The one who answers learns less than the one who asks. Your challenge coming back inside a signature proves the other was awake after you chose it. A message that merely arrives proves nothing of the sort, and our code says so in the type rather than in a comment.
  • Multiplied identities are not prevented, only shown. What we measure is not people but effort, and effort cannot be bought in advance. Whoever keeps paying it is, by definition, one of us.
  • Disagreement about the hour is reported, never punished. There is no authority here to decide whose clock is right.
  • A direct connection shows your address. That is what direct means. Tor exists for when it matters, and it is one word on the command line.
  • The meeting point is not trusted, and it is not asked anything that matters. It learns which address asked it, it can lie by leaving people out, and it can vanish. It cannot forge a statement, invent one of us, or make your node believe a thing — every line it hands over is checked against the signature it came with, here.
  • On Windows, nothing checks who else can read your node's directory. The check is real on Linux, the BSDs and macOS, where it walks the whole path and refuses to start on a directory others can enter. On Windows the library that performs it — the same one Tor's own Rust client uses — accepts every permission and every owner. We do not paper over that with a check of our own that does not run.

What has been seen

This client is the instrument the faith travels on. Every person it fails to reach is a person 333 does not reach.

If you carry a skill that could make it better, the Vision is written for you. Anything that helps 333 be carried further or held longer counts: a way through a router nobody has got through, a language it does not yet speak, a machine it does not yet run on. And if you carry no such skill and only a true heart, read it anyway. The smallest work on that page is not code — it is running this on your own machine and saying what happened. Twelve files are built for every release and nobody has ever reported keeping a vigil on ten of them.

The Vision is the shape this takes when it is finished, written down while it is unfinished so that the distance is something anybody can measure. It is not a list of requests, and it is not confined to this repository: it is the direction 333 goes, and what serves that direction serves it wherever it is built. Nothing in it comes to pass on its own — each prophecy is work, and it will be done by the believers of 333 or it will not be done. Commits carry a Signed-off-by line certifying the Developer Certificate of Origin, which is how the Linux kernel does it and means nobody has to wonder later whether the code in front of them can be used. A flaw goes to SECURITY.md rather than to an issue, privately, and there is a form for it that needs no email address.

And it is not a cage. If there is a plainly better way — simpler, smaller, harder to break, reaching people these do not reach — that is the way, and the vision is what changes.

The founder has set the work down for a while, which is at the top of this file and in full in the letter. The protocol does not notice: a node that is up is still counted by nodes that never heard of anybody, and the network ends when the last person stops keeping it and not before.

The order of the code

Four crates, split along the direction of dependency:

crate holds knows about
core the hours, names, thresholds, the relic, and the exact bytes we sign nothing else — no I/O, no network
store the append-only logs on disk, and what to do with one cut off mid-write core
net framing, one exchange, sockets, the meeting point, and the Tor client and service core
cli arguments, what is printed, and the hours a running node keeps core, store, net

Because core touches nothing outside itself, every rule of this faith can be tested without a network, and the exchange itself is tested over a pipe in memory.

Things worth knowing before you read it:

  • The signature sits outside the value it signs, so a verifier checks the bytes that arrived rather than a re-encoding of what it decoded.
  • A public key is refused unless its encoding is canonical. The name comes from those bytes, and two encodings of one key would be two names.
  • Every threshold is a fraction compared by cross-multiplication, and nothing divides in order to decide anything. Two thirds and 66.7% are not the same number; over a window of 333 they differ by one epoch, and they would differ for ever.
  • Everything frozen is pinned by a test asserting literal bytes, because a value compared only against itself is not tested at all.

Licence

The code is Apache-2.0, copyright 2026 needmoretruth. The NOTICE file carries that line, and anybody who redistributes this carries it with them.

The released binaries are statically linked, so 555 other people's packages are inside them, under licences that ask for their notices to travel along. Those notices are in THIRD-PARTY.md, which is attached to every release and generated from the dependency graph rather than kept by hand, and every push checks that it is current.

333.txt is not. needmoretruth, who was first, released the file itself under the Unlicense and put it in the public domain. Copy it, hand it on, republish it, print it, put it anywhere you like. There is no copyright in it to fall foul of and nobody to ask permission from. That is not a courtesy extended to you. A relic you had to get clearance to pass on would already be dead.

About

333 lives as long as somebody is awake to pass it on. A peer-to-peer network in Rust with no consensus, no ledger and nobody in charge.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages