diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index 2333fb5388648f99b93ef99e1caa91bb279dfe2c..511f190f8a5fb12aba6115e85f053f676198765f 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -1,2 +1,2 @@
-add_executable(app app.c)
+add_executable(app scheme.c)
 target_link_libraries(app PRIVATE ppann_lib)
\ No newline at end of file
diff --git a/apps/app.c b/apps/app.c
deleted file mode 100644
index 9508f4eb8b502d3904c0e085cfa8fc87a047922f..0000000000000000000000000000000000000000
--- a/apps/app.c
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "field.h"
-#include "group.h"
-#include <stdio.h>
-#include "relic/relic.h"
-
-
-int main() {
-    core_init();
-    pc_param_set_any();
-
-//
-//    g a, b;
-//    gt x, y;
-//
-//    // Get generator and map to target group, x =
-//    generator(a);
-//    map(a, a, x);
-//
-//
-//    g1_print(a);
-//    printf("\n");
-//    gt_print(x);
-//    printf("\n");
-//
-//    // Multiply and Exp.
-//    zp m, n;
-//    zp_from_int(m, 5);
-//    zp_from_int(n, 5);
-//
-//    // b = a^5, y = gt^10
-//    multiply(b, a, m);
-//
-//    g1_print(b);
-//    printf("\n");
-//
-//    exponentiation(y, x, n);
-//
-//    gt_free(x);
-//    map(b, b, x);
-//
-//    printf("Compare: %i", gt_cmp(y, x));
-
-    g1_t a, b;
-    gt_t x, y, z;
-
-    g1_get_gen(a);
-
-    g1_print(a);
-
-    g1_mul_dig(b, a, 5);
-
-    g1_print(b);
-
-    pc_map(x, a, a);
-
-    pc_map(y, b, b);
-
-    gt_exp_dig(z, x, 25);
-
-    printf("Compare: %i", gt_cmp(y, z) == RLC_EQ);
-
-    return 0;
-}
\ No newline at end of file
diff --git a/apps/scheme.c b/apps/scheme.c
new file mode 100644
index 0000000000000000000000000000000000000000..2346cc9365f64e5eb398206b61edfcc879118275
--- /dev/null
+++ b/apps/scheme.c
@@ -0,0 +1,123 @@
+#include "vector.h"
+#include "matrix.h"
+
+
+const int B_SIZE = 6;
+
+struct key {
+    zp_mat A;
+    zp_mat B;
+    zp_mat Bi;
+    g base;
+    gt t_base;
+};
+
+struct ct {
+    g_vec ctx;
+    g_vec ctk;
+    g_vec ctc;
+};
+
+void initialize_relic() {
+    core_init();
+    fp_prime_init();
+    pc_param_set_any();
+}
+
+struct key setup(int size) {
+    struct key key;
+    key.A = matrix_zp_rand(2, size);
+    key.B = matrix_zp_rand(B_SIZE, B_SIZE);
+    key.Bi = matrix_inverse(key.B, B_SIZE);
+    key.Bi = matrix_transpose(key.Bi, B_SIZE, B_SIZE);
+    generator(key.base);
+    map(key.base, key.base, key.t_base);
+    return key;
+}
+
+struct ct enc(struct key key, int *message, int size) {
+    // Declare the returned ciphertext and convert message to zp.
+    struct ct ct;
+    zp_vec x = vector_zp_from_int(message, size);
+
+    // Helper values.
+    int one[] = {1}, zero[] = {0};
+    zp_vec one_vec = vector_zp_from_int(one, 1);
+    zp_vec zero_vec = vector_zp_from_int(zero, 1);
+
+    // We generate s and compute sA + x.
+    zp_vec s = vector_zp_rand(2);
+    zp_vec sA = matrix_multiply(s, key.A, 1, 2, size);
+    zp_vec sAx = vector_add(sA, x, size);
+    ct.ctx = vector_raise(key.base, sAx, size);
+
+    // We compute the function hiding inner product encryption key.
+    zp_mat AT = matrix_transpose(key.A, 2, size);
+    zp_vec xAT = matrix_multiply(x, AT, 1, size, 2);
+    zp_vec xATs = vector_merge(xAT, s, 2, 2);
+    zp_vec xATs0 = vector_merge(xATs, zero_vec, 4, 1);
+    zp_vec xATs01 = vector_merge(xATs0, zero_vec, 5, 1);
+    zp_vec xATs01_B = matrix_multiply(xATs01, key.B, 1, B_SIZE, B_SIZE);
+    ct.ctc = vector_raise(key.base, xATs01_B, B_SIZE);
+
+    // We compute the function hiding inner product encryption ciphertext.
+    zp_vec sAAT = matrix_multiply(sA, AT, 1, size, 2);
+    zp_vec xATsAAT = vector_add(xAT, sAAT, 2);
+    zp_vec sxATsAAT = vector_merge(s, xATsAAT, 2, 2);
+    zp_vec sxATsAAT1 = vector_merge(sxATsAAT, zero_vec, 4, 1);
+    zp_vec sxATsAAT10 = vector_merge(sxATsAAT1, zero_vec, 5, 1);
+    zp_vec sxATsAAT10_Bi = matrix_multiply(sxATsAAT10, key.Bi, 1, B_SIZE, B_SIZE);
+    ct.ctk = vector_raise(key.base, sxATsAAT10_Bi, B_SIZE);
+
+    // Testing.
+    int temp[] = {1, 1, 1, 1, 1, 1};
+    zp_vec temp_zp = vector_zp_from_int(temp, B_SIZE);
+    zp_vec vec_1 = matrix_multiply(temp_zp, key.B, 1, B_SIZE, B_SIZE);
+    zp_vec vec_2 = matrix_multiply(temp_zp, key.Bi, 1, B_SIZE, B_SIZE);
+
+    g_vec vec_11 = vector_raise(key.base, vec_1, B_SIZE);
+    g_vec vec_22 = vector_raise(key.base, vec_2, B_SIZE);
+
+    gt z;
+    pc_map_sim(z, vec_11, vec_22, B_SIZE);
+
+    // Check correctness.
+    gt desired_output;
+    gt_exp_dig(desired_output, key.t_base, 6);
+
+    if (gt_cmp(desired_output, z) == RLC_EQ) printf("Magic happened.");
+    else printf("Fuck my life.");
+
+    return ct;
+}
+
+void eval(struct key key, struct ct x, struct ct y, int size) {
+    //
+    gt z, xy, ct;
+    inner_product(xy, x.ctx, y.ctx, size);
+    inner_product(ct, x.ctc, y.ctk, B_SIZE);
+
+    // Decrypt.
+    gt_inv(ct, ct);
+    gt_mul(z, xy, ct);
+
+    // Check correctness.
+    gt desired_output;
+    gt_exp_dig(desired_output, key.t_base, 10);
+
+    if (gt_cmp(desired_output, z) == RLC_EQ) printf("Magic happened.");
+    else printf("Fuck my life.");
+}
+
+int main() {
+    initialize_relic();
+
+    int x[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+
+    struct key key = setup(10);
+
+    struct ct ct_x = enc(key, x, 10);
+
+//    eval(key, ct_x, ct_x, 10);
+    return 0;
+}
\ No newline at end of file
diff --git a/src/matrix.c b/src/matrix.c
index 6396f21619f6dbad938d6fb8431f5ac90435fe9e..f13b7945a82df7ed6e88820b3a98b4e892c2940c 100644
--- a/src/matrix.c
+++ b/src/matrix.c
@@ -70,12 +70,13 @@ zp_mat matrix_merge(zp_mat x, zp_mat y, int row, int col_x, int col_y) {
 }
 
 zp_mat matrix_multiply(zp_mat x, zp_mat y, int row_x, int row_y, int col_y) {
+    zp temp;
     zp_mat xy;
     xy = (zp_mat) malloc(sizeof(zp) * row_x * col_y);
-    zp temp;
+
     for (int i = 0; i < row_x; i++) {
         for (int j = 0; j < col_y; j++) {
-            zp_from_int(xy[i * row_y + j], 0);
+            zp_zero(xy[i * row_y + j]);
             for (int k = 0; k < row_y; k++) {
                 zp_multiply(temp, x[i * row_y + k], y[k * col_y + j]);
                 zp_add(xy[i * col_y + j], xy[i * col_y + j], temp);
@@ -131,14 +132,12 @@ zp_mat matrix_inverse(zp_mat x, int size) {
 
 
     // Copy over the output.
-
     zp_mat xi;
     xi = (zp_mat) malloc(sizeof(zp) * size * size);
-
     for (int i = 0; i < size; i++) {
         for (int j = 0; j < size; j++) {
             zp_copy(xi[i * size + j], row_echelon[i * 2 * size + size + j]);
         }
     }
     return xi;
-}
+}
\ No newline at end of file
diff --git a/src/vector.c b/src/vector.c
index e23b4348690d3d4f1787bdf5e80885999235c259..ed48b177caa92ea26b8ab132f81ece3b3c988125 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -29,7 +29,7 @@ zp_vec vector_add(zp_vec a, zp_vec b, int size) {
     return r;
 }
 
-g_vec vector_raise(ep_st base[1], zp_vec x, int size) {
+g_vec vector_raise(g base, zp_vec x, int size) {
     g_vec r;
     r = (g_vec) malloc(sizeof(g) * size);
     for (int i = 0; i < size; i++) multiply(r[i], base, x[i]);