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";
class Cyphertext {
constructor(key, plainText) {
// Compute g^m r^n mod n^2
let r = random2048();
constructor(key, plainText, r) {
if (r === undefined) {
r = cryptoRandom(4096);
// Resample to avoid modulo bias.
while (r >= key.n) {
r = random2048();
r = cryptoRandom(4096);
}
}
// Compute g^m by binomial theorem.
@ -21,13 +22,11 @@ class Cyphertext {
this.plainText = plainText;
this.readOnly = false;
this.rp = null;
}
update(c) {
this.cyphertext *= c.cyphertext;
this.r *= c.r;
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n ** 2n;
this.r = (this.r * c.r) % this.pubKey.n ** 2n;
this.plainText += c.plainText;
}
@ -48,9 +47,9 @@ class ProofSessionProver {
constructor(cipherText) {
this.cipherText = cipherText;
this.rp = random2048();
this.rp = cryptoRandom(4096);
while (this.rp >= this.cipherText.pubKey.n) {
this.rp = random2048();
this.rp = cryptoRandom(4096);
}
}
@ -59,12 +58,17 @@ class ProofSessionProver {
}
prove(challenge) {
return {
proof:
return (
((this.rp % 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.readOnly = true;
this.proofPromise = null;
}
update(c) {
this.cyphertext *= c.cyphertext;
this.cyphertext = (this.cyphertext * c.cyphertext) % this.pubKey.n ** 2n;
}
async prove() {
// request a proof
let promise = new Promise((res) => (this.proofPromise = res));
prove(plainText, a) {
return new ProofSessionVerifier(this, plainText, a);
}
}
class ProofSessionVerifier {
constructor(cipherText, a) {
constructor(cipherText, plainText, a) {
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;
}
@ -126,8 +129,8 @@ export class PaillierPubKey {
this.g = this.n + 1n;
}
encrypt(m) {
return new Cyphertext(this, m);
encrypt(m, r) {
return new Cyphertext(this, m, r);
}
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";
export function random2048() {
const byteArray = new BigUint64Array(32);
export function cryptoRandom(bits) {
if (bits === undefined) {
bits = 2048;
}
let length = bits / 64;
const byteArray = new BigUint64Array(length);
window.crypto.getRandomValues(byteArray);
let intRepr = 0n;
for (let int of byteArray) {
@ -18,7 +23,7 @@ export function random2048() {
* We generate between 2^2047 and 2^2048 - 1 by adding differences.
*/
function generate_bigint() {
let intRepr = random2048();
let intRepr = cryptoRandom();
// Drop the MSB to force into range from above
intRepr >>= 1n;
@ -56,7 +61,7 @@ function miller_rabin(n, k) {
}
for (; k > 0; k--) {
let a = random2048();
let a = cryptoRandom();
let x = mod_exp(a, d, n);
if (x === 1n || x === n - 1n) {