show action list and remaining placements on a turn
This commit is contained in:
parent
9ffd43e944
commit
b3fd23bba2
@ -76,7 +76,7 @@
|
||||
top: -20px;
|
||||
}
|
||||
|
||||
.action {
|
||||
.actions {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
}
|
||||
|
@ -2,18 +2,18 @@ function unlockMapDom() {
|
||||
Object.values(REGIONS).forEach((region) => {
|
||||
if (!allRegionsClaimed() && region.owner === null) {
|
||||
document
|
||||
.querySelector(`.node[data-name=${region.name}] .action`)
|
||||
.querySelector(`.node[data-name=${region.name}] .actions`)
|
||||
.classList.remove("hidden");
|
||||
} else if (region.owner === us) {
|
||||
document
|
||||
.querySelector(`.node[data-name=${region.name}] .action`)
|
||||
.querySelector(`.node[data-name=${region.name}] .actions`)
|
||||
.classList.remove("hidden");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function lockMapDom() {
|
||||
document.querySelectorAll(".action").forEach((e) => e.classList.add("hidden"));
|
||||
document.querySelectorAll(".actions").forEach((e) => e.classList.add("hidden"));
|
||||
}
|
||||
|
||||
function updateDom() {
|
||||
@ -33,8 +33,32 @@ function updateMapDom() {
|
||||
lockMapDom();
|
||||
}
|
||||
|
||||
if (gameState === PRE_GAME) {
|
||||
if (allRegionsClaimed()) {
|
||||
document.querySelectorAll(".action").forEach((e) => (e.textContent = "Reinf."));
|
||||
document
|
||||
.querySelectorAll(".actions button")
|
||||
.forEach((e) => (e.textContent = "Reinf."));
|
||||
}
|
||||
} else if (gameState === PLAYING) {
|
||||
document.querySelectorAll(".node").forEach((e) => {
|
||||
e.querySelectorAll(".game-action").forEach((el) => {
|
||||
el.remove();
|
||||
});
|
||||
|
||||
let region = Region.getRegion(e.dataset["name"]);
|
||||
for (let n of region.neighbours) {
|
||||
let b = document.createElement("button");
|
||||
b.classList.add("game-action");
|
||||
if (n.owner === us) {
|
||||
b.classList.add("fortify");
|
||||
b.textContent = `Fortify ${n.name}`;
|
||||
} else {
|
||||
b.classList.add("attack");
|
||||
b.textContent = `Attack ${n.name}`;
|
||||
}
|
||||
e.querySelector(".actions").appendChild(b);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (let region of Object.values(REGIONS)) {
|
||||
@ -100,7 +124,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll(".action").forEach((el) =>
|
||||
document.querySelectorAll(".actions button").forEach((el) =>
|
||||
el.addEventListener("click", (ev) => {
|
||||
let region = ev.target.closest(".node").dataset.name;
|
||||
socket.emit("message", Packet.createRegionClaim(region));
|
||||
@ -116,10 +140,16 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
});
|
||||
|
||||
function showRemainingReinforcements() {
|
||||
if (!allPlaced) {
|
||||
if (gameState === PRE_GAME) {
|
||||
document.querySelector(
|
||||
"#remaining-reinforcements"
|
||||
).innerHTML = `<span>Remaining placements: ${reinforcementsRemaining()}</span>`;
|
||||
} else if (gameState === PLAYING) {
|
||||
document.querySelector(
|
||||
"#remaining-reinforcements"
|
||||
).innerHTML = `<span>Remaining placements: ${
|
||||
currentPlayer().reinforcementsAvailable - currentPlayer().reinforcementsPlaced
|
||||
}</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameState === PRE_GAME) {
|
||||
if (!allRegionsClaimed()) {
|
||||
// Claim a region in the pregame.
|
||||
if (currentPlayer().claim(data)) {
|
||||
@ -91,6 +92,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
if (currentPlayer().reinforce(data)) {
|
||||
currentPlayer().endTurn();
|
||||
}
|
||||
}
|
||||
|
||||
if (allReinforcementsPlaced()) {
|
||||
gameState = PLAYING;
|
||||
updateDom();
|
||||
}
|
||||
} else {
|
||||
if (currentPlayer().act(data)) {
|
||||
currentPlayer().endTurn();
|
||||
|
@ -52,6 +52,21 @@ const H = new Region("H", WEST);
|
||||
const I = new Region("I", WEST);
|
||||
const E = new Region("E", WEST);
|
||||
|
||||
Region.setNeighbours(A, B);
|
||||
Region.setNeighbours(A, C);
|
||||
Region.setNeighbours(B, C);
|
||||
Region.setNeighbours(B, J);
|
||||
Region.setNeighbours(C, D);
|
||||
Region.setNeighbours(C, F);
|
||||
Region.setNeighbours(E, J);
|
||||
Region.setNeighbours(E, I);
|
||||
Region.setNeighbours(E, H);
|
||||
Region.setNeighbours(F, J);
|
||||
Region.setNeighbours(F, G);
|
||||
Region.setNeighbours(G, H);
|
||||
Region.setNeighbours(G, I);
|
||||
Region.setNeighbours(H, I);
|
||||
|
||||
function allRegionsClaimed() {
|
||||
return Object.values(REGIONS).find((region) => region.owner === null) === undefined;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
PHASE_REINFORCE = 1;
|
||||
PHASE_ATTACK = 1;
|
||||
PHASE_FORTIFY = 1;
|
||||
const PHASE_REINFORCE = 1;
|
||||
const PHASE_ATTACK = 2;
|
||||
const PHASE_FORTIFY = 3;
|
||||
|
||||
class Player {
|
||||
constructor(id, name) {
|
||||
|
@ -52,52 +52,72 @@
|
||||
<div class="node east" data-name="A" style="left: 280px;">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">A</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node east" data-name="B" style="left: 160px;">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">B</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node east" data-name="C" style="left: 220px; top: -200px;">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">C</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node east" data-name="D" style="left: 380px; top: -200px;">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">D</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node west" data-name="E" style="left: -40px; top: 140px;">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">E</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node west" data-name="F" style="left: -40px; top: -140px;">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">F</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node west" data-name="G" style="left: -280px; top: -80px;">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">G</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node west" data-name="H" style="left: -280px; top: 80px;">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">H</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node west" data-name="I" style="left: -180px;">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">I</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node east" data-name="J" style="">
|
||||
<div class="strength"><strong>U</strong></div>
|
||||
<div class="label">J</div>
|
||||
<button class="action">Claim</button>
|
||||
<div class="actions">
|
||||
<button>Claim</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
BIN
whitepaper/demonstration/carbon.png
Normal file
BIN
whitepaper/demonstration/carbon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
BIN
whitepaper/demonstration/miller-rabin.png
Normal file
BIN
whitepaper/demonstration/miller-rabin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
BIN
whitepaper/demonstration/paillier.png
Normal file
BIN
whitepaper/demonstration/paillier.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
whitepaper/demonstration/pailliercode.png
Normal file
BIN
whitepaper/demonstration/pailliercode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 76 KiB |
Binary file not shown.
@ -28,9 +28,9 @@
|
||||
\item In this variant, players can only see the number of troops stationed within regions they neighbour.
|
||||
\item This variant is therefore only played online, in a \textbf{trusted setup}.
|
||||
\end{itemize}
|
||||
\begin{center}
|
||||
\begin{center}
|
||||
\includegraphics[width=6cm]{fog-of-war}
|
||||
\end{center}
|
||||
\end{center}
|
||||
\end{frame}
|
||||
\begin{frame}{Proposition}
|
||||
\begin{itemize}
|
||||
@ -40,10 +40,10 @@
|
||||
\end{frame}
|
||||
\begin{frame}{Rationale}
|
||||
\begin{itemize}
|
||||
\item \textbf{Federation} \begin{itemize}
|
||||
\item Federated platforms can have longer lifespans than centralised platforms.
|
||||
\item Federated platforms are more resistant to censorship and can help promote anonymity and privacy.
|
||||
\item Federated platforms encourage user freedom.
|
||||
\item \textbf{Decentralised} \begin{itemize}
|
||||
\item Longer lifespans than centralised platforms.
|
||||
\item More resistant to censorship and can help promote anonymity and privacy.
|
||||
\item Encourages user freedom.
|
||||
\end{itemize}
|
||||
\item \textbf{Security} \begin{itemize}
|
||||
\item Constantly looking for ways to secure against threats specific to federated and decentralised infrastructures.
|
||||
@ -56,8 +56,8 @@
|
||||
\item Private key encryption.
|
||||
\item Signatures.
|
||||
\item Additive homomorphic encryption.
|
||||
\item \textbf{Web platform}. Rapidly evolving.
|
||||
\item \textbf{Monero, Zcash}. Decentralised ledgers respectively using the \textit{Bulletproof} and \textit{ZK-SNARK} zero-knowledge proof systems.
|
||||
\item \textbf{Web platform}.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
\begin{frame}{Results}
|
||||
@ -68,9 +68,16 @@
|
||||
\end{frame}
|
||||
\begin{frame}{Results}
|
||||
Generating large primes using ECMAScript \texttt{BigInt} and Rabin-Miller.
|
||||
\begin{tabular}{cc}
|
||||
\includegraphics[width=5cm]{random2048} & \includegraphics[width=5cm]{carbon} \\
|
||||
\multicolumn{2}{c}{\includegraphics[width=65mm]{miller-rabin} }
|
||||
\end{tabular}
|
||||
\end{frame}
|
||||
\begin{frame}{Results}
|
||||
Implementation of the Paillier additive homomorphic cryptosystem.
|
||||
\begin{center}
|
||||
\includegraphics[width=11cm]{paillier}
|
||||
\end{center}
|
||||
\end{frame}
|
||||
\begin{frame}{Results}
|
||||
Implementation of Risk.
|
||||
|
BIN
whitepaper/demonstration/random2048.png
Normal file
BIN
whitepaper/demonstration/random2048.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 79 KiB |
BIN
whitepaper/demonstration/speech.pdf
Normal file
BIN
whitepaper/demonstration/speech.pdf
Normal file
Binary file not shown.
146
whitepaper/demonstration/speech.tex
Normal file
146
whitepaper/demonstration/speech.tex
Normal file
@ -0,0 +1,146 @@
|
||||
\documentclass[a4paper,7pt]{report}
|
||||
|
||||
\usepackage[a4paper,margin=2.6cm]{geometry}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{amssymb}
|
||||
\usepackage{algorithm}
|
||||
\usepackage{algorithmic}
|
||||
\usepackage{mathtools}
|
||||
\usepackage[english]{babel}
|
||||
\usepackage{amsthm}
|
||||
\usepackage{enumitem}
|
||||
\usepackage{xifthen}
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{float}
|
||||
|
||||
\usepackage{tikz}
|
||||
\usetikzlibrary{arrows,shapes,automata,positioning}
|
||||
\tikzset{baseline=(current bounding box.north),node distance=2cm}
|
||||
|
||||
\pagestyle{fancy}
|
||||
\fancyhf{}
|
||||
\fancyhead[RE,LO]{}
|
||||
\fancyhead[LE,RO]{\thepage}
|
||||
|
||||
\newcommand{\func}[3]{#1 : #2 \to #3}
|
||||
\newcommand{\subspace}[2]{#1 \leqslant #2}
|
||||
\newcommand{\nbasis}[3][1]{#2_{#1}, \dots, #2_{#3}}
|
||||
\newcommand{\nsum}[2]{#1_1 + \dots + #1_{#2}}
|
||||
\newcommand{\ndirect}[2]{#1_1 \oplus \dots \oplus #1_{#2}}
|
||||
|
||||
\makeatletter
|
||||
\newcommand*{\encircled}[1]{\relax\ifmmode\mathpalette\@encircled@math{#1}\else\@encircled{#1}\fi}
|
||||
\newcommand*{\@encircled@math}[2]{\@encircled{$\m@th#1#2$}}
|
||||
\newcommand*{\@encircled}[1]{%
|
||||
\tikz[baseline,anchor=base]{\node[draw,ellipse,outer sep=0pt,inner sep=.2ex] {#1};}}
|
||||
\makeatother
|
||||
|
||||
\newcommand{\field}{\mathbb{F}}
|
||||
\newcommand{\nat}{\mathbb{N}}
|
||||
\newcommand{\z}{\mathbb{Z}}
|
||||
\newcommand{\real}{\mathbb{R}}
|
||||
\newcommand{\rat}{\mathbb{Q}}
|
||||
\newcommand{\complex}{\mathbb{C}}
|
||||
\newcommand{\quat}{\mathbb{H}}
|
||||
|
||||
\newtheorem{theorem}{Theorem}[chapter]
|
||||
\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}
|
||||
|
||||
\DeclareMathOperator{\im}{im}
|
||||
\DeclareMathOperator{\jnf}{JNF}
|
||||
\DeclareMathOperator{\res}{Res}
|
||||
\DeclareMathOperator{\rank}{rank}
|
||||
\DeclareMathOperator{\rad}{rad}
|
||||
\DeclareMathOperator{\sol}{sol}
|
||||
\DeclareMathOperator{\ann}{ann}
|
||||
\DeclareMathOperator{\vecspan}{span}
|
||||
\DeclareMathOperator{\diam}{diam}
|
||||
\DeclareMathOperator{\id}{id}
|
||||
|
||||
\title{}
|
||||
\author{}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\subsection{slide1}
|
||||
|
||||
Risk is a popular strategy game in which competing players aim to control all regions on a board by moving pieces and attempting to overthrow neighbouring regions.
|
||||
|
||||
Each region within a player's control has some number of pieces placed onto it. To attack a neighbouring region, a player gambles some of their pieces against the opposing player's pieces.
|
||||
|
||||
Risk was originally a board game, but has since been turned into an online game as well.
|
||||
|
||||
\subsection{slide2}
|
||||
|
||||
In the online variant, there is a mode known as "fog of war", where players can only see the number of pieces that are placed on neighbouring regions. Therefore, this is only played online and in a trusted setup, with players communicating indirectly via a server.
|
||||
|
||||
\subsection{slide3}
|
||||
|
||||
My proposition is to play fog-of-war risk in an untrusted setup, for example in a peer-to-peer network. The same guarantees should be made as in the trusted setup, but without the mediating party (which is the server).
|
||||
|
||||
\subsection{slide4}
|
||||
|
||||
Besides cryptography and decentralised networks being of personal interest, there are further benefits to the expansion of cryptographic methods and their applications to federated platforms.
|
||||
|
||||
decentralised platforms offer many benefits to their users, such as longer lifespans due to being community-ran. A good example of this is networks such as usenets and IRC outlasting many social media platforms, as they still have a community backing them.
|
||||
|
||||
Additionally, decentralised platforms are more resistant to censorship, as they are run by their users, and can be run from any jurisdiction, to avoid laws that may restrict the operation of platforms in certain countries. This also helps promote anonymity and privacy, as the platform isn't being run by a company that may have a legal obligation to collect certain information, or may just collect information for the sake of it.
|
||||
|
||||
Finally, the main benefit is that decentralised platforms promote user freedoms, as the code can be modified and audited to tailor it to the user's needs.
|
||||
|
||||
However, decentralised platforms are exposed to a unique set of challenges than centralised platforms. Secure storage of information is difficult, and attacks against decentralised networks can still be devastating.
|
||||
|
||||
For example, Tor experienced unique attacks against its infrastructure, including denial-of-service against old tor v2 addresses, causing the network to go offline for many users.
|
||||
|
||||
To mitigate security risks, platforms such as torrents revert to centralisation in the form of trackers to validate file chunks being sent via peers. The idea is that we want to avoid this centralisation as much as is possible.
|
||||
|
||||
\subsection{slide5}
|
||||
|
||||
To achieve this, I will be using many of the standard cryptographic protocols such as AES and RSA, but along with the Paillier cryptosystem and zero-knowledge proofs, which are some newer and less appreciated cryptographic schemes.
|
||||
|
||||
The reason i will be using Paillier is that it has an interesting additive homomorphic property, where manipulating cyphertexts actually manipulates the underlying plaintexts.
|
||||
|
||||
Zero-knowledge proofs are currently in use in the blockchain ledgers monero and zcash. They use bulletproofs and zksnarks respectively to obfuscate transaction amounts, recipients and senders.
|
||||
|
||||
My implementation targets the web out of simplicity. This has caused some challenges that I will address however.
|
||||
|
||||
\subsection{slide6}
|
||||
|
||||
My network is an emulated P2P environment using websockets. I went for an emulated environment as it relieves me of implementing UDP hole-punching, and furthermore websockets are a simple way to transfer data in a simple format between clients.
|
||||
|
||||
\subsection{slide7}
|
||||
|
||||
Risk relies on dice-rolling mechanics. To achieve this, I have implemented a scheme to produce shared random values without a beacon by using commitment schemes. Each player submits some encrypted noise, and then each player submits a decryption key to yield a random value within a known range.
|
||||
|
||||
\subsection{slide8}
|
||||
|
||||
As part of the Paillier cryptosystem, the generation of large primes is required. I implemented Rabin-Miller with the ECMAScript 2019 BigInt standard to produce primes of 2048 bit length, for a combined key size of 4096 bits.
|
||||
|
||||
\subsection{slide9}
|
||||
|
||||
Furthermore, I implemented the paillier cryptosystem. This came with some difficulty, as the bigint spec is not followed correctly by major browsers.
|
||||
|
||||
\subsection{slide10}
|
||||
|
||||
Finally, I have a P2P implementation of standard risk. The map is reduced to make testing quicker.
|
||||
|
||||
\subsection{slide11}
|
||||
|
||||
The next steps for the implementation are to blend the paillier cryptosystem with the game itself to get the fog-of-war variant. This requires the implementation of a zero-knowledge proof scheme that is described by INSERT REFERENCE.
|
||||
|
||||
I also want to improve the implementation somewhat to reduce other more general attack surfaces. For example, preventing players from stopping play by not responding to messages, which is currently an effective strategy for a losing player. There is also some cases of modular bias that need to be removed in the dice rolling scheme.
|
||||
|
||||
Further analysis is also necessary of the optimisations I made to the paillier cryptosystem, as certain computations were subtly changed to ensure that the size of intermediary values didn't exceed the upper limit on big integers.
|
||||
|
||||
Following this, I plan to do a more general analysis of the system to check its security and benchmark.
|
||||
|
||||
\end{document}
|
BIN
whitepaper/demonstration/websockets.mp4
Normal file
BIN
whitepaper/demonstration/websockets.mp4
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user