v0.2.0: the series measured again, and docs that say only what the code does
the second release gathers node authentication, authenticated links, onion key rotation and the drawn chain. its numbers were measured again on its own code, and every statement in the documentation was checked against that code.
correction, 2026-10-16: the series of release v0.3.0 on revision 2078098 does not show relays on their own clocks bringing the attack to chance; they lower its auc to medians between 0.44 and 0.67, and five runs per point cannot show more. the claim of chance below is withdrawn; the current numbers are on the research page.
the second release, v0.2.0, gathers what the last three notes described: node authentication, authenticated links between relays, onion key rotation and a chain drawn at random. two more things went into it, and both are about saying no more than is true.
the series was measured again
the numbers on the research page were measured before the first release. since then the cell format, the links and the choice of the chain all changed, so the preliminary series was run again on the code that is released: ten flows, five 30 s runs per configuration, the same seeds.
the conclusions hold.
- cover traffic on top of real messages still does not help: attack auc 1.000 at three times the bandwidth.
- a constant rate at the client alone still does not hide a flow: auc 0.951 at a 70 ms period.
- relays sending on their own clocks bring the attack close to chance: auc 0.523 at a 66.5 ms period and a 10 ms window, for a 185 ms median round trip.
the wording changed in one place. the page used to say that relay clocks bring the attack to chance. the medians lie between 0.46 and 0.64, and the 95% interval of a single run includes 0.5 in 34 of 40 cases. five runs of ten flows cannot tell a small remaining leak from none, so the page now says close to chance, and the full series of thirty runs per point is to settle it.
the docs say only what the code does
every statement in the readme and in the six documents was checked against the code, in both languages. 156 places were corrected. planned parts are now marked as planned, and the table of threats and countermeasures in the threat model has a status column.
what a reader should know after that check:
- there is no recipient client and no end-to-end layer yet. the last relay of a chain reads the message.
- a message has to fit one cell, 444 bytes over three hops. a longer one is refused.
- the measurements use one baseline attack by a passive observer, and the series run in one process on loopback, with no network delay.
- of the experiment programme, flow linking and the choice of chains are measured. key extraction from memory, forward secrecy with stolen keys, the node compromise scenarios and the timing watermark are planned.
- only the key buffers are locked against swap. copies the crypto libraries keep on the heap are not.
the limits page carries all of it.
a defect the check found
reading the client code against the documentation turned up a defect. at a constant rate the client took a message longer than one cell into its queue and reported no error. the schedule then failed on that message and stopped, and with it every cell the client sent, cover included. an observer on the client’s link saw the constant stream end at that moment.
the client now refuses such a message with an error before it is queued. only the user of the client could trigger it, not a remote party. the advisory is GHSA-r8r8-v474-jxm9.
what this does not fix
- five runs per point are still too few to claim a difference as significant.
- the attack is still the baseline one. connection timing, a learned correlator and an active adversary are not measured.
- nothing the check marked as planned became real by being marked.
next on the roadmap are a recipient client with an end-to-end layer and deniable authentication between clients.
the release is on github. the full table is in the readme, the limits in limitations, and what each experiment block measures today in experiment.