Author: Lucas Luhur Last updated: 2026-06-25
Open question:
- See for the analysis: Pareto k analysis
Pareto shape parameter
k(stake inequality). Currently fixed atk=2. Two alternatives:
- Option 1 - calibrate to a real chain: set
k = shape_from_gini(G)from a published stake-Gini (or top-x% share / Nakamoto coefficient) of e.g. Cardano.- Option 2 - sweep it: run
k ∈ {1.5, 2, 3, 5}and report how anonymity varies from very unequal to fairly even stake (turns "the rightk" into a sensitivity analysis).- Decide when: the first anonymity experiments need a committed value / sweep range. Note
k=2has infinite variance - usek=3if a finite-variance, numerically tamer baseline is wanted.
The consensus message generator is the first module in the agreed build order (consensus → broadcast network → adversaries → anonymity measures). It treats consensus as a random message generator: stake is distributed across nodes, nodes run the stake-proportional leader election each slot, and every win is a block-proposal broadcast.
The output is a stream of (slot, node) broadcast events — the input the broadcast-network and
adversary modules consume downstream.
A validation harness that simulates the election over a full epoch and checks the empirical statistics against the closed-form formulas is also implemented.
| Parameter | Symbol | Meaning | Value |
|---|---|---|---|
| Active-slots coefficient | $f$ | per-slot win rate → target block time $1/f$ | $1/30$ |
| Epoch length | $T$ | slots per epoch = stake-inference observation window | $388{,}800$ |
| Nodes | $N$ | number of stakeholders | $1000$ |
| Pareto shape | $k$ | stake inequality | $2$ (baseline) |
| Pareto scale | $x_m$ | cancels after normalisation | $1.0$ |
| Seed | — | reproducibility (set at entry point) | $0$ |
Each node $i$ has weight $w_i > 0$; the election uses the relative stake ****$\alpha_i = w_i / \sum_j w_j$, with $\sum_i \alpha_i = 1$. Raw weights are drawn from a Pareto distribution and normalised (Arnold, 2015, p.41):
$$ w_i \sim \mathrm{Pareto}(k, x_m), \qquad \alpha_i = \frac{w_i}{\sum_j w_j}. $$
Stake is quenched disorder — sampled once and held fixed for the experiment, while the per-slot election noise varies on top of it.
def sample_relative_stakes(N, shape=DEFAULT_SHAPE, scale=1.0, rng=None):
rng = np.random.default_rng(rng)
w = pareto.rvs(b=shape, scale=scale, size=N, random_state=rng)
return w / w.sum()
Why Pareto: Real validator holdings are heavy-tailed. Pareto is the only pure power law, scale-free with a single tail exponent.
Measuring inequality: the Gini coefficient. gini(weights) is implemented to condense a whole
stake vector into one interpretable scalar (0 = perfectly equal, → 1 = a single node owns
everything), using the standard sorted formulation (Arnold, 2015, p.183:
$$ G = \frac{2\sum_i i\,x_{(i)}}{n\sum_i x_i} - \frac{n+1}{n}, \qquad x_{(i)} \text{ sorted ascending}. $$
def gini(weights):
x = np.sort(np.asarray(weights, dtype=float))
n, total = x.size, x.sum()
idx = np.arange(1, n + 1)
return float(2.0 * np.sum(idx * x) / (n * total) - (n + 1.0) / n)