diff --git a/.vscode/settings.json b/.vscode/settings.json
index f33cd36653b3a3dbb38cc531d7ee070e3c0ea1fe..c127f3a71e9a53f61e0cb540d59f3ef28f63bb54 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -46,6 +46,7 @@
         "stdexcept": "cpp",
         "streambuf": "cpp",
         "typeinfo": "cpp",
-        "bit": "cpp"
+        "bit": "cpp",
+        "chrono": "cpp"
     }
 }
\ No newline at end of file
diff --git a/bin/ciphertext.o b/bin/ciphertext.o
index 3dfc07a20ecfae7016cfddd6cfaaf91905c010c1..fdf967e0ee407cb913823f950841084e760e809a 100644
Binary files a/bin/ciphertext.o and b/bin/ciphertext.o differ
diff --git a/bin/ckks.o b/bin/ckks.o
index cc3ed5eeea7736a6881ebc2557bb9970fba809c2..f7177830de07a577c74798d4d92280441eb81259 100644
Binary files a/bin/ckks.o and b/bin/ckks.o differ
diff --git a/bin/encoder.o b/bin/encoder.o
index 75116dfb0aecb58a6c557ebcb47452b00703178d..bcadbac61ceb3d015445657f76d7aa0c56608d2a 100644
Binary files a/bin/encoder.o and b/bin/encoder.o differ
diff --git a/bin/evalkey.o b/bin/evalkey.o
index ba063c472fcf2ad902fc40176de3074f2137d63f..3e28b2d00d2d83df7a6298c1d4f7e85939e0ad28 100644
Binary files a/bin/evalkey.o and b/bin/evalkey.o differ
diff --git a/bin/ntt.o b/bin/ntt.o
index 40679a382429fbc1a6bdbe246ab1e757cb8db3aa..1ade2c809bf9907a892539002ea6f86f45485344 100644
Binary files a/bin/ntt.o and b/bin/ntt.o differ
diff --git a/bin/polynomial.o b/bin/polynomial.o
index 067b06b876f3d1a978807b1711a82b941dea529f..eab4a4b865234a36882fe3d19864fcbdae6a2188 100644
Binary files a/bin/polynomial.o and b/bin/polynomial.o differ
diff --git a/bin/pubkey.o b/bin/pubkey.o
index 170bbe8a88baf2f039c780acd6bddf007ee85e6b..9f076c661993fe6eaf71d983bebb8a22280934f6 100644
Binary files a/bin/pubkey.o and b/bin/pubkey.o differ
diff --git a/bin/seckey.o b/bin/seckey.o
index 257a327b70529a10066ffeb0315e9c7bb497942d..fd6124ac67ea06ef5800f07b7a34639b3b83b710 100644
Binary files a/bin/seckey.o and b/bin/seckey.o differ
diff --git a/run b/run
index f8a7d286a7d0f4d0e133f53be7216f3c2821f13e..2cfdbf179c1f65eaa41ce8f043fbc8efc5822481 100755
Binary files a/run and b/run differ
diff --git a/src/ckks.cpp b/src/ckks.cpp
index ec67b53929e96b45d204241282545ff5a06028c1..c11832b5a44511be19eca4088126cc7379ef1b7f 100644
--- a/src/ckks.cpp
+++ b/src/ckks.cpp
@@ -2,10 +2,54 @@
 #include <complex>
 #include <cmath>
 #include <random>
+#include <vector>
 #include "ckks.h"
+#include "ntt.h"
 
 
 using namespace std;
+#define size(c) ((int)(c).size())
+
+vector<int64_t> vScale(vector<int64_t> a, double scale){
+  int N = size(a);
+  vector<int64_t> out;
+  for(int i=0; i<N; i++){
+    double temp = (double) a[i] * scale;
+    out.push_back((int64_t) temp);
+  }
+  return out;
+}
+
+vector<int64_t> vAdd(vector<int64_t> a, vector<int64_t> b){
+  int N = size(a);
+  vector<int64_t> out;
+  for(int i=0; i<N; i++){
+    out.push_back(a[i] + b[i]);
+  }
+  return out;
+}
+
+vector<int64_t> vMult(vector<int64_t> a, vector<int64_t> b){
+  int N = size(a);
+  vector<int64_t> out;
+  for(int i=0; i<N; i++){
+    out.push_back(a[i] * b[i]);
+  }
+  return out;
+}
+
+Polynomial CKKS::fastMult(Polynomial p1, Polynomial p2, int deg, int64_t w){
+  vector<int64_t> pol1 = ntt.ntt(p1, deg, w);
+  vector<int64_t> pol2 = ntt.ntt(p2, deg, w);
+  
+  vector<int64_t> mult;
+  for(int i=0; i<deg; i++){
+    mult.push_back(pol1[i] * pol2[i]);
+  }
+  
+  Polynomial out = ntt.intt(mult, w);
+  return out;
+}
 
 CKKS::CKKS(int N, PubKey _pk, EvalKey _evk, SecKey _sk){
   pk = _pk;
@@ -80,6 +124,47 @@ Ciphertext CKKS::mult(Ciphertext ct1, Ciphertext ct2){
   Polynomial outC0 = d1.modCoeff(ql) + d3_0.modCoeff(ql);
   Polynomial outC1 = d2.modCoeff(ql) + d3_1.modCoeff(ql);
 
+
+
+  // Rescale
+  ql = (double)ql / (double)pl[level-1];
+  Polynomial c0 = outC0.scaleRoundCoeff(1.0/(double)pl[level-1]);
+  Polynomial c1 = outC1.scaleRoundCoeff(1.0/(double)pl[level-1]);
+
+
+  
+  level -= 1;
+  
+  Ciphertext out(c0.modCoeff(ql), c1.modCoeff(ql));
+
+  return out;
+}
+
+int getNextPow(int deg){
+  int out = 2;
+  while(out < deg){
+    out <<= 1;
+  }
+  return out;
+}
+
+Ciphertext CKKS::multNTT(Ciphertext ct1, Ciphertext ct2){
+  int deg = getNextPow(ct1.c0.degree+ct2.c0.degree-1);
+  cout << deg << endl;
+  int64_t w = ntt.genNthRoot(ntt.M, deg);
+  level += 1;
+  
+  Polynomial d1 = fastMult(ct1.c0, ct2.c0, deg, w).modCoeff(ql);
+  Polynomial d2 = (fastMult(ct1.c0, ct2.c1,deg, w) + fastMult(ct2.c0, ct1.c1,deg, w)).modCoeff(ql);  
+  Polynomial d3 = fastMult(ct1.c1, ct2.c1,deg, w).modCoeff(ql);
+ 
+  // Relin 
+  Polynomial d3_0 = fastMult(d3, evk.b,deg, w).scaleRoundCoeff(1.0/1000.0);
+  Polynomial d3_1 = fastMult(d3, evk.a,deg, w).scaleRoundCoeff(1.0/1000.0);
+
+  Polynomial outC0 = d1.modCoeff(ql) + d3_0.modCoeff(ql);
+  Polynomial outC1 = d2.modCoeff(ql) + d3_1.modCoeff(ql);
+
   // Rescale
   ql = (double)ql / (double)pl[level-1];
   Polynomial c0 = outC0.scaleRoundCoeff(1.0/(double)pl[level-1]);
@@ -87,7 +172,6 @@ Ciphertext CKKS::mult(Ciphertext ct1, Ciphertext ct2){
   
   level -= 1;
   
-  cout << "marker" << endl;
   Ciphertext out(c0.modCoeff(ql), c1.modCoeff(ql));
   return out;
 }
\ No newline at end of file
diff --git a/src/ckks.h b/src/ckks.h
index 2c1c269268537479e180700f0dd2709b5ddfe84b..fa1f8ed0d75d86c7931a76d214b802f6f1b3109a 100644
--- a/src/ckks.h
+++ b/src/ckks.h
@@ -3,6 +3,7 @@
 #include "seckey.h"
 #include "evalkey.h"
 #include "ciphertext.h"
+#include "ntt.h"
 
 
 #ifndef CKKS_H
@@ -18,15 +19,17 @@ class CKKS {
     PubKey pk;
     EvalKey evk;
     SecKey sk;
+    NTT ntt;
 
     CKKS(int N, PubKey _pk, EvalKey _evk, SecKey _sk);
     Polynomial genE(int degree, double var);
     Polynomial genZO();
     Ciphertext encrypt(Polynomial pt);
     Polynomial decrypt(Ciphertext ct);
-
+    Polynomial fastMult(Polynomial p1, Polynomial p2, int deg, int64_t w);
     Ciphertext add(Ciphertext ct1, Ciphertext ct2);
     Ciphertext mult(Ciphertext ct1, Ciphertext ct2);
+    Ciphertext multNTT(Ciphertext ct1, Ciphertext ct2);
 };
 
 #endif
\ No newline at end of file
diff --git a/src/encoder.cpp b/src/encoder.cpp
index 9fdae21755b749432c37c9ca57fb2c34e8a0625a..f4b7eadb744b6c2f57e305d74fe1eb1d4d5e80e0 100644
--- a/src/encoder.cpp
+++ b/src/encoder.cpp
@@ -5,12 +5,24 @@
 #include <eigen3/Eigen/Dense>
 #include "encoder.h"
 
+#include <chrono>
+
+
 using namespace std;
+using namespace std::chrono;
+
+dcomplex vdot(dcomplex a[], dcomplex* b, int size, int offset){
+  dcomplex out (0.0, 0.0);
+  for(int i=0; i<size; i++){
+    out += b[i+offset] * conj(a[i]);
+  }
+  return out;
+}
 
-dcomplex vdot(dcomplex a[], dcomplex b[]){
+dcomplex vdots(dcomplex* a, dcomplex* b, int size, int offset){
   dcomplex out (0.0, 0.0);
-  for(int i=0; i<10; i++){
-    out += b[i] * conj(a[i]);
+  for(int i=0; i<size; i++){
+    out += b[offset+i] * conj(a[offset+i]);
   }
   return out;
 }
@@ -22,20 +34,12 @@ double randomChoice(double val){
   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;
-}
-
 Encoder::Encoder(int in, double inScale){
   M = in;
   scale = inScale;
   root = exp((2*M_PI/M) * J);
+  vandermonde = (dcomplex*) malloc(M/2*M/2*sizeof(dcomplex));
+  sigmaRBasis = (dcomplex*) malloc(M/2*M/2*sizeof(dcomplex));
   initVandermonde(root);
   initSigmaRBasis();
 }
@@ -45,9 +49,7 @@ void Encoder::initVandermonde(dcomplex xi){
   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;
+      vandermonde[i*N+j] = pow(xi, power);
     }
   }
 }
@@ -56,7 +58,7 @@ void Encoder::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];
+      sigmaRBasis[j*N+i] = vandermonde[i*N+j];
     }
   }
 }
@@ -78,28 +80,29 @@ dcomparr Encoder::sigma(Polynomial pol){
   if(pol.degree == 2*N){
     for(int i=0; i<N; i++){
       for (int j=0; j<M/2; j++){
-        out.arr[i] += pol.coeffs[j] * vandermonde[i][j];
+        out.arr[i] += pol.coeffs[j] * vandermonde[i*M/2+j];
       }
     }
   }else{
     int R = 2;
-    dcomplex tempVandermonde[100][100];
     
     while (R < pol.degree){
       R <<=2;
     }
+
+    dcomplex* tempVandermonde = (dcomplex*) malloc(R*R*sizeof(dcomplex));
     
     for(int i=0; i<R; i++){
       for(int j=0; j<R; j++){
         int power = (2*i+1) * j;
         dcomplex temp = pow(exp((2*M_PI/M) * J), power);
-        tempVandermonde[i][j] = temp;
+        tempVandermonde[i*R+j] = temp;
       }
     }
 
     for(int i=0; i<R/2; i++){
       for (int j=0; j<R; j++){
-        out.arr[i] += pol.coeffs[j] * tempVandermonde[i][j];
+        out.arr[i] += pol.coeffs[j] * tempVandermonde[i*R+j];
       }
     }
   }
@@ -107,30 +110,37 @@ dcomparr Encoder::sigma(Polynomial pol){
 }
 
 dcomparr Encoder::decode(Polynomial pol){
+  auto start = high_resolution_clock::now();
   Polynomial unscaled = pol.scaleCoeff(1.0/scale);
-  return sigma(unscaled);
+  dcomparr out = sigma(unscaled);
+  
+  auto stop = high_resolution_clock::now();
+  auto duration = duration_cast<microseconds>(stop - start);
+  //cout << "Decoding: " << duration.count() << endl;
+
+  return out;
 }
 
 dcomparr Encoder::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]);
+    dcomplex zi = vdot(z.arr, sigmaRBasis, M/2, i*M/2) / vdots(sigmaRBasis, sigmaRBasis, M/2, i*M/2);
     out.arr[i] = real(zi);
   }
   
   return out;
 }
 
-coeffarr Encoder::coordinateWRR(dcomparr coordinates){
+dcomparr Encoder::coordinateWRR(dcomparr coordinates){
   double r;
   double f;
 
-  coeffarr roundedCoor;
+  dcomparr roundedCoor;
 
   for (int i=0; i<M/2; i++){
     r = real(coordinates.arr[i]) - floor(real(coordinates.arr[i]));
     f = randomChoice(r);
-    roundedCoor.arr[i] = round(real(coordinates.arr[i])-f);
+    roundedCoor.arr[i] = (double) real(coordinates.arr[i])-f;
   }
 
   return roundedCoor;
@@ -138,31 +148,24 @@ coeffarr Encoder::coordinateWRR(dcomparr coordinates){
 
 dcomparr Encoder::discretization(dcomparr z){
   dcomparr coor = computeCoordinate(z);      
-  coeffarr roundedCoor = coordinateWRR(coor);
-  dcomparr out = matMult(vandermonde, roundedCoor, M/2);
-  return out;
+  dcomparr roundedCoor = coordinateWRR(coor);
+  return roundedCoor;
 }
 
 Polynomial Encoder::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));
+    out.coeffs[i] = (double) round(real(z.arr[i]));
   }
+
   return out;
 }
 
 Polynomial Encoder::encode(dcomparr input){
+  auto start = high_resolution_clock::now();
   dcomparr zPi = piInv(input);
-
   int N = M/4;
   for (int i=0; i<N; i++){
     zPi.arr[i] *= scale;
@@ -172,6 +175,10 @@ Polynomial Encoder::encode(dcomparr input){
   dcomparr roundZ = discretization(zPi);
   Polynomial out = sigmaInv(roundZ);
 
+  auto stop = high_resolution_clock::now();
+  auto duration = duration_cast<microseconds>(stop - start);
+  //cout << "Encoding: " << duration.count() << endl;
+
   return out;
 }
 
diff --git a/src/encoder.h b/src/encoder.h
index 969e082f3d5e57f393955f44ee577fe54e23fc40..552ac6361a52b46785fabd176abe093120239a38 100644
--- a/src/encoder.h
+++ b/src/encoder.h
@@ -5,19 +5,14 @@
 using namespace std;
 
 #define J dcomplex(0.0,1.0)
-#define SIZE 100
+#define SIZE 1000
 
 typedef complex<double> dcomplex;
-typedef Eigen::Matrix<dcomplex, 4, 4> Matrix4dc;
-typedef Eigen::Matrix<dcomplex, 4, 1> Matrix1dc;
 
 struct dcomparr {
-  dcomplex arr[SIZE];
+  dcomplex arr[200];
 };
 
-struct coeffarr {
-  int64_t arr[SIZE];
-};
 
 #ifndef ENCODER_H
 #define ENCODER_H
@@ -27,9 +22,8 @@ class Encoder {
     int M;
     double scale;
     dcomplex root;
-    dcomplex vandermonde[SIZE][SIZE];
-    dcomplex sigmaRBasis[SIZE][SIZE];
-    Matrix4dc vand;
+    dcomplex* vandermonde;
+    dcomplex* sigmaRBasis;
 
     Encoder(int in, double inScale);
     void initVandermonde(dcomplex xi);
@@ -38,7 +32,7 @@ class Encoder {
     dcomparr sigma(Polynomial pol);
     dcomparr decode(Polynomial pol);
     dcomparr computeCoordinate(dcomparr z);
-    coeffarr coordinateWRR(dcomparr coordinates);
+    dcomparr coordinateWRR(dcomparr coordinates);
     dcomparr discretization(dcomparr z);
     Polynomial sigmaInv(dcomparr z);
     Polynomial encode(dcomparr input);
diff --git a/src/evalkey.cpp b/src/evalkey.cpp
index 68bce70e247c52e0c0a8f8da75b0b0f0f8c73808..5c53b7fa0772f22abc7400d5f859b3124cfda937 100644
--- a/src/evalkey.cpp
+++ b/src/evalkey.cpp
@@ -12,7 +12,7 @@ EvalKey::EvalKey(Polynomial _s, int degree, int64_t q){
     p = 1000;
     s = _s;
 
-    generateA(4, 1000);
+    generateA(degree, 100);
     computeB(q);
 }
 
@@ -32,10 +32,10 @@ Polynomial EvalKey::genE(int degree, double var){
 }
 
 void EvalKey::generateA(int degree, int64_t q){
-    int64_t half_q = (p*q)/2;
+    int64_t half_q = (q)/2;
     random_device rd;
     mt19937 gen(rd());
-    uniform_int_distribution<int64_t> dis(-half_q, half_q);
+    uniform_int_distribution<int64_t> dis(0, half_q);
     double a_coeffs[degree];
     
     for (int i=0; i<degree; i++){
diff --git a/src/ntt.cpp b/src/ntt.cpp
index 40be4f1d7c70eeed5024da63d00be543bf5578ce..6a5764181dd3f7984e016ae6599f6c2e60e76cd0 100644
--- a/src/ntt.cpp
+++ b/src/ntt.cpp
@@ -1,9 +1,9 @@
 #include "ntt.h"
 
-int NTT::modExp(int base, int power, int mod){
-    int res = 1;
-    int p = power;
-    int b = base % mod;
+int64_t NTT::modExp(int64_t base, int64_t power, int64_t mod){
+    int64_t res = 1;
+    int64_t p = power;
+    int64_t b = base % mod;
     while (p > 0){
         if (p & 1){
             res = (res * b) % mod;
@@ -15,16 +15,16 @@ int NTT::modExp(int base, int power, int mod){
     return res;
 }
 
-int NTT::modInv(int x, int mod){
-    int t = 0;
-    int t1 = 1;
-    int r = mod;
-    int r1 = x;
+int64_t NTT::modInv(int64_t x, int64_t mod){
+    int64_t t = 0;
+    int64_t t1 = 1;
+    int64_t r = mod;
+    int64_t r1 = x;
 
     while (r1 != 0){
-        int quot = (int) (r/r1);
-        int temp_t = t;
-        int temp_r = r;
+        int64_t quot = (int64_t) (r/r1);
+        int64_t temp_t = t;
+        int64_t temp_r = r;
         t = t1; 
         t1 = (temp_t - quot * t1);
         r = r1;
@@ -71,13 +71,13 @@ int64_t NTT::genNthRoot(int mod, int n){
 
 void NTT::reverse(vector<int64_t> &in, int bitLen){
     for (int i=0; i<size(in); i++){
-        int revN = 0;
+        int64_t revN = 0;
         for(int j=0; j<bitLen ; j++){
             if ((i >> j) & 1){
                 revN |= 1 << (bitLen-1-j);
             }
         }
-        int coeff = in[i];
+        int64_t coeff = in[i];
 
         if (revN > i){
             coeff ^= in[revN];
@@ -99,8 +99,8 @@ void NTT::_ntt(vector<int64_t> &in, int64_t w){
         vector<int64_t> p2;
         for(int j=0; j<N/2; j++){
             int shift = nBit - i - 1;
-            int P = (j >> shift) << shift;
-            int wP = modExp(w, P, M);
+            int64_t P = (j >> shift) << shift;
+            int64_t wP = modExp(w, P, M);
             int64_t odd = in[2*j+1] * wP;
             int64_t even = in[2*j];
             p1.push_back((even + odd) % M);
@@ -129,7 +129,7 @@ void NTT::_ntt(vector<int64_t> &in, int64_t w){
 
 vector<int64_t> NTT::ntt(Polynomial in, int degree, int64_t w){
     vector<int64_t> out(degree,0);
-    for(int i=0; i<degree; i++){
+    for(int i=0; i<in.degree; i++){
         out[i] = (int64_t) in.coeffs[i];
     }
     _ntt(out, w);
@@ -141,11 +141,10 @@ Polynomial NTT::intt(vector<int64_t> &in, int w){
     Polynomial pOut(N);
     double coeff[N];
 
-    int wInv = modInv(w, M);
-    int nInv = modInv(N, M);
+    int64_t wInv = modInv(w, M);
+    int64_t nInv = modInv(N, M);
 
     _ntt(in, wInv);
-    
     for(int i=0; i<size(in); i++){
         coeff[i] = (in[i] * nInv) % M;
     }
diff --git a/src/ntt.h b/src/ntt.h
index 74a6110ac3c456c214e46a32ceb1afea44bd1751..5078f1f82c2edb248ad84898dd70fc22fb95d45c 100644
--- a/src/ntt.h
+++ b/src/ntt.h
@@ -11,10 +11,9 @@ using namespace std;
 
 class NTT{
     public:
-        int g = 3;
         int M = 2013265921;
-        int modExp(int base, int power, int mod);
-        int modInv(int x, int mod);
+        int64_t modExp(int64_t base, int64_t power, int64_t mod);
+        int64_t modInv(int64_t x, int64_t mod);
         int bitLength(int x);
         void reverse(vector<int64_t> &in, int bitLen);
         bool existSmallerN(int r, int mod, int n);
diff --git a/src/polynomial.h b/src/polynomial.h
index e1322333c7fc0c48318b7f977c04217ac7fb36c6..81753efca7bacccf792ffd73ca92009060984690 100644
--- a/src/polynomial.h
+++ b/src/polynomial.h
@@ -5,7 +5,7 @@
 class Polynomial {
   public:
     int degree;
-    double coeffs[100];
+    double coeffs[200];
 
     Polynomial() = default;
     Polynomial(int deg);
@@ -17,6 +17,7 @@ class Polynomial {
     Polynomial scaleRoundCoeff(double scale);
     Polynomial modCoeff(int64_t q);
     Polynomial dot(Polynomial const &obj);
+    Polynomial fastMult(Polynomial p1, Polynomial p2);
     Polynomial operator + (Polynomial const &obj);
     Polynomial operator * (Polynomial const &obj);
 
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index d9deba0a8c5f02aa667810a84f5e262f83d2c6b7..39602619f45a2f9bf94356c031ba9c895c3a5d8b 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -11,7 +11,7 @@ PubKey::PubKey(Polynomial _s, int degree, int64_t q){
     b = Polynomial(degree);
     s = _s;
 
-    generateA(4, 100);
+    generateA(degree, 100);
     computeB(q);
 }
 
@@ -34,7 +34,7 @@ void PubKey::generateA(int degree, int64_t q){
     int64_t half_q = q/2;
     random_device rd;
     mt19937 gen(rd());
-    uniform_int_distribution<int64_t> dis(-half_q, half_q);
+    uniform_int_distribution<int64_t> dis(0, half_q);
     double a_coeffs[degree];
     
     for (int i=0; i<degree; i++){
diff --git a/src/seckey.cpp b/src/seckey.cpp
index 6eb3b518767677876478f50e680197a0da810d35..0ea43644b6ca3318e915f4ef2c93a654bcd99166 100644
--- a/src/seckey.cpp
+++ b/src/seckey.cpp
@@ -5,21 +5,24 @@
 
 using namespace std;
 
-SecKey::SecKey(){
-    s = Polynomial(4);
-    double coeff[4];
+SecKey::SecKey(int deg){
+    double coeff[deg];
 
-    int h = 2;
+    std::random_device rd; 
+    std::mt19937 gen(rd()); 
+    std::uniform_int_distribution<> distr(deg/2, deg);
+
+    int h = distr(gen);
     string ones(h, '1');
-    string zeros(2, '0');
+    string zeros((deg-h), '0');
     
     string key = ones + zeros;
     random_shuffle(key.begin(), key.end());
 
-    for(int i=0; i<4; i++){
+    for(int i=0; i<deg; i++){
         char temp = key.at(i);
-        coeff[i] = (double) (atoi(&temp));
+        coeff[i] = (double) -1 * (atoi(&temp));
     }
 
-    s.setCoeffs(coeff);
+    s = Polynomial(deg, coeff);
 }
diff --git a/src/seckey.h b/src/seckey.h
index 8671f2908adaf07c1920b56aa0bd256a1161237d..4fa51cc835de9e1d2986b668fdd8ab3b279136de 100644
--- a/src/seckey.h
+++ b/src/seckey.h
@@ -8,8 +8,8 @@
 class SecKey{
   public:
     Polynomial s;
-  
-    SecKey();
+    SecKey() = default;
+    SecKey(int deg);
 };
 
 #endif
\ No newline at end of file
diff --git a/test.cpp b/test.cpp
index ce8fe33fb82f8ad660557f307523923d57e547e6..f2482640688e42c6fa71a7d1e987828970490973 100644
--- a/test.cpp
+++ b/test.cpp
@@ -1,4 +1,5 @@
 #include <iostream>
+#include <chrono>
 #include "src/encoder.h"
 #include "src/polynomial.h"
 #include "src/ckks.h"
@@ -8,13 +9,23 @@
 
 
 using namespace std;
+using namespace std::chrono;
 
 int main(){
     Encoder enc(8, 64.0);
-    dcomplex a1 = 3.0 + 4.0 *J; 
-    dcomplex a2 = 2.0 - 1.0 *J;
-    dcomparr input = {a1, a2};
+    dcomplex a1 = 4.0 + 3.0 *J; 
+    dcomplex a2 = 2.0 - 1.0*J;
+    dcomparr input  = {a1, a2};
+
+    // dcomparr input;
+    // dcomplex a = 1.0 + 1.0;
+    // for(int i=0; i<32; i++){
+    //     input.arr[i] = a;
+    // }
+
     Polynomial pt = enc.encode(input);
+    
+    // pt.printPol();
 
     int q0 = 67;
     int pl[6] = {61, 67, 71, 73, 79, 59};
@@ -24,23 +35,42 @@ int main(){
         ql *= pl[i];
     }
 
-    SecKey sk = SecKey();
-    PubKey pk(sk.s, 4, ql);
-    EvalKey evk(sk.s, 4, ql);
+
+    SecKey sk = SecKey(2);
+    PubKey pk(sk.s, 2, ql);
+    // cout << "pk: ";
+    // pk.b.printPol();
+    EvalKey evk(sk.s, 2, ql);
+    // cout << "evk: ";
+    // evk.b.printPol();
     
     Polynomial pt2 = pt * pt;
-    pt2.printPol();
+    // pt2.printPol();
 
     CKKS ckks(4, pk, evk, sk);
     Ciphertext ct = ckks.encrypt(pt);
+    //ct.c0.printPol();
+
+
+    auto start = high_resolution_clock::now();
     Ciphertext ctadd = ckks.mult(ct, ct);
+    auto stop = high_resolution_clock::now();
+    auto duration = duration_cast<microseconds>(stop - start);
+    cout << "Normal Time: " << duration.count() << endl;
+
     
     Polynomial ptOut = ckks.decrypt(ctadd);
+    //ptOut.printPol();
     
-    //problem
+    // //problem
+    // cout << "decode" << endl;
     dcomparr output = enc.decode(ptOut);
-    cout << "test" << endl;
-    cout << endl;
+    // for(int i=0; i<4; i++){
+    //     cout << output.arr[i] << " ";
+    // }
+    // cout << endl;
+    // // cout << "test" << endl;
+    // cout << endl;
 
     cout << "Experiment" << endl;
     cout << "polynomial: ";
@@ -59,22 +89,40 @@ int main(){
     }
     cout << endl;
 
-    cout << "NTT test" << endl;
-    NTT ntt;
-    int64_t w = 1728404513;
-    double coeff[] = {2, 1, 0, 0};
-    Polynomial n(4, coeff);
+    // cout << "NTT test" << endl;
+    
+    auto start1 = high_resolution_clock::now();
+    Ciphertext mult = ckks.multNTT(ct, ct);
+    auto stop1 = high_resolution_clock::now();
+    auto duration1 = duration_cast<microseconds>(stop1 - start1);
+    cout << "NTT Time: " << duration1.count() << endl;
     
-    vector<int64_t> test = ntt.ntt(n, 4, w);
-    cout <<"test"<<endl;
-    for(int i=0;i<4;i++){
-        cout << test[i] << " ";
+    Polynomial nttOut = ckks.decrypt(mult);
+
+    dcomparr nttoutput = enc.decode(nttOut);
+    nttOut.printPol();
+    for(int i=0; i<4; i++){
+         cout << nttoutput.arr[i]/1.0 << " ";
     }
     cout << endl;
+    
+    // double in[] = {2.0, 1.0};
+    // Polynomial p1(4, in);
+
+    // double in2[] = {3.0, 1.0};
+    // Polynomial p2(4, in2);
+
+    // int64_t w = 1934320121;
+    // vector<int64_t> out = ckks.ntt.ntt(p1, 16, w);
+    // for(int i=0; i<16; i++){
+    //     cout << out[i] << " ";
+    // }
+    // cout << endl;
+    // Polynomial test = ckks.ntt.intt(out, w);
+    // test.printPol();
 
-    cout <<"test"<<endl;
-    Polynomial testOut = ntt.intt(test, w);
-    testOut.printPol();
+    // Polynomial test = ckks.fastMult(p1, p2, w);
+    // test.printPol();
 
     return 0;
 }
\ No newline at end of file
diff --git a/test.o b/test.o
index 4a9916dc459ad9e40041cc478df7c8e32c0585b8..36a54436f8b4b466bd16e43bbb5ccb847efd286c 100644
Binary files a/test.o and b/test.o differ