Fix a lot of stuff

This commit is contained in:
jude 2023-04-10 11:19:11 +01:00
parent 848c56ff84
commit 0991c6bff9
8 changed files with 64 additions and 25 deletions

View File

@ -1,7 +1,7 @@
import { cryptoRandom, generate_prime } from "./random_primes.js"; import { cryptoRandom, generate_prime } from "./random_primes.js";
import { mod_exp } from "./math.js"; import { mod_exp } from "./math.js";
class Cyphertext { class Ciphertext {
constructor(key, plainText, r) { constructor(key, plainText, r) {
if (r === undefined) { if (r === undefined) {
r = cryptoRandom(4096); r = cryptoRandom(4096);
@ -46,15 +46,15 @@ class Cyphertext {
} }
prove() { prove() {
return new ProofSessionProver(this); return new ZeroProofSessionProver(this);
} }
asReadOnlyCyphertext() { asReadOnlyCyphertext() {
return new ReadOnlyCyphertext(this.pubKey, this.cyphertext); return new ReadOnlyCiphertext(this.pubKey, this.cyphertext);
} }
} }
class ProofSessionProver { class ZeroProofSessionProver {
constructor(cipherText) { constructor(cipherText) {
this.cipherText = cipherText; this.cipherText = cipherText;
@ -87,9 +87,9 @@ class ProofSessionProver {
} }
} }
window.Cyphertext = Cyphertext; window.Cyphertext = Ciphertext;
export class ReadOnlyCyphertext { export class ReadOnlyCiphertext {
constructor(key, cyphertext) { constructor(key, cyphertext) {
this.cyphertext = cyphertext; this.cyphertext = cyphertext;
this.pubKey = key; this.pubKey = key;
@ -107,15 +107,15 @@ export class ReadOnlyCyphertext {
} }
prove(plainText, a) { prove(plainText, a) {
return new ProofSessionVerifier(this, plainText, a); return new ZeroProofSessionVerifier(this, plainText, a);
} }
clone() { clone() {
return new ReadOnlyCyphertext(this.pubKey, this.cyphertext); return new ReadOnlyCiphertext(this.pubKey, this.cyphertext);
} }
} }
class ProofSessionVerifier { class ZeroProofSessionVerifier {
constructor(cipherText, plainText, a) { constructor(cipherText, plainText, a) {
// Clone, otherwise the update below will mutate the original value // Clone, otherwise the update below will mutate the original value
this.cipherText = cipherText.clone(); this.cipherText = cipherText.clone();
@ -147,7 +147,7 @@ class ProofSessionVerifier {
} }
} }
window.ReadOnlyCyphertext = ReadOnlyCyphertext; window.ReadOnlyCyphertext = ReadOnlyCiphertext;
export class PaillierPubKey { export class PaillierPubKey {
constructor(n) { constructor(n) {
@ -157,7 +157,7 @@ export class PaillierPubKey {
} }
encrypt(m, r) { encrypt(m, r) {
return new Cyphertext(this, m, r); return new Ciphertext(this, m, r);
} }
toJSON() { toJSON() {

View File

@ -148,6 +148,14 @@ document.addEventListener("DOMContentLoaded", () => {
el.addEventListener("click", (ev) => { el.addEventListener("click", (ev) => {
let region = ev.target.closest(".node").dataset.name; let region = ev.target.closest(".node").dataset.name;
game.us.sendReinforce(region); game.us.sendReinforce(region);
if (game.isPregame()) {
game.us.endTurn();
if (game.allReinforcementsPlaced()) {
game.incrementState();
}
}
}) })
); );

View File

@ -125,7 +125,7 @@ document.addEventListener("ACT", async (ev) => {
game.setReady(data.author, data.ready); game.setReady(data.author, data.ready);
} else { } else {
// Throw out our own packets // Throw out our own packets
if (data.author === game.us) { if (data.author === game.us.id) {
return; return;
} }
@ -149,6 +149,10 @@ document.addEventListener("ACT", async (ev) => {
game.currentPlayer().endTurn(); game.currentPlayer().endTurn();
} }
} }
if (game.allReinforcementsPlaced()) {
game.incrementState();
}
} else { } else {
if (await game.currentPlayer().act(data)) { if (await game.currentPlayer().act(data)) {
game.currentPlayer().endTurn(); game.currentPlayer().endTurn();
@ -163,8 +167,16 @@ document.addEventListener("ACT", async (ev) => {
// todo has to filter by player // todo has to filter by player
document.addEventListener("PROOF", async (ev) => { document.addEventListener("PROOF", async (ev) => {
const data = ev.detail; const data = ev.detail;
if (data.stage === "REQUEST") {
let region = Region.getRegion(data.region);
// todo check if this is a valid request e.g actually has neighbour
if (region.owner === game.us) {
region.prove();
}
}
if (data.stage === "CONJECTURE") { if (data.stage === "CONJECTURE") {
// find the relevant entity
let region = Region.getRegion(data.region); let region = Region.getRegion(data.region);
region.verify(BigInt(data.plainText), BigInt(data.a)); region.verify(BigInt(data.plainText), BigInt(data.a));

View File

@ -157,6 +157,10 @@ export class Region {
this.strength.prove(this.name); this.strength.prove(this.name);
} }
requestProof() {
socket.emit("message", Packet.createProofRequest(this.name));
}
verify(plainText, a) { verify(plainText, a) {
this.strength.verify(this.name, plainText, a); this.strength.verify(this.name, plainText, a);
} }

View File

@ -117,6 +117,14 @@ export class Packet {
}); });
} }
static createProofRequest(region) {
return this._sign({
...this._createBase("PROOF"),
stage: "REQUEST",
region: region,
});
}
static createProofConjecture(region, plainText, a) { static createProofConjecture(region, plainText, a) {
return this._sign({ return this._sign({
...this._createBase("PROOF"), ...this._createBase("PROOF"),

View File

@ -1,7 +1,7 @@
import { Packet } from "./packet.js"; import { Packet } from "./packet.js";
import { socket, game, random } from "./main.js"; import { socket, game, random } from "./main.js";
import { RsaPubKey } from "../crypto/rsa.js"; import { RsaPubKey } from "../crypto/rsa.js";
import { PaillierPubKey, ReadOnlyCyphertext } from "../crypto/paillier.js"; import { PaillierPubKey, ReadOnlyCiphertext } from "../crypto/paillier.js";
import { Region } from "./map.js"; import { Region } from "./map.js";
import { showDefenseDom } from "./dom.js"; import { showDefenseDom } from "./dom.js";
@ -88,7 +88,7 @@ export class Player {
if (region.owner === null) { if (region.owner === null) {
region.claim( region.claim(
this, this,
new ReadOnlyCyphertext(this.paillierPubKey, BigInt(data.cipherText)) new ReadOnlyCiphertext(this.paillierPubKey, BigInt(data.cipherText))
); );
this.totalStrength += 1; this.totalStrength += 1;
@ -112,7 +112,7 @@ export class Player {
if (region.owner === this) { if (region.owner === this) {
region.reinforce( region.reinforce(
new ReadOnlyCyphertext( new ReadOnlyCiphertext(
this.paillierPubKey, this.paillierPubKey,
BigInt(data.regions[regionName]) BigInt(data.regions[regionName])
) )
@ -122,6 +122,13 @@ export class Player {
this.totalStrength += 1; this.totalStrength += 1;
// request proofs
for (let region of this.getRegions()) {
if ([...region.neighbours.values()].find((r) => r.owner === game.us)) {
region.requestProof();
}
}
return true; return true;
} }
@ -154,15 +161,13 @@ export class Player {
this.totalStrength += 1; this.totalStrength += 1;
// send proofs if (game.isPlaying()) {
for (let region of this.getRegions()) { this.reinforcementsPlaced += 1;
// eh
if ([...region.neighbours.values()].find((r) => r.owner !== this)) {
region.prove();
}
}
this.endTurn(); if (this.reinforcementsPlaced === this.reinforcementsAvailable) {
this.turnPhase = PHASE_ATTACK;
}
}
} }
/** /**
@ -173,7 +178,7 @@ export class Player {
*/ */
async act(data) { async act(data) {
if (this.turnPhase === PHASE_REINFORCE) { if (this.turnPhase === PHASE_REINFORCE) {
if (data.region !== undefined) { if (data.regions !== undefined) {
if (this.reinforce(data)) { if (this.reinforce(data)) {
this.reinforcementsPlaced += 1; this.reinforcementsPlaced += 1;
} }

Binary file not shown.

View File

@ -510,7 +510,7 @@ Various parts of the implementation use the random oracle model: in particular,
Paillier ciphertexts are constant size, each $\sim$1.0kB in size (as they are taken modulo $n^2$, where $n$ is the product of two 2048 bit primes). This is small enough for the memory and network limitations of today. Paillier ciphertexts are constant size, each $\sim$1.0kB in size (as they are taken modulo $n^2$, where $n$ is the product of two 2048 bit primes). This is small enough for the memory and network limitations of today.
The proof of zero uses two Paillier ciphertexts, a challenge of size 2048 bits, and a proof statement of size 4096 bits. In total, this is $\sim$2.8kB. These are constant size, and since they run in a single round, take constant time. The proof of zero uses two Paillier ciphertexts, a challenge of size 2048 bits, and a proof statement of size 4096 bits. In total, this is a constant size of $\sim$2.8kB.
On the other hand, \hyperref[protocol1]{Protocol~\ref*{protocol1}} requires multiple rounds. Assume that we use 42 rounds: this provides an acceptable level of soundness, with a cheat probability of $\left(\frac{1}{2}\right)^{-42} \approx 2.3 \times 10^{-13}$. Additionally, assume that there are 10 regions to verify. Each round then requires ten Paillier ciphertexts alongside ten proofs of zero. This results in a proof size of $\sim$1.7MB. Whilst this is still within current memory limitations, the network cost is extreme; and this value may exceed what can be reasonably operated on within a processor's cache. On the other hand, \hyperref[protocol1]{Protocol~\ref*{protocol1}} requires multiple rounds. Assume that we use 42 rounds: this provides an acceptable level of soundness, with a cheat probability of $\left(\frac{1}{2}\right)^{-42} \approx 2.3 \times 10^{-13}$. Additionally, assume that there are 10 regions to verify. Each round then requires ten Paillier ciphertexts alongside ten proofs of zero. This results in a proof size of $\sim$1.7MB. Whilst this is still within current memory limitations, the network cost is extreme; and this value may exceed what can be reasonably operated on within a processor's cache.
@ -520,6 +520,8 @@ This is all in an ideal situation without compression or signatures: in the impl
The size of the proof of zero communication is, in total, $3290 + 1744 + 2243$ characters, i.e $\sim$7.3kB. This is about 2-3 times larger than the ideal size. A solution to this is to use a more compact format, for example msgpack \cite{msgpack} (which also has native support for binary literals). The size of the proof of zero communication is, in total, $3290 + 1744 + 2243$ characters, i.e $\sim$7.3kB. This is about 2-3 times larger than the ideal size. A solution to this is to use a more compact format, for example msgpack \cite{msgpack} (which also has native support for binary literals).
This only considers the network footprint. The other consideration is the memory footprint. The proof of zero requires auxiliary memory beyond the new values communicated. In particular, it must clone the ciphertext being proven, in order to prevent mutating the original ciphertext when multiplying by $g^{-m}$.
\subsubsection{Time complexity} \subsubsection{Time complexity}
It is remarked that Paillier encryption performs considerably slower than RSA on all key sizes. \cite{paillier1999public} provides a table of theoretic results, suggesting that Paillier encryption can be over 1,000 times slower than RSA for the same key size. It is remarked that Paillier encryption performs considerably slower than RSA on all key sizes. \cite{paillier1999public} provides a table of theoretic results, suggesting that Paillier encryption can be over 1,000 times slower than RSA for the same key size.