// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.2 <0.9.0; contract PaillierHomomorphicEncryption { uint256 public p; uint256 public q; uint256 public n; uint256 public g; uint256 public l; uint256 public m; struct PrivateKey { uint256 l; uint256 m; } struct PublicKey { uint256 n; uint256 n_sq; uint256 g; } PublicKey publicKey; PrivateKey privateKey; constructor() { // Initialize key generation parameters (simplified) p = 1000000009; // Replace with a prime number q = 1000000007; // Replace with another prime number n = p * q; l = (p - 1) * (q - 1); m = modInverse(l, n, 1000000); // Calculate the modular inverse publicKey = PublicKey(n, n * n, n+1); privateKey = PrivateKey(l, m); } function modInverse(uint256 a, uint256 pp, uint256 maxiter) public pure returns (uint256) { uint256 r = a; uint256 d = 1; for (uint256 i = 0; i < min(pp, maxiter); i++) { d = ((pp / r + 1) * d) % pp; r = (d * a) % pp; if (r == 1) { break; } } return d; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } // Encrypt a plaintext value function encrypt(uint256 plaintext) public view returns (uint256) { require(plaintext < n, "Plaintext must be smaller than n"); uint256 r = 5; uint256 x = powmod(r, publicKey.n, publicKey.n_sq); return (powmod(publicKey.g, plaintext, publicKey.n_sq) * x) % publicKey.n_sq; } // Decrypt a ciphertext value function decrypt(uint256 ciphertext) public view returns (uint256) { uint256 c1 = (powmod(ciphertext, privateKey.l, publicKey.n_sq) - 1) % publicKey.n_sq; uint256 plaintext = ((c1 / publicKey.n) * privateKey.m) % publicKey.n; return plaintext; } function add(uint256 a, uint256 b) public view returns (uint256) { uint256 a_enc = encrypt(a); uint256 b_enc = encrypt(b); uint256 product_enc = (a_enc * b_enc) % publicKey.n_sq; return decrypt(product_enc); } function powmod(uint256 a, uint256 b, uint256 n) public pure returns (uint256) { if(a > n) a-=n; if (b == 0) { return 1; } else if (b % 2 == 0) { uint256 temp = powmod(a, b / 2, n); return (temp * temp) % n; } else { uint256 temp = powmod(a, (b - 1) / 2, n); return (a * ((temp * temp) % n)) % n; } } }