aaaaaaaaaaaaaaaaaa

This commit is contained in:
jude 2023-04-30 18:42:52 +01:00
parent 0fed48b79d
commit 9c6b251a25
12 changed files with 294 additions and 88 deletions

View File

@ -1,3 +1,14 @@
/**
* Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
* This work is free. You can redistribute it and/or modify it
* under the terms of the WTFPL, Version 2
* For more information see LICENSE.txt or http://www.wtfpl.net/
*
* For more information, the home page:
* http://pieroxy.net/blog/pages/lz-string/testing.html
*
* LZ-based compression algorithm, version 1.4.5
*/
var LZString = (function () {
var r = String.fromCharCode,
o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

View File

@ -1,6 +1,6 @@
import { mod_exp } from "./math.js";
export const KEY_SIZE = 1024;
export const KEY_SIZE = 512;
export function cryptoRandom(bits) {
if (bits === undefined) {
@ -90,7 +90,7 @@ function miller_rabin(n, k) {
export function generate_prime() {
while (true) {
let n = generate_bigint();
let n = generate_bigint() | 0b11n;
if (small_prime_test(n) && miller_rabin(n, 40)) {
return n;
}
@ -109,6 +109,8 @@ export function generate_safe_prime() {
}
}
window.generate_safe_prime = generate_safe_prime;
const SMALL_PRIMES = [
2n,
3n,

View File

@ -12,6 +12,7 @@ export class Game {
this.us = null;
this.players = {};
this.state = WAITING;
this.contendedRegion = null;
this.allPlaced = false;
}

View File

@ -165,6 +165,11 @@ document.addEventListener("ACT", async (ev) => {
}
});
document.addEventListener("RESOLVE", (ev) => {
const data = ev.detail;
game.contendedRegion.handleResolve(data);
});
// todo has to filter by player
document.addEventListener("PROOF", async (ev) => {
const data = ev.detail;

View File

@ -113,6 +113,10 @@ export class Region {
this.neighbours = new Set();
this.continent = continent;
this.attackResolver = null;
this.attackerRes = null;
this.defenderRes = null;
REGIONS[name] = this;
}
@ -172,6 +176,48 @@ export class Region {
verify(plainText, a) {
this.strength.verify(this.name, plainText, a);
}
async handleResolve(resolution) {
await navigator.locks.request(`region-${this.name}`, () => {
if (resolution.author === this.owner.id) {
this.defenderRes = resolution;
} else {
this.attackerRes = resolution;
}
if (
this.attackResolver !== null &&
this.defenderRes !== null &&
this.attackerRes !== null
) {
this.attackResolver({
attackerRes: this.attackerRes,
defenderRes: this.defenderRes,
});
}
});
}
async resolveAttack() {
let promise;
await navigator.locks.request(`region-${this.name}`, () => {
if (this.attackerRes === null || this.defenderRes === null) {
let resolver;
promise = new Promise((resolve) => {
resolver = resolve;
});
this.attackResolver = resolver;
} else {
promise = new Promise((resolve) => {
resolve({
attackerRes: this.attackerRes,
defenderRes: this.defenderRes,
});
});
}
});
return promise;
}
}
window.Region = Region;

View File

@ -161,4 +161,28 @@ export class Packet {
region: region,
});
}
static createRegionProof(proof) {
return this._sign({
...this._createBase("RESOLVE"),
action: "MAINTAIN",
proof: proof,
});
}
static createRegionYield() {
return this._sign({
...this._createBase("RESOLVE"),
action: "YIELD",
proof: proof,
});
}
static createRegionCapture(cipherText) {
return this._sign({
...this._createBase("RESOLVE"),
action: "CAPTURE",
cipherText: cipherText,
});
}
}

View File

@ -5,6 +5,7 @@ import { PaillierPubKey, ReadOnlyCiphertext } from "../crypto/paillier.js";
import { Region } from "./map.js";
import { showDefenseDom } from "./dom.js";
import {
proveBitLength,
proveFortify,
proveRange,
proveRegions,
@ -325,6 +326,8 @@ export class Player {
return false;
}
game.contendedRegion = defender;
// If we're the defender, we need to send a packet to state our defense.
if (defender.owner === game.us) {
showDefenseDom(defender.name);
@ -340,8 +343,6 @@ export class Player {
defenderStrength = await defender.owner.getDefense();
}
console.log(defenderStrength);
/* How do Risk attacks work?
- Offender signs 1-3 armies, defender signs 1-2 armies
- Both roll respective dice
@ -387,10 +388,16 @@ export class Player {
// Handle aftermath.
if (defender.owner === game.us) {
if (defender.strength.cipherText.plainText === 0n) {
// Handle region loss
// State we don't control the region. This makes programming easier.
socket.emit("message", Packet.createRegionYield());
} else {
let ct = defender.strength.cipherText.clone();
ct.update(new Ciphertext(ct.pubKey, -2n, 0n));
// Prove we still control the region
let proof = proveRange(defender.strength.cipherText, 2n ** 32n);
let proof = proveBitLength(ct);
// Send proof we maintain it
socket.emit("message", Packet.createRegionProof(proof));
}
} else if (this === game.us) {
if (defender.strength.assumedStrength === 0n) {
@ -400,14 +407,29 @@ export class Player {
new Ciphertext(this.paillierPubKey, offenderRolls.length + 1),
defender.name
);
// Send the new ciphertext
socket.emit(
"message",
Packet.createRegionCapture(defender.strength.cipherText)
);
} else {
// State we didn't capture. Again, makes programming easier.
socket.emit("message", Packet.createRegionYield());
}
} else {
await defender.resolveConflict();
let resolutions = await defender.resolveAttack();
console.log(resolutions);
}
// Reset the promises in case they attack again.
defender.owner.defenderPromise = null;
defender.owner.defenderAmount = null;
defender.defenderRes = null;
defender.attackerRes = null;
defender.attackResolver = null;
game.contendedRegion = null;
}
async setDefense(amount) {

View File

@ -1,7 +1,7 @@
import { cryptoRandom } from "../crypto/random_primes.js";
import { Region } from "./map.js";
const ROUNDS = 24;
const ROUNDS = 12;
function cryptoRange(upper) {
// This is ridiculous: why implement a BigInt primitive, have it behave like a number, and then _not_ offer

View File

@ -7,7 +7,7 @@
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<script src="{{ url_for('static', filename='js/lz-string.js') }}"></script>
<script src="{{ url_for('static', filename='js/lz-string.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/sha3.js') }}"></script>
<script src="{{ url_for('static', filename='js/modules/interface/main.js') }}" type="module"></script>
<script src="{{ url_for('static', filename='js/modules/crypto/main.js') }}" type="module"></script>
@ -423,6 +423,24 @@
console.log(`Bench done. Time per verification: ${performance.measure("rv-duration", "rv-start", "rv-end").duration / ROUNDS}`)
}
function PrimeBench() {
const ROUNDS = 20;
for (let i = 0; i < 2; i++) {
generate_safe_prime()
}
console.log("Benching")
performance.mark("p-start")
for (let i = 0; i < ROUNDS; i++) {
generate_safe_prime()
}
performance.mark("p-end")
console.log(`Bench done. Time per generation: ${performance.measure("p-duration", "p-start", "p-end").duration / ROUNDS}`)
}
// https://gist.github.com/kawanet/352a2ed1d1656816b2bc
function string_to_buffer(src) {
return (new Uint16Array([].map.call(src, function(c) {
@ -455,6 +473,31 @@
};
}
function FortifySize() {
const regions = {
A: paillier.pubKey.encrypt(0n),
B: paillier.pubKey.encrypt(3n),
C: paillier.pubKey.encrypt(-3n),
D: paillier.pubKey.encrypt(0n),
E: paillier.pubKey.encrypt(0n)
}
let ROUNDS = 10;
let size = 0;
let compressedSize = 0;
for (let x = 0; x < ROUNDS; x++) {
let s = JSON.stringify(proveFortify(regions));
size += string_to_buffer(s).byteLength;
compressedSize += LZString.compressToUint8Array(s).length;
}
return {
size: size / ROUNDS,
compressedSize: compressedSize / ROUNDS
};
}
function BitLengthSize() {
const ct = paillier.pubKey.encrypt(5n)
let ROUNDS = 10;

View File

@ -465,3 +465,18 @@ doi={10.1109/SP.2014.36}}
pages = {},
title = {Bulletproofs: A Non-Interactive Zero Knowledge Proof Protocol For Blockchain Security}
}
@article{bittorrent2008,
author = {Williams, Christopher},
date = {2008-06-02},
title = {{UK cops arrest six alleged BitTorrent music uploaders}},
journal = {The Register},
url = {https://www.theregister.com/2008/06/02/onk_further_arrests},
urldate = {2008-06-02}
}
@misc{bch,
author = {Bitcoin Cash},
title = {{Bitcoin Cash -- Peer-to-peer Electronic Cash}},
howpublished = {\url{https://bitcoincash.org}}
}

Binary file not shown.

View File

@ -109,7 +109,7 @@ For playing games over an internet connection, multiple solutions already exist.
\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, playable as an app.
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.
@ -117,11 +117,27 @@ Without patching the executables, there is no way for a user to run their own se
\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 platform operators may be forced to invade the privacy of their users, and consequences are felt by the platform and not the user.
\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}
In peer-to-peer (P2P) networks, traffic may be routed directly to other peers, or servers may be operated by third parties (sometimes called "federated networks"). This form of communication is 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.
There are two alternatives to traditional centralised networks: peer-to-peer (P2P) and federated.
The main advantage of P2P networks over centralised networks is longevity. Games such as Unreal Tournament 99 (which is now federated) 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}.
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 can result in legal consequence against users themselves rather than the platform \cite{bittorrent2008}.
\item \textbf{Ownership.} Games such as Unreal Tournament 99 (which is now federated) 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}.
\end{itemize}
However, security can often be worse in fully P2P networks than that of fully centralised networks. Peers may send malicious communications, or behave in ways that violate the general rules of the service. As there is no trusted server, there is no easy way to validate communications to prevent peers from cheating.
@ -131,13 +147,13 @@ Some P2P services try to address issues with security. In file-sharing protocols
Currently, there exists an online centralised version of the board game Risk.
I aim to apply bit-commitment schemes, zero-knowledge proofs, and homomorphic encryption to an online P2P variant of Risk, to 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.
We aim to apply bit-commitment schemes, zero-knowledge proofs, and homomorphic encryption to an online P2P variant of Risk, to 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.
\section{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, something else must be done to simulate the randomness.
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 dice rolling, we want that \begin{itemize}
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}
@ -151,7 +167,7 @@ Bit-commitment schemes provide a mechanism for one party to commit to some hidde
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 some well-known one-way function, such as SHA, with randomly generated salts.
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.
\subsubsection{Bit-commitment with one-way functions}
@ -163,9 +179,9 @@ Bit-commitment schemes can also be implemented using one-way functions: \begin{e
\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 though to generate numbers in the range of 1-6, as 6 is not a power of 2.
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, and nicely generalises Blum's original paper.
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.
\subsection{Zero-knowledge proofs}
@ -196,7 +212,7 @@ Zero-knowledge proofs are particularly applicable to the presented problem. They
\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. This relies strongly upon the random-oracle model however \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.
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.
\subsubsection{Games as graphs}
@ -216,7 +232,7 @@ The main game protocol can be considered as the following graph mutations for a
\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 then to identify ways to secure this protocol by obscuring the edges and weights, whilst preventing the ability for the player to cheat.
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.
\subsubsection{Graphs \& zero-knowledge proofs}
@ -226,7 +242,7 @@ Identifying Risk as a graph therefore enables us to construct isomorphisms as pa
\subsubsection{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 wish to obscure values of tokens within the system.
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}.
@ -250,16 +266,16 @@ In general, this approach uses a decomposition of the plaintext message $m$ into
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*}
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 $r \in \mathbb{Z}^*_{n^2}$.
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, as 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 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. Many optimisations have been presented of the Paillier cryptosystem.
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$ by binomial theorem.
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
@ -276,9 +292,9 @@ Jurik states that the optimised form can lead to a theoretic four times speedup
\subsubsection{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, clearly, proving a summation $a + b = v$ can be performed by proving $v - a - b = 0$ in an additive homomorphic 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.
So, using some such scheme to obscure edge weights should enable verification of the edge values without revealing their actual values.
Therefore, using Paillier's scheme to obscure edge weights should enable verification of the edge values without revealing their actual values.
\subsubsection{Reducing communication}
@ -291,7 +307,7 @@ An alternative general protocol is the $\Sigma$-protocol \cite{groth2004honest}.
\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, which results in simpler network code.
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.
@ -308,7 +324,10 @@ In particular, the final point allows for the use of purely JSON messages, which
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{tikzpicture}[every node/.style={anchor=north west,minimum height=20pt}]
\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,
@ -431,15 +450,16 @@ The game is broken down into three main stages, each of which handles events in
\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{landscape}
\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}, and \texttt{ACT}. 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.
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} is used by players to submit actions for their turn during gameplay.
\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.
@ -451,13 +471,31 @@ ECMAScript typically stores integers as floating point numbers, giving precision
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, and operates frequently on secret data. A savvy attacker may be able to use this to leak information about an adversary's private key; however, as decryption is not performed, this risk is considerably reduced as there is less need to perform optimisations based on Chinese remainder theorem which would require treating the modulus $n$ as its two components $p$ and $q$.
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}
\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 of bit length $L$, somewhere between $L$ and $2L$ multiply-and-modulo operations are performed, which gives overall a logarithmic time complexity supposing bit-shifts and multiply-and-modulo are constant time operations.
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}
@ -485,9 +523,9 @@ As the prime generation routine generates primes of equal length, this property
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 to perform exponentiation, exponentiation also does not require auxiliary memory to store intermediary values used in the calculation.
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. One method to guarantee this is to use safe primes, which are primes of form $2p+1$ for $p$ prime.
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$
@ -525,23 +563,7 @@ In the original Paillier scheme, ciphertexts are computed as $E(m, r) = c = g^m
\end{align*}
Jurik remarks that $E'(m, r) = E(m, h^r \bmod n)$.
To achieve a better speed-up, pre-computation of the fixed base $h^n \bmod n$ is used. By pre-computing powers of the powers of two, exponentiation is reduced to at most $|r|$ multiplications. Let $h[i] = h^{(2^i)} \bmod n$. 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}
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}
@ -557,11 +579,11 @@ Let $c$ be the ciphertext. The corresponding plaintext is computed as \begin{ali
\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. This makes it capable of proving by the scheme presented below.
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, some fair protocol must be used to generate random values consistently across each peer without any peer being able to manipulate the outcomes.
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 through bit-commitment and properties of $\mathbb{Z}_n$. The protocol for two peers is as follows, and generalises to $n$ peers.
@ -595,9 +617,9 @@ This is achieved through bit-commitment and properties of $\mathbb{Z}_n$. The pr
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 turned into a random value within a 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. To combine noises, then use the XOR operation.
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 to prevent a malicious party creating a ciphertext which decrypts to multiple valid values through using different keys.
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.
@ -617,11 +639,11 @@ The encryption function used must also guarantee the integrity of decrypted ciph
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{Resampling}
\subsection{Modular bias}
A common approach is to take the modulus of the random noise. This causes modular bias to appear however, where some values are less likely to be generated.
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.
The typical way to avoid modular bias is 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}$.
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}
@ -630,7 +652,7 @@ Random values are used in two places. \begin{itemize}
\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. This has another benefit as the unique name can then be used with the Web Locks API to prevent race conditions that may occur due to this protocol running asynchronously.
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}
@ -680,7 +702,7 @@ The first proof to discuss is the honest-verifier protocol to prove knowledge th
\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} \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.
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.
@ -853,7 +875,7 @@ Validating $E(m)$ is done with the proof of zero. Then it remains to prove that
\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 5$.
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.
@ -1032,7 +1054,7 @@ We can apply the Fiat-Shamir heuristic to make proofs of zero non-interactive \c
\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 many times.}
\caption{An example turn during the game incorporates each of the protocols presented above, some multiple times.}
\end{figure}
\chapter{Review}
@ -1041,11 +1063,11 @@ We can apply the Fiat-Shamir heuristic to make proofs of zero non-interactive \c
\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 hypothesis, a machine cannot produce infinite truly random output with only finite input.
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: a necessary property when constructing non-interactive proofs in order to prevent a prover manipulating the signature used to derive the proof.
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}
@ -1053,7 +1075,7 @@ Paillier is broken if factoring large numbers is computationally feasible \cite[
\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, and a malicious verifier may be able to extract additional information from the prover (such as the blinding value used).
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}
@ -1068,13 +1090,13 @@ The interactive proof of zero uses two Paillier ciphertexts (each size $2|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 this value may exceed what can be placed within a processor's cache, leading to potential slowdown during verification.
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.
This is all 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 this are shown in \hyperref[table3]{Table~\ref*{table3}}. Some potential solutions are discussed here.
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, but this is somewhat negligible in the face of the time taken to produce and verify proofs in the first place.
\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).
@ -1082,7 +1104,7 @@ This is all in an ideal situation without compression or signatures: in the impl
\subsection{Time complexity}
Theoretic timing results versus RSA are backed experimentally by my implementation. The following benchmarking code was executed.
Theoretic timing results versus RSA are backed experimentally by the implementation. The following benchmarking code was executed.
\begin{minted}{javascript}
console.log("Warming up")
@ -1118,7 +1140,7 @@ I tested this on top of the alternative Paillier scheme from above. This resulte
\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.
The other proofs do not translate so trivially to this structure however. In fact, in some contexts the proofs required may be considerably more complicated, becoming round-based proofs which may be slower and use more Paillier encryptions to achieve the same effect.
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}.
@ -1140,7 +1162,7 @@ All measurements were taken on Brave 1.50.114 (Chromium 112.0.5615.49) 64-bit, u
\midrule
$|n| = 1024$ & 6ms & 4ms & 1.4ms & 0.015ms \\
$|n| = 2048$ & 34ms & 22ms & 7.6ms & 0.040ms \\
$|n| = 4096$ & 189ms & 128ms & -- & 0.093ms \\
$|n| = 4096$ & 190ms & 130ms & -- & 0.093ms \\
\bottomrule
\end{tabularx}
\end{table}
@ -1162,7 +1184,7 @@ All measurements were taken on Brave 1.50.114 (Chromium 112.0.5615.49) 64-bit, u
\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 & & \\
$|n| = 4096$ & 225ms & 292ms & 41,500ms & 34,400ms & 14,300ms & 11,400ms & 112,000ms & 79,300ms & 40,500ms & 29,100ms \\
\bottomrule
\end{tabularx}
\parnotes
@ -1172,16 +1194,20 @@ All measurements were taken on Brave 1.50.114 (Chromium 112.0.5615.49) 64-bit, u
\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}}
\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$}
\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}
& JSON & with LZ-String & JSON & with LZ-String & JSON & with LZ-String & JSON & with LZ-String \\
\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 \\
$|n| = 2048$ & 3,153B & 1,050B & 662,233B & 187,333B & 252,230B & 70,868B & 1,746,017B & 485,787B \\
$|n| = 4096$ & 6,226B & 1,999B & 1,315,027B & 368,646B & 484,117B & 135,990B & 3,458,376B & 964,913B \\
$|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
@ -1193,7 +1219,7 @@ All measurements were taken on Brave 1.50.114 (Chromium 112.0.5615.49) 64-bit, u
\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 needed to make it efficient enough for large amounts of encryptions, as seen in \hyperref[protocol4]{Protocol~\ref{protocol4}}.
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.
@ -1201,11 +1227,11 @@ Multi-round proofs combining set membership and graph isomorphism are among the
\section{Domain}
The protocols devised are effective in the target domain of online games. With multi-round proofs of 24 rounds, players can be confident to a reasonably high probability that other players are not trying to cheat.
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 should be that the other players can decide to remove a misbehaving player from the protocol.
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}
@ -1239,9 +1265,20 @@ Another consideration in this domain is the use of homomorphic encryption scheme
\subsection{JavaScript}
JavaScript was the incorrect choice of language for this project. Whilst the event-based methodology was useful, I believe overall that JavaScript made development much more difficult.
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. This was seen in the results shown before.
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.