diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..d7568504da65e57eb219720716ef0fed1c7ac80a
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+    "files.associations": {
+        "complex": "cpp"
+    }
+}
\ No newline at end of file
diff --git a/src/cipher.cpp b/src/cipher.cpp
deleted file mode 100644
index fe73379a646f8dc43eafe0e898d9ea325917f10c..0000000000000000000000000000000000000000
--- a/src/cipher.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <complex>
-#include <cmath>
-#include <random>
\ No newline at end of file
diff --git a/src/ciphertext.cpp b/src/ciphertext.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..80945f068d05cd9c2d3b10c712d84fd0ae13e336
--- /dev/null
+++ b/src/ciphertext.cpp
@@ -0,0 +1,18 @@
+#include <complex>
+#include <cmath>
+#include <random>
+#include <polynomial.h>
+#include <ciphertext.h>
+
+
+Ciphertext::Ciphertext(Polynomial _c0, Polynomial _c1){
+    c0 = Polynomial(4, _c0.coeffs);
+    c1 = Polynomial(4, _c1.coeffs);
+}
+
+Ciphertext Ciphertext:: operator + (Ciphertext const &obj){
+    Polynomial out1 = c0 + obj.c0;
+    Polynomial out2 = c1 + obj.c1;
+    Ciphertext out(out1, out2);
+    return out;
+}
diff --git a/src/ciphertext.h b/src/ciphertext.h
new file mode 100644
index 0000000000000000000000000000000000000000..8c9745c43e9657fb5baa330874c0fb9f3c6a21ff
--- /dev/null
+++ b/src/ciphertext.h
@@ -0,0 +1,15 @@
+#include <polynomial.h>
+
+#ifndef CIPHERTEXT_H
+#define CIPHERTEXT_H
+
+class Ciphertext {
+  public:
+    Polynomial c0;
+    Polynomial c1;
+
+    Ciphertext(Polynomial _c0, Polynomial _c1);
+    Ciphertext operator + (Ciphertext const &obj);
+};
+
+#endif
\ No newline at end of file
diff --git a/src/ckks.cpp b/src/ckks.cpp
index d78c0a7998dd3dd5a0ec5cafed905ac2cb4d3acd..ddb9881631e70e90d87b873794fc0c7138a92e1e 100644
--- a/src/ckks.cpp
+++ b/src/ckks.cpp
@@ -2,6 +2,8 @@
 #include <complex>
 #include <cmath>
 #include <random>
+#include <polynomial.h>
+#include <pubkey.h>
 #include <eigen3/Eigen/Dense>
 #define J dcomplex(0.0,1.0)
 
@@ -46,67 +48,6 @@ dcomparr matMult(dcomplex mat[SIZE][SIZE], coeffarr in, int m){
   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];
   
@@ -122,62 +63,7 @@ Polynomial genError(int degree, double var){
   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:
@@ -228,137 +114,7 @@ class CKKS {
 };
 
 
-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(){
diff --git a/src/encoder.cpp b/src/encoder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fb30b0ea88bb26370a2ed9decfa6326cc34834f4
--- /dev/null
+++ b/src/encoder.cpp
@@ -0,0 +1,155 @@
+#include<iostream>
+#include <complex>
+#include <cmath>
+#include <random>
+#include <polynomial.h>
+#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];
+};
+
+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;
+    }
+};
\ No newline at end of file
diff --git a/src/encoder.h b/src/encoder.h
new file mode 100644
index 0000000000000000000000000000000000000000..7876df70a1d10edf60b04a5ed21663b03fcffac8
--- /dev/null
+++ b/src/encoder.h
@@ -0,0 +1,31 @@
+#include <polynomial.h>
+#include <util.h>
+
+#ifndef ENCODER_H
+#define ENCODER_H
+
+class Encoder {
+  public: 
+    int M;
+    double scale;
+    dcomplex root;
+    dcomplex vandermonde[10][10];
+    dcomplex sigmaRBasis[10][10];
+    Matrix4dc vand;
+
+    Encoder(int in, double inScale);
+    void initVandermonde(dcomplex xi);
+    void initSigmaRBasis();
+    dcomparr piInv(dcomparr input);
+    dcomparr sigma(Polynomial pol);
+    dcomparr decode(Polynomial pol);
+    dcomparr computeCoordinate(dcomparr z);
+    coeffarr coordinateWRR(dcomparr coordinates);
+    dcomparr discretization(dcomparr z);
+    Polynomial sigmaInv(dcomparr z);
+    Polynomial encode(dcomparr input);
+
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/polynomial.cpp b/src/polynomial.cpp
index fe73379a646f8dc43eafe0e898d9ea325917f10c..2eb705591c06b3a43d0ec2d2935447ca60704d66 100644
--- a/src/polynomial.cpp
+++ b/src/polynomial.cpp
@@ -1,3 +1,59 @@
 #include <complex>
 #include <cmath>
-#include <random>
\ No newline at end of file
+#include <random>
+#include <polynomial.h>
+
+
+Polynomial::Polynomial(int deg){
+    degree = deg;
+}
+
+Polynomial::Polynomial(int deg, double coeff[]){
+    degree = deg;
+    for(int i=0; i<degree; i++){
+    coeffs[i] = coeff[i];
+    }
+}
+
+void  Polynomial::setDegree(int N){
+    degree = N;
+}
+
+void Polynomial::setCoeffs(double coeff[]){
+    for(int i=0; i<degree; i++){
+    coeffs[i] = coeff[i];
+    }
+}
+
+Polynomial Polynomial::scaleCoeff(double scale){
+    Polynomial out(degree);
+    for (int i=0; i<degree; i++){
+    out.coeffs[i] = coeffs[i] * scale;
+    }
+    return out;
+}
+
+Polynomial 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 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;
+}
diff --git a/src/polynomial.h b/src/polynomial.h
new file mode 100644
index 0000000000000000000000000000000000000000..046503a2f12c35a6cdb3fffe791e4b33dc0fcf66
--- /dev/null
+++ b/src/polynomial.h
@@ -0,0 +1,21 @@
+#ifndef POLYNOMIAL_H
+#define POLYNOMIAL_H
+
+class Polynomial {
+  public:
+    int degree;
+    double coeffs[10];
+
+    Polynomial() = default;
+    Polynomial(int deg);
+    Polynomial(int deg, double coeff[]);
+
+    void setDegree(int N);
+    void setCoeffs(double coeff[]);
+    Polynomial scaleCoeff(double scale);
+    Polynomial operator + (Polynomial const &obj);
+    Polynomial operator * (Polynomial const &obj);
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index fe73379a646f8dc43eafe0e898d9ea325917f10c..1badba4c447b19e0e8de27e10040eda68d924a63 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -1,3 +1,33 @@
+#include<iostream>
 #include <complex>
 #include <cmath>
-#include <random>
\ No newline at end of file
+#include <random>
+#include <polynomial.h>
+#include <pubkey.h>
+
+using namespace std;
+
+PubKey::PubKey(){
+    a = Polynomial(4);
+    b = Polynomial(4);
+    double test[4] = {1.0,-1.0,1.0,-2.0};
+    generateA(4, 4);
+    b.setCoeffs(test);
+}
+
+void PubKey::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 PubKey::computeB(){
+
+}
diff --git a/src/pubkey.h b/src/pubkey.h
new file mode 100644
index 0000000000000000000000000000000000000000..0d44aa94effe5ec697f039da2782c97a921a380b
--- /dev/null
+++ b/src/pubkey.h
@@ -0,0 +1,16 @@
+#include <polynomial.h>
+
+#ifndef PUBKEY_H
+#define PUBKEY_H
+
+class PubKey{
+  public:
+    Polynomial a;
+    Polynomial b;
+
+    PubKey();
+    void generateA(int degree, int q);
+    void computeB();
+};
+
+#endif
\ No newline at end of file
diff --git a/src/seckey.cpp b/src/seckey.cpp
index fe73379a646f8dc43eafe0e898d9ea325917f10c..44cd8048dadd2b9d318eecd54b6fcd95db56a5c9 100644
--- a/src/seckey.cpp
+++ b/src/seckey.cpp
@@ -1,3 +1,11 @@
 #include <complex>
 #include <cmath>
-#include <random>
\ No newline at end of file
+#include <random>
+#include <polynomial.h>
+#include <seckey.h>
+
+SecKey::SecKey(){
+    s = Polynomial(4);
+    double test[4] = {1.0,-1.0,1.0,0.0};
+    s.setCoeffs(test);
+}
diff --git a/src/seckey.h b/src/seckey.h
new file mode 100644
index 0000000000000000000000000000000000000000..6439e256592d12a47bea5850cd43585a3d368115
--- /dev/null
+++ b/src/seckey.h
@@ -0,0 +1,14 @@
+#include <polynomial.h>
+
+#ifndef SECKEY_H
+#define SECKEY_H
+
+
+class SecKey{
+  public:
+    Polynomial s;
+    
+    SecKey();
+};
+
+#endif
\ No newline at end of file
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000000000000000000000000000000000000..d2ac39910083f8c7e3a993b67372798f3432c5fa
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,24 @@
+#include <eigen3/Eigen/Dense>
+#include <complex>
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#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];
+};
+
+#endif
\ No newline at end of file