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 EAST = new Continent("East");
const WEST = new Continent("West"); const WEST = new Continent("West");

View File

@ -103,11 +103,11 @@ export class Packet {
}); });
} }
static createFortify(fortify, verification) { static createFortify(fortify) {
return this._sign({ return this._sign({
...this._createBase("ACT"), ...this._createBase("ACT"),
action: "FORTIFY",
fortify: 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 { PaillierPubKey, ReadOnlyCiphertext } from "../crypto/paillier.js";
import { Region } from "./map.js"; import { Region } from "./map.js";
import { showDefenseDom } from "./dom.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 // Timeout to consider a player disconnected
const TIMEOUT = 30_000; const TIMEOUT = 30_000;
@ -184,22 +190,40 @@ export class Player {
* @param data Data received via socket * @param data Data received via socket
*/ */
fortify(data) { fortify(data) {
let sender = Region.getRegion(data.startRegion); if (!verifyFortify(data.fortify, this.paillierPubKey)) {
let receiver = Region.getRegion(data.endRegion); console.log("Failed to verify fortify!");
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; 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) { sendFortify(startRegion, endRegion, amount) {
@ -209,12 +233,16 @@ export class Player {
}; };
for (let r of this.getRegions()) { for (let r of this.getRegions()) {
if (!fortify.hasOwnProperty(r)) { if (!fortify.hasOwnProperty(r.name)) {
fortify[r] = new Ciphertext(this.paillierPubKey, 0n); 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 (data.action === "FORTIFY") {
if (this === game.us) { if (this === game.us) {
return; return true;
} else { } else {
return this.fortify(data); return this.fortify(data);
} }

View File

@ -549,16 +549,18 @@ export function proveFortify(fortify) {
// Show pair is joined by edge // Show pair is joined by edge
let pairName = pair.sort(); let pairName = pair.sort();
verification.pairEdgeSalt = input.edges.find( verification.pairEdgeSalt =
(e) => e.edge[0] === pairName[0] && e.edge[1] === pairName[1] "0x" +
).salt; input.edges
.find((e) => e.edge[0] === pairName[0] && e.edge[1] === pairName[1])
.salt.toString(16);
verifications.push(verification); verifications.push(verification);
} else { } else {
// Show isomorphism // Show isomorphism
let edges = {}; let edges = {};
for (let e of input.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 = {}; let zeroProofs = {};
@ -618,7 +620,7 @@ export function verifyFortify(obj, key) {
// Check remaining pair sums to zero // Check remaining pair sums to zero
let pair = [...regions.values()].sort(); let pair = [...regions.values()].sort();
let c = new ReadOnlyCiphertext(key, BigInt(proof.regions[pair[0]])); 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); let p = c.verifyNI(verification.pairCipherText);
if (p !== 0n) { if (p !== 0n) {
return false; return false;
@ -628,7 +630,7 @@ export function verifyFortify(obj, key) {
let hasher = new jsSHA("SHA3-256", "TEXT"); let hasher = new jsSHA("SHA3-256", "TEXT");
hasher.update(pair[0]); hasher.update(pair[0]);
hasher.update(pair[1]); hasher.update(pair[1]);
hasher.update(verification.pairEdgeSalt.toString(16)); hasher.update(BigInt(verification.pairEdgeSalt).toString(16));
let hash = hasher.getHash("HEX"); let hash = hasher.getHash("HEX");
if (!proof.edges.includes(hash)) { if (!proof.edges.includes(hash)) {
@ -652,7 +654,7 @@ export function verifyFortify(obj, key) {
// Ciphertexts match? // Ciphertexts match?
for (let r of regionNames) { for (let r of regionNames) {
let c = new ReadOnlyCiphertext(key, BigInt(proof.regions[r])); 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]); let p = c.verifyNI(verification.zeroProofs[r]);
if (p !== 0n) { if (p !== 0n) {
@ -674,7 +676,7 @@ export function verifyFortify(obj, key) {
let hasher = new jsSHA("SHA3-256", "TEXT"); let hasher = new jsSHA("SHA3-256", "TEXT");
hasher.update(psiRegion); hasher.update(psiRegion);
hasher.update(psiNeighbour); hasher.update(psiNeighbour);
hasher.update(edgeSalt.toString(16)); hasher.update(BigInt(edgeSalt).toString(16));
let hash = hasher.getHash("HEX"); let hash = hasher.getHash("HEX");
if (proverEdges.has(hash)) { 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{enumerate}
\end{protocol} \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. 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} \subsection{Proving fortifications}