diff --git a/static/js/modules/interface/map.js b/static/js/modules/interface/map.js index 72b93fa..d4e220d 100644 --- a/static/js/modules/interface/map.js +++ b/static/js/modules/interface/map.js @@ -174,6 +174,8 @@ export class Region { } } +window.Region = Region; + const EAST = new Continent("East"); const WEST = new Continent("West"); diff --git a/static/js/modules/interface/packet.js b/static/js/modules/interface/packet.js index 66a9f6a..fd61ec6 100644 --- a/static/js/modules/interface/packet.js +++ b/static/js/modules/interface/packet.js @@ -103,11 +103,11 @@ export class Packet { }); } - static createFortify(fortify, verification) { + static createFortify(fortify) { return this._sign({ ...this._createBase("ACT"), + action: "FORTIFY", fortify: fortify, - verification: verification, }); } diff --git a/static/js/modules/interface/player.js b/static/js/modules/interface/player.js index 0edb4df..46fe980 100644 --- a/static/js/modules/interface/player.js +++ b/static/js/modules/interface/player.js @@ -4,7 +4,13 @@ import { RsaPubKey } from "../crypto/rsa.js"; import { PaillierPubKey, ReadOnlyCiphertext } from "../crypto/paillier.js"; import { Region } from "./map.js"; import { showDefenseDom } from "./dom.js"; -import { proveFortify, proveRange, proveRegions, verifyRegions } from "./proofs.js"; +import { + proveFortify, + proveRange, + proveRegions, + verifyFortify, + verifyRegions, +} from "./proofs.js"; // Timeout to consider a player disconnected const TIMEOUT = 30_000; @@ -184,22 +190,40 @@ export class Player { * @param data Data received via socket */ fortify(data) { - let sender = Region.getRegion(data.startRegion); - let receiver = Region.getRegion(data.endRegion); - let strength = parseInt(data.strength); - - if ( - sender.owner === this && - receiver.owner === this && - sender.strength > strength && - strength > 0 - ) { - receiver.reinforce(strength); - sender.strength -= strength; - return true; - } else { + if (!verifyFortify(data.fortify, this.paillierPubKey)) { + console.log("Failed to verify fortify!"); return false; } + + if ( + !Object.keys(data.fortify.fortify).reduce( + (c, r) => c && Region.getRegion(r).owner === this, + true + ) + ) { + console.log("Invalid fortify"); + return false; + } + + for (let regionName of Object.keys(data.fortify.fortify)) { + let region = Region.getRegion(regionName); + + region.reinforce( + new ReadOnlyCiphertext( + this.paillierPubKey, + BigInt(data.fortify.fortify[regionName]) + ) + ); + } + + // request proofs + for (let region of this.getRegions()) { + if ([...region.neighbours.values()].find((r) => r.owner === game.us)) { + region.requestProof(); + } + } + + return true; } sendFortify(startRegion, endRegion, amount) { @@ -209,12 +233,16 @@ export class Player { }; for (let r of this.getRegions()) { - if (!fortify.hasOwnProperty(r)) { - fortify[r] = new Ciphertext(this.paillierPubKey, 0n); + if (!fortify.hasOwnProperty(r.name)) { + fortify[r.name] = new Ciphertext(this.paillierPubKey, 0n); } } - socket.emit("message", Packet.createFortify(fortify, proveFortify(fortify))); + for (let r of Object.keys(fortify)) { + Region.getRegion(r).reinforce(fortify[r]); + } + + socket.emit("message", Packet.createFortify(proveFortify(fortify))); } /** @@ -253,7 +281,7 @@ export class Player { if (data.action === "FORTIFY") { if (this === game.us) { - return; + return true; } else { return this.fortify(data); } diff --git a/static/js/modules/interface/proofs.js b/static/js/modules/interface/proofs.js index 123bc15..2e59d2a 100644 --- a/static/js/modules/interface/proofs.js +++ b/static/js/modules/interface/proofs.js @@ -549,16 +549,18 @@ export function proveFortify(fortify) { // Show pair is joined by edge let pairName = pair.sort(); - verification.pairEdgeSalt = input.edges.find( - (e) => e.edge[0] === pairName[0] && e.edge[1] === pairName[1] - ).salt; + verification.pairEdgeSalt = + "0x" + + input.edges + .find((e) => e.edge[0] === pairName[0] && e.edge[1] === pairName[1]) + .salt.toString(16); verifications.push(verification); } else { // Show isomorphism let edges = {}; for (let e of input.edges) { - edges[e.edge[0] + e.edge[1]] = e.salt; + edges[e.edge[0] + e.edge[1]] = "0x" + e.salt.toString(16); } let zeroProofs = {}; @@ -618,7 +620,7 @@ export function verifyFortify(obj, key) { // Check remaining pair sums to zero let pair = [...regions.values()].sort(); let c = new ReadOnlyCiphertext(key, BigInt(proof.regions[pair[0]])); - c.update(proof.regions[pair[1]]); + c.update(new ReadOnlyCiphertext(key, BigInt(proof.regions[pair[1]]))); let p = c.verifyNI(verification.pairCipherText); if (p !== 0n) { return false; @@ -628,7 +630,7 @@ export function verifyFortify(obj, key) { let hasher = new jsSHA("SHA3-256", "TEXT"); hasher.update(pair[0]); hasher.update(pair[1]); - hasher.update(verification.pairEdgeSalt.toString(16)); + hasher.update(BigInt(verification.pairEdgeSalt).toString(16)); let hash = hasher.getHash("HEX"); if (!proof.edges.includes(hash)) { @@ -652,7 +654,7 @@ export function verifyFortify(obj, key) { // Ciphertexts match? for (let r of regionNames) { let c = new ReadOnlyCiphertext(key, BigInt(proof.regions[r])); - c.update(fortify[psiMap[r]]); + c.update(new ReadOnlyCiphertext(key, BigInt(fortify[psiMap[r]]))); let p = c.verifyNI(verification.zeroProofs[r]); if (p !== 0n) { @@ -674,7 +676,7 @@ export function verifyFortify(obj, key) { let hasher = new jsSHA("SHA3-256", "TEXT"); hasher.update(psiRegion); hasher.update(psiNeighbour); - hasher.update(edgeSalt.toString(16)); + hasher.update(BigInt(edgeSalt).toString(16)); let hash = hasher.getHash("HEX"); if (proverEdges.has(hash)) { diff --git a/whitepaper/Dissertation.pdf b/whitepaper/Dissertation.pdf index 078f79b..d1b2c8c 100644 Binary files a/whitepaper/Dissertation.pdf and b/whitepaper/Dissertation.pdf differ diff --git a/whitepaper/Dissertation.tex b/whitepaper/Dissertation.tex index 6b05495..fae706c 100644 --- a/whitepaper/Dissertation.tex +++ b/whitepaper/Dissertation.tex @@ -806,6 +806,8 @@ 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$. + Range proof is used in points (3), (4), and (5). In (3), this is to convince other players that the number of units is sufficient for the action. In (4), this is to show that the region is not totally depleted. In (5), this is to ensure the number of units being fortified is less than the strength of the region. All of these are performed using \hyperref[protocol4]{Protocol~\ref*{protocol4}} and by using the additive homomorphic property to subtract the lower range from $m$ first. \subsection{Proving fortifications}