diff --git a/src/cipher.cpp b/src/cipher.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe73379a646f8dc43eafe0e898d9ea325917f10c --- /dev/null +++ b/src/cipher.cpp @@ -0,0 +1,3 @@ +#include <complex> +#include <cmath> +#include <random> \ No newline at end of file diff --git a/src/ckks.cpp b/src/ckks.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d78c0a7998dd3dd5a0ec5cafed905ac2cb4d3acd --- /dev/null +++ b/src/ckks.cpp @@ -0,0 +1,366 @@ +#include<iostream> +#include <complex> +#include <cmath> +#include <random> +#include <eigen3/Eigen/Dense> +#define J dcomplex(0.0,1.0) + +#define SIZE 10 + +using namespace std; + +typedef complex<double> dcomplex; +typedef Eigen::Matrix<dcomplex, 4, 4> Matrix4dc; +typedef Eigen::Matrix<dcomplex, 4, 1> Matrix1dc; + +struct dcomparr { + dcomplex arr[10]; +}; + +struct coeffarr { + int arr[10]; +}; + +dcomplex vdot(dcomplex a[], dcomplex b[]){ + dcomplex out (0.0, 0.0); + for(int i=0; i<10; i++){ + out += b[i] * conj(a[i]); + } + return out; +} + +double randomChoice(double val){ + default_random_engine generator; + discrete_distribution<int> distribution {round(1.0 - val), round(val)}; + int number = distribution(generator); + return ((number == 0) ? val : (val - 1.0)); +} + +dcomparr matMult(dcomplex mat[SIZE][SIZE], coeffarr in, int m){ + dcomparr out; + for(int i=0; i<m; i++){ + for(int j=0; j<m; j++){ + out.arr[i] += mat[i][j] * (double)in.arr[j]; + } + } + return out; +} + + +class Polynomial { + public: + int degree; + double coeffs[10]; + + Polynomial(int deg){ + degree = deg; + } + + Polynomial(int deg, double coeff[]){ + degree = deg; + for(int i=0; i<degree; i++){ + coeffs[i] = coeff[i]; + } + } + + void setDegree(int N){ + degree = N; + } + + void setCoeffs(double coeff[]){ + for(int i=0; i<degree; i++){ + coeffs[i] = coeff[i]; + } + } + + Polynomial scaleCoeff(double scale){ + Polynomial out(degree); + for (int i=0; i<degree; i++){ + out.coeffs[i] = coeffs[i] * scale; + } + return out; + } + + Polynomial operator + (Polynomial const &obj){ + + double coeff[degree]; + for(int i=0; i<degree; i++){ + coeff[i] = coeffs[i] + obj.coeffs[i]; + } + + Polynomial out(degree, coeff); + return out; + } + + Polynomial operator * (Polynomial const &obj){ + int deg = degree + obj.degree - 1; + double coeff[deg] = {0.0}; + + for(int i=0; i<degree; i++){ + for(int j=0; j<obj.degree; j++){ + coeff[i+j] += coeffs[i] * obj.coeffs[j]; + } + } + + Polynomial out(deg, coeff); + return out; + } +}; + +Polynomial genError(int degree, double var){ + double errCoeffs[degree]; + + random_device rd; + mt19937 gen(rd()); + normal_distribution<double> dis(0, var); + + for(int i=0; i<degree; i++){ + errCoeffs[i] = (double) round(dis(gen)); + } + + Polynomial err(4, errCoeffs); + return err; +} + +class PubKey{ + public: + Polynomial a = Polynomial(4); + Polynomial b = Polynomial(4); + + PubKey(){ + double test[4] = {1.0,-1.0,1.0,-2.0}; + generateA(4, 4); + b.setCoeffs(test); + } + + void generateA(int degree, int q){ + int half_q = q/2; + random_device rd; + mt19937 gen(rd()); + uniform_int_distribution<int> dis(-half_q, half_q); + double a_coeffs[degree]; + + for (int i=0; i<degree; i++){ + a_coeffs[i] = (double) dis(gen); + } + a.setCoeffs(a_coeffs); + } + + void computeB(){ + + } +}; + +class SecKey{ + public: + Polynomial s = Polynomial(4); + + SecKey(){ + double test[4] = {1.0,-1.0,1.0,0.0}; + s.setCoeffs(test); + } +}; + +class Ciphertext { + public: + Polynomial c0 = Polynomial(4); + Polynomial c1 = Polynomial(4); + + Ciphertext(Polynomial _c0, Polynomial _c1){ + c0.setCoeffs(_c0.coeffs); + c1.setCoeffs(_c1.coeffs); + } + + Ciphertext operator + (Ciphertext const &obj){ + Polynomial out1 = c0 + obj.c0; + Polynomial out2 = c1 + obj.c1; + Ciphertext out(out1, out2); + return out; + } +}; + +class CKKS { + private: + SecKey sk; + + public: + int deg; + PubKey pk; + + CKKS(int N){ + deg = N; + } + + Polynomial genError(){ + double test[4] = {1.0, 1.0, 1.0, 1.0}; + Polynomial err(4, test); + return err; + } + + Ciphertext encrypt(Polynomial pt){ + Polynomial e = genError(); + Polynomial c0 = (e + pt) + pk.b; + Polynomial c1 = pk.a; + + Ciphertext ct(c0, c1); + return ct; + } + + Polynomial genZO(){ + default_random_engine generator; + double val[3] = {-1.0, 1.0, 0}; + discrete_distribution<int> distribution {0.25, 0.25, 0.5}; + + double zoCoeffs[deg]; + for(int i=0; i<deg; i++){ + int number = distribution(generator); + zoCoeffs[i] = val[number]; + } + + Polynomial zo(deg, zoCoeffs); + return zo; + } + + Polynomial decrypt(Ciphertext ct){ + Polynomial pt = ct.c0 + (ct.c1 * sk.s); + return pt; + } +}; + + +class Encoder { + public: + int M; + double scale; + dcomplex root; + dcomplex vandermonde[10][10]; + dcomplex sigmaRBasis[10][10]; + Matrix4dc vand; + + Encoder(int in, double inScale){ + M = in; + scale = inScale; + root = exp((2*M_PI/M) * J); + initVandermonde(root); + initSigmaRBasis(); + } + + void initVandermonde(dcomplex xi){ + int N = M/2; + for(int i=0; i<N; i++){ + for(int j=0; j<N; j++){ + int power = (2*i+1) * j; + dcomplex temp = pow(xi, power); + vandermonde[i][j] = temp; + vand(i,j) = temp; + + } + } + } + + void initSigmaRBasis(){ + int N = M/2; + for(int i=0; i<N; i++){ + for(int j=0; j<N; j++){ + sigmaRBasis[j][i] = vandermonde[i][j]; + } + } + } + + dcomparr piInv(dcomparr input){ + int N = M/4; + dcomparr out; + for (int i=0; i<N; i++){ + out.arr[i] = input.arr[i]; + out.arr[2*N-i-1] = conj(input.arr[i]); + } + + return out; + } + + dcomparr sigma(Polynomial pol){ + int N = M/4; + dcomparr out; + for(int i=0; i<N; i++){ + for (int j=0; j<M/2; j++){ + out.arr[i] += pol.coeffs[j] * vandermonde[i][j]; + } + } + + return out; + } + + dcomparr decode(Polynomial pol){ + Polynomial unscaled = pol.scaleCoeff(1.0/scale); + return sigma(unscaled); + } + + dcomparr computeCoordinate(dcomparr z){ + dcomparr out; + for (int i=0; i<M/2; i++){ + dcomplex zi = vdot(z.arr, sigmaRBasis[i]) / vdot(sigmaRBasis[i], sigmaRBasis[i]); + out.arr[i] = real(zi); + } + + return out; + } + + coeffarr coordinateWRR(dcomparr coordinates){ + double r; + double f; + + coeffarr roundedCoor; + + for (int i=0; i<10; i++){ + r = real(coordinates.arr[i]) - floor(real(coordinates.arr[i])); + f = randomChoice(r); + roundedCoor.arr[i] = round(real(coordinates.arr[i])-f); + } + + return roundedCoor; + } + + dcomparr discretization(dcomparr z){ + dcomparr coor = computeCoordinate(z); + coeffarr roundedCoor = coordinateWRR(coor); + dcomparr out = matMult(vandermonde, roundedCoor, M/2); + return out; + } + + Polynomial sigmaInv(dcomparr z){ + Matrix1dc zRounded; + int N = M/2; + Polynomial out(N); + + for (int i=0; i<N; i++){ + zRounded(i,0) = z.arr[i]; + } + + Matrix1dc res = vand.lu().solve(zRounded); + + for(int i=0; i<N; i++){ + out.coeffs[i] = real(res(i,0)); + } + return out; + } + + Polynomial encode(dcomparr input){ + dcomparr zPi = piInv(input); + + int N = M/4; + for (int i=0; i<N; i++){ + zPi.arr[i] *= scale; + zPi.arr[i+N] *= scale; + } + + dcomparr roundZ = discretization(zPi); + Polynomial out = sigmaInv(roundZ); + + return out; + } +}; + + +int main(){ + +} \ No newline at end of file diff --git a/src/polynomial.cpp b/src/polynomial.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe73379a646f8dc43eafe0e898d9ea325917f10c --- /dev/null +++ b/src/polynomial.cpp @@ -0,0 +1,3 @@ +#include <complex> +#include <cmath> +#include <random> \ No newline at end of file diff --git a/src/pubkey.cpp b/src/pubkey.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe73379a646f8dc43eafe0e898d9ea325917f10c --- /dev/null +++ b/src/pubkey.cpp @@ -0,0 +1,3 @@ +#include <complex> +#include <cmath> +#include <random> \ No newline at end of file diff --git a/src/seckey.cpp b/src/seckey.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe73379a646f8dc43eafe0e898d9ea325917f10c --- /dev/null +++ b/src/seckey.cpp @@ -0,0 +1,3 @@ +#include <complex> +#include <cmath> +#include <random> \ No newline at end of file