This commit is contained in:
2023-04-24 14:20:44 +01:00
parent 88cf76f815
commit f4020aadec
8 changed files with 265 additions and 112 deletions

View File

@ -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;
// }
}
}
}

View File

@ -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

View File

@ -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"),

View File

@ -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.
*/

View File

@ -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)})