chore: Use parameters curves generated files and expose security level options

This commit is contained in:
Quentin Bourgerie
2023-01-16 11:51:56 +01:00
parent f60bd16e2b
commit d0308dda43
20 changed files with 101 additions and 138 deletions

3
.gitmodules vendored
View File

@@ -10,3 +10,6 @@
path = compiler/concrete-core
url = git@github.com:zama-ai/concrete-core.git
shallow = true
[submodule "compiler/parameter-curves"]
path = compiler/parameter-curves
url = git@github.com:zama-ai/parameter-curves.git

View File

@@ -7,6 +7,7 @@ ignore:
- llvm-project/
- compiler/concrete-optimizer
- compiler/concrete-core
- compiler/parameter-curves
- google-benchmark
rules:

View File

@@ -54,6 +54,11 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
include(AddConcretelangDoc)
set(CONCRETELANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
# -------------------------------------------------------------------------------
# Concrete Security curves Configuration
# -------------------------------------------------------------------------------
include_directories(${PROJECT_SOURCE_DIR}/parameter-curves/concrete-security-curves-cpp/include)
# -------------------------------------------------------------------------------
# Concrete FFI Configuration
# -------------------------------------------------------------------------------

View File

@@ -268,13 +268,14 @@ $(FIXTURE_CPU_DIR)/bug_report.yaml:
generate-cpu-tests: $(FIXTURE_CPU_DIR)/end_to_end_leveled.yaml $(FIXTURE_CPU_DIR)/end_to_end_apply_lookup_table.yaml $(FIXTURE_CPU_DIR)/end_to_end_linalg_apply_lookup_table.yaml $(FIXTURE_CPU_DIR)/bug_report.yaml
SECURITY_TO_TEST=80 128
run-end-to-end-tests: build-end-to-end-tests generate-cpu-tests
$(BUILD_DIR)/tools/concretelang/tests/end_to_end_tests/end_to_end_jit_test
$(BUILD_DIR)/tools/concretelang/tests/end_to_end_tests/end_to_end_jit_encrypted_tensor
$(BUILD_DIR)/tools/concretelang/tests/end_to_end_tests/end_to_end_jit_fhelinalg
$(BUILD_DIR)/tools/concretelang/tests/end_to_end_tests/end_to_end_jit_lambda
$(BUILD_DIR)/tools/concretelang/tests/end_to_end_tests/end_to_end_test \
--backend=cpu --jit $(FIXTURE_CPU_DIR)/*.yaml
$(foreach security,$(SECURITY_TO_TEST),$(BUILD_DIR)/tools/concretelang/tests/end_to_end_tests/end_to_end_test \
--backend=cpu --security-level=$(security) --jit $(FIXTURE_CPU_DIR)/*.yaml;)
### end-to-end-tests GPU
@@ -327,11 +328,12 @@ $(BENCHMARK_CPU_DIR)/%.yaml: tests/end_to_end_fixture/%_gen.py
generate-cpu-benchmarks: $(BENCHMARK_CPU_DIR) $(BENCHMARK_CPU_DIR)/end_to_end_linalg_apply_lookup_table.yaml $(BENCHMARK_CPU_DIR)/end_to_end_apply_lookup_table.yaml $(BENCHMARK_CPU_DIR)/end_to_end_leveled.yaml
SECURITY_TO_BENCH=128
run-cpu-benchmarks: build-benchmarks generate-cpu-benchmarks
$(BUILD_DIR)/bin/end_to_end_benchmark \
--backend=cpu \
--benchmark_out=benchmarks_results.json --benchmark_out_format=json \
$(BENCHMARK_CPU_DIR)/*.yaml
$(foreach security,$(SECURITY_TO_BENCH),$(BUILD_DIR)/bin/end_to_end_benchmark \
--backend=cpu --security-level=$(security)\
--benchmark_out=benchmarks_results.json --benchmark_out_format=json \
$(BENCHMARK_CPU_DIR)/*.yaml;)
## benchmark GPU

View File

@@ -19,7 +19,7 @@ using ::concretelang::clientlib::ClientParameters;
llvm::Expected<ClientParameters>
createClientParametersForV0(V0FHEContext context, llvm::StringRef functionName,
mlir::ModuleOp module);
mlir::ModuleOp module, int bitsOfSecurity);
} // namespace concretelang
} // namespace mlir

View File

@@ -1,46 +0,0 @@
// Part of the Concrete Compiler Project, under the BSD3 License with Zama
// Exceptions. See
// https://github.com/zama-ai/concrete-compiler-internal/blob/main/LICENSE.txt
// for license information.
#ifndef CONCRETELANG_SUPPORT_V0CURVES_H_
#define CONCRETELANG_SUPPORT_V0CURVES_H_
#include <cstddef>
namespace mlir {
namespace concretelang {
#define SECURITY_LEVEL_80 0
#define SECURITY_LEVEL_128 1
#define SECURITY_LEVEL_192 2
#define SECURITY_LEVEL_256 3
#define SECURITY_LEVEL_MAX 4
#define KEY_FORMAT_BINARY 0
#define KEY_FORMAT_MAX 1
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) {}
double getVariance(int glweDimension, int polynomialSize, int logQ) {
auto a = std::pow(
2, (linearTerm1 * glweDimension * polynomialSize + linearTerm2) * 2);
auto b = std::pow(2, -2 * (logQ - 2));
return a > b ? a : b;
}
};
V0Curves *getV0Curves(int securityLevel, int keyFormat);
} // namespace concretelang
} // namespace mlir
#endif

View File

@@ -72,6 +72,10 @@ void mlir::concretelang::python::populateCompilerAPISubmodule(
.def("set_global_p_error",
[](CompilationOptions &options, double global_p_error) {
options.optimizerConfig.global_p_error = global_p_error;
})
.def("set_security_level",
[](CompilationOptions &options, int security_level) {
options.optimizerConfig.security = security_level;
});
pybind11::class_<mlir::concretelang::CompilationFeedback>(

View File

@@ -195,3 +195,17 @@ class CompilationOptions(WrapperCpp):
if not 0.0 <= global_p_error <= 1.0:
raise ValueError("global_p_error be a probability in ]0; 1]")
self.cpp().set_global_p_error(global_p_error)
def set_security_level(self, security_level: int):
"""Set security level.
Args:
security_level (int): the target number of bits of security to compile the circuit
Raises:
TypeError: if the value to set is not int
ValueError: if the value to set is not in interval ]0; 1]
"""
if not isinstance(security_level, int):
raise TypeError("can't set security_level to a non-int value")
self.cpp().set_security_level(security_level)

View File

@@ -7,13 +7,10 @@ add_mlir_library(
JITSupport.cpp
LambdaArgument.cpp
V0Parameters.cpp
V0Curves.cpp
V0ClientParameters.cpp
logging.cpp
Jit.cpp
LLVMEmitFile.cpp
ADDITIONAL_HEADER_DIRS
${PROJECT_SOURCE_DIR}/include/concretelang/Support
DEPENDS
mlir-headers
LINK_LIBS

View File

@@ -350,8 +350,9 @@ CompilerEngine::compile(llvm::SourceMgr &sm, Target target, OptionalLib lib) {
res.clientParameters = emptyParams;
} else {
auto clientParametersOrErr =
mlir::concretelang::createClientParametersForV0(*res.fheContext,
funcName, module);
mlir::concretelang::createClientParametersForV0(
*res.fheContext, funcName, module,
options.optimizerConfig.security);
if (!clientParametersOrErr)
return clientParametersOrErr.takeError();

View File

@@ -11,12 +11,12 @@
#include <mlir/Dialect/Func/IR/FuncOps.h>
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
#include "concrete/curves.h"
#include "concretelang/ClientLib/ClientParameters.h"
#include "concretelang/Conversion/Utils/GlobalFHEContext.h"
#include "concretelang/Dialect/Concrete/IR/ConcreteTypes.h"
#include "concretelang/Dialect/FHE/IR/FHETypes.h"
#include "concretelang/Support/Error.h"
#include "concretelang/Support/V0Curves.h"
namespace mlir {
namespace concretelang {
@@ -30,9 +30,7 @@ using ::concretelang::clientlib::LweSecretKeyID;
using ::concretelang::clientlib::Precision;
using ::concretelang::clientlib::Variance;
const auto securityLevel = SECURITY_LEVEL_128;
const auto keyFormat = KEY_FORMAT_BINARY;
const auto v0Curve = getV0Curves(securityLevel, keyFormat);
const auto keyFormat = concrete::BINARY;
/// For the v0 the secretKeyID and precision are the same for all gates.
llvm::Expected<CircuitGate> gateFromMLIRType(V0FHEContext fheContext,
@@ -127,8 +125,15 @@ llvm::Expected<CircuitGate> gateFromMLIRType(V0FHEContext fheContext,
llvm::Expected<ClientParameters>
createClientParametersForV0(V0FHEContext fheContext,
llvm::StringRef functionName,
mlir::ModuleOp module) {
llvm::StringRef functionName, mlir::ModuleOp module,
int bitsOfSecurity) {
const auto v0Curve = concrete::getSecurityCurve(bitsOfSecurity, keyFormat);
if (v0Curve == nullptr) {
return StreamStringError("Cannot find security curves for ")
<< bitsOfSecurity << "bits";
}
V0Parameter &v0Param = fheContext.parameter;
Variance inputVariance =
v0Curve->getVariance(1, v0Param.getNBigLweDimension(), 64);

View File

@@ -1,30 +0,0 @@
// Part of the Concrete Compiler Project, under the BSD3 License with Zama
// Exceptions. See
// https://github.com/zama-ai/concrete-compiler-internal/blob/main/LICENSE.txt
// for license information.
#include <cmath>
#include "concretelang/Support/V0Curves.h"
namespace mlir {
namespace concretelang {
V0Curves curves[SECURITY_LEVEL_MAX][KEY_FORMAT_MAX] = {
{V0Curves(SECURITY_LEVEL_80, -0.04042633119364589, 1.6609788641436722, 450,
1)},
{V0Curves(SECURITY_LEVEL_128, -0.02640502876522622, 2.4826422691043177, 450,
1)},
{V0Curves(SECURITY_LEVEL_192, -0.018610403247590085, 3.2996236848399008,
606, 1)},
{V0Curves(SECURITY_LEVEL_256, -0.014606812351714953, 3.8493629234693003,
826, 1)}};
V0Curves *getV0Curves(int securityLevel, int keyFormat) {
if (securityLevel >= SECURITY_LEVEL_MAX || keyFormat >= KEY_FORMAT_MAX) {
return nullptr;
}
return &curves[securityLevel][keyFormat];
}
} // namespace concretelang
} // namespace mlir

View File

@@ -222,6 +222,12 @@ llvm::cl::opt<double> globalErrorProbability(
llvm::cl::init(
mlir::concretelang::optimizer::DEFAULT_CONFIG.global_p_error));
llvm::cl::opt<double> securityLevel(
"security-level",
llvm::cl::desc(
"Specify the security level to target for compiling the program"),
llvm::cl::init(mlir::concretelang::optimizer::DEFAULT_CONFIG.security));
llvm::cl::opt<bool> displayOptimizerChoice(
"display-optimizer-choice",
llvm::cl::desc("Display the information returned by the optimizer"),

View File

@@ -103,21 +103,6 @@ static void BM_Evaluate(benchmark::State &state, EndToEndDesc description,
}
}
std::string getOptionsName(mlir::concretelang::CompilationOptions options) {
std::ostringstream os;
if (options.loopParallelize)
os << "_loop";
if (options.dataflowParallelize)
os << "_dataflow";
if (options.emitGPUOps)
os << "_gpu";
auto ostr = os.str();
if (ostr.size() == 0) {
os << "_default";
}
return os.str().substr(1);
}
enum Action {
COMPILE,
KEYGEN,

View File

@@ -138,17 +138,7 @@ std::string getTestName(EndToEndDesc desc,
mlir::concretelang::CompilationOptions options,
int testNum) {
std::ostringstream os;
if (options.loopParallelize)
os << "_loop";
if (options.dataflowParallelize)
os << "_dataflow";
if (options.emitGPUOps)
os << "_gpu";
auto ostr = os.str();
if (ostr.size() == 0) {
os << "_default";
}
os << "." << desc.description << "." << testNum;
os << getOptionsName(options) << "." << desc.description << "." << testNum;
return os.str().substr(1);
}

View File

@@ -64,6 +64,10 @@ parseEndToEndCommandLine(int argc, char **argv) {
llvm::cl::init(llvm::None));
// Optimizer options
llvm::cl::opt<int> securityLevel(
"security-level",
llvm::cl::desc("Set the number of bit of security to target"),
llvm::cl::init(mlir::concretelang::optimizer::DEFAULT_CONFIG.security));
llvm::cl::opt<bool> optimizerDisplay(
"optimizer-display",
llvm::cl::desc("Set the optimizerConfig.display compilation options to "
@@ -98,6 +102,7 @@ parseEndToEndCommandLine(int argc, char **argv) {
compilationOptions.batchConcreteOps =
batchConcreteOps.getValue().getValue();
compilationOptions.optimizerConfig.display = optimizerDisplay.getValue();
compilationOptions.optimizerConfig.security = securityLevel.getValue();
std::vector<EndToEndDescFile> parsedDescriptionFiles;
for (auto descFile : descriptionFiles) {
@@ -115,4 +120,22 @@ parseEndToEndCommandLine(int argc, char **argv) {
return std::make_tuple(compilationOptions, libpath, parsedDescriptionFiles);
}
std::string getOptionsName(mlir::concretelang::CompilationOptions options) {
std::ostringstream os;
if (options.loopParallelize)
os << "_loop";
if (options.dataflowParallelize)
os << "_dataflow";
if (options.emitGPUOps)
os << "_gpu";
auto ostr = os.str();
if (ostr.size() == 0) {
os << "_default";
}
if (options.optimizerConfig.security != 128) {
os << "_security" << options.optimizerConfig.security;
}
return os.str().substr(1);
}
#endif

View File

@@ -218,7 +218,7 @@ def test_lib_compilation_artifacts():
assert not os.path.exists(engine.get_shared_lib_path())
def test_lib_compile_and_run_p_error(keyset_cache):
def _test_lib_compile_and_run_with_options(keyset_cache, options):
mlir_input = """
func.func @main(%arg0: !FHE.eint<7>) -> !FHE.eint<7> {
%tlu = arith.constant dense<[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]> : tensor<128xi64>
@@ -229,27 +229,29 @@ def test_lib_compile_and_run_p_error(keyset_cache):
args = (73,)
expected_result = 73
engine = LibrarySupport.new("./py_test_lib_compile_and_run_custom_perror")
compile_run_assert(engine, mlir_input, args, expected_result, keyset_cache, options)
def test_lib_compile_and_run_p_error(keyset_cache):
options = CompilationOptions.new("main")
options.set_p_error(0.00001)
options.set_display_optimizer_choice(True)
compile_run_assert(engine, mlir_input, args, expected_result, keyset_cache, options)
_test_lib_compile_and_run_with_options(keyset_cache, options)
def test_lib_compile_and_run_p_error(keyset_cache):
mlir_input = """
func.func @main(%arg0: !FHE.eint<7>) -> !FHE.eint<7> {
%tlu = arith.constant dense<[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]> : tensor<128xi64>
%1 = "FHE.apply_lookup_table"(%arg0, %tlu): (!FHE.eint<7>, tensor<128xi64>) -> (!FHE.eint<7>)
return %1: !FHE.eint<7>
}
"""
args = (73,)
expected_result = 73
engine = LibrarySupport.new("./py_test_lib_compile_and_run_custom_perror")
def test_lib_compile_and_run_global_p_error(keyset_cache):
options = CompilationOptions.new("main")
options.set_global_p_error(0.00001)
options.set_display_optimizer_choice(True)
compile_run_assert(engine, mlir_input, args, expected_result, keyset_cache, options)
_test_lib_compile_and_run_with_options(keyset_cache, options)
def test_lib_compile_and_run_security_level(keyset_cache):
options = CompilationOptions.new("main")
options.set_security_level(80)
options.set_display_optimizer_choice(True)
_test_lib_compile_and_run_with_options(keyset_cache, options)
@pytest.mark.parallel

View File

@@ -1,8 +1,8 @@
#include <gtest/gtest.h>
#include "concrete/curves.h"
#include "concretelang/ClientLib/ClientParameters.h"
#include "concretelang/ClientLib/EncryptedArguments.h"
#include "concretelang/Support/V0Curves.h"
#include "tests_tools/assert.h"
namespace clientlib = concretelang::clientlib;
@@ -53,8 +53,8 @@ clientlib::ClientParameters generateClientParameterOneScalarOneScalar(
params.secretKeys.insert({clientlib::SMALL_KEY, {/*.dimension =*/dimension}});
// One input and output encryption gate on the same secret key and encoded
// with the same precision
const auto v0Curve =
mlir::concretelang::getV0Curves(SECURITY_LEVEL_128, KEY_FORMAT_BINARY);
const auto v0Curve = concrete::getSecurityCurve(128, concrete::BINARY);
clientlib::EncryptionGate encryption;
encryption.secretKeyID = clientlib::SMALL_KEY;
encryption.encoding.precision = precision;