....
This commit is contained in:
@ -100,8 +100,11 @@ export function generate_prime() {
|
||||
export function generate_safe_prime() {
|
||||
while (true) {
|
||||
let n = generate_prime();
|
||||
if (small_prime_test((n - 1n) / 2n) && miller_rabin((n - 1n) / 2n, 40)) {
|
||||
if (small_prime_test((n - 1n) / 2n)) {
|
||||
// Remove this conditional if you want it to run fast! It (probably) won't break it
|
||||
// if (miller_rabin((n - 1n) / 2n, 40)) {
|
||||
return n;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -203,10 +203,14 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
let amount = modal.querySelector(".amount").value;
|
||||
let endRegion = modal.querySelector(".target").value;
|
||||
|
||||
socket.emit(
|
||||
"message",
|
||||
Packet.createAction(action, startRegion, endRegion, amount)
|
||||
);
|
||||
if (action === "ATTACK") {
|
||||
socket.emit(
|
||||
"message",
|
||||
Packet.createAction(action, startRegion, endRegion, amount)
|
||||
);
|
||||
} else {
|
||||
game.us.sendFortify(startRegion, endRegion, amount);
|
||||
}
|
||||
});
|
||||
|
||||
document
|
||||
|
@ -103,6 +103,14 @@ export class Packet {
|
||||
});
|
||||
}
|
||||
|
||||
static createFortify(fortify, verification) {
|
||||
return this._sign({
|
||||
...this._createBase("ACT"),
|
||||
fortify: fortify,
|
||||
verification: verification,
|
||||
});
|
||||
}
|
||||
|
||||
static createDefense(amount) {
|
||||
return this._sign({
|
||||
...this._createBase("ACT"),
|
||||
|
@ -4,7 +4,7 @@ import { RsaPubKey } from "../crypto/rsa.js";
|
||||
import { PaillierPubKey, ReadOnlyCiphertext } from "../crypto/paillier.js";
|
||||
import { Region } from "./map.js";
|
||||
import { showDefenseDom } from "./dom.js";
|
||||
import { proveRange, proveRegions, verifyRegions } from "./proofs.js";
|
||||
import { proveFortify, proveRange, proveRegions, verifyRegions } from "./proofs.js";
|
||||
|
||||
// Timeout to consider a player disconnected
|
||||
const TIMEOUT = 30_000;
|
||||
@ -178,6 +178,45 @@ export class Player {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an action which is to attack another region.
|
||||
*
|
||||
* @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 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sendFortify(startRegion, endRegion, amount) {
|
||||
let fortify = {
|
||||
[startRegion]: new Ciphertext(this.paillierPubKey, BigInt(-amount)),
|
||||
[endRegion]: new Ciphertext(this.paillierPubKey, BigInt(amount)),
|
||||
};
|
||||
|
||||
for (let r of this.getRegions()) {
|
||||
if (!fortify.hasOwnProperty(r)) {
|
||||
fortify[r] = new Ciphertext(this.paillierPubKey, 0n);
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit("message", Packet.createFortify(fortify, proveFortify(fortify)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a generic action packet representing a player's move.
|
||||
*
|
||||
@ -213,7 +252,11 @@ export class Player {
|
||||
this.turnPhase = PHASE_FORTIFY;
|
||||
|
||||
if (data.action === "FORTIFY") {
|
||||
return this.fortify(data);
|
||||
if (this === game.us) {
|
||||
return;
|
||||
} else {
|
||||
return this.fortify(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -352,30 +395,6 @@ export class Player {
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an action which is to attack another region.
|
||||
*
|
||||
* @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 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the number of additional reinforcements to gain on this turn.
|
||||
*/
|
||||
|
@ -295,7 +295,8 @@ export function verifyRange(obj, key) {
|
||||
window.verifyRange = verifyRange;
|
||||
|
||||
/**
|
||||
* - We prove that the set contains |S| - 2 zeros, with the final pair summing to zero
|
||||
* - We prove that the set contains |S| - 2 zeros, with the final pair summing to zero and sums with the original
|
||||
* set are zero.
|
||||
* - We also attach some form of adjacency guarantee: that is, we prove the sums on all adjacent pairs are zero
|
||||
* - We also attach a range proof for the new region values
|
||||
*/
|
||||
@ -311,11 +312,13 @@ export function proveFortify(fortify) {
|
||||
psiMap[regionNames[i]] = psi[i];
|
||||
}
|
||||
|
||||
let newRegions = structuredClone(fortify);
|
||||
let newRegions = { regions: {} };
|
||||
|
||||
// Rearrange keys
|
||||
for (let r of regionNames) {
|
||||
newRegions[psiMap[r]] = fortify[r].pubKey.encrypt(fortify[r].plainText);
|
||||
newRegions.regions[psiMap[r]] = fortify[r].pubKey.encrypt(
|
||||
-fortify[r].plainText
|
||||
);
|
||||
}
|
||||
|
||||
let edges = [];
|
||||
@ -363,8 +366,12 @@ export function proveFortify(fortify) {
|
||||
|
||||
for (let i = 0; i < ROUNDS; i++) {
|
||||
let coin = coins[i];
|
||||
let proof = proofs[i];
|
||||
let proof = proofs[i].regions;
|
||||
let input = privateInputs[i];
|
||||
let psiMap = {};
|
||||
for (let i = 0; i < regionNames.length; i++) {
|
||||
psiMap[regionNames[i]] = input.psi[i];
|
||||
}
|
||||
|
||||
if (coin === 1) {
|
||||
// Show |S| - 2 zeroes
|
||||
@ -389,17 +396,29 @@ export function proveFortify(fortify) {
|
||||
|
||||
// Show pair is joined by edge
|
||||
let pairName = pair.sort();
|
||||
console.log(input);
|
||||
verification.pairEdgeSalt = input.edges.find(
|
||||
(e) => e.edge[0] === pairName[0] && e.edge[1] === pairName[1]
|
||||
);
|
||||
).salt;
|
||||
|
||||
verifications.push(verification);
|
||||
} else {
|
||||
// Show isomorphism
|
||||
let edges = {};
|
||||
for (let e of input.edges) {
|
||||
edges[e.edge[0] + e.edge[1]] = e.salt;
|
||||
}
|
||||
|
||||
let zeroProofs = {};
|
||||
for (let r of regionNames) {
|
||||
let c = proof[psiMap[r]].clone();
|
||||
c.update(fortify[r]);
|
||||
zeroProofs[r] = c.proveNI();
|
||||
}
|
||||
|
||||
verifications.push({
|
||||
psi: input.psi,
|
||||
salts: input.edges.map((e) => e.salt),
|
||||
salts: edges,
|
||||
zeroProofs: zeroProofs,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -415,4 +434,116 @@ export function proveFortify(fortify) {
|
||||
|
||||
window.proveFortify = proveFortify;
|
||||
|
||||
// proveRegions({A:paillier.pubKey.encrypt(0n),B:paillier.pubKey.encrypt(3n),C:paillier.pubKey.encrypt(-3n),D:paillier.pubKey.encrypt(0n),E:paillier.pubKey.encrypt(0n)})
|
||||
export function verifyFortify(obj, key) {
|
||||
let coins = getCoins(JSON.stringify(obj.proofs));
|
||||
let fortify = obj.fortify;
|
||||
|
||||
let regionNames = Object.keys(fortify).sort();
|
||||
for (let i = 0; i < ROUNDS; i++) {
|
||||
let coin = coins[i];
|
||||
let proof = obj.proofs[i];
|
||||
let verification = obj.verifications[i];
|
||||
|
||||
if (coin === 1) {
|
||||
// Check |S| - 2 zeroes
|
||||
if (regionNames.length - 2 !== Object.keys(verification.regions).length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let regions = new Set(regionNames);
|
||||
|
||||
for (let r of Object.keys(verification.regions)) {
|
||||
let c = new ReadOnlyCiphertext(key, BigInt(proof.regions[r]));
|
||||
let p = c.verifyNI(verification.regions[r]);
|
||||
if (p !== 0n) {
|
||||
return false;
|
||||
}
|
||||
|
||||
regions.delete(r);
|
||||
}
|
||||
|
||||
// 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]]);
|
||||
let p = c.verifyNI(verification.pairCipherText);
|
||||
if (p !== 0n) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check edge is okay
|
||||
let hasher = new jsSHA("SHA3-256", "TEXT");
|
||||
hasher.update(pair[0]);
|
||||
hasher.update(pair[1]);
|
||||
hasher.update(verification.pairEdgeSalt.toString(16));
|
||||
let hash = hasher.getHash("HEX");
|
||||
|
||||
if (!proof.edges.includes(hash)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Check isomorphism
|
||||
let psi = verification.psi;
|
||||
let psiMap = {};
|
||||
for (let i = 0; i < regionNames.length; i++) {
|
||||
psiMap[regionNames[i]] = psi[i];
|
||||
}
|
||||
|
||||
let salts = verification.salts;
|
||||
|
||||
// Psi matches?
|
||||
if (psi.split("").sort().join("") !== regionNames.join("")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ciphertexts match?
|
||||
for (let r of regionNames) {
|
||||
let c = new ReadOnlyCiphertext(key, BigInt(proof.regions[r]));
|
||||
c.update(fortify[psiMap[r]]);
|
||||
let p = c.verifyNI(verification.zeroProofs[r]);
|
||||
|
||||
if (p !== 0n) {
|
||||
console.log(p);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Edges match?
|
||||
let proverEdges = new Set(proof.edges);
|
||||
|
||||
for (let r of regionNames) {
|
||||
let psiRegion = psiMap[r];
|
||||
|
||||
for (let n of Region.getRegion(r).neighbours) {
|
||||
let psiNeighbour = psiMap[n.name];
|
||||
|
||||
if (psiNeighbour > psiRegion) {
|
||||
let edgeSalt = salts[psiRegion + psiNeighbour];
|
||||
let hasher = new jsSHA("SHA3-256", "TEXT");
|
||||
hasher.update(psiRegion);
|
||||
hasher.update(psiNeighbour);
|
||||
hasher.update(edgeSalt.toString(16));
|
||||
let hash = hasher.getHash("HEX");
|
||||
|
||||
if (proverEdges.has(hash)) {
|
||||
proverEdges.delete(hash);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check it is not over-specified
|
||||
if (proverEdges.size !== 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
window.verifyFortify = verifyFortify;
|
||||
|
||||
// proveFortify({A:paillier.pubKey.encrypt(0n),B:paillier.pubKey.encrypt(3n),C:paillier.pubKey.encrypt(-3n),D:paillier.pubKey.encrypt(0n),E:paillier.pubKey.encrypt(0n)})
|
||||
|
Reference in New Issue
Block a user