Ensure bit length of randomly generated numbers are fine
This commit is contained in:
parent
6b001d9f2c
commit
6de13d3b70
@ -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();
|
||||
// Resample to avoid modulo bias.
|
||||
while (r >= key.n) {
|
||||
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:
|
||||
((this.rp % this.cipherText.pubKey.n) *
|
||||
mod_exp(this.cipherText.r, challenge, this.cipherText.pubKey.n)) %
|
||||
this.cipherText.pubKey.n,
|
||||
};
|
||||
return (
|
||||
((this.rp % this.cipherText.pubKey.n) *
|
||||
mod_exp(this.cipherText.r, challenge, 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() {
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user