Riskless/static/js/modules/crypto/paillier.js

72 lines
1.7 KiB
JavaScript
Raw Normal View History

import { random2048, generate_prime } from "./random_primes.js";
import { mod_exp } from "./math.js";
2023-03-13 14:52:14 +00:00
export class PaillierPubKey {
constructor(n) {
this.n = n;
// this.g = this.n + 1n;
2023-02-11 14:59:24 +00:00
}
encrypt(m) {
// Compute g^m r^n mod n^2
let r = random2048();
2023-02-11 14:59:24 +00:00
// Resample to avoid modulo bias.
while (r >= this.n) {
2023-02-11 14:59:24 +00:00
r = random2048();
}
// Compute g^m by binomial theorem.
let gm = (1n + this.n * m) % this.n ** 2n;
// Compute g^m r^n from crt
return (gm * mod_exp(r, this.n, this.n ** 2n)) % this.n ** 2n;
2023-02-08 17:55:45 +00:00
}
2023-03-13 14:52:14 +00:00
toJSON() {
return {
n: "0x" + this.n.toString(16),
};
}
static fromJSON(data) {
return new PaillierPubKey(BigInt(data.n));
}
2023-02-08 17:55:45 +00:00
}
2023-03-13 14:52:14 +00:00
class PaillierPrivKey {
constructor(p, q) {
this.n = p * q;
this.lambda = (p - 1n) * (q - 1n);
this.mu = mod_exp(this.lambda, this.lambda - 1n, this.n);
}
decrypt(c) {
return (
(((mod_exp(c, this.lambda, this.n ** 2n) - 1n) / this.n) * this.mu) % this.n
);
2023-02-08 15:52:02 +00:00
}
2023-02-08 17:55:45 +00:00
}
export function generate_keypair() {
2023-03-13 14:52:14 +00:00
let p, q, pubKey, privKey;
if (window.sessionStorage.getItem("p") === null) {
p = generate_prime();
window.sessionStorage.setItem("p", p);
} else {
p = BigInt(window.sessionStorage.getItem("p"));
}
if (window.sessionStorage.getItem("q") === null) {
q = generate_prime();
window.sessionStorage.setItem("q", q);
} else {
q = BigInt(window.sessionStorage.getItem("q"));
}
2023-02-08 17:55:45 +00:00
2023-03-13 14:52:14 +00:00
pubKey = new PaillierPubKey(p * q);
privKey = new PaillierPrivKey(p, q);
return { pubKey, privKey };
}