aaaaaaaaaaaaaaaaaa

This commit is contained in:
jude
2023-04-30 18:42:52 +01:00
parent 0fed48b79d
commit 9c6b251a25
12 changed files with 294 additions and 88 deletions

View File

@ -1,3 +1,14 @@
/**
* Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
* This work is free. You can redistribute it and/or modify it
* under the terms of the WTFPL, Version 2
* For more information see LICENSE.txt or http://www.wtfpl.net/
*
* For more information, the home page:
* http://pieroxy.net/blog/pages/lz-string/testing.html
*
* LZ-based compression algorithm, version 1.4.5
*/
var LZString = (function () {
var r = String.fromCharCode,
o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

View File

@ -1,6 +1,6 @@
import { mod_exp } from "./math.js";
export const KEY_SIZE = 1024;
export const KEY_SIZE = 512;
export function cryptoRandom(bits) {
if (bits === undefined) {
@ -90,7 +90,7 @@ function miller_rabin(n, k) {
export function generate_prime() {
while (true) {
let n = generate_bigint();
let n = generate_bigint() | 0b11n;
if (small_prime_test(n) && miller_rabin(n, 40)) {
return n;
}
@ -109,6 +109,8 @@ export function generate_safe_prime() {
}
}
window.generate_safe_prime = generate_safe_prime;
const SMALL_PRIMES = [
2n,
3n,

View File

@ -12,6 +12,7 @@ export class Game {
this.us = null;
this.players = {};
this.state = WAITING;
this.contendedRegion = null;
this.allPlaced = false;
}

View File

@ -165,6 +165,11 @@ document.addEventListener("ACT", async (ev) => {
}
});
document.addEventListener("RESOLVE", (ev) => {
const data = ev.detail;
game.contendedRegion.handleResolve(data);
});
// todo has to filter by player
document.addEventListener("PROOF", async (ev) => {
const data = ev.detail;

View File

@ -113,6 +113,10 @@ export class Region {
this.neighbours = new Set();
this.continent = continent;
this.attackResolver = null;
this.attackerRes = null;
this.defenderRes = null;
REGIONS[name] = this;
}
@ -172,6 +176,48 @@ export class Region {
verify(plainText, a) {
this.strength.verify(this.name, plainText, a);
}
async handleResolve(resolution) {
await navigator.locks.request(`region-${this.name}`, () => {
if (resolution.author === this.owner.id) {
this.defenderRes = resolution;
} else {
this.attackerRes = resolution;
}
if (
this.attackResolver !== null &&
this.defenderRes !== null &&
this.attackerRes !== null
) {
this.attackResolver({
attackerRes: this.attackerRes,
defenderRes: this.defenderRes,
});
}
});
}
async resolveAttack() {
let promise;
await navigator.locks.request(`region-${this.name}`, () => {
if (this.attackerRes === null || this.defenderRes === null) {
let resolver;
promise = new Promise((resolve) => {
resolver = resolve;
});
this.attackResolver = resolver;
} else {
promise = new Promise((resolve) => {
resolve({
attackerRes: this.attackerRes,
defenderRes: this.defenderRes,
});
});
}
});
return promise;
}
}
window.Region = Region;

View File

@ -161,4 +161,28 @@ export class Packet {
region: region,
});
}
static createRegionProof(proof) {
return this._sign({
...this._createBase("RESOLVE"),
action: "MAINTAIN",
proof: proof,
});
}
static createRegionYield() {
return this._sign({
...this._createBase("RESOLVE"),
action: "YIELD",
proof: proof,
});
}
static createRegionCapture(cipherText) {
return this._sign({
...this._createBase("RESOLVE"),
action: "CAPTURE",
cipherText: cipherText,
});
}
}

View File

@ -5,6 +5,7 @@ import { PaillierPubKey, ReadOnlyCiphertext } from "../crypto/paillier.js";
import { Region } from "./map.js";
import { showDefenseDom } from "./dom.js";
import {
proveBitLength,
proveFortify,
proveRange,
proveRegions,
@ -325,6 +326,8 @@ export class Player {
return false;
}
game.contendedRegion = defender;
// If we're the defender, we need to send a packet to state our defense.
if (defender.owner === game.us) {
showDefenseDom(defender.name);
@ -340,8 +343,6 @@ export class Player {
defenderStrength = await defender.owner.getDefense();
}
console.log(defenderStrength);
/* How do Risk attacks work?
- Offender signs 1-3 armies, defender signs 1-2 armies
- Both roll respective dice
@ -387,10 +388,16 @@ export class Player {
// Handle aftermath.
if (defender.owner === game.us) {
if (defender.strength.cipherText.plainText === 0n) {
// Handle region loss
// State we don't control the region. This makes programming easier.
socket.emit("message", Packet.createRegionYield());
} else {
let ct = defender.strength.cipherText.clone();
ct.update(new Ciphertext(ct.pubKey, -2n, 0n));
// Prove we still control the region
let proof = proveRange(defender.strength.cipherText, 2n ** 32n);
let proof = proveBitLength(ct);
// Send proof we maintain it
socket.emit("message", Packet.createRegionProof(proof));
}
} else if (this === game.us) {
if (defender.strength.assumedStrength === 0n) {
@ -400,14 +407,29 @@ export class Player {
new Ciphertext(this.paillierPubKey, offenderRolls.length + 1),
defender.name
);
// Send the new ciphertext
socket.emit(
"message",
Packet.createRegionCapture(defender.strength.cipherText)
);
} else {
// State we didn't capture. Again, makes programming easier.
socket.emit("message", Packet.createRegionYield());
}
} else {
await defender.resolveConflict();
let resolutions = await defender.resolveAttack();
console.log(resolutions);
}
// Reset the promises in case they attack again.
defender.owner.defenderPromise = null;
defender.owner.defenderAmount = null;
defender.defenderRes = null;
defender.attackerRes = null;
defender.attackResolver = null;
game.contendedRegion = null;
}
async setDefense(amount) {

View File

@ -1,7 +1,7 @@
import { cryptoRandom } from "../crypto/random_primes.js";
import { Region } from "./map.js";
const ROUNDS = 24;
const ROUNDS = 12;
function cryptoRange(upper) {
// This is ridiculous: why implement a BigInt primitive, have it behave like a number, and then _not_ offer