diff --git a/CMakeLists.txt b/CMakeLists.txt index ab9f81bedd388dcdfbda7785899cf95174d8994c..c59e16b49a42541996247773aca2b5c1ced97e15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,15 +6,15 @@ project( PPANN VERSION 0.1 DESCRIPTION "This project implements the inner product revealing encryption." - LANGUAGES C + LANGUAGES CXX ) # Set standards and include tests. if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) - set(CMAKE_C_STANDARD 17) + set(CMAKE_CXX_STANDARD 17) set_property(GLOBAL PROPERTY USE_FOLDERS ON) include(CTest) -endif() +endif () # Find the relic library. find_library(RELIC_LIB relic) diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 63f43d77e568953425fe69d23a691374a00edb3b..530e768631176d1fb2e02442ec81020d5db86696 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,3 +1,3 @@ # Call this executable app. -add_executable(app scheme.c) +add_executable(app app.cpp) target_link_libraries(app PRIVATE ppann_lib) \ No newline at end of file diff --git a/apps/app.cpp b/apps/app.cpp new file mode 100644 index 0000000000000000000000000000000000000000..576dde40976821c80d0d4fb6eb32475f6c29102f --- /dev/null +++ b/apps/app.cpp @@ -0,0 +1,7 @@ +#include <iostream> + +using namespace std; + +int main() { + cout << "Hello from app." << endl; +} \ No newline at end of file diff --git a/apps/scheme.c b/apps/scheme.c deleted file mode 100644 index a071ac6c876e8c41bb9d34eb20941699bfc5306d..0000000000000000000000000000000000000000 --- a/apps/scheme.c +++ /dev/null @@ -1,104 +0,0 @@ -#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; - bn_t modular; -}; - -struct ct { - g_vec ctx; - g_vec ctk; - g_vec ctc; -}; - -void initialize_relic() { - core_init(); - pc_param_set_any(); -} - -struct key setup(int size) { - struct key key; - pc_get_ord(key.modular); - gen(key.base); - bp_map(key.base, key.base, key.t_base); - key.A = matrix_zp_rand(2, size, key.modular); - key.B = matrix_zp_rand(B_SIZE, B_SIZE, key.modular); - key.Bi = matrix_transpose(matrix_inverse(key.B, B_SIZE, key.modular), B_SIZE, B_SIZE); - return key; -} - -struct ct enc(struct key key, const 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, key.modular); - - // Helper values. - int one[] = {1}, zero[] = {0}; - zp_vec one_vec = vector_zp_from_int(one, 1, key.modular); - zp_vec zero_vec = vector_zp_from_int(zero, 1, key.modular); - - // We generate s and compute sA + x. - zp_vec s = vector_zp_rand(2, key.modular); - zp_vec sA = matrix_multiply(s, key.A, 1, 2, size, key.modular); - 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, key.modular); - 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, one_vec, 5, 1); - zp_vec xATs01_B = matrix_multiply(xATs01, key.B, 1, B_SIZE, B_SIZE, key.modular); - 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, key.modular); - zp_vec xATsAAT = vector_add(xAT, sAAT, 2); - zp_vec sxATsAAT = vector_merge(s, xATsAAT, 2, 2); - zp_vec sxATsAAT1 = vector_merge(sxATsAAT, one_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, key.modular); - ct.ctk = vector_raise(key.base, sxATsAAT10_Bi, B_SIZE); - - return ct; -} - -void eval(struct key key, struct ct x, struct ct y, int size) { - // Decrypt components. - gt xy, ct; - inner_product(xy, x.ctx, y.ctx, size); - inner_product(ct, x.ctc, y.ctk, B_SIZE); - - // Decrypt final result. - gt_inv(ct, ct); - gt_mul(xy, xy, ct); - - // Check correctness. - gt desired_output; - gt_exp_dig(desired_output, key.t_base, 65); - if (gt_cmp(desired_output, xy) == RLC_EQ) printf("Magic happened"); -} - -int main() { - // Initialize relic. - initialize_relic(); - // Set x, y vectors. - int x[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 2}; - int y[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - // Initialize the scheme. - struct key key = setup(10); - // Encrypt the messages. - struct ct ct_x = enc(key, x, 10); - struct ct ct_y = enc(key, y, 10); - // Evaluate the two ciphertexts. - eval(key, ct_x, ct_y, 10); - return 0; -} \ No newline at end of file diff --git a/include/field.h b/include/field.h index 527654316e50511e0fd25ea2e41d77be5886dc9f..67cd008fc23253684ad7b4440ea1871252da51a1 100644 --- a/include/field.h +++ b/include/field.h @@ -1,35 +1,37 @@ #ifndef PPANN_FIELD_H #define PPANN_FIELD_H +#include <gmp.h> + +extern "C" { #include "relic/relic.h" +} struct zp { - bn_t point; - bn_t modular; + bn_t point{}; + bn_t modular{}; }; -struct zp new_zp(); - -struct zp rand_zp(bn_t modular); +zp rand_zp(bn_t modular); -struct zp zp_zero(bn_t modular); +zp zp_zero(bn_t modular); -struct zp zp_one(bn_t modular); +zp zp_one(bn_t modular); -struct zp zp_copy(struct zp x); +zp zp_copy(zp x); -struct zp zp_from_int(int x, bn_t modular); +zp zp_from_int(int x, bn_t modular); -struct zp zp_add(struct zp x, struct zp y); +zp zp_add(zp x, zp y); -struct zp zp_neg(struct zp x); +zp zp_neg(zp x); -struct zp zp_mul(struct zp x, struct zp y); +zp zp_mul(zp x, zp y); -struct zp zp_inv(struct zp x); +zp zp_inv(zp x); -int zp_cmp(struct zp x, struct zp y); +int zp_cmp(zp x, zp y); -int zp_cmp_int(struct zp x, int y); +int zp_cmp_int(zp x, int y); #endif //PPANN_FIELD_H \ No newline at end of file diff --git a/include/group.h b/include/group.h index 9a94d5943f47ffe11efe731979bebaa060f8ad0e..6b956f10e0428850acf8210710bd0f01faf79ed7 100644 --- a/include/group.h +++ b/include/group.h @@ -8,9 +8,9 @@ typedef gt_t gt; void gen(g x); -void g_mul(g r, g x, struct zp y); +void g_mul(g r, g x, zp y); -void gt_raise(gt r, gt x, struct zp y); +void gt_raise(gt r, gt x, zp y); void bp_map(g a, g b, gt r); diff --git a/include/ipre.h b/include/ipre.h new file mode 100644 index 0000000000000000000000000000000000000000..cd84869bf372d929d2c8d55199a084f49510e29c --- /dev/null +++ b/include/ipre.h @@ -0,0 +1,30 @@ +#ifndef PPANN_IPRE_H +#define PPANN_IPRE_H + +#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; + bn_t modular; +}; + +struct ct { + g_vec ctx; + g_vec ctk; + g_vec ctc; +}; + +key setup(int size); + +ct enc(key key, const int *message, int size); + +int eval(key key, ct x, ct y, int size, int bound); + +#endif //PPANN_IPRE_H \ No newline at end of file diff --git a/include/matrix.h b/include/matrix.h index b3c8e7a8c081aa0b4cd2dc307dd5231b4ea6d347..f0f7f6d20cd7175c9242e6029e2e83d4d672b031 100644 --- a/include/matrix.h +++ b/include/matrix.h @@ -4,7 +4,7 @@ #include "field.h" #include "group.h" -typedef struct zp *zp_mat; +typedef zp *zp_mat; zp_mat matrix_zp_from_int(const int *int_mat, int row, int col, bn_t modular); diff --git a/include/vector.h b/include/vector.h index 21e0f7c2c94ad14182fc8e303a572c6ca773ba47..355f93519603ade2c3120336e09ebedb03c9741d 100644 --- a/include/vector.h +++ b/include/vector.h @@ -4,7 +4,7 @@ #include "field.h" #include "group.h" -typedef struct zp *zp_vec; +typedef zp *zp_vec; typedef g *g_vec; zp_vec vector_zp_from_int(const int *int_vec, int size, bn_t modular); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 109948d972988e2f326d4eba59959cc5c747dd44..ff0a517ba790ead1dcda9c088a4a983952adfdba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,7 @@ set(HEADER_LIST "${CMAKE_SOURCE_DIR}/include/") # Add all files to the library. -add_library(ppann_lib field.c group.c vector.c matrix.c ${HEADER_LIST}) +add_library(ppann_lib field.cpp group.cpp vector.cpp matrix.cpp ipre.cpp ${HEADER_LIST}) # We need this directory, and users of our library will need it too target_include_directories(ppann_lib PUBLIC ../include) diff --git a/src/field.c b/src/field.cpp similarity index 58% rename from src/field.c rename to src/field.cpp index fe727080e23220046ac5f3ce13be30b4b90b440e..21b9119920d5ee6530b2e8c3a13b7de112035e78 100644 --- a/src/field.c +++ b/src/field.cpp @@ -1,82 +1,75 @@ #include "field.h" -struct zp new_zp() { - struct zp result; - bn_new(result.point); - bn_new(result.modular); - return result; -} - -struct zp rand_zp(bn_st *modular) { - struct zp result = new_zp(); +zp rand_zp(bn_st *modular) { + zp result; bn_rand_mod(result.point, modular); bn_copy(result.modular, modular); return result; } -struct zp zp_zero(bn_st *modular) { - struct zp result = new_zp(); +zp zp_zero(bn_st *modular) { + zp result; bn_set_dig(result.point, 0); bn_copy(result.modular, modular); return result; } -struct zp zp_one(bn_st *modular) { - struct zp result = new_zp(); +zp zp_one(bn_st *modular) { + zp result; bn_set_dig(result.point, 1); bn_copy(result.modular, modular); return result; } -struct zp zp_copy(struct zp x) { - struct zp result = new_zp(); +zp zp_copy(zp x) { + zp result; bn_copy(result.point, x.point); bn_copy(result.modular, x.modular); return result; } -struct zp zp_from_int(int x, bn_st *modular) { - struct zp result = new_zp(); +zp zp_from_int(int x, bn_st *modular) { + zp result; bn_set_dig(result.point, x); bn_copy(result.modular, modular); return result; } -struct zp zp_add(struct zp x, struct zp y) { - struct zp result = new_zp(); +zp zp_add(zp x, zp y) { + zp result; bn_add(result.point, x.point, y.point); bn_mod(result.point, result.point, x.modular); bn_copy(result.modular, x.modular); return result; } -struct zp zp_neg(struct zp x) { - struct zp result = new_zp(); +zp zp_neg(zp x) { + zp result; bn_neg(result.point, x.point); bn_mod(result.point, result.point, x.modular); bn_copy(result.modular, x.modular); return result; } -struct zp zp_mul(struct zp x, struct zp y) { - struct zp result = new_zp(); +zp zp_mul(zp x, zp y) { + zp result; bn_mul(result.point, x.point, y.point); bn_mod(result.point, result.point, x.modular); bn_copy(result.modular, x.modular); return result; } -struct zp zp_inv(struct zp x) { - struct zp result = new_zp(); +zp zp_inv(zp x) { + zp result; bn_mod_inv(result.point, x.point, x.modular); bn_copy(result.modular, x.modular); return result; } -int zp_cmp(struct zp x, struct zp y) { +int zp_cmp(zp x, zp y) { return bn_cmp(x.point, y.point) == RLC_EQ; } -int zp_cmp_int(struct zp x, int y) { +int zp_cmp_int(zp x, int y) { return bn_cmp_dig(x.point, y) == RLC_EQ; } \ No newline at end of file diff --git a/src/group.c b/src/group.cpp similarity index 66% rename from src/group.c rename to src/group.cpp index e6307a5e0f9226982e87f210a92836875bd0628b..6558d9930a812577683a7ee8590ef1513f9c5a20 100644 --- a/src/group.c +++ b/src/group.cpp @@ -4,11 +4,11 @@ void gen(ep_st *x) { g1_get_gen(x); } -void g_mul(ep_st *r, ep_st *x, struct zp y) { +void g_mul(ep_st *r, ep_st *x, zp y) { g1_mul(r, x, y.point); } -void gt_raise(fp_t *r, fp_t *x, struct zp y) { +void gt_raise(fp_t *r, fp_t *x, zp y) { gt_exp(r, x, y.point); } diff --git a/src/matrix.c b/src/matrix.cpp similarity index 89% rename from src/matrix.c rename to src/matrix.cpp index f83056481cf4130de0812bbf9f985e2b74e37f1c..27836f19ca26bbe11ce15a926e309d7341fb87a6 100644 --- a/src/matrix.c +++ b/src/matrix.cpp @@ -2,7 +2,7 @@ zp_mat matrix_zp_from_int(const int *int_mat, int row, int col, bn_st *modular) { zp_mat x; - x = (zp_mat) malloc(sizeof(struct zp) * row * col); + x = (zp_mat) malloc(sizeof(zp) * row * col); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { x[i * col + j] = zp_from_int(int_mat[i * col + j], modular); @@ -13,7 +13,7 @@ zp_mat matrix_zp_from_int(const int *int_mat, int row, int col, bn_st *modular) zp_mat matrix_zp_rand(int row, int col, bn_st *modular) { zp_mat x; - x = (zp_mat) malloc(sizeof(struct zp) * row * col); + x = (zp_mat) malloc(sizeof(zp) * row * col); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { x[i * col + j] = rand_zp(modular); @@ -24,7 +24,7 @@ zp_mat matrix_zp_rand(int row, int col, bn_st *modular) { zp_mat matrix_identity(int size, bn_st *modular) { zp_mat x; - x = (zp_mat) malloc(sizeof(struct zp) * size * size); + x = (zp_mat) malloc(sizeof(zp) * size * size); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (i == j) x[i * size + j] = zp_one(modular); @@ -46,7 +46,7 @@ int matrix_is_identity(zp_mat x, int size) { zp_mat matrix_transpose(zp_mat x, int row, int col) { zp_mat xt; - xt = (zp_mat) malloc(sizeof(struct zp) * row * col); + xt = (zp_mat) malloc(sizeof(zp) * row * col); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { xt[j * row + i] = zp_copy(x[i * col + j]); @@ -57,7 +57,7 @@ zp_mat matrix_transpose(zp_mat x, int row, int col) { zp_mat matrix_merge(zp_mat x, zp_mat y, int row, int col_x, int col_y) { zp_mat xy; - xy = (zp_mat) malloc(sizeof(struct zp) * row * (col_x + col_y)); + xy = (zp_mat) malloc(sizeof(zp) * row * (col_x + col_y)); for (int i = 0; i < row; i++) { for (int j = 0; j < col_x; j++) { xy[i * (col_x + col_y) + j] = zp_copy(x[i * col_x + j]); @@ -70,7 +70,7 @@ 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, bn_st *modular) { - zp_mat xy = (zp_mat) malloc(sizeof(struct zp) * row_x * col_y); + auto xy = (zp_mat) malloc(sizeof(zp) * row_x * col_y); for (int i = 0; i < row_x; i++) { for (int j = 0; j < col_y; j++) { @@ -89,7 +89,8 @@ zp_mat matrix_inverse(zp_mat x, int size, bn_st *modular) { zp_mat row_echelon = matrix_merge(x, identity, size, size, size); // Declare temp value. - struct zp temp_multiplier, temp_neg; + zp temp_multiplier; + zp temp_neg; // Bottom left half to all zeros. for (int i = 0; i < size; i++) { @@ -128,7 +129,7 @@ zp_mat matrix_inverse(zp_mat x, int size, bn_st *modular) { // Copy over the output. zp_mat xi; - xi = (zp_mat) malloc(sizeof(struct zp) * size * size); + xi = (zp_mat) malloc(sizeof(zp) * size * size); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { xi[i * size + j] = zp_copy(row_echelon[i * 2 * size + size + j]); diff --git a/src/vector.c b/src/vector.cpp similarity index 83% rename from src/vector.c rename to src/vector.cpp index 24f234470b9d553a257488d0723d0d685a988b6f..33de4488d3152c641c71d2ec53ec57416b359572 100644 --- a/src/vector.c +++ b/src/vector.cpp @@ -2,21 +2,21 @@ zp_vec vector_zp_from_int(const int *int_vec, int size, bn_st *modular) { zp_vec x; - x = (zp_vec) malloc(sizeof(struct zp) * size); + x = (zp_vec) malloc(sizeof(zp) * size); for (int i = 0; i < size; i++) x[i] = zp_from_int(int_vec[i], modular); return x; } zp_vec vector_zp_rand(int size, bn_st *modular) { zp_vec x; - x = (zp_vec) malloc(sizeof(struct zp) * size); + x = (zp_vec) malloc(sizeof(zp) * size); for (int i = 0; i < size; i++) x[i] = rand_zp(modular); return x; } zp_vec vector_merge(zp_vec a, zp_vec b, int size_a, int size_b) { zp_vec r; - r = (zp_vec) malloc(sizeof(struct zp) * (size_a + size_b)); + r = (zp_vec) malloc(sizeof(zp) * (size_a + size_b)); for (int i = 0; i < size_a; i++) r[i] = zp_copy(a[i]); for (int i = 0; i < size_b; i++) r[i + size_a] = zp_copy(b[i]); return r; @@ -24,7 +24,7 @@ zp_vec vector_merge(zp_vec a, zp_vec b, int size_a, int size_b) { zp_vec vector_add(zp_vec a, zp_vec b, int size) { zp_vec r; - r = (zp_vec) malloc(sizeof(struct zp) * size); + r = (zp_vec) malloc(sizeof(zp) * size); for (int i = 0; i < size; i++) r[i] = zp_add(a[i], b[i]); return r; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ef1621db4e243c9ee0ecf000bd59ce3a57e0e82d..bf74047755caeac69a4d612122ce20e6e84bb361 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,17 +1,20 @@ # Add tests as separate executables. -add_executable(test_field test_field.c) -add_executable(test_group test_group.c) -add_executable(test_vector test_vector.c) -add_executable(test_matrix test_matrix.c) +add_executable(test_field test_field.cpp) +add_executable(test_group test_group.cpp) +add_executable(test_vector test_vector.cpp) +add_executable(test_matrix test_matrix.cpp) +add_executable(test_ipre test_ipre.cpp) # Link tests to the main library. target_link_libraries(test_field PRIVATE ppann_lib) target_link_libraries(test_group PRIVATE ppann_lib) target_link_libraries(test_vector PRIVATE ppann_lib) target_link_libraries(test_matrix PRIVATE ppann_lib) +target_link_libraries(test_ipre PRIVATE ppann_lib) # Register the previous tests. add_test(NAME test_field COMMAND test_field) add_test(NAME test_group COMMAND test_group) add_test(NAME test_vector COMMAND test_vector) -add_test(NAME test_matrix COMMAND test_matrix) \ No newline at end of file +add_test(NAME test_matrix COMMAND test_matrix) +add_test(NAME test_ipre COMMAND test_ipre) \ No newline at end of file diff --git a/tests/test_field.c b/tests/test_field.cpp similarity index 63% rename from tests/test_field.c rename to tests/test_field.cpp index 8a13422c5adf726b4a9166b3bc85768af125a5ae..f5f4e3ed9380ac3e1e14c98c008fbf5eb1649f0f 100644 --- a/tests/test_field.c +++ b/tests/test_field.cpp @@ -1,51 +1,51 @@ #include "field.h" int test_zp_zero(bn_st *N) { - struct zp x = zp_zero(N); + zp x = zp_zero(N); return zp_cmp_int(x, 0); } int test_zp_one(bn_st *N) { - struct zp x = zp_one(N); + zp x = zp_one(N); return zp_cmp_int(x, 1); } int test_zp_copy(bn_st *N) { - struct zp x = zp_from_int(10, N); - struct zp y = zp_copy(x); + zp x = zp_from_int(10, N); + zp y = zp_copy(x); return zp_cmp(x, y); } int test_zp_from_int(bn_st *N) { - struct zp x = zp_from_int(3, N); + zp x = zp_from_int(3, N); return zp_cmp_int(x, 3); } int test_zp_add(bn_st *N) { - struct zp x = zp_from_int(10, N); - struct zp y = zp_from_int(20, N); - struct zp z = zp_add(x, y); + zp x = zp_from_int(10, N); + zp y = zp_from_int(20, N); + zp z = zp_add(x, y); return zp_cmp_int(z, 30); } int test_zp_neg(bn_st *N) { - struct zp x = rand_zp(N); - struct zp y = zp_neg(x); - struct zp z = zp_add(x, y); + zp x = rand_zp(N); + zp y = zp_neg(x); + zp z = zp_add(x, y); return zp_cmp_int(z, 0); } int test_zp_mul(bn_st *N) { - struct zp x = zp_from_int(10, N); - struct zp y = zp_from_int(20, N); - struct zp z = zp_mul(x, y); + zp x = zp_from_int(10, N); + zp y = zp_from_int(20, N); + zp z = zp_mul(x, y); return zp_cmp_int(z, 200); } int test_zp_inv(bn_st *N) { - struct zp x = rand_zp(N); - struct zp y = zp_inv(x); - struct zp z = zp_mul(x, y); + zp x = rand_zp(N); + zp y = zp_inv(x); + zp z = zp_mul(x, y); return zp_cmp_int(z, 1); } diff --git a/tests/test_group.c b/tests/test_group.cpp similarity index 90% rename from tests/test_group.c rename to tests/test_group.cpp index b3c0d220575bb794d28c6569bbb2ce99e30f559a..3905e5138853bab1cdc48b4db61ee1ae092ce962 100644 --- a/tests/test_group.c +++ b/tests/test_group.cpp @@ -8,8 +8,8 @@ int test_generator() { int test_all(bn_st *N) { // Set integers. - struct zp m = zp_from_int(5, N); - struct zp n = zp_from_int(25, N); + zp m = zp_from_int(5, N); + zp n = zp_from_int(25, N); // Declare variables. g a, b; diff --git a/tests/test_matrix.c b/tests/test_matrix.cpp similarity index 100% rename from tests/test_matrix.c rename to tests/test_matrix.cpp diff --git a/tests/test_vector.c b/tests/test_vector.cpp similarity index 100% rename from tests/test_vector.c rename to tests/test_vector.cpp