Fix a lot of stuff
This commit is contained in:
parent
848c56ff84
commit
0991c6bff9
@ -1,7 +1,7 @@
|
|||||||
import { cryptoRandom, generate_prime } from "./random_primes.js";
|
import { cryptoRandom, generate_prime } from "./random_primes.js";
|
||||||
import { mod_exp } from "./math.js";
|
import { mod_exp } from "./math.js";
|
||||||
|
|
||||||
class Cyphertext {
|
class Ciphertext {
|
||||||
constructor(key, plainText, r) {
|
constructor(key, plainText, r) {
|
||||||
if (r === undefined) {
|
if (r === undefined) {
|
||||||
r = cryptoRandom(4096);
|
r = cryptoRandom(4096);
|
||||||
@ -46,15 +46,15 @@ class Cyphertext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prove() {
|
prove() {
|
||||||
return new ProofSessionProver(this);
|
return new ZeroProofSessionProver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
asReadOnlyCyphertext() {
|
asReadOnlyCyphertext() {
|
||||||
return new ReadOnlyCyphertext(this.pubKey, this.cyphertext);
|
return new ReadOnlyCiphertext(this.pubKey, this.cyphertext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProofSessionProver {
|
class ZeroProofSessionProver {
|
||||||
constructor(cipherText) {
|
constructor(cipherText) {
|
||||||
this.cipherText = cipherText;
|
this.cipherText = cipherText;
|
||||||
|
|
||||||
@ -87,9 +87,9 @@ class ProofSessionProver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.Cyphertext = Cyphertext;
|
window.Cyphertext = Ciphertext;
|
||||||
|
|
||||||
export class ReadOnlyCyphertext {
|
export class ReadOnlyCiphertext {
|
||||||
constructor(key, cyphertext) {
|
constructor(key, cyphertext) {
|
||||||
this.cyphertext = cyphertext;
|
this.cyphertext = cyphertext;
|
||||||
this.pubKey = key;
|
this.pubKey = key;
|
||||||
@ -107,15 +107,15 @@ export class ReadOnlyCyphertext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prove(plainText, a) {
|
prove(plainText, a) {
|
||||||
return new ProofSessionVerifier(this, plainText, a);
|
return new ZeroProofSessionVerifier(this, plainText, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
clone() {
|
clone() {
|
||||||
return new ReadOnlyCyphertext(this.pubKey, this.cyphertext);
|
return new ReadOnlyCiphertext(this.pubKey, this.cyphertext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProofSessionVerifier {
|
class ZeroProofSessionVerifier {
|
||||||
constructor(cipherText, plainText, a) {
|
constructor(cipherText, plainText, a) {
|
||||||
// Clone, otherwise the update below will mutate the original value
|
// Clone, otherwise the update below will mutate the original value
|
||||||
this.cipherText = cipherText.clone();
|
this.cipherText = cipherText.clone();
|
||||||
@ -147,7 +147,7 @@ class ProofSessionVerifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.ReadOnlyCyphertext = ReadOnlyCyphertext;
|
window.ReadOnlyCyphertext = ReadOnlyCiphertext;
|
||||||
|
|
||||||
export class PaillierPubKey {
|
export class PaillierPubKey {
|
||||||
constructor(n) {
|
constructor(n) {
|
||||||
@ -157,7 +157,7 @@ export class PaillierPubKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
encrypt(m, r) {
|
encrypt(m, r) {
|
||||||
return new Cyphertext(this, m, r);
|
return new Ciphertext(this, m, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
|
@ -148,6 +148,14 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
el.addEventListener("click", (ev) => {
|
el.addEventListener("click", (ev) => {
|
||||||
let region = ev.target.closest(".node").dataset.name;
|
let region = ev.target.closest(".node").dataset.name;
|
||||||
game.us.sendReinforce(region);
|
game.us.sendReinforce(region);
|
||||||
|
|
||||||
|
if (game.isPregame()) {
|
||||||
|
game.us.endTurn();
|
||||||
|
|
||||||
|
if (game.allReinforcementsPlaced()) {
|
||||||
|
game.incrementState();
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ document.addEventListener("ACT", async (ev) => {
|
|||||||
game.setReady(data.author, data.ready);
|
game.setReady(data.author, data.ready);
|
||||||
} else {
|
} else {
|
||||||
// Throw out our own packets
|
// Throw out our own packets
|
||||||
if (data.author === game.us) {
|
if (data.author === game.us.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +149,10 @@ document.addEventListener("ACT", async (ev) => {
|
|||||||
game.currentPlayer().endTurn();
|
game.currentPlayer().endTurn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (game.allReinforcementsPlaced()) {
|
||||||
|
game.incrementState();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (await game.currentPlayer().act(data)) {
|
if (await game.currentPlayer().act(data)) {
|
||||||
game.currentPlayer().endTurn();
|
game.currentPlayer().endTurn();
|
||||||
@ -163,8 +167,16 @@ document.addEventListener("ACT", async (ev) => {
|
|||||||
// todo has to filter by player
|
// todo has to filter by player
|
||||||
document.addEventListener("PROOF", async (ev) => {
|
document.addEventListener("PROOF", async (ev) => {
|
||||||
const data = ev.detail;
|
const data = ev.detail;
|
||||||
|
if (data.stage === "REQUEST") {
|
||||||
|
let region = Region.getRegion(data.region);
|
||||||
|
|
||||||
|
// todo check if this is a valid request e.g actually has neighbour
|
||||||
|
if (region.owner === game.us) {
|
||||||
|
region.prove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (data.stage === "CONJECTURE") {
|
if (data.stage === "CONJECTURE") {
|
||||||
// find the relevant entity
|
|
||||||
let region = Region.getRegion(data.region);
|
let region = Region.getRegion(data.region);
|
||||||
|
|
||||||
region.verify(BigInt(data.plainText), BigInt(data.a));
|
region.verify(BigInt(data.plainText), BigInt(data.a));
|
||||||
|
@ -157,6 +157,10 @@ export class Region {
|
|||||||
this.strength.prove(this.name);
|
this.strength.prove(this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestProof() {
|
||||||
|
socket.emit("message", Packet.createProofRequest(this.name));
|
||||||
|
}
|
||||||
|
|
||||||
verify(plainText, a) {
|
verify(plainText, a) {
|
||||||
this.strength.verify(this.name, plainText, a);
|
this.strength.verify(this.name, plainText, a);
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,14 @@ export class Packet {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static createProofRequest(region) {
|
||||||
|
return this._sign({
|
||||||
|
...this._createBase("PROOF"),
|
||||||
|
stage: "REQUEST",
|
||||||
|
region: region,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static createProofConjecture(region, plainText, a) {
|
static createProofConjecture(region, plainText, a) {
|
||||||
return this._sign({
|
return this._sign({
|
||||||
...this._createBase("PROOF"),
|
...this._createBase("PROOF"),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Packet } from "./packet.js";
|
import { Packet } from "./packet.js";
|
||||||
import { socket, game, random } from "./main.js";
|
import { socket, game, random } from "./main.js";
|
||||||
import { RsaPubKey } from "../crypto/rsa.js";
|
import { RsaPubKey } from "../crypto/rsa.js";
|
||||||
import { PaillierPubKey, ReadOnlyCyphertext } 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";
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ export class Player {
|
|||||||
if (region.owner === null) {
|
if (region.owner === null) {
|
||||||
region.claim(
|
region.claim(
|
||||||
this,
|
this,
|
||||||
new ReadOnlyCyphertext(this.paillierPubKey, BigInt(data.cipherText))
|
new ReadOnlyCiphertext(this.paillierPubKey, BigInt(data.cipherText))
|
||||||
);
|
);
|
||||||
|
|
||||||
this.totalStrength += 1;
|
this.totalStrength += 1;
|
||||||
@ -112,7 +112,7 @@ export class Player {
|
|||||||
|
|
||||||
if (region.owner === this) {
|
if (region.owner === this) {
|
||||||
region.reinforce(
|
region.reinforce(
|
||||||
new ReadOnlyCyphertext(
|
new ReadOnlyCiphertext(
|
||||||
this.paillierPubKey,
|
this.paillierPubKey,
|
||||||
BigInt(data.regions[regionName])
|
BigInt(data.regions[regionName])
|
||||||
)
|
)
|
||||||
@ -122,6 +122,13 @@ export class Player {
|
|||||||
|
|
||||||
this.totalStrength += 1;
|
this.totalStrength += 1;
|
||||||
|
|
||||||
|
// request proofs
|
||||||
|
for (let region of this.getRegions()) {
|
||||||
|
if ([...region.neighbours.values()].find((r) => r.owner === game.us)) {
|
||||||
|
region.requestProof();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,15 +161,13 @@ export class Player {
|
|||||||
|
|
||||||
this.totalStrength += 1;
|
this.totalStrength += 1;
|
||||||
|
|
||||||
// send proofs
|
if (game.isPlaying()) {
|
||||||
for (let region of this.getRegions()) {
|
this.reinforcementsPlaced += 1;
|
||||||
// eh
|
|
||||||
if ([...region.neighbours.values()].find((r) => r.owner !== this)) {
|
|
||||||
region.prove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.endTurn();
|
if (this.reinforcementsPlaced === this.reinforcementsAvailable) {
|
||||||
|
this.turnPhase = PHASE_ATTACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -173,7 +178,7 @@ export class Player {
|
|||||||
*/
|
*/
|
||||||
async act(data) {
|
async act(data) {
|
||||||
if (this.turnPhase === PHASE_REINFORCE) {
|
if (this.turnPhase === PHASE_REINFORCE) {
|
||||||
if (data.region !== undefined) {
|
if (data.regions !== undefined) {
|
||||||
if (this.reinforce(data)) {
|
if (this.reinforce(data)) {
|
||||||
this.reinforcementsPlaced += 1;
|
this.reinforcementsPlaced += 1;
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -510,7 +510,7 @@ Various parts of the implementation use the random oracle model: in particular,
|
|||||||
|
|
||||||
Paillier ciphertexts are constant size, each $\sim$1.0kB in size (as they are taken modulo $n^2$, where $n$ is the product of two 2048 bit primes). This is small enough for the memory and network limitations of today.
|
Paillier ciphertexts are constant size, each $\sim$1.0kB in size (as they are taken modulo $n^2$, where $n$ is the product of two 2048 bit primes). This is small enough for the memory and network limitations of today.
|
||||||
|
|
||||||
The proof of zero uses two Paillier ciphertexts, a challenge of size 2048 bits, and a proof statement of size 4096 bits. In total, this is $\sim$2.8kB. These are constant size, and since they run in a single round, take constant time.
|
The proof of zero uses two Paillier ciphertexts, a challenge of size 2048 bits, and a proof statement of size 4096 bits. In total, this is a constant size of $\sim$2.8kB.
|
||||||
|
|
||||||
On the other hand, \hyperref[protocol1]{Protocol~\ref*{protocol1}} requires multiple rounds. Assume that we use 42 rounds: this provides an acceptable level of soundness, with a cheat probability of $\left(\frac{1}{2}\right)^{-42} \approx 2.3 \times 10^{-13}$. Additionally, assume that there are 10 regions to verify. Each round then requires ten Paillier ciphertexts alongside ten proofs of zero. This results in a proof size of $\sim$1.7MB. Whilst this is still within current memory limitations, the network cost is extreme; and this value may exceed what can be reasonably operated on within a processor's cache.
|
On the other hand, \hyperref[protocol1]{Protocol~\ref*{protocol1}} requires multiple rounds. Assume that we use 42 rounds: this provides an acceptable level of soundness, with a cheat probability of $\left(\frac{1}{2}\right)^{-42} \approx 2.3 \times 10^{-13}$. Additionally, assume that there are 10 regions to verify. Each round then requires ten Paillier ciphertexts alongside ten proofs of zero. This results in a proof size of $\sim$1.7MB. Whilst this is still within current memory limitations, the network cost is extreme; and this value may exceed what can be reasonably operated on within a processor's cache.
|
||||||
|
|
||||||
@ -520,6 +520,8 @@ This is all in an ideal situation without compression or signatures: in the impl
|
|||||||
|
|
||||||
The size of the proof of zero communication is, in total, $3290 + 1744 + 2243$ characters, i.e $\sim$7.3kB. This is about 2-3 times larger than the ideal size. A solution to this is to use a more compact format, for example msgpack \cite{msgpack} (which also has native support for binary literals).
|
The size of the proof of zero communication is, in total, $3290 + 1744 + 2243$ characters, i.e $\sim$7.3kB. This is about 2-3 times larger than the ideal size. A solution to this is to use a more compact format, for example msgpack \cite{msgpack} (which also has native support for binary literals).
|
||||||
|
|
||||||
|
This only considers the network footprint. The other consideration is the memory footprint. The proof of zero requires auxiliary memory beyond the new values communicated. In particular, it must clone the ciphertext being proven, in order to prevent mutating the original ciphertext when multiplying by $g^{-m}$.
|
||||||
|
|
||||||
\subsubsection{Time complexity}
|
\subsubsection{Time complexity}
|
||||||
|
|
||||||
It is remarked that Paillier encryption performs considerably slower than RSA on all key sizes. \cite{paillier1999public} provides a table of theoretic results, suggesting that Paillier encryption can be over 1,000 times slower than RSA for the same key size.
|
It is remarked that Paillier encryption performs considerably slower than RSA on all key sizes. \cite{paillier1999public} provides a table of theoretic results, suggesting that Paillier encryption can be over 1,000 times slower than RSA for the same key size.
|
||||||
|
Loading…
Reference in New Issue
Block a user