import { socket } from "./main.js"; import { Packet } from "./packet.js"; const REGIONS = {}; class Continent { constructor(name) { this.name = name; this.yield = 0; } } class Strength { constructor(cipherText, regionName) { this.cipherText = cipherText; this.assumedStrength = null; this.prover = null; document.addEventListener("PROOF", (ev) => { const data = ev.detail; if ( data.region === regionName && data.stage === "CHALLENGE" && this.prover !== null ) { let z = this.prover.prove(BigInt(data.challenge)); socket.emit( "message", Packet.createProof(regionName, "0x" + z.toString(16)) ); } }); this.verifier = null; document.addEventListener("PROOF", (ev) => { const data = ev.detail; if ( data.region === regionName && data.stage === "PROOF" && this.verifier !== null ) { let result = this.verifier.verify(BigInt(data.z)); if (result > 0) { this.assumedStrength = this.verifier.plainText; document.dispatchEvent(new CustomEvent("updateStrengths")); } else { console.warn(`Failed to verify ciphertext! ${result}`); } } }); } transparentUpdate(value) { this.cipherText.update(new Ciphertext(this.cipherText.pubKey, value, 0n)); if (this.assumedStrength !== null) { this.assumedStrength += value; } } update(cipherText) { if (this.cipherText === null) { this.cipherText = cipherText; } else { this.cipherText.update(cipherText); } this.assumedStrength = null; } prove(region) { if (this.cipherText.readOnly) { return; } this.prover = this.cipherText.prove(); socket.emit( "message", Packet.createProofConjecture( region, "0x" + this.cipherText.plainText.toString(), "0x" + this.prover.a.toString(16) ) ); } verify(region, plainText, a) { if (!this.cipherText.readOnly) { return; } this.verifier = this.cipherText.prove(plainText, a); socket.emit( "message", Packet.createProofChallenge( region, "0x" + this.verifier.challenge.toString(16) ) ); } } export class Region { constructor(name, continent) { this.name = name; this.owner = null; this.strength = new Strength(null, name); this.neighbours = new Set(); this.continent = continent; REGIONS[name] = this; } static setNeighbours(region1, region2) { region1.neighbours.add(region2); region2.neighbours.add(region1); } static allRegionsClaimed() { return ( Object.values(REGIONS).find((region) => region.owner === null) === undefined ); } static getRegion(name) { return REGIONS[name]; } static getAllRegions() { return Object.values(REGIONS); } claim(player, cipherText) { this.owner = player; this.strength.update(cipherText); this.strength.assumedStrength = 1n; } reinforce(cipherText) { this.strength.update(cipherText); } isClaimed() { return this.strength.cipherText !== null; } displayStrength() { if (this.owner === null) { return ""; } else if (!this.strength.cipherText.readOnly) { return this.strength.cipherText.plainText.toString(); } else if (this.strength.assumedStrength !== null) { return this.strength.assumedStrength.toString(); } else { return "?"; } } prove() { this.strength.prove(this.name); } requestProof() { socket.emit("message", Packet.createProofRequest(this.name)); } verify(plainText, a) { this.strength.verify(this.name, plainText, a); } } const EAST = new Continent("East"); const WEST = new Continent("West"); const A = new Region("A", EAST); const B = new Region("B", EAST); const C = new Region("C", EAST); const D = new Region("D", EAST); const J = new Region("J", EAST); const F = new Region("F", WEST); const G = new Region("G", WEST); 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);