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";
|
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() {
|
||||||
|
@ -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";
|
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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user