Skip to content

Commit

Permalink
Add probabilities for vote splitting attack to doc
Browse files Browse the repository at this point in the history
  • Loading branch information
amesgen committed Jan 28, 2025
1 parent fb01e08 commit eb28004
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 5 deletions.
20 changes: 16 additions & 4 deletions design/appendix/attack-scenarios.tex
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ \subsection{Honest vote splitting}\label{sec:honest vote splitting}
\end{enumerate}
Condition~\ref{enumi:honest vote splitting:a} guarantees that $V_C\neq V_D$, and condition~\ref{enumi:honest vote splitting:b} makes sure that $D$ is preferrable to $C$.

\begin{lemma}
We stress that this is not the only scenario where the attack can be executed; for example, we have not considered tiebreakers and honest short forks.

\begin{lemma}\label{lemma:honest vote splitting prob}
For an adversary with stake $\alpha$ the probability that the events~\ref{enumi:honest vote splitting:a} and~\ref{enumi:honest vote splitting:b} occur before some Peras round is given by \[ P(H\le A) \cdot P(A' \ge 1) \]
where $H\sim\operatorname{Binom}(L,\phi(1-\alpha))$, $A\sim\operatorname{Binom}(L,\phi(\alpha))$, $A' \sim \operatorname{Binom}(H',\phi(\alpha))$, $H' \sim \operatorname{Geom}(\phi(1-\alpha))$, and where $L= \perasBlockMinSlots$ and $\phi(\sigma) = 1-{(1-\asc)}^\sigma$ \parencite[(1)]{david2018ouroboros}.
where $H\sim\operatorname{Binom}(L,\phi(1-\alpha))$, $A\sim\operatorname{Binom}(L,\phi(\alpha))$, $A' \sim \operatorname{Binom}(H',\phi(\alpha))$, $H' \sim \operatorname{Geom}(\phi(1-\alpha))$\footnote{Here, we use the convention of counting the number of failures until the first success.}, and where $L= \perasBlockMinSlots$ and $\phi(\sigma) = 1-{(1-\asc)}^\sigma$ \parencite[(1)]{david2018ouroboros}.
\end{lemma}
\begin{proof}
Note that~\ref{enumi:honest vote splitting:a} and~\ref{enumi:honest vote splitting:b} are independent as they refer to disjoint sets of slots.
Expand All @@ -52,8 +54,18 @@ \subsection{Honest vote splitting}\label{sec:honest vote splitting}
Thus, $P(\enquote{\ref{enumi:honest vote splitting:b}}) = P(A'\ge 1)$.
\end{proof}

\medskip
We stress that this is not the only scenario where the attack can be executed; for example, we have not considered tiebreakers and honest short forks.
In \cref{lemma:honest vote splitting prob}, we assume that the gap $H'$, i.e.\ the length of the interval $(h,s-\perasBlockMinSlots)$, is sampled geometrically due to the leader schedule.
However, it can also be instructive to set it to a concrete value (letting $H'$ have a one-point distribution), especially if an adversary could force a long gap in some other way.

\begin{figure}[h]
% see honest-vote-splitting.py
\includegraphics[width=0.95\textwidth]{./appendix/plot-honest-vote-splitting.png}
\centering
\caption{Probabilities (lower bounds) for \cref{lemma:honest vote splitting prob} for realistic parameters. The right plot assumes a slot length of one second and $\perasRoundSlots = 90$.}\label{fig:honest vote splitting prob}
\end{figure}
We plot the propabilities of \cref{lemma:honest vote splitting prob} for realistic parameters in \cref{fig:honest vote splitting prob}.
We observe that for small values for \perasBlockMinSlots{}, even relatively weak adversaries can execute a vote splitting attack rather frequently.
This is relevant in particular as it allows them to trigger a cooldown phase.

\section{Attacks on a variant of the block creation rule}

Expand Down
Binary file added design/appendix/plot-honest-vote-splitting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 27 additions & 1 deletion scripts/honest-vote-splitting.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# See "Honest vote splitting" in the design doc for context

import matplotlib.pyplot as plt
import numpy as np
from scipy import stats

asc = 1 / 20
Expand All @@ -15,7 +17,7 @@ def Psuccess(alpha, perasBlockMinSlots):
Hp = stats.geom(phi(1 - alpha))
# P(Ap ≥ 1) where Ap ~ Binom(Hp, phi(alpha))
cutoff = int(Hp.ppf(1 - 1e-10))
Apge1 = sum([Hp.pmf(x) * stats.binom(x, phi(alpha)).sf(0) for x in range(cutoff)])
Apge1 = sum([Hp.pmf(x + 1) * stats.binom(x, phi(alpha)).sf(0) for x in range(cutoff)])

return HleA * Apge1

Expand All @@ -24,3 +26,27 @@ def Psuccess(alpha, perasBlockMinSlots):
for perasBlockMinSlots in [30, 60, 90, 120, 150, 300]:
p = Psuccess(alpha, perasBlockMinSlots)
print(f"alpha = {alpha}, L = {perasBlockMinSlots}: {p}")

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))

alpha = np.linspace(0, 0.25, num=20)

for perasBlockMinSlots in [30, 60, 90, 120, 150, 300]:
Ps = np.vectorize(lambda a: Psuccess(a, perasBlockMinSlots))(alpha)
ax1.plot(alpha, Ps, label=f"perasBlockMinSlots = {perasBlockMinSlots}")
expected = 90 / Ps / 3600
ax2.plot(alpha, expected, label=f"perasBlockMinSlots = {perasBlockMinSlots}")

ax1.legend()
ax1.grid(True)
ax1.set_xlabel("adversarial stake")
ax1.set_ylabel("attack success probability")

ax2.legend()
ax2.grid(True)
ax2.set_ylim(0, 100)
ax2.set_xlabel("adversarial stake")
ax2.set_ylabel("expected time until successful attack [h]")

fig.tight_layout()
fig.savefig("plot-honest-vote-splitting.png", dpi=300, bbox_inches="tight")

0 comments on commit eb28004

Please sign in to comment.