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