,....
This commit is contained in:
@ -16,11 +16,11 @@ class Ciphertext {
|
||||
let gm = (1n + key.n * plainText) % key.n2;
|
||||
|
||||
// Compute g^m r^n from crt.
|
||||
this.cyphertext = (gm * mod_exp(r, key.n, key.n2)) % key.n2;
|
||||
this.cipherText = (gm * mod_exp(r, key.n, key.n2)) % key.n2;
|
||||
|
||||
// Force into range.
|
||||
while (this.cyphertext < 0n) {
|
||||
this.cyphertext += key.n2;
|
||||
while (this.cipherText < 0n) {
|
||||
this.cipherText += key.n2;
|
||||
}
|
||||
|
||||
this.r = r;
|
||||
@ -31,30 +31,69 @@ class Ciphertext {
|
||||
}
|
||||
|
||||
update(c) {
|
||||
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n2;
|
||||
this.cipherText = (this.cipherText * c.cipherText) % 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.n2;
|
||||
while (this.cipherText < 0n) {
|
||||
this.cipherText += this.pubKey.n2;
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
return "0x" + this.cyphertext.toString(16);
|
||||
return "0x" + this.cipherText.toString(16);
|
||||
}
|
||||
|
||||
prove() {
|
||||
return new ZeroProofSessionProver(this);
|
||||
return new ValueProofSessionProver(this);
|
||||
}
|
||||
|
||||
asReadOnlyCyphertext() {
|
||||
return new ReadOnlyCiphertext(this.pubKey, this.cyphertext);
|
||||
// Construct a non-interactive proof
|
||||
proveNI() {
|
||||
let rp = cryptoRandom(4096);
|
||||
while (rp >= this.pubKey.n) {
|
||||
rp = cryptoRandom(4096);
|
||||
}
|
||||
|
||||
let a = mod_exp(rp, this.pubKey.n, this.pubKey.n2);
|
||||
let hasher = new jsSHA("SHAKE256", "HEX");
|
||||
|
||||
let plainText = this.plainText.toString(16);
|
||||
if (plainText.length % 2 !== 0) {
|
||||
plainText = "0" + plainText;
|
||||
}
|
||||
|
||||
let aStr = a.toString(16);
|
||||
if (aStr.length % 2 !== 0) {
|
||||
aStr = "0" + aStr;
|
||||
}
|
||||
|
||||
hasher.update(this.pubKey.g.toString(16));
|
||||
hasher.update(plainText);
|
||||
hasher.update(aStr);
|
||||
|
||||
let challenge = BigInt("0x" + hasher.getHash("HEX", { outputLen: 2048 }));
|
||||
|
||||
return {
|
||||
plainText: "0x" + this.plainText.toString(16),
|
||||
a: "0x" + a.toString(16),
|
||||
challenge: "0x" + challenge.toString(16),
|
||||
proof:
|
||||
"0x" +
|
||||
(
|
||||
((rp % this.pubKey.n) * mod_exp(this.r, challenge, this.pubKey.n)) %
|
||||
this.pubKey.n
|
||||
).toString(16),
|
||||
};
|
||||
}
|
||||
|
||||
asReadOnlyCiphertext() {
|
||||
return new ReadOnlyCiphertext(this.pubKey, this.cipherText);
|
||||
}
|
||||
}
|
||||
|
||||
class ZeroProofSessionProver {
|
||||
class ValueProofSessionProver {
|
||||
constructor(cipherText) {
|
||||
this.cipherText = cipherText;
|
||||
|
||||
@ -82,46 +121,63 @@ class ZeroProofSessionProver {
|
||||
|
||||
asVerifier() {
|
||||
return this.cipherText
|
||||
.asReadOnlyCyphertext()
|
||||
.asReadOnlyCiphertext()
|
||||
.prove(this.cipherText.plainText, this.noise());
|
||||
}
|
||||
}
|
||||
|
||||
window.Cyphertext = Ciphertext;
|
||||
window.Ciphertext = Ciphertext;
|
||||
|
||||
export class ReadOnlyCiphertext {
|
||||
constructor(key, cyphertext) {
|
||||
this.cyphertext = cyphertext;
|
||||
constructor(key, cipherText) {
|
||||
this.cipherText = cipherText;
|
||||
this.pubKey = key;
|
||||
|
||||
this.readOnly = true;
|
||||
}
|
||||
|
||||
update(c) {
|
||||
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n2;
|
||||
this.cipherText = (this.cipherText * c.cipherText) % this.pubKey.n2;
|
||||
|
||||
// Force into range
|
||||
while (this.cyphertext < 0n) {
|
||||
this.cyphertext += this.pubKey.n2;
|
||||
while (this.cipherText < 0n) {
|
||||
this.cipherText += this.pubKey.n2;
|
||||
}
|
||||
}
|
||||
|
||||
prove(plainText, a) {
|
||||
return new ZeroProofSessionVerifier(this, plainText, a);
|
||||
return new ValueProofSessionVerifier(this, plainText, a);
|
||||
}
|
||||
|
||||
verifyNI(statement) {
|
||||
let verifier = new ValueProofSessionVerifier(
|
||||
this,
|
||||
BigInt(statement.plainText),
|
||||
BigInt(statement.a),
|
||||
BigInt(statement.challenge)
|
||||
);
|
||||
|
||||
return verifier.verify(BigInt(statement.proof));
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new ReadOnlyCiphertext(this.pubKey, this.cyphertext);
|
||||
return new ReadOnlyCiphertext(this.pubKey, this.cipherText);
|
||||
}
|
||||
}
|
||||
|
||||
class ZeroProofSessionVerifier {
|
||||
constructor(cipherText, plainText, a) {
|
||||
class ValueProofSessionVerifier {
|
||||
constructor(cipherText, plainText, a, challenge) {
|
||||
// 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;
|
||||
|
||||
if (challenge === undefined) {
|
||||
// Shift the challenge down by 1 to ensure it is smaller than either prime factor.
|
||||
this.challenge = cryptoRandom(2048) << 1n;
|
||||
} else {
|
||||
this.challenge = challenge;
|
||||
}
|
||||
|
||||
this.a = a;
|
||||
|
||||
this.plainText = plainText;
|
||||
@ -130,14 +186,14 @@ class ZeroProofSessionVerifier {
|
||||
verify(proof) {
|
||||
// check coprimality
|
||||
if (gcd(proof, this.cipherText.pubKey.n) !== 1n) return -1;
|
||||
if (gcd(this.cipherText.cyphertext, this.cipherText.pubKey.n) !== 1n) return -2;
|
||||
if (gcd(this.cipherText.cipherText, this.cipherText.pubKey.n) !== 1n) return -2;
|
||||
if (gcd(this.a, this.cipherText.pubKey.n) !== 1n) return -3;
|
||||
|
||||
// check exp
|
||||
return mod_exp(proof, this.cipherText.pubKey.n, this.cipherText.pubKey.n2) ===
|
||||
(this.a *
|
||||
mod_exp(
|
||||
this.cipherText.cyphertext,
|
||||
this.cipherText.cipherText,
|
||||
this.challenge,
|
||||
this.cipherText.pubKey.n2
|
||||
)) %
|
||||
@ -147,7 +203,7 @@ class ZeroProofSessionVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
window.ReadOnlyCyphertext = ReadOnlyCiphertext;
|
||||
window.ReadOnlyCiphertext = ReadOnlyCiphertext;
|
||||
|
||||
export class PaillierPubKey {
|
||||
constructor(n) {
|
||||
|
@ -5,6 +5,7 @@ import { Packet } from "./packet.js";
|
||||
import { Game } from "./game.js";
|
||||
import { Region } from "./map.js";
|
||||
import "./dom.js";
|
||||
import "./proofs.js";
|
||||
|
||||
export const ID = window.crypto.randomUUID();
|
||||
export const game = new Game();
|
||||
|
17
static/js/modules/interface/proofs.js
Normal file
17
static/js/modules/interface/proofs.js
Normal file
@ -0,0 +1,17 @@
|
||||
function cryptoShuffle(l) {
|
||||
for (let i = 0; i < l.length - 1; i++) {}
|
||||
}
|
||||
|
||||
window.cryptoShuffle = cryptoShuffle;
|
||||
|
||||
function proveRegions(regions) {
|
||||
// Construct prover coins
|
||||
let regionNames = Object.keys(regions.keys());
|
||||
let psi = [regionNames];
|
||||
|
||||
// Construct verifier coins
|
||||
let hasher = new jsSHA("SHA3-256", "TEXT");
|
||||
hasher.update(JSON.stringify(regions));
|
||||
|
||||
// Construct prover proofs
|
||||
}
|
21
static/js/sha3.js
Normal file
21
static/js/sha3.js
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user