diff --git a/cpp/compile_test.py b/cpp/compile_test.py new file mode 100644 index 000000000..5fa7b2621 --- /dev/null +++ b/cpp/compile_test.py @@ -0,0 +1,85 @@ +import subprocess +from ctypes import * +import os +import numpy as np + +v0_parameters_path = "cpp" + +def compile(): + # Creating build directory + try: + os.mkdir(f"{v0_parameters_path}/build") + print("> Successfully created build/ directory") + except FileExistsError: + print("> build/ directory already exists") + # Compile the C++ source as a shared object + subprocess.run( + [ + "g++", + "-c", + "-o", + f"{v0_parameters_path}/build/test.o", + f"{v0_parameters_path}/test.cpp", + ] + ) + subprocess.run( + [ + "gcc", + "-shared", + "-o", + f"{v0_parameters_path}/build/libtest.so", + f"{v0_parameters_path}/build/test.o", + ] + ) + print("> Successfully compiled C++ source") + + +def load_library(): + # Load library in python and define argtype / restype + lib = CDLL(f"{v0_parameters_path}/build/libtest.so") + # defining the structure at python level + class v0curves(Structure): + _fields_ = [ + ("securityLevel", c_int), + ("linearTerm1", c_double), + ("linearTerm2", c_double), + ("nAlpha", c_int), + ("keyFormat", c_int), + ] + + get = lib.security_estimator + get.argtypes = [c_int, c_int] + get.restype = POINTER(v0curves) + print("> Successfully loading shared library") + + return get + + +def stringify_struct(struct): + return f"security_level: {struct.contents.securityLevel}, linear_term1: {struct.contents.linearTerm1}, linear_term2: {struct.contents.linearTerm2} , nAlpha: {struct.contents.nAlpha}, keyFormat: {struct.contents.keyFormat} " + +def check_codegen( + curves_dict +): + # compiling as shared library + compile() + # loading library + security_estimator = load_library() + # checking everything + + for security_level, key_format in curves_dict: + c_struct = security_estimator(security_level, key_format ) + python_struct = curves_dict[(security_level, key_format)] + print(f"(securityLevel, keyFormat) = ({security_level, key_format} : {stringify_struct(c_struct)} ") + assert python_struct[0] == c_struct.contents.linearTerm1, f"linearTerm1: (securityLevel, keyFormat) = ({security_level, key_format} -> (Py) {python_struct[0]} (C++) {c_struct.contents.linearTerm1})" + assert python_struct[1] == c_struct.contents.linearTerm2, f"linearTerm2: (securityLevel, keyFormat) = ({security_level, key_format} -> (Py) {python_struct[1]} (C++) {c_struct.contents.linearTerm2})" + assert python_struct[2] == c_struct.contents.nAlpha, f"nAlpha: (securityLevel, keyFormat) = ({security_level, key_format} -> (Py) {python_struct[2]} (C++) {c_struct.contents.nAlpha})" + print(curves_dict) + print("> Successfully compared C++ array with Python dictionary") + + +if __name__ == "__main__": + from v0curves import curves_dict + compile() + load_library() + check_codegen(curves_dict) diff --git a/cpp/cpp/build/libtest.so b/cpp/cpp/build/libtest.so new file mode 100755 index 000000000..f803f868e Binary files /dev/null and b/cpp/cpp/build/libtest.so differ diff --git a/cpp/cpp/build/test.o b/cpp/cpp/build/test.o new file mode 100644 index 000000000..da76ef12b Binary files /dev/null and b/cpp/cpp/build/test.o differ diff --git a/cpp/cpp/test.cpp b/cpp/cpp/test.cpp new file mode 100644 index 000000000..6ccffe2b7 --- /dev/null +++ b/cpp/cpp/test.cpp @@ -0,0 +1,52 @@ +#include +using namespace std; + +const int num_sec_levels = 4; +const int num_key_format = 1; + +typedef struct v0curves +{ + int securityLevel; + double linearTerm1; + double linearTerm2; + int nAlpha; + int keyFormat; + + v0curves( int securityLevel_, + double linearTerm1_, + double linearTerm2_, + int nAlpha_, + int keyFormat_) + { + securityLevel = securityLevel_; + linearTerm1 = linearTerm1_; + linearTerm2 = linearTerm2_; + nAlpha = nAlpha_; + keyFormat = keyFormat_; + } + +} v0curves; + +v0curves parameters[num_sec_levels][num_key_format] = { + {v0curves(1, 4.13213, 7.123123, 1, 1)}, + {v0curves(2, 5.123123, 8.123123, 1, 2)}, + {v0curves(3, 6.123123, 9.1231223, 1, 3)}, + {v0curves(4, 10.1231, 10.123123, 1, 4)} +}; + +extern "C" v0curves *security_estimator(int securityLevel, int keyFormat) +{ + if (securityLevel == 80 ){ + return ¶meters[0][keyFormat]; + } + else if (securityLevel == 128 ){ + return ¶meters[1][keyFormat]; + } + else if (securityLevel == 192 ){ + return ¶meters[2][keyFormat]; + } + else if (securityLevel == 256 ){ + return ¶meters[3][keyFormat]; + } +} + \ No newline at end of file diff --git a/cpp/gen_cpp.py b/cpp/gen_cpp.py index e9bd1edf8..d24b63a57 100644 --- a/cpp/gen_cpp.py +++ b/cpp/gen_cpp.py @@ -19,14 +19,17 @@ typedef struct v0curves int rlweDimension; int polynomialSize; int ciphertextModulus; + int keyFormat; v0curves(int rlweDimension, int polynomialSize_, - int ciphertextModulus) + int ciphertextModulus, + int keyFormat) { rlweDimension = rlweDimension_; polynomialSize = polynomialSize_; ciphertextModulus = ciphertextModulus_; + keyFormat = keyFormat_; } } v0curves;""" @@ -37,20 +40,22 @@ v0curves parameters[num_sec_levels] = """ get_string = """ -extern "C" int security_estimator(int rlweDimension, int polynomialSize, int ciphertextModulus) +extern "C" int security_estimator(int securityLevel, int keyFormat) { + return ¶meters[securityLevel][keyFormat]; }""" -def constructor(rlweDimension, polynomialSize, ciphertextModulus): - return f"v0curves({rlweDimension}, {polynomialSize}, {ciphertextModulus})," +def constructor(rlweDimension, polynomialSize, ciphertextModulus, keyFormat): + return f"v0curves({rlweDimension}, {polynomialSize}, {ciphertextModulus}, {keyFormat})," def fill_parameters( # Return a string with parameters for the c++ array initialization polynomial_size_results, rlwe_dimension_results, - ciphertextModulus, + ciphertext_modulus_results, + key_format_results ): parameters = "{}{{".format(table_string) for security_level in range(num_sec_levels): @@ -62,9 +67,10 @@ def fill_parameters( int(polynomial_size_results[security_level]), int(rlwe_dimension_results[security_level]), int(ciphertext_modulus_results[security_level]), + int(key_format_results[security_level]), ) except ValueError: - line += constructor(0, 0,0) + line += constructor(0, 0, 0, 0) line = line[:-1] line += "}," parameters += line @@ -77,6 +83,7 @@ def codegen( polynomial_size_results, rlwe_dimension_results, ciphertext_modulus_results, + key_format_results, ): # Generate the C++ file as a string code = f""" @@ -86,7 +93,8 @@ def codegen( {fill_parameters( polynomial_size_results, rlwe_dimension_results, - ciphertext_modulus_results + ciphertext_modulus_results, + key_format_results )} {get_string} """ @@ -96,13 +104,15 @@ def codegen( def write_codegen( polynomial_size_results, rlwe_dimension_results, - ciphertext_modulus_results + ciphertext_modulus_results, + key_format_results, ): # Create the c++ source code = codegen( polynomial_size_results, rlwe_dimension_results, - ciphertext_modulus_results + ciphertext_modulus_results, + key_format_results ) # TODO: insert correct filename here with a path with open(f"test.cpp", "w") as f: @@ -115,12 +125,15 @@ def main_codegen(): ( polynomial_size_results, rlwe_dimension_results, - ciphertext_modulus_resultss + ciphertext_modulus_results, + key_format_results, + ) = main_optimization_v0() # code generation write_codegen( polynomial_size_results, rlwe_dimension_results, - ciphertext_modulus_results + ciphertext_modulus_results, + key_format_results ) diff --git a/cpp/v0curves.py b/cpp/v0curves.py index 363ace0f2..f9d30a71a 100644 --- a/cpp/v0curves.py +++ b/cpp/v0curves.py @@ -1,6 +1,9 @@ + curves = [ - (80, -0.04047677865612648, 1.1433465085639063, 160), - (128, -0.026374888765705498, 2.012143923330495, 256), - (192, -0.018504919354426233, 2.6634073426215843, 384), - (256, -0.014327640360322604, 2.899270827311091, 781), -] \ No newline at end of file + (80, -0.04047677865612648, 1.1433465085639063, 160, 0), + (128, -0.026374888765705498, 2.012143923330495, 256, 0), + (192, -0.018504919354426233, 2.6634073426215843, 384, 0), + (256, -0.014327640360322604, 2.899270827311091, 781, 0), +] + +curves_dict = {(tuple[0], tuple[-1]): tuple[1:4] for tuple in curves}