fortify working and verifying

This commit is contained in:
jude 2023-04-27 12:52:02 +01:00
parent 9e4a57605d
commit dee1da6fb1
6 changed files with 63 additions and 29 deletions

View File

@ -174,6 +174,8 @@ export class Region {
}
}
window.Region = Region;
const EAST = new Continent("East");
const WEST = new Continent("West");

View File

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

View File

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

View File

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

Binary file not shown.

View File

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