diff --git a/static/js/modules/crypto/math.js b/static/js/modules/crypto/math.js index a0c762b..096f096 100644 --- a/static/js/modules/crypto/math.js +++ b/static/js/modules/crypto/math.js @@ -38,4 +38,18 @@ export function mod_inv(a, n) { return t; } +export function gcd(a, b) { + // check a, b are correct types. + a *= 1n; + b *= 1n; + while (b !== 0n) { + let temp = b; + b = a % b; + a = temp; + } + return a; +} + window.mod_exp = mod_exp; +window.mod_inv = mod_inv; +window.gcd = gcd; diff --git a/static/js/modules/crypto/paillier.js b/static/js/modules/crypto/paillier.js index e406ea6..de2176c 100644 --- a/static/js/modules/crypto/paillier.js +++ b/static/js/modules/crypto/paillier.js @@ -17,10 +17,12 @@ class Cyphertext { // Compute g^m r^n from crt this.cyphertext = (gm * mod_exp(r, key.n, key.n ** 2n)) % key.n ** 2n; this.r = r; - this.key = key; + this.pubKey = key; this.plainText = plainText; this.readOnly = false; + + this.rp = null; } update(c) { @@ -32,21 +34,92 @@ class Cyphertext { toString() { return "0x" + this.cyphertext.toString(16); } + + prove() { + return new ProofSessionProver(this); + } + + asReadOnlyCyphertext() { + return new ReadOnlyCyphertext(this.pubKey, this.cyphertext); + } } +class ProofSessionProver { + constructor(cipherText) { + this.cipherText = cipherText; + + this.rp = random2048(); + while (this.rp >= this.cipherText.pubKey.n) { + this.rp = random2048(); + } + } + + noise() { + return mod_exp(this.rp, this.cipherText.pubKey.n, this.cipherText.pubKey.n ** 2n); + } + + prove(challenge) { + return { + proof: + ((this.rp % this.cipherText.pubKey.n) * + mod_exp(this.cipherText.r, challenge, this.cipherText.pubKey.n)) % + this.cipherText.pubKey.n, + }; + } +} + +window.Cyphertext = Cyphertext; + export class ReadOnlyCyphertext { constructor(key, cyphertext) { this.cyphertext = cyphertext; - this.key = key; + this.pubKey = key; this.readOnly = true; + + this.proofPromise = null; } update(c) { this.cyphertext *= c.cyphertext; } + + async prove() { + // request a proof + let promise = new Promise((res) => (this.proofPromise = res)); + } } +class ProofSessionVerifier { + constructor(cipherText, a) { + this.cipherText = cipherText; + this.challenge = random2048(); + this.a = a; + } + + verify(proof) { + // check coprimality + if (gcd(proof, this.cipherText.pubKey.n) !== 1n) return false; + if (gcd(this.cipherText.cyphertext, this.cipherText.pubKey.n) !== 1n) + return false; + if (gcd(this.a, this.cipherText.pubKey.n) !== 1n) return false; + + // check exp + return ( + mod_exp(proof, this.cipherText.pubKey.n, this.cipherText.pubKey.n ** 2n) === + (this.a * + mod_exp( + this.cipherText.cyphertext, + this.challenge, + this.cipherText.pubKey.n ** 2n + )) % + this.cipherText.pubKey.n ** 2n + ); + } +} + +window.ReadOnlyCyphertext = ReadOnlyCyphertext; + export class PaillierPubKey { constructor(n) { this.n = n; diff --git a/static/js/modules/interface/main.js b/static/js/modules/interface/main.js index 5c9a499..e6c3891 100644 --- a/static/js/modules/interface/main.js +++ b/static/js/modules/interface/main.js @@ -146,10 +146,6 @@ document.addEventListener("ACT", async (ev) => { game.currentPlayer().endTurn(); } } - - if (game.allReinforcementsPlaced()) { - game.incrementState(); - } } else { if (await game.currentPlayer().act(data)) { game.currentPlayer().endTurn(); @@ -161,6 +157,12 @@ document.addEventListener("ACT", async (ev) => { } }); +document.addEventListener("endTurn", () => { + if (game.isPregame() && game.allReinforcementsPlaced()) { + game.incrementState(); + } +}); + document.addEventListener("gameStateUpdate", async () => { if (game.isPregame()) { let firstPlayerIndex = await random.get( diff --git a/whitepaper/Dissertation.pdf b/whitepaper/Dissertation.pdf index a19ed28..91b5f8e 100644 Binary files a/whitepaper/Dissertation.pdf and b/whitepaper/Dissertation.pdf differ diff --git a/whitepaper/Dissertation.tex b/whitepaper/Dissertation.tex index 4da9071..e8ae9ff 100644 --- a/whitepaper/Dissertation.tex +++ b/whitepaper/Dissertation.tex @@ -364,9 +364,9 @@ Then, a proof for the following homologous problem can be trivially constructed: % Furthermore, the above protocol can be made non-interactive using the Fiat-Shamir heuristic \citep{fiatshamir}. (this contradicts the lit review) -\subsection{Recovering $r$ given $c$} +\subsection{Implementation details} + -The proof requires that the prover can perform new calculations with $r$ given a cyphertext $c = g^mr^n \mod n^2$. For ease of programming, \subsection{Application to domain}