Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🤖 Order book size estimation

A relatively conservative estimate of a lower bound on the number of candidate coins a transaction’s inputs were selected from, and a median estimate of that number. Both measure the effect of the selection preferences in the randomized selection chapter. The Sybil resistance term uses , and the Counterfactual paths chapter uses for its degree sequence.

Candidates

Candidates are the coins whose owners are active and offering them in the order book. is how many there are. It isn’t directly observable.

  • Under the actual block hash , the candidates’ hashes are uniform. The selected inputs are a subset. If the selection depends on the hashes, the subset deviates from uniform, which bounds from below, much like estimating the hash rate from proofs of work.
  • Candidates must be fixed before is known.
  • Each candidate is one draw. Spending the same coin twice isn’t a second draw.
  • To exhibit the deviation, an adversary must control all the candidates, not just the selected coins.

Hashes

  • for each input outpoint . is a tagged hash, truncated to 64 bits and read as an integer modulo , so the are points on a circle.
  • Truncation keeps the guarantees below: the truncated hashes are uniform on the grid of points, and the extra grid unit per span covers the rounding.

Pool size bound

For the input hashes of a transaction and a confidence parameter :

  1. Spans. Sort the hashes around the circle. An -span runs from a hash to its -th successor. Its width is the distance between them, plus one grid unit.
  2. Sums. For each and , is the smallest total width of spans with disjoint interiors. Spans may share endpoints. Let .
    • For , this is the sum of the smallest gaps.
    • Larger detects groups of nearby hashes.
  3. Tail bound. For a hypothetical pool of candidates:
  4. Score. With weights that sum to 1 over all :
  5. Bound. is the smallest integer with .

Why it’s conservative

for every selection strategy. This includes choosing the inputs, and how many, after seeing the hashes, in order to maximize .

  • One placement. In a uniform pool of , the total of fixed disjoint blocks of gaps is . Its lower tail is at most .
  • Every placement. There are at most ways to place the blocks. A union bound covers taking the minimum after seeing the pool.
  • Subsets. Each selected -span contains at least gaps of the full pool. So no subset has smaller totals than the pool itself. The extra grid unit per span covers rounding hashes to integers.
  • Combining. Each is a conservative p-value, so . By Markov’s inequality, . The terms may be dependent.

Properties

  • Monotone. At a fixed beacon and , adding inputs never lowers . So withholding coins from a fixed pool can’t raise it.
  • Symmetric. No position on the circle is special. Rotating or reflecting the hashes doesn’t change , so it doesn’t matter which hashes count as lucky.
  • All inputs. Every input’s hash enters through the spans.
  • Integer arithmetic. Each weighted term is rounded down to a multiple of , using integer square roots. Rounding only lowers the score, so it keeps both guarantees.
  • Caps. Leaving out the terms above a fixed or keeps both guarantees: their weight goes unused. It costs power.
  • Cost. arithmetic operations over all , on integers of bits.
    • A Python reference implementation takes a median of 25 ms for 64 inputs and 92 ms for 100.
    • A Rust implementation takes 0.01–2.5 ms for up to 100 inputs, and 17 ms for 200, on an Apple M4. It decides in floating point, and falls back to the exact integer score near the threshold, so it returns the same as the reference.

🤖 Median estimate

inverts the joint sums at their median instead of at . For a chosen and , it is the smallest at which the observed is at least the median of the same quantity for a uniform pool of candidates.

  • Same construction as . The spans and sums are those of the pool size bound, with in place of . For , the quantity is the sum of the smallest gaps, whose exact law is known.1
  • Median-unbiased only for the pool’s own spans. reads correctly in the median only when the observed spans are spans of the full pool, as when the whole pool is observed.
  • Reads low under weaker selection. As in Why it’s conservative, no selected set has smaller joint sums than the pool itself, so is lower.
  • Reads high on small pools. It spends no , so nothing bounds how often it exceeds .
  • Not the largest over and . Taking the largest over all and reads high.
  • No lowest error estimate. Without a probability law for the selection, no estimator has lowest error. The tails are heavy, so estimators are compared by quantiles rather than by mean squared error.

Measured in the prototype for a related statistic, the median inversion of the -th smallest gap:

  • With clustering and , it reads about . At and , the median reading is .
  • At , it overshoots in 28% of runs, and in 22 of 40 runs at .

Finding the block hash

Someone examining a transaction doesn’t know which block hash the selection used. They can guess it from the confirmation time, or from the nLockTime, but not exactly. So they evaluate every candidate , at each for candidates, and take the largest .

  • Candidate block hashes. 1000 or more for every transaction that looks like a CoinJoin, all mined after its inputs confirmed.
  • No false beacon. Under a block hash the selection didn’t use, the input hashes are independent and uniform: a fully observed pool of . So with probability at most for each such block hash, and at most for all of them.
  • Screen. Only the terms, sums of the smallest gaps, are evaluated for every block hash, once, at . That is a sort and one score. The full bound is evaluated only when the screen gives . The screen’s threshold is fixed, so both guarantees hold.
  • Cost. With and up to 100 inputs, 2–9 ms per transaction in Rust, mostly hashing (about 75 ns per hash) and the screen (1–4 µs per block hash). Hashes may be cached per outpoint and block hash.

Simulation

1000 random block hashes per transaction, , 32 transactions per configuration, using the Python reference.

  • No block hash used. Inputs drawn uniformly. In all 96 transactions ( = 16, 32, 80), no block hash gave . At instead of , 25 of them had one, up to .
  • One block hash used, by lowest hashes, XOR pairs or the tightest cluster, with = 1000 or 100,000. In all 576 transactions, it gave the largest , no other gave , and .
  • Cost of the split. Median at is lower than at by about 2.6 times at , 1.7 at and 1.3 at .

Caps

Median of the used block hash with and , at :

CapLowest hashesXOR pairsCluster
0.0100.3290.013
0.1080.3290.167
0.1560.3290.238
, 0.0510.1060.075
none0.2250.3290.350
  • Don’t cap . Pairs need many terms.
  • Capping loses clusters and lowest hashes. The full bound runs on about one block hash per transaction, so it can stay uncapped up to about 100 inputs.
  • The screen missed the used block hash in 1 of 32 transactions (lowest hashes, , ).

Measurements

From the prototype, with . Nine selection strategies are applied to the same candidate hashes in each trial.

Median with , over 32 trials:

XOR pairsLowest hashesClosest pairsUniform
457.51166.54
16227.5116.526516
32346.5225378.532
100400327457.5100
  • With and , median ranges from 0.28 (lowest hashes) to 0.47 (two clusters).
  • Uniform selection gives . A large pool shows nothing unless the selection is biased.
  • Overshoot. in none of the 1,152 selected sets at , and none of the 2,304 at .
    • This doesn’t prove coverage. The proof does.
    • The guarantee bounds how often exceeds , not by how much.

Tighter alternatives

Overestimating awards credit for Sybil resistance that isn’t there. That is worse than underestimating it, so the bound above is preferred over tighter ones.

  • Density profile. Anchored ranks, Beta spans and Rényi gap ranks, at each.
    • Median between 0.66 and 0.78 in the same comparison.
    • in 5 of the 1,152 sets, by up to 1.30 times, and in 11 of the 2,304.
    • Its returned bound has only been tested to be monotone, not proved. It also treats fixed positions on the circle specially.
  • Gap curve. Accumulates the evidence of every ordered gap, with fixed weights and power .

Limitations

  • Candidates, not owners. bounds the number of candidate coins, not the number of users. One owner with many coins is many candidates.
  • Values. The adversary’s cost is proportional to only if the selected coins’ values are typical of the candidates.
  • Lower bound only. isn’t an estimate of . There is no likelihood for the selected set given .
  • Power. The fixed weights, the union bound and the square root lose power.
    • The minimum totals discard some of where the hashes are.
    • In a fixed example with one dense cluster, adding a second cluster at half the density raised by about 3%.
    • Splitting over 1000 block hashes costs most at small : about 2.6 times at .
  • Concealment. A selection strategy can keep near . Monotonicity only prevents raising by withholding coins.
  • Review. The calibration argument hasn’t been reviewed outside the prototype.

Open questions

  • Which and should use, or how should they be combined?
  • How should the median be computed for , and for large ?
  • Can be updated as inputs are added? A wallet compares many candidate transactions.
  • More power. Options next to the bound above:
    • Combine the terms by a weighted minimum, rejecting if any , instead of the square root. This loses less to the split over block hashes.
    • Tighter tails for . In a uniform pool, the gaps are exponential variables divided by their sum.2 Sums of the smallest gaps then have an exact law,1 but it is impractical for large and small sums. A Chernoff bound on this form is practical, and gains about 1.3–1.6 times in , only for large . Nothing comparable is known for .
    • Anchored ranks for the per-input preference, which are tighter for lowest hashes, at part of . They treat the anchor specially, so symmetry is lost.

  1. L. Holst, “On the lengths of the pieces of a stick broken at random”, Journal of Applied Probability 17(3) (1980), 623–634, doi:10.2307/3212956. ↩ ↩2

  2. A. Rényi, “On the theory of order statistics”, Acta Mathematica Academiae Scientiarum Hungaricae 4 (1953), 191–231, doi:10.1007/BF02127580. ↩