Ensure ciphertexts are cloned to avoid mutating actual object.

This commit is contained in:
2023-04-09 18:36:58 +01:00
parent 5557a8bff6
commit 848c56ff84
6 changed files with 133 additions and 126 deletions

View File

@ -23,7 +23,6 @@ class Cyphertext {
this.cyphertext += key.n2;
}
console.log(performance.now());
this.r = r;
this.pubKey = key;
this.plainText = plainText;
@ -32,16 +31,13 @@ class Cyphertext {
}
update(c) {
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n ** 2n;
this.r = (this.r * c.r) % this.pubKey.n ** 2n;
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n2;
this.r = (this.r * c.r) % this.pubKey.n2;
this.plainText += c.plainText;
// Force into range
while (this.cyphertext < 0n) {
this.cyphertext += this.pubKey.n ** 2n;
}
while (this.r < 0n) {
this.r += this.pubKey.n ** 2n;
this.cyphertext += this.pubKey.n2;
}
}
@ -69,11 +65,11 @@ class ProofSessionProver {
}
get a() {
return mod_exp(this.rp, this.cipherText.pubKey.n, this.cipherText.pubKey.n ** 2n);
return mod_exp(this.rp, this.cipherText.pubKey.n, this.cipherText.pubKey.n2);
}
noise() {
return mod_exp(this.rp, this.cipherText.pubKey.n, this.cipherText.pubKey.n ** 2n);
return mod_exp(this.rp, this.cipherText.pubKey.n, this.cipherText.pubKey.n2);
}
prove(challenge) {
@ -102,26 +98,33 @@ export class ReadOnlyCyphertext {
}
update(c) {
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n ** 2n;
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n2;
// Force into range
while (this.cyphertext < 0n) {
this.cyphertext += this.pubKey.n ** 2n;
this.cyphertext += this.pubKey.n2;
}
}
prove(plainText, a) {
return new ProofSessionVerifier(this, plainText, a);
}
clone() {
return new ReadOnlyCyphertext(this.pubKey, this.cyphertext);
}
}
class ProofSessionVerifier {
constructor(cipherText, plainText, a) {
this.cipherText = cipherText;
// Clone, otherwise the update below will mutate the original value
this.cipherText = cipherText.clone();
this.cipherText.update(this.cipherText.pubKey.encrypt(-1n * plainText, 1n));
// Shift the challenge down by 1 to ensure it is smaller than either prime factor.
this.challenge = cryptoRandom(2048) << 1n;
this.a = a;
this.plainText = plainText;
}
verify(proof) {
@ -204,3 +207,5 @@ export function generate_keypair() {
return { pubKey, privKey };
}
// p = a.prove(); v = p.asVerifier(); v.verify(p.prove(v.challenge));

View File

@ -34,7 +34,7 @@ document.addEventListener("DOMContentLoaded", () => {
});
socket.on("message", async (packet) => {
window.console.log(`Received size: ${JSON.stringify(packet).length}`);
// window.console.log(`Received size: ${JSON.stringify(packet).length}`);
let data = packet.payload;
if (data.type !== "KEEPALIVE") window.console.log(data);

View File

@ -11,9 +11,46 @@ class Continent {
}
class Strength {
constructor(cipherText) {
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}`);
}
}
});
}
update(cipherText) {
@ -31,33 +68,14 @@ class Strength {
return;
}
const controller = new AbortController();
let proofSessionProver = this.cipherText.prove();
document.addEventListener(
"PROOF",
(ev) => {
const data = ev.detail;
if (data.region === region && data.stage === "CHALLENGE") {
let z = proofSessionProver.prove(BigInt(data.challenge));
socket.emit(
"message",
Packet.createProof(region, "0x" + z.toString(16))
);
controller.abort();
}
},
{ signal: controller.signal }
);
this.prover = this.cipherText.prove();
socket.emit(
"message",
Packet.createProofConjecture(
region,
"0x" + this.cipherText.plainText.toString(),
"0x" + proofSessionProver.a.toString(16)
"0x" + this.prover.a.toString(16)
)
);
}
@ -67,33 +85,13 @@ class Strength {
return;
}
const controller = new AbortController();
let proofSessionVerifier = this.cipherText.prove(plainText, a);
document.addEventListener(
"PROOF",
(ev) => {
const data = ev.detail;
if (data.region === region && data.stage === "PROOF") {
let result = proofSessionVerifier.verify(BigInt(data.z));
if (result > 0) {
this.assumedStrength = plainText;
document.dispatchEvent(new CustomEvent("updateStrengths"));
controller.abort();
} else {
console.warn(`Failed to verify ciphertext! ${result}`);
}
}
},
{ signal: controller.signal }
);
this.verifier = this.cipherText.prove(plainText, a);
socket.emit(
"message",
Packet.createProofChallenge(
region,
"0x" + proofSessionVerifier.challenge.toString(16)
"0x" + this.verifier.challenge.toString(16)
)
);
}
@ -103,7 +101,7 @@ export class Region {
constructor(name, continent) {
this.name = name;
this.owner = null;
this.strength = new Strength(null);
this.strength = new Strength(null, name);
this.neighbours = new Set();
this.continent = continent;

View File

@ -156,7 +156,10 @@ export class Player {
// send proofs
for (let region of this.getRegions()) {
region.prove();
// eh
if ([...region.neighbours.values()].find((r) => r.owner !== this)) {
region.prove();
}
}
this.endTurn();