Ensure bit length of randomly generated numbers are fine

This commit is contained in:
jude 2023-03-19 15:31:29 +00:00
parent 6b001d9f2c
commit 6de13d3b70
3 changed files with 41 additions and 61 deletions

View File

@ -1,14 +1,15 @@
import { random2048, 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 Cyphertext {
constructor(key, plainText) { constructor(key, plainText, r) {
// Compute g^m r^n mod n^2 if (r === undefined) {
let r = random2048(); r = cryptoRandom(4096);
// Resample to avoid modulo bias. // Resample to avoid modulo bias.
while (r >= key.n) { while (r >= key.n) {
r = random2048(); r = cryptoRandom(4096);
}
} }
// Compute g^m by binomial theorem. // Compute g^m by binomial theorem.
@ -21,13 +22,11 @@ class Cyphertext {
this.plainText = plainText; this.plainText = plainText;
this.readOnly = false; this.readOnly = false;
this.rp = null;
} }
update(c) { update(c) {
this.cyphertext *= c.cyphertext; this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n ** 2n;
this.r *= c.r; this.r = (this.r * c.r) % this.pubKey.n ** 2n;
this.plainText += c.plainText; this.plainText += c.plainText;
} }
@ -48,9 +47,9 @@ class ProofSessionProver {
constructor(cipherText) { constructor(cipherText) {
this.cipherText = cipherText; this.cipherText = cipherText;
this.rp = random2048(); this.rp = cryptoRandom(4096);
while (this.rp >= this.cipherText.pubKey.n) { while (this.rp >= this.cipherText.pubKey.n) {
this.rp = random2048(); this.rp = cryptoRandom(4096);
} }
} }
@ -59,12 +58,17 @@ class ProofSessionProver {
} }
prove(challenge) { prove(challenge) {
return { return (
proof:
((this.rp % this.cipherText.pubKey.n) * ((this.rp % this.cipherText.pubKey.n) *
mod_exp(this.cipherText.r, challenge, this.cipherText.pubKey.n)) % mod_exp(this.cipherText.r, challenge, this.cipherText.pubKey.n)) %
this.cipherText.pubKey.n, this.cipherText.pubKey.n
}; );
}
asVerifier() {
return this.cipherText
.asReadOnlyCyphertext()
.prove(this.cipherText.plainText, this.noise());
} }
} }
@ -76,24 +80,23 @@ export class ReadOnlyCyphertext {
this.pubKey = key; this.pubKey = key;
this.readOnly = true; this.readOnly = true;
this.proofPromise = null;
} }
update(c) { update(c) {
this.cyphertext *= c.cyphertext; this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n ** 2n;
} }
async prove() { prove(plainText, a) {
// request a proof return new ProofSessionVerifier(this, plainText, a);
let promise = new Promise((res) => (this.proofPromise = res));
} }
} }
class ProofSessionVerifier { class ProofSessionVerifier {
constructor(cipherText, a) { constructor(cipherText, plainText, a) {
this.cipherText = cipherText; this.cipherText = cipherText;
this.challenge = random2048(); 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.a = a;
} }
@ -126,8 +129,8 @@ export class PaillierPubKey {
this.g = this.n + 1n; this.g = this.n + 1n;
} }
encrypt(m) { encrypt(m, r) {
return new Cyphertext(this, m); return new Cyphertext(this, m, r);
} }
toJSON() { toJSON() {

View File

@ -1,28 +0,0 @@
import { random2048 } from "./random_primes.js";
import { mod_exp } from "./math";
class PlaintextVerifier {
constructor(cyphertext, value, pub_key) {
this.proving =
(cyphertext * mod_exp(pub_key.g, value, pub_key.n ** 2)) % pub_key.n ** 2;
this.challenge = random2048();
}
verify(response) {}
}
class PlaintextProver {
constructor(cyphertext, pub_key, priv_key) {
this.value = priv_key.decrypt(cyphertext.text);
this.mixin = random2048();
this.pubKey = pub_key;
}
handleChallenge(challenge) {
return (
(this.mixin * mod_exp(cyphertext.mixin, challenge, this.pubKey.n)) %
this.pubKey.n
);
}
}

View File

@ -1,7 +1,12 @@
import { mod_exp } from "./math.js"; import { mod_exp } from "./math.js";
export function random2048() { export function cryptoRandom(bits) {
const byteArray = new BigUint64Array(32); if (bits === undefined) {
bits = 2048;
}
let length = bits / 64;
const byteArray = new BigUint64Array(length);
window.crypto.getRandomValues(byteArray); window.crypto.getRandomValues(byteArray);
let intRepr = 0n; let intRepr = 0n;
for (let int of byteArray) { for (let int of byteArray) {
@ -18,7 +23,7 @@ export function random2048() {
* We generate between 2^2047 and 2^2048 - 1 by adding differences. * We generate between 2^2047 and 2^2048 - 1 by adding differences.
*/ */
function generate_bigint() { function generate_bigint() {
let intRepr = random2048(); let intRepr = cryptoRandom();
// Drop the MSB to force into range from above // Drop the MSB to force into range from above
intRepr >>= 1n; intRepr >>= 1n;
@ -56,7 +61,7 @@ function miller_rabin(n, k) {
} }
for (; k > 0; k--) { for (; k > 0; k--) {
let a = random2048(); let a = cryptoRandom();
let x = mod_exp(a, d, n); let x = mod_exp(a, d, n);
if (x === 1n || x === n - 1n) { if (x === 1n || x === n - 1n) {