% !TeX document-id = {551c9545-e493-4534-9812-732e4f9d41b0}
% !TeX TXS-program:compile = txs:///pdflatex/[--shell-escape]
\documentclass[12pt,a4paper]{report}

%todo writing style stream of concisense
% move stuff to lit review and explain/justify
% finish implementation
% requirements spec, clear evaluation of security with links to proofs etc.
% clear achievements of content in regards to goals
% reflect on achievemtns, difficulties, novelty etc.

\usepackage{algorithmicx}
\usepackage{algpseudocode}
\usepackage[toc,page]{appendix}
\usepackage{Bath-CS-Dissertation}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage{float}
\usepackage{tikz}
\usepackage{minted}
\usepackage{lscape}
\usepackage{multirow}
\usepackage{tabularx}
\usepackage{booktabs}
\usepackage{ragged2e}
\usepackage{hyperref}
\usepackage[alph]{parnotes}

\usetikzlibrary{decorations.pathreplacing,decorations.markings}

\DeclareMathOperator{\lcm}{lcm}
\DeclareMathOperator{\id}{id}
\DeclareMathOperator{\pr}{pr}

\newtheorem{theorem}{Theorem}[section]
\newtheorem{proposition}[theorem]{Proposition}

\theoremstyle{definition}
\newtheorem{definition}[theorem]{Definition}
\newtheorem{lemma}[theorem]{Lemma}
\newtheorem{remark}[theorem]{Remark}
\newtheorem{corollary}[theorem]{Corollary}
\newtheorem{example}[theorem]{Example}
\newtheorem{protocol}[theorem]{Protocol}

\title{Cryptographic protocol for playing Risk in an untrusted setting}
\author{Jude Southworth}
\date{Bachelor of Science in Computer Science and Mathematics \\
      The University of Bath \\
      2023 \\}

\begin{document}

\hypersetup{pageanchor=false}
\setcounter{page}{0}
\pagenumbering{arabic}

\maketitle

\chapter*{}

\section{Disambiguation}

\begin{table}[htp]
	\begin{tabularx}{\textwidth}{c X}
		\toprule
		Symbol & Meaning
		\\
		\midrule
		$|a|$ & Bit length of value $a$ \\
		$\left(\frac{a}{b}\right)$ & Jacobi symbol for $a, b$ or division (context dependent) \\
		$\frac{a}{b}$ & Division \\
		$\mathbb{Z}_k$ & Additive group of integers modulo $k$ \\
		$\mathbb{Z}^*_k$ & Multiplicative group of units modulo $k$ \\
		$\gcd(a, b)$ & Greatest common divisor of $a, b$ \\
		$\lcm(a, b)$ & Least common multiple of $a, b$ \\
		$\phi(k)$ & Euler's totient function \\
		$\lambda(k)$ & Carmichael's totient function \\
		$H(\dots)$ & Ideal cryptographic hash function \\
		$\in_R$ & Selection at random \\
		\bottomrule
	\end{tabularx}
\end{table}

\vspace*{0.1\paperheight}
\begin{center}
	"Never create anything, it will be misinterpreted, it will chain you and follow you for the rest of your life." - Hunter S. Thompson

	\vspace*{0.05\paperheight}
	Artefact available at \url{https://gitea.jellypro.xyz/jude/Riskless}
\end{center}

\clearpage

\chapter{Outline}

Risk is a strategy game developed by Albert Lamorisse in 1957. It is a highly competitive game, in which players battle for control over regions of a world map by stationing units within their territories in order to launch attacks on neighbouring territories that are not in their control.

\section{Existing solutions}

For playing games over an internet connection, multiple solutions already exist. These can roughly be broken down into those that are centralised and those that are decentralised, although many decentralised systems rely on federated or centralised communications for peer discovery.

\subsection{Centralised}

In highly centralised networks, traffic is routed to a number of servers that are operated by the same organisation who maintains the game or service. This is the current standard for the majority of the internet: in fact, this is the methodology used by the official version of Risk, which is available as an app.

Without patching the executables, there is no way for a user to run their own servers, or to connect to a third party's server. This has two main advantages: \begin{itemize}
    \item \textbf{Moderation.} The developers can enforce their own rules through some form of EULA, and this would be properly enforceable, as if a user is banned from the official servers, there is no alternative.

    \item \textbf{Security.} The server acts as a trusted party, and validates all communications from players. Hence, players cannot subvert a (properly implemented) service's protocol.
\end{itemize}

However, centralised services have a number of major downsides. \begin{itemize}
	\item \textbf{User freedom.} Users often cannot audit or modify the underlying source code. Furthermore, users must follow rules enforced by the platform, which can be arbitrarily set and enforced.

	\item \textbf{Liability.} In some jurisdictions, platforms are held legally responsible for content on their platforms. This means that consequences of illegal activities are sometimes felt by the platform and not the criminal user, and this encourages platforms to invade the privacy of their users.

	\item \textbf{Ownership.} The service is owned by the operators. If the operators wish to close the service, it is at their own discretion.
\end{itemize}

\subsection{Peer-to-peer networks}

There are two alternatives to traditional centralised networks: peer-to-peer (P2P) and federated.

In P2P networks, traffic may be routed directly to other peers. In federated networks, servers may be operated by third parties (and in fact, the developers of the service may not run any servers themselves). These network models are still popular in certain games or services, for example BitTorrent is primarily a P2P service; and titles from the Counter-Strike video game series may be considered federated, with a wide selection of third party hosts.

P2P and federated networks address each of the disadvantages listed above. \begin{itemize}
	\item \textbf{User freedom.} The platform is run by its users. Whilst this doesn't require that the source code is available, it allows the auditing of data collected, and the network may diverge to meet the needs of different groups of users. For example, Bitcoin Cash is a fork from Bitcoin intended to address concerns over transaction fees \cite{bch}.

	\item \textbf{Liability.} Users are legally responsible for their own behaviours. This results in legal consequence against criminal users, and relative immunity of the platform \cite{bittorrent2008}.

	\item \textbf{Ownership.} Games such as Unreal Tournament 99 still have playable servers, as the servers are community-run, and so as long as people still wish to play the game, they will remain online (despite the original developers no longer officially supporting the title) \cite{eatsleeput.com_2022,epic}.
\end{itemize}

However, general privacy can often be worse in fully P2P networks than that of fully centralised networks. As there is no trusted server, there is no easy way to hide traffic of certain users or maintain, validate, and operate on private state. For example, most popular cryptocurrencies (such as Bitcoin and Ethereum) are public-ledger, meaning transactions can be publicly tracked. This is far less private than services such as banks or cash \cite{bitcoin08,bitcoindeanon}.

Some P2P services try to address issues with privacy. Monero and Zcash are privacy coins that use cryptographic protocols to obscure transaction amounts \cite{monero,zcash}. The P2P file-sharing protocol Soulseek keeps a user's download history private by using direct communication between the two peers \cite{slsk}. The downside of this approach is that if the first user goes offline, files will no longer be available. BitTorrent overcomes this by pooling peers with the file into a "seed pool". The disadvantage of this approach is that the users who download files is now public knowledge \cite{cohen_2017}.

\subsection{Untrusted setups}

Currently, there exists an online centralised version of the board game Risk.

We aim to apply bit-commitment schemes, zero-knowledge proofs, and homomorphic encryption to an online P2P variant of Risk. This will allow peers to play the game whilst preventing cheating and needing no trusted parties. The variant of the game that is of interest is the "fog of war" variant, where a player cannot see the unit counts of regions besides those that they own or are neighbouring: this introduces private state to be operated on.

\chapter{Literature review}

Centralised systems can securely perform the generation of random values, through using a cryptographically secure random number generator on the server-side, and distributing the values to the clients. This is how dice rolls are processed in centralised online games. However, in a P2P system, another approach must be taken to simulate the randomness, to ensure all peers receive the same random value.

For such randomness, we also want that \begin{itemize}
    \item No peer can change the probable outcome of the dice (random),
    \item No peer can deny having rolled the dice (non-repudiation).
\end{itemize}
We apply the concept of bit-commitment schemes to form these guarantees.

\section{Bit-commitment schemes}

Bit-commitment schemes provide a mechanism for one party to commit to some hidden value and reveal it later. This can be achieved through the use of commutative cryptographic algorithms and with one-way functions.

\subsection{Commutative cryptography}

Protocols exist that utilise bit-commitment to play poker \cite{Shamir1981}. They offer a bit-commitment scheme using commutative encryption algorithms based on modular arithmetic. This scheme works by each player encrypting cards, and decrypting in a different order as to obscure the value of the actual cards until all players have decrypted.

However, almost all well-documented encryption schemes are not commutative. One alternative is to use a well-known one-way function, such as SHA \cite{FIPS202}, with randomly generated salts.

\subsection{Bit-commitment with one-way functions}

Bit-commitment schemes can also be implemented using one-way functions: \begin{enumerate}
    \item The first party decides on the value $m$ to be committed to.
    \item The first party generates some random value $r$.
    \item The first party generates and publishes some value $c = H(m, r)$, where $H$ is an agreed-upon public one-way function.
    \item The first party publishes $m$ and $r$ to the second party some time later.
    \item The second party computes $c' = H(m, r)$ and validates that $c = c'$.
\end{enumerate}

Protocols exist for flipping fair coins "across a telephone", which is isomorphic to selecting a random value from a set of two values \cite{blum1983coin}. This cannot be simply repeated to generate numbers in the range of 1-6, as 6 is not a power of 2.

However, a similar protocol can be used where each player commits to a single value $x \in \mathbb{Z}_6$. As the distribution of outcomes of addition in the group $\mathbb{Z}_n$ is fair, we can then sum the values of $x$ committed to by both players to deduce a final value for the roll. This is a standard application of bit-commitment to form a "secret sharing" protocol.

\section{Zero-knowledge proofs}

Informally, zero-knowledge proofs can be considered to be protocols between two parties (the prover and the verifier) that operate on some given statement. The protocol holds the following three properties: \begin{itemize}
	\item \textbf{Completeness.} If the statement is true, an honest verifier will be convinced of its truth by a prover.
	\item \textbf{Soundness.} If the statement is false, a cheating prover cannot convince an honest verifier (except with some small probability).
	\item \textbf{Zero-knowledge.} If the statement is true, the verifier cannot learn any other information besides its truthfulness.
\end{itemize}

Typically, this protocol will involve the verifier producing a set of challenges, which the prover will respond to.

Formally, a zero-knowledge proof system for a language $L$ is:
\begin{itemize}
	\item For every $x \in L$, the verifier will accept $x$ following interaction with a prover.
	\item For some polynomial $p$ and any $x \notin S$, the verifier will reject $x$ with probability at least $\frac{1}{p(|x|)}$.
	\item A verifier can produce a simulator $S$ such that for all $x \in L$, the outputs of $S(x)$ are indistinguishable from a transcript of the proving steps taken with the prover on $x$.
\end{itemize}

The final point describes a proof as being \textit{computationally zero-knowledge}. Some stronger conditions exist, which describe the distributions of the outputs of the simulator versus the distributions of the outputs of interaction with the prover. \begin{itemize}
	\item \textbf{Statistical.} A simulator produced by a verifier gives transcripts distributed identically, except for some constant number of exceptions.
	\item \textbf{Perfect.} A simulator produced by a verifier produces outputs that are distributed identically to real transcripts.
\end{itemize}

Zero-knowledge proofs are particularly applicable to the presented problem. They primarily solve two problems: \begin{itemize}
	\item The disclosure of some information without leaking other information.
	\item The proof presented can only be trusted by the verifier, and not by other parties.
\end{itemize}

\emph{Honest-verifier} zero-knowledge is a subset of general zero-knowledge, in which the verifier is required to act in accordance with the protocol for the simulator distribution to behave as expected. This imposes a significant issue: a malicious verifier may behave as to try and attain additional information.

One solution to this is to transform a proof into a non-interactive zero-knowledge proof. The Fiat-Shamir transformation \cite{fiatshamir} converts an interactive zero-knowledge proof into a non-interactive zero-knowledge proof. In this process, the ability for a verifier to behave maliciously is lost, as the verifier no longer produces challenges themselves. However, this relies strongly upon the random-oracle model \cite{randomoracle}. As the random-oracle model is not realistically attainable, it must be approximated, typically by a cryptographic hash function. This introduces greater ability for the prover to cheat if they know a preimage in the hash function used.

\subsection{Games as graphs}

The board used to play Risk can be viewed as an undirected graph. Each region is a node, with edges connecting it to the adjacent regions. For convenience, we also consider the player's hand to be a node, which has all units not in play placed upon it.

Furthermore, the actions taken when playing the game can be seen as constructing new edges on a directed weighted graph. This makes us interested in the ability to prove that the new edges conform to certain rules.

The main game protocol can be considered as the following graph mutations for a player $P$: \begin{itemize}
	\item \textbf{Reinforcement.} A player updates the weight on some edges of the graph that lead from the hand node $H_P$ to region nodes $R_1, \dots, R_n$ in their control. \begin{itemize}
		\item Any adjacent players will then need to undergo proving the number of units on neighbouring regions.
	\end{itemize}

	\item \textbf{Attack.} Player $P$ attacks $R_B$ from $R_A$. In the event of losing units, the player updates the edge on the graph from $R_A$ to the hand node $H_P$.

	In the event of winning the attack, the player updates the edge from $R_A$ to $R_B$ to ensure some non-zero amount of units is located in the region.

	\item \textbf{Unit movement.} The player updates an edge from one region $R_1$ to another neighbouring region $R_2$.
\end{itemize}

The goal is to identify ways to secure this protocol by obscuring the edges and weights, whilst preventing the ability for the player to cheat.

\subsection{Graphs \& zero-knowledge proofs}

A typical example for zero-knowledge proofs is graph isomorphism \cite{10.1145/116825.116852}.

Identifying Risk as a graph therefore enables us to construct isomorphisms as part of the proof protocol. For example, when a player wishes to commit to a movement, it is important to prove that the initial node and the new node are adjacent. This can be proven by communicating isomorphic graphs, and constructing challenges based on the edges of the original graph.

\subsection{Cheating with negative values}

Zerocash is a ledger system that uses zero-knowledge proofs to ensure consistency and prevent cheating. Ledgers are the main existing use case of zero-knowledge proofs, and there are some limited similarities between ledgers and Risk in how they need to obscure values of tokens within the system.

\emph{Publicly-verifiable preprocessing zero-knowledge succinct non-interactive arguments of knowledge} (zk-SNARKs) are the building blocks of Zerocash \cite{6956581}, and its successor Zcash. A zk-SNARK consists of three algorithms: \texttt{KeyGen}, \texttt{Prove}, \texttt{Verify}.

These are utilised to construct and verify transactions called \texttt{POUR}s. A \texttt{POUR} takes, as input, a certain "coin", and splits this coin into multiple outputs whose values are non-negative and sum to the same value as the input. The output coins may also be associated with different wallet addresses.

Zerocash then uses zk-SNARKs as a means to prove that the value of the inputs into a \texttt{POUR} is the same as the value of the outputs. This prevents users from generating "debt", or from generating value without going through a minting process (also defined in the Zerocash spec).

A similar issue appears in the proposed system: a cheating player could update the weights on their graph to cause a region to be "in debt". This can be achieved by using range proofs.

The BCDG range proof proves that a commitment to a plaintext in the interval $[0, \ell]$ lies within the interval $[-\ell, 2\ell]$, where $\ell$ is some well-known value \cite[Section~2]{bcdg1987}.

The distinction between the soundness and completeness intervals in the BCDG proof is important, as through selection of specific private inputs, a prover can create a proof for a plaintext $m$ in the soundness interval and not the completeness interval. In this case, the proof is also not in zero-knowledge, as the verifier may be able to infer a stronger upper or lower bound on $m$. This is a major downside to this protocol.

The state of the art in range proofs is Bulletproofs \cite{bulletproofs}. Bulletproofs are utilised by the Monero blockchain ledger, and use linear algebraic properties to allow multiple verifying parties to process a single prover's proof.

Bulletproofs have advantages in size and "batch verification", where a verifier can verify multiple proofs simultaneously. However, the proofs are very complex, and a multi-round approach that borrows some of the concepts used in Bulletproofs could be used instead.

In general, this approach uses a decomposition of the plaintext message $m$ into its bits. This allows a verifying party to reconstruct an encryption of $m$, and check the bit length, without discovering $m$ \cite[Section~1.2.1]{Boudot2000EfficientPT}.

\section{Additive homomorphic cryptosystems}

Some cryptosystems admit an additive homomorphic property: that is, given the public key and two encrypted values $\sigma_1 = E(m_1), \sigma_2 = E(m_2)$, the value $\sigma_1 + \sigma_2 = E(m_1 + m_2)$ is the ciphertext of the underlying operation.

The Paillier cryptosystem, which is based on composite residuosity classes, express the additive homomorphic property \cite{paillier1999public}. This is due to the structure of ciphertexts in the Paillier cryptosystem. A public key is of structure $(n, g)$, where $n$ is the product of two large primes and $g$ is a generator of $\mathbb{Z}^*_n$. Under the public key, the encryption $c$ of a message $m$ is computed as \begin{align*}
	c = g^mr^n \mod n^2
\end{align*}
for some random blinding value $r \in \mathbb{Z}^*_{n^2}$.

The Paillier cryptosystem has disadvantages in its time and space complexity compared to other public-key cryptosystems such as RSA. In space complexity, Paillier ciphertexts are twice the size of their corresponding plaintext. This is because for a modulus $n$, ciphertexts are computed modulo $n^2$ for a message in range up to $n$. This cost can be reduced by employing some form of compression on the resulting ciphertexts.

The main concern is the issue of time complexity of Paillier. Theoretic results based on the number of multiplications performed indicate that Paillier can be 1,000 times slower than RSA encryption (although this depends heavily on the key size). Many optimisations to the Paillier cryptosystem have been presented in literature.

The first is in the selection of public parameter $g$. The original paper suggests a choice of $g = 2$, however the choice of $g = 1 + n$ is very common, as the exponentiation $g^m = 1 + mn$ directly from the binomial theorem.

Another optimisation is that of Jurik \cite[Section~2.3.1]{Jurik2003ExtensionsTT}: Jurik proposes that the public-key is instead $(n, g, h)$, where $h$ is the generator of the group $\mathbb{Z}^*_{n}[+]$ (the group of units with Jacobi symbol $+1$). Then, an encryption $c'$ of a message $m$ is computed as \begin{align*}
	c' = g^m (h^r \mod n)^n\mod n^2
\end{align*}
for some random $r \in \mathbb{Z}^*_{n}$.

The optimisation comes in two parts: firstly, the mantissa is smaller, resulting in faster multiplications. Secondly, by taking $h_n = h^n \mod n^2$, we find the following equivalence: \begin{align*}
	(h^r \mod n)^n \mod n^2 = h_n^r \mod n^2
\end{align*}

Exponentials of the fixed base $h_n$ can then be pre-computed to speed up exponentiation by arbitrary $r$.

Jurik states that the optimised form can lead to a theoretic four times speedup over Paillier's original form.

\subsection{Zero-knowledge proofs in Paillier cryptosystem}

There exist honest-verifier zero-knowledge proofs for proving a given value is 0 \cite[Section~5.2]{damgard2003}. Hence, proving a summation $a + b = v$ can be performed by proving $v - a - b = 0$, which is possible by the additive homomorphic property.

Therefore, using Paillier's scheme to obscure edge weights should enable verification of the edge values without revealing their actual values.

\subsection{Reducing communication}

In the presented algorithms, interaction is performed fairly constantly, leading to a large number of communications. This will slow the system considerably, and make proofs longer to perform due to network latency.

An alternative general protocol is the $\Sigma$-protocol \cite{groth2004honest}. In the $\Sigma$-protocol, three communications occur: \begin{itemize}
    \item The prover sends the conjecture.
    \item The verifier sends a random string.
    \item The prover sends some proofs generated using the random string.
\end{itemize}
This reduces the number of communications to a constant, even for varying numbers of challenges.

The Fiat-Shamir heuristic \cite{fiatshamir}, as discussed above, is another way to reduce communication by using a random oracle. For ledgers, non-interactive zero-knowledge proofs are necessary, as the ledger must be resilient to a user going offline. This is not the same in our case, however non-interactive zero-knowledge proofs are still beneficial as the amount of communications can be reduced significantly, resulting in simpler network code.

The downside of using the Fiat-Shamir heuristic in our implementation is that any third party can verify proofs. In some situations, we do not want this to be the case.

\chapter{Implementation}

The implementation provided uses WebSockets as the communication primitive. This is therefore a centralised implementation. However, no verification occurs in the server code, which instead simply "echoes" messages received to all connected clients.

Despite this approach being centralised, it does emulate a fully P2P environment, and has notable benefits: \begin{itemize}
    \item There is no need for NAT hole-punching or port-forwarding.
    \item WebSockets are highly flexible in how data is structured and interpreted.
\end{itemize}

In particular, the final point allows for the use of purely JSON messages, which are readily parsed and processed by the client-side JavaScript.

The game is broken down into three main stages, each of which handles events in a different way. These are shown below. Boxes in blue are messages received from other players (or transmitted by ourselves). Boxes in green require us to transmit a message to complete.

\begin{landscape}
	\begin{figure}
		\caption{Decomposition of general game structure as a P2P system}
		\begin{tikzpicture}[every node/.style={anchor=north west,minimum height=20pt}]
	% Create outlines
	\node[
	rectangle,
	dotted,
	draw,
	minimum width=0.5\hsize-4pt,
	minimum height=0.5\textheight-4pt,
	align=right,
	] at (0, 0.5\textheight) {};

	\node[anchor=south west] at (0, 2pt) {Setup};

	\node[
		rectangle,
		dotted,
		draw,
		minimum width=0.5\hsize-4pt,
		minimum height=0.5\textheight-4pt,
		align=right
	] at (0, -2pt) {};

	\node[anchor=south west] at (0, -0.5\textheight) {Pre-game};

	\node[
		rectangle,
		dotted,
		draw,
		minimum width=0.5\hsize-4pt,
		minimum height=\textheight-2pt,
		align=right,
	] at (0.5\hsize+2pt, 0.5\textheight) {};

	% This node doesnt position correctly......
	\node[anchor=south west] at (0.5\hsize+4pt, -0.5\textheight+2pt) {Game};

	% Player connect handling
	\node[draw=blue!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Connect) at (56pt, 0.5\textheight-4pt) {Player connects};

	\node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Addplayer) at (56pt, 0.5\textheight-36pt) {Add player $P_i$};

	\draw[very thick,->] (Connect) -- (Addplayer);

	\node[draw=green!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Announce) at (56pt, 0.5\textheight-68pt) {Announce self};

	\draw[very thick,->] (Addplayer) -- (Announce);

	\node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Starttimer) at (56pt, 0.5\textheight-100pt) {Start timer $T_i$};

	\draw[very thick,->] (Announce) -- (Starttimer);

	% Player disconnect handling
	\node[draw=blue!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Disconnect) at (170pt, 0.5\textheight-4pt) {Player disconnects};

	\node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Removeplayer) at (170pt, 0.5\textheight-36pt) {Remove player $P_i$};

	\draw[very thick,dashed,->] (Starttimer)-- (170pt, 0.5\textheight-109.5pt)-- node[right] {Timer expires} ++(Removeplayer);
	\draw[very thick,->] (Disconnect) -- (Removeplayer);

	% Player keep-alive handling
	\node[draw=blue!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Keepalive) at (290pt, 0.5\textheight-4pt) {Player keep-alives};

	\node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Resettimer) at (290pt, 0.5\textheight-36pt) {Reset timer $T_i$};

	\draw[very thick,->] (Keepalive) -- (Resettimer);

	% Player ready handling
	\node[draw=blue!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Ready) at (170pt, 80pt) {Player becomes ready};

	\node[draw=black!50,rectangle,fill=white,very thick,rounded corners=0.1mm,anchor=north] (MoveStage1) at (170pt, 10pt) {Update game stage};

	\node[draw=green!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Random1) at (170pt, -22pt) {Decide first player};

	\draw[very thick,dashed,->] (Ready)-- node[right] {All players ready} ++(MoveStage1);
	\draw[very thick,->] (MoveStage1) -- (Random1);

	% Player act handling
	\node[draw=blue!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Act1) at (60pt, -58pt) {Current player acts};

    \node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Claim) at (60pt, -114pt) {Claim region};

    \node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Reinf) at (200pt, -114pt) {Reinforce region};

    \node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (End1) at (200pt, -148pt) {End turn};

    \draw[very thick,->] (Reinf) -- (End1);
    \draw[very thick,->,dashed] (Act1)-- node[right] {Not all regions claimed} ++(Claim);
    \draw[very thick,->,dashed] (Act1) -- (200pt, -67.5pt)-- node[right] {All regions claimed} ++(Reinf);

    \node[draw=black!50,fill=white,rotate=270,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Update2) at (0.5\paperwidth + 60pt, -158pt) {Update game stage};

    \draw[very thick,->,dashed] (End1)-- node[below] {All reinf. placed} ++(Update2);

    % Player act handling 2
    \node[draw=blue!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Act2) at (0.5\paperwidth+112pt, 0.5\textheight-4pt) {Current player acts};

    \node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Reinf2) at (0.5\paperwidth+280pt, 140pt) {Reinforce regions};

    \node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Attack1) at (0.5\paperwidth+210pt, 70pt) {Attack region};

    \node[draw=green!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Attack2) at (0.5\paperwidth+210pt, 20pt) {Send defence};

    \node[draw=blue!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Attack3) at (0.5\paperwidth+340pt, 20pt) {Target defends};

    \node[draw=green!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Attack4) at (0.5\paperwidth+210pt, -30pt) {Resolve dice roll};

    \draw[very thick,->,dashed] (Attack1) -- node[right] {Target region owned by us} ++ (Attack2);
    \draw[very thick,->] (Attack2) -- (Attack4);
    \draw[very thick,->] (Attack3) -- (0.5\paperwidth+340pt, -15pt) -- (0.5\paperwidth+210pt, -15pt) -- (Attack4);

    \node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (Fortify) at (0.5\paperwidth+210pt, -90pt) {Fortify region};

    \node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (End2) at (0.5\paperwidth+210pt, -140pt) {End turn};

    \node[draw=black!50,rectangle,very thick,rounded corners=0.1mm,anchor=north] (End3) at (0.5\paperwidth+210pt, -190pt) {End game};

    \draw[very thick,->,dashed] (End2) -- node[right] {All regions controlled by one player} ++(End3);
    \draw[very thick,->] (Fortify) -- (End2);

    \draw[very thick,->,dashed] (Act2) -- (0.5\paperwidth+112pt, 130pt) -- node[below] {Reinf. remaining} ++ (Reinf2);
    \draw[very thick,->,dashed] (0.5\paperwidth+112pt, 130pt) -- (0.5\paperwidth+112pt, 60pt) -- (Attack1);
    \draw[very thick,->,dashed] (0.5\paperwidth+112pt, 60pt) -- (0.5\paperwidth+112pt, -100pt) -- (Fortify);
    \draw[very thick,->,dashed] (0.5\paperwidth+112pt, -100pt) -- (0.5\paperwidth+112pt, -150pt) -- (End2);
\end{tikzpicture}\end{figure}
\end{landscape}

\section{Message structure}

Each JSON message holds an \texttt{author} field, being the sender's ID; a message ID to associate related messages; a timestamp to prevent replay attacks; and an \texttt{action}, which at a high level dictates how each client should process the message.

The "action" is one of \texttt{ANNOUNCE}, \texttt{DISCONNECT}, \texttt{KEEPALIVE}, \texttt{RANDOM}, \texttt{PROOF}, \texttt{ACT}, and \texttt{RESOLVE}. The first three of these are used for managing the network by ensuring peers are aware of each other and know the state of the network. \texttt{ANNOUNCE} is transmitted upon a player joining to ensure the new player is aware of all other players. The \texttt{ANNOUNCE} message contains the player's encryption keys and the player's ID.

\texttt{RANDOM} and \texttt{PROOF} are designated to be used by sub-protocols defined later on. \texttt{ACT} and \texttt{RESOLVE} are used by players to submit actions for their turn during gameplay, and to resolve the outcomes of these actions.

Each message is also signed to verify the author. This is a standard application of RSA. A SHA-3 hash of the message is taken, then encrypted with the private key. This can be verified with the public key.

Players trust RSA keys on a trust-on-first-use (TOFU) basis. TOFU is the same protocol as used by Gemini \cite{projectgemini}. The main issue with TOFU is that if a malicious party intercepts the first communication, they may substitute the RSA credentials transmitted by the intended party, resulting in a man-in-the-middle attack.

\section{Paillier cryptosystem}

ECMAScript typically stores integers as floating point numbers, giving precision up to $2^{53}$. This is clearly inappropriate for the generation of sufficiently large primes for the Paillier cryptosystem.

In 2020, ECMAScript introduced \texttt{BigInt}, which are, as described in the spec, "arbitrary precision integers" \cite{tc39}. Whilst this does not hold true in common ECMAScript implementations (such as Chrome's V8), these "big integers" still provide sufficient precision for the Paillier cryptosystem.

It must be noted that \texttt{BigInt} is inappropriate for cryptography in practice, due to the possibility of timing attacks as operations are not necessarily constant time \cite{tc39}. In particular, modular exponentiation is non-constant time. However, as decryption is not performed during the program's runtime, it is unlikely that an attacker could use this to execute a timing attack against another player.

\subsection{Modular exponentiation}\label{subsection:modexp}

As \texttt{BigInt}'s V8 implementation does not optimise modular exponentiation itself, we employ the use of addition chaining \cite{schneier_1996}. Addition chaining breaks a modular exponentiation into repeated square-and-modulo operations, which are less expensive to perform.

The number of operations is dependent primarily on the size of the exponent. For an exponent $b$, between $|b|$ and $2|b|$ multiply-and-modulo operations are performed.

In the case of a fixed base, further speedup can be gained through pre-computation of fixed base powers. By pre-computing powers of the powers of two, exponentiation is reduced to at most $L$ multiplications. For some fixed base $h$ and modulus $n$, let $h[i] = h^{(2^i)} \bmod n$ represent cached values. Then, the following algorithm computes ${h^b \bmod n}$.

\begin{algorithmic}
	\Function{FixedBaseExp}{$b$}
	\State $index \gets 0$
	\State $counter \gets 1$

	\While{$b \neq 0$}
	\If {$b \equiv 1 \mod 2$}
	\State $ctr \gets ctr \times h[i]$
	\State $ctr \gets ctr \bmod n$
	\EndIf
	\State $i \gets i + 1$
	\State $b \gets \lfloor \frac{b}{2} \rfloor$
	\EndWhile
	\EndFunction
\end{algorithmic}

\subsection{Public key}

In the Paillier cryptosystem, the public key is a pair $(n, g)$ where $n = pq$ for primes $p, q$ satisfying $\gcd(pq, (p - 1)(q - 1)) = 1$ and $g \in \mathbb{Z}^*_{n^2}$. The range of plaintexts $m$ is restricted to $0 < m < n$.

Generating primes is a basic application of the Rabin-Miller primality test \cite{RABIN1980128}. This produces probabilistic primes, however upon completing sufficiently many rounds of verification, the likelihood of these numbers actually not being prime is dwarfed by the likelihood of some other failure, such as hardware failure.

The Paillier cryptosystem is otherwise generic over the choice of primes $p, q$. However, by choosing $p, q$ of equal length, the required property of $pq$ and $(p - 1)(q - 1)$ being coprime is guaranteed.

\begin{proposition}
	For $p, q$ prime of equal length, $\gcd(pq, (p - 1)(q - 1)) = 1$.
\end{proposition}

\begin{proof}
	Without loss of generality, assume $p > q$. Suppose $\gcd(pq, (p - 1)(q - 1)) \neq 1$. Then, $q \mid p - 1$. However, the bit-lengths of $p, q$ are identical. So $\frac{1}{2}(p - 1) < q$. This is a contradiction to $q \mid p - 1$ (as 2 is the smallest possible divisor), and so we must have $\gcd(pq, (p - 1)(q - 1)) = 1$ as required.
\end{proof}

As the prime generation routine generates primes of equal length, this property is therefore guaranteed. The next step is to select the public parameter $g$ as $g = 1 + n$.

\begin{proposition}
	$1 + n \in \mathbb{Z}^*_{n^2}$.
\end{proposition}

\begin{proof}
	We see that $(1 + n)^n \equiv 1 \mod n^2$ from binomial expansion. So $1 + n$ is invertible as required.
\end{proof}

Besides reducing the number of operations performed, this selection of $g$ also does not require auxiliary memory to store intermediary values using during exponentiation.

In Jurik's form, we also need to compute $h$, a generator of the Jacobi subgroup, and impose restrictions on $p, q$. In particular, it is required that $p \equiv q \equiv 3 \mod 4$, $\gcd(p-1, q-1) = 2$, and that $p-1, q-1$ consist of large factors except for 2. Using safe primes guarantees this. Safe primes are primes of form $2p+1$ for $p$ prime.

\begin{proposition}
	For $p > 5$ a safe prime, $p \equiv 3 \mod 4$
\end{proposition}

\begin{proof}
	Let $q$ prime and $p = 2q+1$ the corresponding safe prime. Then, \begin{align*}
		q \equiv 1 \mod 4 &\implies 2q+1 \equiv 3 \mod 4 \\
		q \equiv 3 \mod 4 &\implies 2q+1 \equiv 3 \mod 4
	\end{align*}
	as required.
\end{proof}

\begin{proposition}
	For safe primes $p \neq q$ with $p, q > 5$, $\gcd(p - 1, q - 1) = 2$
\end{proposition}

\begin{proof}
	As $p, q$ are safe, $\frac{p - 1}{2}$ and $\frac{q - 1}{2}$ are prime. So \begin{align*}
		\gcd\left(\frac{p - 1}{2}, \frac{q - 1}{2}\right) = 1 \implies \gcd(p - 1, q - 1) = 2
	\end{align*}
\end{proof}

To identify safe primes, first we generate a prime $p$, and then test the primality of $\frac{p - 1}{2}$.
Finally, to get the public parameter $h$, we compute $h = -x^2 \mod n$ for some random $x \in \mathbb{Z}_n^*$. With high likelihood $x$ is coprime to $n$, and so the Jacobi symbol is computed as \begin{align*}
	\left(\frac{-x^2}{n}\right) = \left(\frac{-x^2}{p}\right)\left(\frac{-x^2}{q}\right) = (-1)^2 = 1
\end{align*}

This gives us our public key $(n, g, h)$.

\subsection{Encryption}

In the original Paillier scheme, ciphertexts are computed as $E(m, r) = c = g^m r^n \mod n^2$ for $r < n$ some random secret value. In Jurik's form, ciphertexts are computed as \begin{align*}
	E'(m, r) = c' = g^m(h^r \bmod n)^n \equiv g^m(h^n \bmod n)^r \mod n^2
\end{align*}
Jurik remarks that $E'(m, r) = E(m, h^r \bmod n)$.

The main speedup as a result of using Jurik's form originates from fixed base exponentiation, as discussed in \hyperref[subsection:modexp]{Section~\ref*{subsection:modexp}}

\subsection{Private key}

The private key is the value of the Carmichael function $\lambda = \lambda(n)$, defined as the exponent of the group $\mathbb{Z}^*_n$. From the Chinese remainder theorem, $\lambda(n) = \lambda(pq)$ can be computed as $\lcm(\lambda(p), \lambda(q))$. From Carmichael's theorem, this is equivalent to $\lcm(\phi(p), \phi(q))$. Hence, from the definition of $\phi$, and as $p, q$ are equal length, $\lambda = (p - 1)(q - 1) = \phi(n)$.

We also need to compute $\mu = \lambda^{-1} \mod n$ as part of decryption. Fortunately, this is easy, as from Euler's theorem, $\lambda^{\phi(n)} \equiv 1 \mod n$, and so we propose $\mu = \lambda^{\phi(n) - 1} \mod n$. As $\phi(n)$ is easily computable with knowledge of $p, q$, we get ${\mu = \lambda^{(p - 1)(q - 1)} \mod n}$, a relatively straight-forward computation.

\subsection{Decryption}

Let $c$ be the ciphertext. The corresponding plaintext is computed as \begin{align*}
	m = L(c^\lambda \mod n^2) \cdot \mu \mod n,
\end{align*} where $L(x) = \frac{x - 1}{n}$. This operation can be optimised by applying Chinese remainder theorem. However, in the application presented, decryption is not used and is only useful as a debugging measure. So this optimisation is not applied.

\subsection{Implementation details}

Paillier is implemented by four classes: \texttt{PubKey}, \texttt{PrivKey}, \texttt{Ciphertext}, and \texttt{ReadOnlyCiphertext}. \texttt{PubKey.encrypt} converts a \texttt{BigInt} into either a \texttt{Ciphertext} or a \texttt{ReadOnlyCiphertext} by the encryption function above. The distinction between these is that a \texttt{ReadOnlyCiphertext} does not know the random $r$ that was used to form it, and so is created by decrypting a ciphertext that originated with another peer. A regular \texttt{Ciphertext} maintains knowledge of $r$ and the plaintext it enciphers, which enables using \hyperref[protocol0]{Protocol~\ref*{protocol0}}.

\section{Shared random values}

A large part of Risk involves random behaviour dictated by rolling some number of dice. To achieve this, a fair protocol must be used to generate random values consistently across each peer without any peer being able to manipulate the outcomes.

This is achieved with a standard application of bit-commitment, and properties of $\mathbb{Z}_n$. The protocol for two peers is as follows, and generalises to $n$ peers.

\begin{protocol}[Shared random values]\label{protocol2}
\begin{center}
    \begin{tikzpicture}[
        every node/.append style={very thick,rounded corners=0.1mm}
        ]

        \node[draw,rectangle] (A) at (0,0) {Peer A};

        \node[draw,rectangle] (B) at (6,0) {Peer B};

        \node[draw=blue!50,rectangle,thick,text width=4cm] (NoiseA) at (0,-1.5) {Generate random noise $N_A$, random key $k_A$};
        \node[draw=blue!50,rectangle,thick,text width=4cm] (NoiseB) at (6,-1.5) {Generate random noise $N_B$, random key $k_B$};

        \draw [->,very thick] (0,-3)--node [auto] {$E_{k_A}(N_A)$}++(6,0);
        \draw [<-,very thick] (0,-4)--node [auto] {$E_{k_B}(N_B)$}++(6,0);

        \draw [->,very thick] (0,-5)--node [auto] {$k_A$}++(6,0);
        \draw [<-,very thick] (0,-6)--node [auto] {$k_B$}++(6,0);

        \node[draw=blue!50,rectangle,thick] (CA) at (0,-7) {Compute $N_A + N_B$};
        \node[draw=blue!50,rectangle,thick] (CB) at (6,-7) {Compute $N_A + N_B$};

        \draw [very thick] (A)-- (NoiseA)-- (CA)-- (0,-7);
        \draw [very thick] (B)-- (NoiseB)-- (CB)-- (6,-7);
    \end{tikzpicture}
\end{center}
\end{protocol}

To generalise this to $n$ peers, we ensure that each peer waits to receive all encrypted noises before transmitting their decryption key.

Depending on how $N_A + N_B$ is then moved into the required range, this system may be manipulated by an attacker who has some knowledge of how participants are generating their noise. As an example, suppose a random value within range is generated by taking $N_A + N_B \mod 3$, and participants are producing 2-bit noises. An attacker could submit a 3-bit noise with the most-significant bit set, in which case the probability of the final result being a 1 is significantly higher than the probability of a 0 or a 2. This is a typical example of modular bias. To avoid this problem, peers should agree beforehand on the number of bits to transmit, and compute the final value as $N_A \oplus N_B$.

The encryption function used must also guarantee the integrity of decrypted ciphertexts. Otherwise, a malicious party could create a ciphertext which decrypts to multiple valid values by using different keys.

\begin{proposition}
    With the above considerations, the scheme shown is not manipulable by a single cheater.
\end{proposition}

\begin{proof}
    Suppose $P_1, \dots, P_{n-1}$ are honest participants, and $P_n$ is a cheater with a desired outcome.

    In step 1, each participant $P_i$ commits $E_{k_i}(N_i)$. The cheater $P_n$ commits a constructed noise $E_{k_n}(N_n)$.

    The encryption function $E_k$ holds the confidentiality property: that is, without $k$, $P_i$ cannot retrieve $m$ given $E_k(m)$. So $P_n$'s choice of $N_n$ cannot be directed by other commitments.

    The final value is dictated by the sum of all decrypted values. $P_n$ is therefore left in a position of choosing $N_n$ to control the outcome of $a + N_n$, where $a$ is selected uniformly at random from the abelian group $\mathbb{Z}_{2^\ell}$ for $\ell$ the agreed upon bit length.

    As every element of this group is of order $2^\ell$, the distribution of $a + N_n$ is identical no matter the choice of $N_n$. So $P_n$ maintains no control over the outcome of $a + N_n$.
\end{proof}

This extends inductively to support $n-1$ cheating participants, even if colluding. Finally, we must consider how to reduce random noise to useful values.

\subsection{Modular bias}

Despite restricting each player's random noise to a fixed bit length, we must still avoid the modular bias that occurs when taking the modulus of a bit sequence.

We achieve this by resampling. To avoid excessive communication, resampling can be performed within the bit sequence by partitioning into blocks of $n$ bits and taking blocks until one falls within range. This is appropriate in the presented use case as random values need only be up to 6, so the probability of consuming over 63 bits of noise when resampling for a value in the range 0 to 5 is $\left(\frac{1}{4}\right)^{21} \approx 2.3 \times 10^{-13}$.

\subsection{Application to domain}

Random values are used in two places. \begin{itemize}
    \item Selecting the first player.
    \item Rolling dice.
\end{itemize}

As this protocol must run many times during a game, we consider each operation of the protocol as a "session", each of which has a unique name that is derived from the context. A benefit of this is that the unique name can be used with the Web Locks API to prevent race conditions that may occur due to this protocol running asynchronously.

\section{Proof system}

Players should prove a number of properties of their game state to each other to ensure fair play. These are as follows. \begin{enumerate}
    \item The number of reinforcements placed during the first stage of a turn.

    \item The number of units on a region neighbouring another player.

    \item The number of units available for an attack/defence.

    \item The number of units lost during an attack/defence (including total depletion of units and loss of the region).

    \item The number of units moved when fortifying.
\end{enumerate}

These points are referenced in the following sections.

\subsection{Proof of zero}

The first proof to discuss is the honest-verifier protocol to prove knowledge that a ciphertext is an encryption of zero \cite[Section~5.2]{damgard2003}.

\begin{protocol}[Proof of zero]\label{protocol0}
	\begin{center}
	\begin{tikzpicture}[every node/.append style={very thick,rounded corners=0.1mm}]

	    \node[draw,rectangle] (P) at (0,0) {Prover};
	    \node[draw,rectangle] (V) at (6,0) {Verifier};

	    \node[draw=blue!50,rectangle,thick,text width=5.05cm] (v) at (0,-1.5) {$r \in \mathbb{Z}_n^*$ with $c = r^n \mod n^2$};
	    \draw [->,very thick] (0,-3)--node [auto] {$c$}++(6,0);

	    \node[draw=blue!50,rectangle,thick] (r) at (0,-4) {Choose random $r^* \in \mathbb{Z}_n^*$};
	    \draw [->,very thick] (0,-5)--node [auto] {$a = (r^*)^n \mod n^2$}++(6,0);

	    \node[draw=blue!50,rectangle,thick] (e) at (6,-6) {Choose random $e$};
	    \draw [<-,very thick] (0,-7)--node [auto] {$e$}++(6,0);

	    \draw [->,very thick] (0,-8)--node [auto] {$z = r^*r^e \mod n$}++(6,0);
	    \node[draw=blue!50,rectangle,thick,text width=5cm] (verify) at (6,-9) {Verify $z, c, a$ coprime to $n$\\ Verify $z^n \equiv ac^e \mod n^2$};

	    \node[draw=none] (term) at (0,-9) {};
	    \fill (term) circle [radius=2pt];

	    \draw [very thick] (P)-- (v)-- (r)-- (0,-9);
	    \draw [very thick] (V)-- (e)-- (verify)-- (6,-9);
	\end{tikzpicture}
	\end{center}
\end{protocol}

A proof for the following homologous problem can be trivially constructed: given some ciphertext $c = g^mr^n \mod n^2$, prove that the text $cg^{-m} \equiv r^n \mod n^2$ is an encryption of 0. The text $cg^{-m}$ is constructed by the verifier. The prover then proceeds with the proof as normal, since $cg^{-m}$ is an encryption of 0 under the same noise as the encryption of $m$ given.

This is used in point (2), as one player can then convince a neighbour in zero-knowledge of the number of units within their region. It is also used throughout the other proofs presented.

\subsection{Proving reinforcement}

Consider point (1). One option is to prove that the sum of the committed values is 1 by using the additive homomorphic property. However, this allows a player to cheat by using negative values. To overcome this, we want a new protocol that is still in zero-knowledge, but proves additional properties of a reinforce action.

\begin{figure}[H]
    \centering
    \begin{tikzpicture}
        \tikzstyle{style}=[circle,minimum size=15mm,draw=black,fill=white]

        \node (im1) {\begin{tikzpicture}
                \node[style] (A) at (-1.5, 3) {$n_1$};
                \node[style] (B) at (-3, 0) {$n_2$};
                \node[style] (C) at (0, 0) {$n_3$};
                \node[style] (D) at (1.5, 3) {$n_4$};

                \path[draw] (A) -- (C) -- (B) -- (A);
                \path[draw] (A) -- (D);
        \end{tikzpicture}};

        \node (im2) at (0.5\textwidth, 0) {\begin{tikzpicture}
                \node[style,label=center:$n_1 + 0$] (A) at (-1.5, 3) {};
                \node[style,label=center:$n_2 + 0$] (B) at (-3, 0) {};
                \node[style,label=center:$n_3 + 1$] (C) at (0, 0) {};
                \node[style,label=center:$n_4 + 0$] (D) at (1.5, 3) {};

                \path[draw] (A) -- (C) -- (B) -- (A);
                \path[draw] (A) -- (D);
        \end{tikzpicture}};

        \path[draw,->,very thick] (im1) -- (im2);
    \end{tikzpicture}
    \caption{Example state change from reinforce action.}
\end{figure}

\begin{figure}[H]
    \centering
    \begin{tikzpicture}
        \tikzstyle{style}=[circle,draw=black,minimum size=10mm,fill=white]

        \node[anchor=north,black!40!green] at (-0.5, -0.75) {Valid};

        \node[style] (A) at (-1, 2) {$0$};
        \node[style] (B) at (-2, 0) {$+1$};
        \node[style] (C) at (0, 0) {$0$};
        \node[style] (D) at (1, 2) {$0$};

        \path[draw] (A) -- (C) -- (B) -- (A);
        \path[draw] (A) -- (D);
    \end{tikzpicture}
    \begin{tikzpicture}
        \tikzstyle{style}=[circle,draw=black,minimum size=10mm,fill=white]

        \node[anchor=north,black!40!green] at (-0.5, -0.75) {Valid};

        \node[style] (A) at (-1, 2) {$0$};
        \node[style] (B) at (-2, 0) {$0$};
        \node[style] (C) at (0, 0) {$0$};
        \node[style] (D) at (1, 2) {$+1$};

        \path[draw] (A) -- (C) -- (B) -- (A);
        \path[draw] (A) -- (D);
    \end{tikzpicture}

    \begin{tikzpicture}
        \tikzstyle{style}=[circle,draw=black,minimum size=10mm,fill=white]

        \node[anchor=north,black!40!red] at (-0.5, -0.75) {Invalid};

        \node[style] (A) at (-1, 2) {$+1$};
        \node[style] (B) at (-2, 0) {$+1$};
        \node[style] (C) at (0, 0) {$0$};
        \node[style] (D) at (1, 2) {$0$};

        \path[draw] (A) -- (C) -- (B) -- (A);
        \path[draw] (A) -- (D);
    \end{tikzpicture}
    \begin{tikzpicture}
        \tikzstyle{style}=[circle,draw=black,minimum size=10mm,fill=white]

        \node[anchor=north,black!40!red] at (-0.5, -0.75) {Invalid};

        \node[style] (A) at (-1, 2) {$0$};
        \node[style] (B) at (-2, 0) {$+2$};
        \node[style] (C) at (0, 0) {$-1$};
        \node[style] (D) at (1, 2) {$0$};

        \path[draw] (A) -- (C) -- (B) -- (A);
        \path[draw] (A) -- (D);
    \end{tikzpicture}
    \caption{Valid and invalid reinforce messages. Notably, the final invalid message would not be caught by the additive homomorphic check.}
\end{figure}

To prove this, the prover will demonstrate that a bijection exists between the elements in the reinforcement set and a "good" set.

\begin{protocol}\label{protocol1}
	The prover transmits the set \begin{align*}
		S = \{ (R_1, E(n_1, r_1)), \dots, (R_N, E(n_N, r_N)) \}
	\end{align*} as their reinforcement step. Verifier wants that the second projection of this set maps to 1 exactly once.

	Run $t$ times in parallel:

	\begin{enumerate}
		\item Prover transmits $\{ (\psi(R_i), E(n_i, r_i^*)) \mid 0 < i \leq N \}$ where $\psi$ is a random bijection on the regions.

		\item Verifier picks $c \in_R \{0, 1\}$. \begin{enumerate}
			\item If $c = 0$, the verifier requests the definition of $\psi$. They then compute the product of the $E(x, r_i) \cdot E(x, r_i^*)$ and request proofs that each of these is zero.

			\item If $c = 1$, the verifier requests a proof that each $E(n_i, r_i^*)$ is as claimed.
		\end{enumerate}
	\end{enumerate}
\end{protocol}

This protocol has the following properties, given that the proof of zero from before also holds the same properties \cite{damgard2003}.
\begin{itemize}
	\item \textbf{Complete.} The verifier will clearly always accept $S$ given that $S$ is valid.
	\item \textbf{Sound.} A cheating prover will trick a verifier with probability $2^{-t}$. So select a sufficiently high $t$.
	\item \textbf{Zero-knowledge.} Supposing each $\psi$, $r_i$, and $r_i^*$ are generated in a truly random manner, the verifier gains no additional knowledge of the prover's private state.
\end{itemize}

Additionally, this protocol is perfectly simulatable.

\begin{proposition}
	\hyperref[protocol1]{Protocol~\ref*{protocol1}} is perfectly simulatable in the random-oracle model.
\end{proposition}

\begin{proof}
	To prove perfect simulation, we require a polynomial-time algorithm $T^*$ such that for all verifiers and for all valid sets $S$, the set of transcripts $T(P, V, S) = T^*(S)$, and the distributions are identical.

	Such a $T^*$ can be defined for any $S$. \begin{enumerate}
		\item Choose a random $\psi'$ from the random oracle.
		\item Choose random $(r_i^*)'$ from the random oracle.
		\item Encrypt under $P$'s public-key.
		\item Verifier picks $c$ as before.
		\item Perform proofs of zero, which are also perfect simulation \cite[Lemma~3]{damgard2003}.
	\end{enumerate}

	This gives $T^*$ such that $T^*(S) = T(P, V, S)$, and the output distributions are identical. Hence, this proof is perfectly simulatable under random oracle model.
\end{proof}

In practice, as we are using Jurik's form of Paillier, this is computational zero-knowledge. This is because Jurik's form relies upon the computational indistinguishability of the sequence generated by powers of $h$ to random powers.

\subsection{Range proof}

The range proof we use proves an upper bound on $|m|$ by constructing commitments to the bits of $m$, and using homomorphic properties \cite[Section~1.2.1]{Boudot2000EfficientPT}. Given valid encryptions of a sequence of bits, we can reconstruct the number: let $b_1, \dots, b_{|m|}$ be the bits of $m$ ($b_1$ being the LSB), and $c_i = E(b_i) = g^{b_i} r^n \mod n^2$. Then, we can construct an encryption of $m$ as \begin{align*}
	E(m) = (c_1)^{(2^0)} \cdot (c_2)^{(2^1)} \cdot (c_3)^{(2^2)} \cdot \ldots \cdot (c_{|m|})^{(2^{|m| - 1})}.
\end{align*}

Validating $E(m)$ is done with the proof of zero. Then it remains to prove that each $c_i$ enciphers either a 0 or a 1. This can be done in a similar way to \hyperref[protocol1]{Protocol~\ref*{protocol1}}.

\begin{protocol}\label{protocol4}
	The prover transmits $c = E(m)$, and encryptions of the bits $c_1, \dots, c_{|m|}$, except using $-1$ in place of $1$.

	\begin{enumerate}
		\item The verifier computes \begin{align*}
			c \cdot \prod_i^{|m|} (c_i)^{(2^{i-1})}
		\end{align*} and requests a proof of zero.

		\item Perform $t$ times for each $i$: \begin{enumerate}
			\item Prover transmits $S = \{ E(0), E(1) \}$.

			\item Verifier picks $a \in_R \{ 0, 1 \}$. \begin{enumerate}
				\item If $a = 0$, the verifier requests a proof that $S = \{ 0, 1 \}$.

				\item If $a = 1$, the verifier requests a proof that $c_i \cdot s_i$ is zero for one of the $s_i \in S$.
			\end{enumerate}
		\end{enumerate}
	\end{enumerate}
\end{protocol}

The downside of this proof over the BCDG proof \cite{bcdg1987} is that the time to perform and verify this proof grows linearly with $|m|$. However, in most cases $|m|$ should be "small": i.e, $|m| \leq 6$, as Risk unit counts rarely exceed 64 on a single region.

Range proof is used in points (3), (4), and (5). In (3), this is to convince other players that the number of units is sufficient for the action. In (4), this is to show that the region is not totally depleted. In (5), this is to ensure the number of units being fortified is less than the strength of the region. All of these are performed using \hyperref[protocol4]{Protocol~\ref*{protocol4}} and by using the additive homomorphic property to subtract the lower range from $m$ first.

\subsection{Proving fortifications}

Point (5) still remains, as the range proof alone only works to prevent negative values from appearing in the resolution of a fortify action. Fortify actions need to be of form $\{ k, -k, 0, \dots, 0 \}$) and the regions corresponding to $k, -k$ amounts must be adjacent.

\begin{figure}[H]
\centering
\begin{tikzpicture}
    \tikzstyle{style}=[circle,minimum size=15mm,draw=black,fill=white]

    \node (im1) {\begin{tikzpicture}
            \node[style] (A) at (-1.5, 3) {$n_1$};
            \node[style] (B) at (-3, 0) {$n_2$};
            \node[style] (C) at (0, 0) {$n_3$};
            \node[style] (D) at (1.5, 3) {$n_4$};

            \path[draw] (A) -- (C) -- (B) -- (A);
            \path[draw] (A) -- (D);
        \end{tikzpicture}};

    \node (im2) at (0.5\textwidth, 0) {\begin{tikzpicture}
            \node[style,label=center:$n_1 + k$] (A) at (-1.5, 3) {};
            \node[style,label=center:$n_2 + 0$] (B) at (-3, 0) {};
            \node[style,label=center:$n_3 - k$] (C) at (0, 0) {};
            \node[style,label=center:$n_4 + 0$] (D) at (1.5, 3) {};

            \path[draw] (A) -- (C) -- (B) -- (A);
            \path[draw] (A) -- (D);
    \end{tikzpicture}};

    \path[draw,->,very thick] (im1) -- (im2);
\end{tikzpicture}
\caption{Example state change from fortify action.}
\end{figure}

\begin{figure}[H]
    \centering
    \begin{tikzpicture}
        \tikzstyle{style}=[circle,draw=black,minimum size=10mm,fill=white]

        \node[anchor=north,black!40!green] at (-0.5, -0.75) {Valid};

        \node[style] (A) at (-1, 2) {$0$};
        \node[style] (B) at (-2, 0) {$+k$};
        \node[style] (C) at (0, 0) {$-k$};
        \node[style] (D) at (1, 2) {$0$};

        \path[draw] (A) -- (C) -- (B) -- (A);
        \path[draw] (A) -- (D);
    \end{tikzpicture}
    \begin{tikzpicture}
        \tikzstyle{style}=[circle,draw=black,minimum size=10mm,fill=white]

        \node[anchor=north,black!40!green] at (-0.5, -0.75) {Valid};

        \node[style] (A) at (-1, 2) {$-k$};
        \node[style] (B) at (-2, 0) {$0$};
        \node[style] (C) at (0, 0) {$+k$};
        \node[style] (D) at (1, 2) {$0$};

        \path[draw] (A) -- (C) -- (B) -- (A);
        \path[draw] (A) -- (D);
    \end{tikzpicture}

    \begin{tikzpicture}
        \tikzstyle{style}=[circle,draw=black,minimum size=10mm,fill=white]

        \node[anchor=north,black!40!red] at (-0.5, -0.75) {Invalid};

        \node[style] (A) at (-1, 2) {$0$};
        \node[style] (B) at (-2, 0) {$+k$};
        \node[style] (C) at (0, 0) {$0$};
        \node[style] (D) at (1, 2) {$-k$};

        \path[draw] (A) -- (C) -- (B) -- (A);
        \path[draw] (A) -- (D);
    \end{tikzpicture}
    \begin{tikzpicture}
        \tikzstyle{style}=[circle,draw=black,minimum size=10mm,fill=white]

        \node[anchor=north,black!40!red] at (-0.5, -0.75) {Invalid};

        \node at (1, 1) {$k_1 \neq k_2$};

        \node[style] (A) at (-1, 2) {$0$};
        \node[style,label=center:$+k_1$] (B) at (-2, 0) {};
        \node[style,label=center:$-k_2$] (C) at (0, 0) {};
        \node[style] (D) at (1, 2) {$0$};

        \path[draw] (A) -- (C) -- (B) -- (A);
        \path[draw] (A) -- (D);
    \end{tikzpicture}
    \caption{Valid and invalid fortify messages.}
\end{figure}

We combine some ideas from the graph isomorphism proofs with ideas from before to get the following protocol.

\begin{protocol}\label{protocol3}
    The prover transmits the set \begin{align*}
        S = \{ (R_1, E(k, r_1)), (R_2, E(-k, r_2)), (R_3, E(0, r_3)) \dots, (R_N, E(0, r_N)) \}
    \end{align*} as their fortify message.

    Run $t$ times in parallel:

    \begin{enumerate}
        \item Prover transmits $\{ (\psi(R_i), E(-n_i, r_i^*)) \mid 0 < i \leq N \}$ where $\psi$ is a random bijection on the regions, and $\{ H(R_i, R_j, s_{ij}) \mid R_i \text{ neighbours } R_j \}$ where $s_{ij}$ is a random salt.

        \item Verifier chooses a random $c \in \{0, 1\}$. \begin{enumerate}
            \item If $c = 0$, the verifier requests the definition of $\psi$ and each salt. They check that the resulting graph is isomorphic to the original graph. They then compute $E(n_i, r_i) \cdot E(-n_i, r_i^*)$ for each $i$ and request a proof that each is zero. Finally, they compute each edge hash and check that there are precisely the correct number of hashes.

            \item If $c = 1$, the verifier requests proofs that $|S| - 2$ elements are zero and that the remaining pair add to zero. They then request the salt used to produce the hash along the edge joining the two non-zero elements, and test that this hash is correct.
        \end{enumerate}
    \end{enumerate}
\end{protocol}

\subsection{Optimising}

It is preferred that these proofs can be performed with only a few communications: this issue is particularly prevalent for protocols requiring multiple rounds to complete. The independence of each round on the next means the proof can be performed in parallel, so the prover computes all of their private state, then the verifier computes all of their challenges. However, still is the issue of performing proofs of zero.

We can apply the Fiat-Shamir heuristic to make proofs of zero non-interactive \cite{fiatshamir}. In place of a random oracle, we use a cryptographic hash function. We take the hash of some public parameters to prevent cheating by searching for some values that hash in a preferable manner. In this case, selecting $e = H(g, m, a)$ is a valid choice. To get a hash of desired length, an extendable output function such as SHAKE256 can be used \cite{FIPS202}. The library jsSHA \cite{jssha} provides an implementation of SHAKE256 that works within a browser.

\subsection{Application to domain}

\begin{figure}[H]
	\centering
	\begin{tikzpicture}[every node/.append style={
			very thick,fill=white,
			rounded corners=0.1mm,
			minimum height=20pt}]

		\node[draw,rectangle] (P1) at (0,-0.5) {Player 1};
		\node[draw,rectangle] (V) at (6,-0.5) {World};
		\node[draw,rectangle] (P2) at (12,-0.5) {Player 2};

		\draw [very thick] (P1)-- (0,-15);
		\draw [very thick] (V) -- (6,-15);
		\draw [very thick] (P2)-- (12,-15);

		\draw [->,very thick] (0,-3)--node [auto] {\hyperref[protocol1]{Protocol~\ref*{protocol1}}}++(6,0);
		\draw [->,very thick] (6,-3)--(12,-3);
		\node[draw=blue!50,rectangle] at (0,-2) {Reinforce regions};

		\draw [<->,very thick] (12,-4)-- node[above] {\hyperref[protocol0]{Protocol~\ref*{protocol0}} (neighbouring counts)} ++ (-12,0);

		\node[draw=blue!50,rectangle] at (0,-5) {Attack Player 2};

		\draw [->,very thick] (0,-6)--node [auto] {\hyperref[protocol4]{Protocol~\ref*{protocol4}}}++(6,0);
		\draw [->,very thick] (6,-6)--++(6,0);

		\node[draw=blue!50,rectangle] at (12,-7) {Send defence};

		\draw [->,very thick] (12,-8)--node [above] {\hyperref[protocol4]{Protocol~\ref*{protocol4}}}++(-6,0);
		\draw [->,very thick] (6,-8)--++(-6,0);

		\path (0,-9)-- node[above] {\hyperref[protocol2]{Protocol~\ref*{protocol2}} (resolve dice)} ++ (12,0);
		\draw [<->,very thick] (0,-9)--++ (6,0);
		\draw [<->,very thick] (6,-9)--++ (6,0);

		\path (0,-10)-- node[above] {\hyperref[protocol4]{Protocol~\ref*{protocol4}} (prove maintained ownership)} ++ (12,0);
		\draw [<->,very thick] (0,-10)--++ (6,0);
		\draw [<->,very thick] (6,-10)--++ (6,0);

		\node[draw=blue!50,rectangle] at (0,-11) {Fortify};
		\draw [->,very thick] (0,-12)--node [auto] {\hyperref[protocol3]{Protocol~\ref*{protocol3}}}++(6,0);
		\draw [->,very thick] (6,-12)--(12,-12);

		\draw [<->,very thick] (12,-13)-- node[above] {\hyperref[protocol0]{Protocol~\ref*{protocol0}} (neighbouring counts)} ++ (-12,0);

		\path (0,-14)--node [auto] {\hyperref[protocol4]{Protocol~\ref*{protocol4}} (prove non-negative)}++(12,0);
		\draw [->,very thick] (0,-14)--++(6,0);
		\draw [->,very thick] (6,-14)--++(6,0);

		\fill (0,-15) circle [radius=2pt] ;
		\fill (6,-15) circle [radius=2pt] ;
		\fill (12,-15) circle [radius=2pt] ;
	\end{tikzpicture}
	\caption{An example turn during the game incorporates each of the protocols presented above, some multiple times.}
\end{figure}

\chapter{Review}

\section{Theoretic considerations}

\subsection{Random oracles}

Various parts of the implementation use the random oracle model: in particular, the zero-knowledge proof sections. The random oracle model is theoretic, as according to the Church-Turing thesis, an algorithm with infinite description cannot be computed on a finite machine.

The random oracle model is used for two guarantees. The first is in the construction of truly random values that will not reveal information about the prover's state. In practice, a cryptographically secure pseudo-random number generator will suffice for this application, as CSPRNGs typically incorporate environmental data to ensure outputs are unpredictable \cite{random(4)}.

The second is to associate a non-random value with a random value. In practice, a cryptographic hash function such as SHAKE is used. This gives appropriately pseudo-random outputs that appear truly random, and additionally are assumed to be preimage resistant. This property is necessary when constructing non-interactive proofs, to prevent a prover manipulating the signature used to derive the proof.

\subsection{Quantum resistance}

Paillier is broken if factoring large numbers is computationally feasible \cite[Theorem~9]{paillier1999public}. Therefore, it is vulnerable to the same quantum threat as RSA is, known as Shor's algorithm \cite{shor_1997}. Alternative homomorphic encryption schemes are available, which are believed to be quantum-resistant, as they are based on lattice methods (e.g, \cite{fhe}).

\subsection{Honest-verifier}

The proof of zero is honest-verifier \cite[Section~5.2]{damgard2003}. However, applying the Fiat-Shamir heuristic converts such a proof into a general zero-knowledge proof \cite[Section~5]{fiatshamir}. This means that, supposing the choice of transform used is appropriate, \hyperref[protocol1]{Protocol~\ref*{protocol1}} should also be general zero-knowledge. However, the interactive proofs performed as part of the game are still only honest-verifier. Consequently, a malicious verifier may be able to extract additional information from the prover (such as the blinding value used).

\section{Efficiency}

\subsection{Storage complexity}

Let $n$ be the Paillier modulus.

Paillier ciphertexts are constant size, each $2|n|$ in size (as they are taken modulo $n^2$). This is small enough for the memory and network limitations of today.

The interactive proof of zero uses two Paillier ciphertexts (each size $2|n|$), a challenge of size $|n|$, and a proof statement of size $|n|$. In total, this is a constant size of $6|n|$.

On the other hand, the non-interactive variant needs not communicate the challenge (as it is computed as a function of other variables). So the non-interactive proof size is $5|n|$.

The non-interactive \hyperref[protocol1]{Protocol~\ref*{protocol1}} requires multiple rounds. Assume that we use 48 rounds: this provides a good level of soundness, with a cheat probability of $\left(\frac{1}{2}\right)^{-48} \approx 3.6 \times 10^{-15}$. Additionally, assume that there are five regions to verify. Each prover round then requires five Paillier ciphertexts, and each verifier round five non-interactive proofs of zero plus some negligible amount of additional storage for the bijection.
This results in a proof size of $(10|n| + 10|n|) \times 48 = 960|n|$. For key size $|n| = 2048$, this is $240kB$. This is a fairly reasonable size for memory and network, but risks exceeding what can be placed within a processor's cache, leading to potential slowdown during verification.

This could be overcome by reducing the number of rounds, which comes at the cost of increasing the probability of cheating. In a protocol designed to only facilitate a single game session, this may be acceptable to the parties involved. For example, reducing the number of rounds to 24 will increase the chance of cheating to $\left(\frac{1}{2}\right)^{-24} \approx 6.0 \times 10^{-8}$, but the size would reduce by approximately half.

Each of these calculations is in an ideal situation without compression or signatures: in the implementation presented, the serialisation of a ciphertext is larger than this, since it serialises to a string of the hexadecimal representation and includes a digital signature for authenticity. In JavaScript, encoding a byte string as hexadecimal should yield approximately a four times increase in size, as one byte uses two hexadecimal characters, which are encoded as UTF-16. Results for the actual sizes of each proof are given in \hyperref[table3]{Table~\ref*{table3}}. Some potential solutions are discussed here.

\textbf{Compression.} One solution is to use string compression. String compression can reduce the size considerably, as despite the ciphertexts being random, the hex digits only account for a small amount of the UTF-8 character space. LZ-String, a popular JavaScript string compression library, can reduce the size of a single hex-encoded ciphertext to about 35\% of its original size. This will result in some slowdown due to compression time. However, this is somewhat negligible in the face of the time taken to produce and verify proofs in the first place.

\textbf{Message format.} Another solution is to use a more compact message format, for example msgpack \cite{msgpack} (which also has native support for binary literals).

\textbf{Smaller key size.} The size of ciphertexts depends directly on the size of the key. Using a smaller key will reduce the size of the ciphertexts linearly.

\subsection{Time complexity}

Theoretic timing results versus RSA are backed experimentally by the implementation. The following benchmarking code was executed.

\begin{minted}{javascript}
    console.log("Warming up")

    for (let i = 0n; i < 100n; i++) {
        keyPair.pubKey.encrypt(i);
    }

    console.log("Benching")

    performance.mark("start")
    for (let i = 0n; i < 250n; i++) {
        keyPair.pubKey.encrypt(i);
    }
    performance.mark("end")

    console.log(performance.measure("duration", "start", "end").duration)
\end{minted}

Performing 250 Paillier encrypts required 47,000ms. On the other hand, performing 250 RSA encrypts required just 40ms. Results are shown in \hyperref[table1]{Table~\ref*{table1}}.

The speed of decryption is considerably less important in this circumstance, as Paillier ciphertexts are not decrypted during the execution of the program.

Some potential further optimisations to the implementation are as follows.

\textbf{Caching.} As the main values being encrypted are 0 or 1, a peer could maintain a cache of encryptions of these values and transmit these instantly. Caching may be executed in a background "web worker". A consideration is whether a peer may be able to execute a timing-related attack by first exhausting a peer's cache of a known plaintext value, and then requesting an unknown value and using the time taken to determine if the value was sent from the exhausted cache or not.

\textbf{Smaller key size.} The complexity of Paillier encryption increases with key size. Using a smaller key could considerably reduce the time taken \cite{paillier1999public}.

I tested this on top of the alternative Paillier scheme from above. This resulted in linear reductions in encryption time: encryption under a 1024-bit modulus took a sixth of the amount of time as under a 2048-bit modulus, and encryption under a 2048-bit modulus took a sixth of the amount of time as under a 4096-bit modulus.

\textbf{Vectorised plaintexts.} The maximum size of a plaintext is $|n|$: in our case, this is 4096 bits. By considering this as a vector of 128 32-bit values, peers could use a single ciphertext to represent their entire state. This process is discussed as a way to allow embedded devices to use Paillier encryption \cite{10.1145/2809695.2809723}.

\hyperref[protocol1]{Protocol~\ref*{protocol1}} can be modified by instead testing that the given ciphertext is contained in a set of valid ciphertexts. There would still be a large number of Paillier encryptions required during this proof.

However, the other proofs do not translate so trivially to this structure. In fact, in some contexts the proofs required may be considerably more complicated, which may be slower and use more Paillier encryptions to achieve the same effect.

\textbf{Optimising language.} An optimising language may be able to reduce the time taken to encrypt. On the browser, this could involve using WASM as a way to execute compiled code within the browser, although WASM does not always outperform JavaScript \cite{wasm}.

Another approach is to use a web extension to communicate with a system daemon providing the relevant functionality. This is language-agnostic (except that the extension itself must be JavaScript), and the daemon could take advantage of other system features such as multiple cores. The multi-round proofs in particular are embarrassingly parallel, as each round is independent of the other rounds.

\subsection{Complexity results}

All measurements were taken on Brave 1.50.114 (Chromium 112.0.5615.49) 64-bit, using a Ryzen 5 3600 CPU: a consumer CPU from 2019. Absolute timings are extremely dependent on the browser engine: for example Firefox 111.0.1 was typically 4 times slower than the results shown.

\begin{landscape}

\begin{table}
	\fontsize{10pt}{10pt}\selectfont
	\caption{Time to encrypt}
    \label{table1}
	\begin{tabularx}{\hsize}{c *4{>{\Centering}X}}
		\toprule
		Modulus & Paillier encrypt & Jurik encrypt & Jurik encrypt with pre-computation & RSA encrypt \\
		\midrule
		$|n| = 1024$   & 6ms & 4ms & 1.4ms & 0.015ms \\
		$|n| = 2048$   & 34ms & 22ms & 7.6ms & 0.040ms \\
		$|n| = 4096$   & 190ms & 130ms & -- & 0.093ms \\
		\bottomrule
	\end{tabularx}
\end{table}

\begin{table}
	\fontsize{10pt}{10pt}\selectfont
	\caption{Time\parnote{$|n| = 4096$ uses a less-optimised encryption method, as the browser frequently timed out attempting to pre-compute for the more-optimised version.} to process non-interactive proofs}
	\begin{tabularx}{\hsize}{c *8{>{\Centering}X} *2{>{\Centering}X}}
		\toprule
		\multirow{2}{*}{Modulus} &
		\multicolumn{2}{c}{\hyperref[protocol0]{Protocol~\ref*{protocol0}}} &
		\multicolumn{2}{c}{\hyperref[protocol1]{Protocol~\ref*{protocol1}} with $t = 24$} &
		\multicolumn{2}{c}{BCDG Range with $t = 24$} &
		\multicolumn{2}{c}{\hyperref[protocol4]{Protocol~\ref*{protocol4}} with $t = 24$} &
		\multicolumn{2}{c}{\hyperref[protocol3]{Protocol~\ref*{protocol3}} with $t = 24$}
		\tabularnewline
		\cmidrule(l){2-3}\cmidrule(l){4-5}\cmidrule(l){6-7}\cmidrule(l){8-9}\cmidrule(l){10-11}
		& Prover & Verifier & Prover & Verifier & Prover & Verifier & Prover & Verifier & Prover & Verifier \\
		\midrule
		$|n| = 1024$ & 10ms & 18ms & 1,420ms & 2,140ms & 443ms & 655ms & 3,530ms & 5,310ms & 1,350ms & 2,070ms \\
		$|n| = 2048$ & 44ms & 68ms & 6,390ms & 8,140ms & 1,980ms & 2,400ms & 15,800ms & 19,000ms & 5,800ms & 7,790ms \\
		$|n| = 4096$ & 225ms & 292ms & 41,500ms & 34,400ms & 14,300ms & 11,400ms & 112,000ms & 79,300ms & 40,500ms & 29,100ms \\
		\bottomrule
	\end{tabularx}
	\parnotes
\end{table}

\begin{table}
	\fontsize{10pt}{10pt}\selectfont
	\caption{Byte size\parnote{1 UTF-16 character, as used by ECMAScript \cite[Section~6.1.4]{ecma2024262}, is 2 or more bytes.} of encoded non-interactive proofs}
    \label{table3}
	\begin{tabularx}{\hsize}{c *8{>{\Centering}X} *2{>{\Centering}X}}
		\toprule
		\multirow{2}{*}{Modulus} & \multicolumn{2}{c}{\hyperref[protocol0]{Protocol~\ref*{protocol0}}} &
		\multicolumn{2}{c}{\hyperref[protocol1]{Protocol~\ref*{protocol1}} with $t = 24$} &
		\multicolumn{2}{c}{BCDG Range with $t = 24$} &
		\multicolumn{2}{c}{\hyperref[protocol4]{Protocol~\ref*{protocol4}} with $t = 24$} &
		\multicolumn{2}{c}{\hyperref[protocol3]{Protocol~\ref*{protocol3}} with $t = 24$}
		\tabularnewline
		\cmidrule(l){2-3}\cmidrule(l){4-5}\cmidrule(l){6-7}\cmidrule(l){8-9}\cmidrule(l){10-11}
		& JSON & with LZ-String & JSON & with LZ-String & JSON & with LZ-String & JSON & with LZ-String & JSON & with LZ-String \\
		\midrule
		$|n| = 1024$ & 1,617B & 576B & 338,902B & 95,738B & 123,354B & 34,857B & 895,474B & 248,420B & 322,946B & 92,042B \\
		$|n| = 2048$ & 3,153B & 1,050B & 662,233B & 187,333B & 252,230B & 70,868B & 1,746,017B & 485,787B & 620,206B & 176,854B \\
		$|n| = 4096$ & 6,226B & 1,999B & 1,315,027B & 368,646B & 484,117B & 135,990B & 3,458,376B & 964,913B & 1,206,657B & 341,028B \\
		\bottomrule
	\end{tabularx}
	\parnotes
\end{table}

\end{landscape}

\chapter{Conclusions}

\section{Contributions}

This project has contributed an implementation of an optimised form of Paillier that is compatible with modern web browsers. Benchmarks show that, considering current hardware, Paillier in Jurik's form can be a viable cryptosystem for occasional use. However, additional work is required to make it efficient enough for large amounts of encryptions, as seen in \hyperref[protocol4]{Protocol~\ref*{protocol4}}.

The Paillier implementation provides capability for Schnorr-style proofs of knowledge and also multi-round proofs of knowledge, which serialise to JSON. These are made non-interactive by applying the SHAKE cryptographic hash suite.

Multi-round proofs combining set membership and graph isomorphism are among the implementations, and have strong zero-knowledge properties once used with the Fiat-Shamir transform.

\section{Domain}

The protocols devised are effective in the target domain of online games. With multi-round proofs of 24 rounds, players can be reasonably confident that other players are not cheating.

For the most part, the protocols shown run in a time-frame that would not disrupt the experience, with the exception of the bit length proof. With additional work, this proof could be replaced with a Bulletproof \cite{bulletproofs}, which may use less bandwidth and perform faster.

A large outstanding problem with the implementation is conflict resolution. Currently, if a player submits proofs that do not verify, other players simply ignore the message. However, a better solution would be to allow other players to remove a misbehaving player from the protocol.

\section{Wider application}

P2P software solutions have many benefits to end users: mainly being greater user freedom. I believe that the content presented here shows clear ways to extend P2P infrastructure, and reduce dependence on centralised services.

I propose some ideas which could build off the content here.

\subsection{Larger scale games}

Many other games exist that the ideas presented could be applied to. Games of larger scale with a similar structure, such as Unciv, could benefit from P2P networking implemented in a similar manner. In particular, similar protocols to \hyperref[protocol4]{Protocol~\ref*{protocol4}} would form an intrinsic part of such games, as they have a similar graph structure which requires guarantees of adjacency for many actions.

The downsides of this are that the complexity of P2P networking is far greater than in a centralised model. This would be a considerable burden on the developers, and could hurt the performance of such a game. Additionally, some modern routers no longer support NAT hole-punching or UPnP due to security concerns \cite{upnp}, which makes accessing P2P services more difficult for end users.

\subsection{Decentralised social media}

The schemes presented here could be applies to the concept of a decentralised social media platform. Such a platform may use zero-knowledge proofs as a way to allow for "private" profiles: the content of a profile may stay encrypted, but zero-knowledge proofs could be used as a way to allow certain users to view private content in a manner that allows for repudiation, and disallows one user from sharing private content to unauthorised users.

To store data, IPFS could be used. IPFS is a P2P data storage protocol \cite{ipfs}. This poses an advantage that users can store their own data, but other users can mirror data to protect against outages or users going offline. The amount of effective storage would also grow as more users join the network.

Decentralised platforms promote user privacy, as users can control their own data. Additionally, decentralised platforms promote standardisation of common operations such as instant messaging. This can include end-to-end encryption, and so confidentiality is then a choice of the user rather than the platform, and the consequences of backdoors or legislation targetting platforms is reduced.

Some P2P messaging standards already coexist that could be used here, for example Matrix and XMPP.

\subsection{Handling of confidential data}

The ability to prove the contents of a dataset to a second party without guaranteeing authenticity to a third party is another potential application of the protocol presented. Handling of confidential data is a critical concern for pharmaceutical companies, where a data leak imposes serious legal and competitive consequences for the company. To allow a second party to process data, some guarantee of the correctness of the data is required. Proofs are one way of achieving this, although other techniques such as keyed hashing may be more effective.

Another consideration in this domain is the use of homomorphic encryption schemes to allow a third party to process data without actually viewing the data. This protects the data from viewing by the third party, and the processing methods from viewing by the first party. For example, common statistical functions such as regression can be performed on data that is encrypted under fully homomorphic encryption schemes.

\section{Limitations}

\subsection{JavaScript}

JavaScript was the incorrect choice of language for this project. Whilst the event-based methodology was useful, I believe that JavaScript made development much more difficult.

JavaScript is a slow language. Prime generation takes a considerable amount of time, and this extends to encryption and decryption being slower than in an implementation in an optimising compiled language.

\begin{table}[H]
	\caption{Time to generate safe primes}
	\begin{tabularx}{\hsize}{c *2{>{\Centering}X}}
		\toprule
		 & My implementation & \texttt{openssl dhparam 512} \\
		\midrule
		$|p| = 512$  & 8,660ms & 66ms \\
		\bottomrule
	\end{tabularx}
\end{table}

JavaScript's type system makes debugging difficult. It is somewhat obvious that this problem is far worse in systems with more interacting parts. TypeScript may have been a suitable alternative, but most likely the easiest solution was to avoid both and go with a language that was designed with stronger typing in mind from the outset.

JavaScript is a re-entrant language: this means that the interpreter does not expose threads or parallelism to the developer, but it may still use threads under-the-hood and switch contexts to handle new events. This introduces the possibility of race conditions despite no explicit threading being used. The re-entrant nature is however beneficial to a degree, as it means that long-running code won't cause the WebSocket to close or block other communications from being processed.

Using a language that can interact with the operating system would have further advantages, as key generation can be performed by standard tools such as OpenSSL and stored in the system keychain, and features like SIMD could be utilised for parallelism.

\subsection{Resources}

The P2P implementation requires more processing power and more bandwidth on each peer than a client-server implementation would. This is the main limitation of the P2P implementation. The program ran in a reasonable time, using a reasonable amount of resources on the computers I had access to, but these are not representative of the majority of computers in use today. Using greater processing power increases power consumption, which is undesirable. In a client-server implementation, the power consumption should be lower than the P2P implementation presented as no processing time is spent validating proofs or using the Paillier cryptosystem, which is less efficient than the hybrid cryptosystems used in standard online communication.

\emph{Final word count: 9,086}

\bibliography{Dissertation}

\end{document}
