02 — Anchor protocol

Every node is an anchor, and every anchor is the same

The anchor protocol is the only thing that carries traffic on a VeilNet network. This is the model it follows: what an anchor is, who it will talk to, how it finds and reaches the others, and what it does and does not promise.

On this page

What an anchor is

An anchor is a node on the overlay, and every node is one. There are no node classes. Whichever anchor happens to be reachable will help a newcomer find the realm, introduce two peers that cannot see each other, and carry traffic for a pair that cannot connect directly.

To what runs on top of it, the overlay is one Ethernet segment, and each anchor's segment holds only the members it may exchange data with. Its switch is filled in from the membership rather than learned, so a frame for an address nobody holds is dropped rather than flooded, and broadcast and multicast are flooded one hop at a capped rate.

Through a host interface the segment carries IP alone. The overlay is IPv6, IPv4 is translated into IPv6 before it enters, and there is no ARP: every neighbour is already known. An application with an anchor built in can put any other EtherType on the segment directly.

Fig. 01 — What an anchor is, layer by layer
01Your applicationsIP, AND ANYTHING ON TOP OF IT02One Ethernet segmentEVERY MEMBER IT MAY EXCHANGE DATA WITH03Sealed end to endML-KEM-1024 BY DEFAULT · RELAYS CANNOT READ04Admitted transportMEMBERS ONLY · POST-QUANTUM HANDSHAKE

IP runs over the overlay unchanged, and an application with an anchor built in can send any EtherType. Beneath it, every frame is sealed for its destination, and beneath that, only admitted members can open a connection at all.

Identity is a key

An anchor's identity is an ML-DSA public key. There is no registry and no naming authority above it. The AnchorID is derived from the key, so claiming an identity means holding the private key for it, and nothing else does.

The key pair comes from a 32-byte seed, and the seed is the identity. Anyone holding it holds the anchor, so it is treated like an SSH host key, and it is small enough to back up on paper. An identity is never rotated: a new key is a new anchor.

Fig. 02 — Everything an anchor is called comes from one seed
SEED · 32 BYTES7f3a 91c0 5d2e 08b4 … 6a1f 2be8 c901PRIVATE KEYSTAYS WITH THE SEEDPUBLIC KEY · ML-DSA-87the identity itselfANCHORID · A HASH OF THE PUBLIC KEYanchor6btpa3gn6w4stipba…7mfanaiept5aOVERLAY IPV6 ADDRESSfd80:c4b9:99ae:4411:c531:fd4f:754f:f08aFROM THE GENESIS ROOT IDFROM THE ANCHORID

The address works like IPv6 SLAAC, with the AnchorID standing in for the hardware address. Every member can compute every other member's address, so nothing hands addresses out. The key shown is the default suite's.

Addresses follow from the same keys. The overlay's IPv6 prefix, a /48 inside the unique-local range, is derived from the identifier of the tree's genesis root, so the whole tree shares it, two trees never collide, and nobody draws up an address plan. An anchor's address inside that prefix is derived from its AnchorID, so every member can compute every other member's address before either has started.

Realms and credentials

A realm is a root key, and a tree of realms grows from one, the genesis. What members must agree on before either has proved anything, such as the address space and the taint tags, is derived from the genesis root that every member of the tree pins, a sub-realm's members included, so a realm needs no configuration beyond that one key. There is no shared secret, anywhere.

Membership is a credential: a signature, from the realm's root or from a key it delegated to, saying that this anchor belongs. An anchor presents its chain of credentials to each peer, and the peer checks it back to the root before any data flows. It is the arrangement a certificate authority already is: a root, a chain, and nothing held in common.

  • Every credential has an expiry, chosen by whoever signs it.
  • Renewing is signing a fresh credential. A running anchor takes it in place, without dropping a session.
  • A renewal must keep the anchor in the same realm, with the same taints. Moving it to another realm is a fresh start, and moving its compartments is a Taints order.
  • It is a post-quantum PKI tree, not a blockchain: every link is an ML-DSA signature, and there is no ledger, no consensus and no history.

Delegation, and the cut

A realm can delegate. Its root hands a realm of its own to another key, which admits its own anchors and may delegate again, as many levels as its delegation allows. That is how an organisation's root node runs a sub-realm for each site beneath its own realm.

Fig. 03 — A lapsed delegation cuts the tree01 / 03
ROOT KEYrootLAPSEDRENEWEDREALMeastREALMwestSUB-REALMlabSTILL RUNNING

Delegate. A root signs a credential for each realm beneath it, and each of those realms admits its own anchors. A delegation has an expiry, like any other credential.

Lapse. When a delegation is not renewed, the tree is cut at that edge, and nothing is revoked. The realm beneath carries on as a tree of its own, its members still admitting each other.

Its operators are told it has been cut off; its members carry on.

Renew. Renewing a delegation is one signature, installed on one anchor. The rest of the realm learns it by gossip, and the edge is whole again.

Powers

A credential also says what its holder may do to the other members of its realm. Each power is named, and a credential grants only the powers it names.

PowerLets its holder
telemetryAsk another member how it is: its status, its routes and its counters
subnetsRead or rewrite the networks another member forwards for the realm
blockMake an anchor of its own realm an outsider to every member, and lift a block
taintRead or move another member's compartments while it runs
allEvery power, including any a later build defines
  • A chain grants what every link on it grants. Powers are intersected down the chain, so a realm delegated without a power cannot grant it however it signs, and nor can anything beneath it.
  • A delegation grants all unless -caps names less, because it hands a realm the right to run itself. An anchor credential grants none unless -caps names some, so an ordinary member can do nothing to another.
  • The root node is the anchor whose credential carries every power in its realm. It uses them through the gossip controls.

What crosses a realm boundary

Five permissions, five rules
PermissionAllowed between
ConnectThe same realm, or two realms on one line of descent
Serve: carry a circuitThe same realm, or a realm anywhere above carrying for one below
Collect telemetryThe same realm only, and only by an asker whose credential carries telemetry. It is an order
BlockThe same realm only, and only with the block power
Exchange dataThe same realm only
Fig. 04 — Carried, never read
REALM ABOVEparentCARRIES SEALEDCHILD REALMoneCHILD REALMtwoSIBLINGS NEVER MEET

A realm above may relay its descendants' traffic: sealed end to end, it can neither read it nor send any of its own into that realm. Two realms side by side never exchange anything at all.

Data does not widen. A realm above can carry its descendants' traffic without being able to read it or send any into it, which is also what lets two realms reuse one address range. Two realms side by side never meet at all, so one organisation's anchors never become another's transit.

Nor does running a realm. Blocking and collecting follow data's rule rather than serving's: delegating a realm hands over the running of it. A realm above may carry a descendant's traffic, and may neither shut it out nor question it.

Taints

Inside a realm, taints decide which anchors may exchange data. A taint is a label such as prod, lab or a generated string, and the rule is containment, not overlap: two anchors exchange data only if one of them carries every taint the other does.

Taints are granted by the credential. The root that admits an anchor puts it in its compartments: the credential commits to a digest of the set, and the anchor must start under exactly that set or it is refused. A renewal that grants other taints is refused too, so a member cannot put itself in a compartment.

Fig. 05 — Containment, not overlapTry it
A{x}B{x, y}C{x, z}D{x, y}
Start from

The hub carries only the label every spoke has, so it reaches them all; spokes with different second labels cannot reach each other.

Taints each machine carries
A
{x}
B
{x, y}
C
{x, z}
D
{x, y}
Which pairs exchange data
  • A ↔ ByesA's set is contained in B's
  • C ↔ Dnothey share {x}, but neither contains the other
  • A ↔ CyesA's set is contained in C's
  • B ↔ Dyesthe same set
  • A ↔ DyesA's set is contained in D's
  • B ↔ Cnothey share {x}, but neither contains the other

Taints decide data and nothing else: machines in different compartments still connect, find each other, relay for each other, and receive the realm's orders and knowledge. They just cannot exchange data. A real anchor carries up to 32 taints, each granted by its credential.

  • Generality is reach. An anchor with fewer taints reaches more of the realm, so the label everyone shares is the one worth choosing carefully.
  • An anchor with no taints is not exempt. It carries the realm's default compartment, so starting to taint a realm means tainting all of it.
  • Taint names are not secrets. Anyone who knows the tree can compute the tag for a name they can guess: a generated name is unguessable, and prod is not. A member that guesses one learns which peers are in it, and cannot join it.
  • An anchor carries at most 32 taints. A name is 1 to 64 bytes of printing characters, in any script, with no whitespace and no @ or +, which bind a served network to compartments.

Moving a member while it runs

A member holding the taint power can move another to other compartments with a Taints order. The member moved writes the grant down, moves at once, and publishes a taint record into the realm's knowledge, and every peer holds it to the newest record. A member started without a state directory refuses to be moved, since it would forget the move at its next start.

A data send to a moved member whose record has not reached the sender yet waits for it, for as long as the sender's deadline allows. Control traffic does not wait, because taints do not gate it.

Admission, in three stages

An anchor admits a peer in three stages, and nothing is admitted before the third one completes.

Fig. 06 — Nothing is admitted before the third stage01 / 03
memberpeerSTRANGERSEALED KNOCK · ANSWEREDNO ANSWER, NOT EVEN A REFUSALHYBRID ML-KEM · IDENTITY PROVENADMITTED · DATA MAY FLOWROOTREALMMEMBERTAINTS CONTAINED

The knock. Before anything else, the dialler sends a sealed knock carrying proof of membership. A member's knock is answered.

Anyone else gets silence, not even a refusal. The port behaves like port security on a switch, and a scanner cannot tell that anything is listening.

The handshake. A TLS 1.3 handshake with hybrid post-quantum key exchange proves each side's identity. It proves who an anchor is, not yet that it belongs.

Membership. Each side checks the other's credential chain back to the root, and its taints, bound to the session just opened. Only then does data flow.

Post-quantum, on every connection

The default suite, NIST category 5
LayerWithSo that
Key exchangeHybrid ML-KEM, the only group offeredPost-quantum key exchange is required on every connection, never merely preferred
IdentityML-DSA-87An anchor's name and its signatures are post-quantum
End to endML-KEM-1024 and AES-256-GCM, with keys rotating every ten minutesRelays carry traffic they cannot read, and recorded traffic stays unreadable

A tree can instead be generated in suite 0x02, which uses ML-DSA-65 with ML-KEM-768 at category 3 for a smaller handshake. The suite is chosen once, when the genesis is generated, and every key in the tree follows it.

Every hop between two anchors is encrypted, and the whole path is sealed end to end, separately. That second layer is what makes a relay blind rather than merely trusted. Recorded traffic is not decryptable by a future quantum computer.

Finding and reaching peers

An anchor starts knowing one address and ends up knowing the whole realm. There is no directory server: a realm is a known, bounded set of members, so finding a peer is a lookup in what gossip has already delivered.

Fig. 07 — From one address to a direct path01 / 04
NATNATPUNCHED THROUGH · DIRECTSYMMETRIC NATRELAYED · STILL SEALEDyoupeerANY MEMBERONE ADDRESS IS ENOUGH203.0.113.7:41641AS PEERS SEE YOU

Bootstrap. Any member's address is a usable starting point. The new anchor dials it, and news of the arrival spreads peer to peer.

On a local network, a sealed probe finds members of the same tree with no address at all. The probe decides who is worth dialling, never who is let in.

Learn your address. An anchor cannot see the address it appears from behind a NAT, so its peers tell it. Their reports are weighed one peer, one vote, which also reveals whether the address changes with the destination.

Punch through. Two anchors behind NATs coordinate through a peer they share, then dial each other at the same moment. Most home and office NATs open a direct path this way.

Or relay. Where a NAT gives a new address for every destination, no punch can land. Traffic stays relayed through a member both ends can reach, sealed end to end as always.

Changes travel as soon as the network can carry them, never on a timer. An anchor that is leaving says so; silence is never passed on as a departure, so a network that splits heals by itself.

Routing

Reaching another anchor is a computation, not a protocol. The sender plans the whole route from what gossip has told it, so routes are loop-free by construction. Which route it takes, it learns from measurement.

A direct connection, where there is one, is one of the paths the anchor scores, and the first it tries. A path costs the sum of the round trips on every leg, the last one to the destination included, so a direct path and a relayed one are compared like with like. Traffic stays on the path it is using until the learner rates another clearly better, twenty times over and for long enough to count. Then it moves, off a direct connection as readily as off a relayed path, and the direct connection stays up.

Fig. 08 — Each hop knows its neighbours and nothing else
UP TO FIVE RELAYS ON ONE ROUTEsenderPLANS THEWHOLE ROUTErelay 1KNOWSSENDERRELAY 2relay 2KNOWSRELAY 1RELAY 3relay 3KNOWSRELAY 2RECEIVERreceiverTHE ONLY ONETHAT OPENS ITONION HEADER THE SAME SIZE AT EVERY HOP

The sender computes the route itself, from what gossip has told it. A direct connection is one of the paths it scores, and traffic leaves one only for a path rated clearly better. The circuit's onion header is the same size whatever the route, so no relay can tell how far it is from either end.

  • Relaying is offered, never requested. Anchors relay by default, except where they are known to sit behind a NAT that makes them a poor relay.
  • A relay is not a hub. Once two anchors punch through, their traffic moves to the direct path, and goes back through a relay only if a relayed path is rated clearly better.

Addresses on the overlay

IPv6 is the overlay's own address family, and every anchor's IPv6 address is derived from its identity. IPv4 is different. Thirty-two bits are too few to derive without collisions, so an anchor's IPv4 is whatever its operator chooses, another anchor's included, because it never reaches the overlay as IPv4: traffic sent from it is translated into IPv6 from the derived address.

  • The same IPv4 can exist in two realms without conflict. An overlay address means nothing without its realm.
  • Several anchors at one IPv4 are one destination. Each flow, one host talking to that address, is given one of them by what reaching each costs, and keeps it.
  • A private IPv4 is advertised, and peers reach the anchor at it. A public one is sent from and never advertised.

Subnet routers and exits

An anchor can offer more than itself. A subnet router offers a private network it is attached to, so machines with no anchor at all can be reached across the overlay. An exit offers the public internet. The client's only setting is whether to use an exit.

Fig. 09 — Machines with no anchor, reached through one that has
laptopON THE OVERLAYSUBNET ROUTEREXIT192.168.1.0/24NO ANCHOR HEREPRINTERCAMERAINTERNET

A subnet router offers a private network it is attached to; an exit offers the internet. Both offers spread by gossip, and a client's taints decide which router it may use. On Linux with a host interface, the anchor sets its host up to forward as it starts and puts it back as it stops; without one, it forwards from its own process.

  • Offers spread by gossip, so clients need no per-router configuration. The compartments choose the router: an offer is usable only by anchors whose taints permit it, and a router can narrow one network to some of its compartments, as -serve-subnets lab0@lab does.
  • -serve-subnets alone serves every private network the host is on, and follows them as they come and go. A holder of the subnets power can rewrite what a router serves while it runs, and an anchor started with nothing to serve starts forwarding when it is given something.
  • Load is shared per flow: one host talking to one destination. A new flow's router is chosen by weighted rendezvous hashing on what reaching the destination through each costs, and the flow keeps it until it has been idle for fifteen minutes or the router leaves, so a connection never changes hands mid-way.
  • The networks an anchor offers are its egress filter. An exit refuses private ranges, and traffic that arrived from the overlay never leaves by it again.

A hole in the realm's edge, opened deliberately

Offering a route is the operator's decision, and it is the one that changes the host. On Linux with a host interface, a router sets its own host up as it starts and puts it back as it stops: forwarding, router advertisements, masquerade of the translation pool and the overlay, MSS clamping, and accepting forwarded traffic past the firewall. All of it is runtime only, and nothing is saved to survive a reboot. On other systems the anchor names the commands and leaves them to the operator.

Without a host interface, a router forwards TCP and UDP from its own process, with no privilege and nothing on the host set up. Separately, every anchor with a host interface lets its own UDP ports in past the host's firewall while it runs, and takes them out as it stops.

Ways to run an anchor

ModeWhat the host seesWhen to use it
InterfaceA network interface that any program can useServers and laptops that should simply be on the network. Needs administrator rights and the host's IPv6. One per host; a second runs in a container of its own.
UserspaceNothing; the overlay lives inside the anchorContainers, CI, and applications that only talk to other anchors. Needs no privilege, and can still be an exit or a subnet router, carrying TCP and UDP from its own process.
Reverse proxyNothing, except the services it publishesPublishing a service at an overlay port, with no interface. The service needs no changes.
UplinkA serial line, instead of a networkMachines with no IP network beneath them. One link carries one peer.
Low latencyNo differenceReal-time traffic: a lost frame stays lost rather than holding up the ones behind it.
EmbeddedWhatever the app or phone choosesApps and phones carrying an anchor of their own. An embedded anchor starts with credentials it was given and cannot issue any.

Conflux runs the first two of these as conflux up and conflux proxy, and either of them over an uplink.

Gossip controls

A realm is run by its own members. The gossip controls are its control plane, in two forms: an order, which one member gives one other and is over when it is answered, and the realm's knowledge, which every member holds for as long as it lasts. A member holding a power uses it through them. On a private network the root node holds them all.

The controls, and the power each needs
ControlFormWhat it doesNeeds
TelemetryOrderReads one member's status, routes and counters, never its peers or its traffictelemetry
SubnetsOrderReads or rewrites what one router serves, which it keeps across restartssubnets
TaintsOrder, then a taint recordMoves one member to other compartments; the member publishes the recordtaint
Block and unblockKnowledgeMakes an anchor an outsider to every member, or lifts thatblock

Orders

An order is signed by the member giving it and carries that member's credential chain, so the member it names checks it against the root both pin and trusts nothing about whoever carried it. It goes to that member alone, end to end, so a relay of any realm carries it and reads none of it. It lives as long as its sender waits for the answer, ten minutes at most, and is not carried out after that.

The realm's knowledge

Knowledge is signed entries that every member holds. A member with a state directory writes them down there, so when it restarts it holds them before it meets anybody. Blocks, unblocks and taint records are knowledge.

  • It spreads as a tree, not an epidemic. The issuer splits the members it knows into up to eight groups and hands the entry to one member of each, which does the same with its share. Every member is handed it once, in about log₈(N) hand-overs for a realm of N members, each bounded at 25 seconds.
  • A member that was away is caught up. Two members compare fingerprints of what they hold whenever they link up, and exchange only what differs.
  • Nothing deleted comes back. An entry carries a horizon, how long it must be remembered after it stops being true, and members keep a deletion at least as long as what it replaced. An entry can also silence an issuer: a block makes what its target signs from then on count for nothing.
  • It is checked as of when it was signed. Every member checks an entry against the root it pins, with the issuer's chain as it stood at signing, so an entry outlives its issuer's credential. One signed more than ten minutes ahead of a member's clock is refused.
  • It is not a ledger. A member holds the latest word from each issuer about each subject, and forgets an entry once nothing needs it. There is no history and no consensus.
  • Some things only an anchor may say about itself. Its taint record is signed by the anchor it is about and carries the order that moved it. Its departure, which travels with the membership gossip rather than as knowledge, is signed by the anchor leaving.

What they reach

Control traffic is not gated by taints. Orders and knowledge pass the realm gate alone, so a member is reachable by its realm whatever compartment it is in, including by the order that moves it.

They stop at the realm boundary. Orders and knowledge never leave the realm they belong to. A realm above carries a descendant's traffic, and can neither shut it out nor question it. Each realm is run by the members of it that hold its powers, and the root node holds every power in its own.

Revocation: expiry and blocks

There are two ways to remove an anchor from a realm, and they answer different needs. Expiry is permanent, and takes as long as the anchor's credential has left to run. A block makes the anchor an outsider on each member as it spreads, and lasts until a member lifts it or the days it names run out. It leaves the credential untouched. To remove a machine now and for good, use both.

ExpiryBlockBoth
HowThe issuer stops renewing the anchor's credentialA member holding the block power signs an entry in the realm's knowledge naming the anchorBlock it, and stop renewing it
Who canWhoever issues the anchor's credentialA member of the anchor's own realm whose credential carries blockThe issuer, and a holder of block in the same realm
Takes effectWhen the credential lapses: within its lifetime, thirty days by defaultOn each member as the block reaches it, in a handful of hand-oversAs the block spreads, and for good at the lapse
Can it be undoneYes, by issuing a fresh credentialYes. Any holder of block may unblock, whoever issued itOnly by lifting the block and issuing a fresh credential
How long it lastsFor good: a lapsed credential stays lapsedUntil a member unblocks it, or for the days it namesFor good
Needs the target reachableNo. Nothing is sent anywhereNo. Every member holds the block and hands it to members that were awayNo
Fig. 10 — Expiry, a block, or both
ExpirySTOP RENEWINGSTILL ADMITTED UNTIL IT LAPSESREFUSEDBlockUNTIL LIFTEDAN OUTSIDERA MEMBER AGAINBothPERMANENTSHUT OUT, AND NEVER RENEWEDDECIDEDLIFTED OR ENDSCREDENTIAL LAPSESAS IT SPREADS

Expiry is permanent but waits out the credential's lifetime. A block holds on each member as it arrives and lasts until its end or until a member lifts it, and it leaves the credential untouched. Together they shut a machine out now and remove it for good.

Expiry

A credential that is not renewed lapses, and from that moment every peer refuses its holder, and live connections are closed. Nothing is distributed and no list is kept. The credential's lifetime is the removal window, and whoever issues credentials chooses it: a shorter lifetime removes a machine sooner, and is renewed more often.

Blocks

A block does not stop an anchor, and the anchor is told nothing. It makes the anchor an outsider to its realm: every member the block reaches treats it as it treats an anchor of another tree. Its knock is refused, its connections are closed, nothing is dialled, routed, carried or sealed to it, and what it signs from the block on counts for nothing.

It is one command, block -target ID [-days N] [-reason TEXT]. unblock -target ID lifts one, and blocks lists them.

  • It needs the power and a proved target. The issuer's credential must carry block, and the target must have been proved to be in the issuer's own realm, by a connection or a fetched credential chain. An AnchorID nothing has met is refused rather than blocked on trust.
  • The realm holds it, not the issuer. A block is an entry in the realm's knowledge. Every member holds it, writes it down and hands it to a member that was away, so no connection to the target is ever needed. It spreads member to member in a handful of hand-overs.
  • It can be lifted. Without -days it lasts until a member unblocks it, and any holder of block may unblock, whoever issued it. With -days it ends at that instant on every member. A mistyped AnchorID is one unblock away from being undone.
  • It outlives its issuer's credential. A block is checked against the issuer's chain as of when it was signed, so it stays in force after that credential lapses.
  • It is not a revocation. The credential still verifies, and a member the block has not reached yet still admits the anchor. Removing a machine for good is still expiry. A block is what to reach for when expiry is too long to wait.
  • It stays in the realm. A realm above may carry a descendant's traffic and may not block it, whatever its own credential carries.

What it does not promise

Each of these is a deliberate boundary, not an oversight.

  • Timing and volume are untouched. Nothing here hides traffic analysis; only cover traffic would.
  • A relay is an admitted member, and it is not trusted. It cannot read, alter or impersonate what it carries, but it can see the hops beside it and how much passes, and it can drop traffic.
  • Taint names and the tree's identifier are public to anyone who knows the realm.
  • Removal is not instant. Expiry takes as long as the credential has left. A block is in force on each member as it arrives, and a member it has not reached yet still admits the anchor.
  • During pre-release, the protocol may change incompatibly between versions.

Where next

The guardian stack is an optional console beside the root node: it manages the credentials in an organisation's own realm and shows their telemetry, and issues no gossip controls itself. Conflux is how a machine runs an anchor.