mirror of
https://github.com/luxfhe/torus.git
synced 2026-10-30 17:07:26 +00:00
The headers said 'BSD3 License with Lux Industries Exceptions', which is not a licence that exists — the sweep that removed the upstream vendor's name substituted ours into the licence title instead of correcting it. LICENSE.txt is the BSD 3-Clause Clear License and the headers now say so.
2226 lines
92 KiB
C++
2226 lines
92 KiB
C++
// Part of the Torus Compiler Project, under the BSD 3-Clause Clear
|
|
// License. See
|
|
// https://github.com/luxfhe/torus/blob/main/LICENSE.txt
|
|
// for license information.
|
|
|
|
#include "toruslang/Bindings/Python/CompilerAPIModule.h"
|
|
#include "torus-optimizer.hpp"
|
|
#include "torus-protocol.capnp.h"
|
|
#include "toruslang/ClientLib/ClientLib.h"
|
|
#include "toruslang/Common/Csprng.h"
|
|
#include "toruslang/Common/Keys.h"
|
|
#include "toruslang/Common/Keysets.h"
|
|
#include "toruslang/Common/Values.h"
|
|
#include "toruslang/Runtime/DFRuntime.hpp"
|
|
#include "toruslang/Runtime/GPUDFG.hpp"
|
|
#include "toruslang/ServerLib/ServerLib.h"
|
|
#include "toruslang/Support/CompilerEngine.h"
|
|
#include "toruslang/Support/Error.h"
|
|
#include "toruslang/Support/V0Parameters.h"
|
|
#include "toruslang/Support/logging.h"
|
|
#include <filesystem>
|
|
#include <memory>
|
|
#include <mlir-c/Bindings/Python/Interop.h>
|
|
#include <mlir/CAPI/IR.h>
|
|
|
|
#include <optional>
|
|
#include <pybind11/cast.h>
|
|
#include <pybind11/numpy.h>
|
|
#include <pybind11/operators.h>
|
|
#include <pybind11/pybind11.h>
|
|
#include <pybind11/pytypes.h>
|
|
#include <pybind11/stl.h>
|
|
#include <signal.h>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
using toruslang::clientlib::ClientCircuit;
|
|
using toruslang::clientlib::ClientProgram;
|
|
using toruslang::keysets::Keyset;
|
|
using toruslang::keysets::KeysetCache;
|
|
using toruslang::keysets::ServerKeyset;
|
|
using toruslang::serverlib::ServerCircuit;
|
|
using toruslang::serverlib::ServerProgram;
|
|
using toruslang::values::TransportValue;
|
|
using toruslang::values::Value;
|
|
using mlir::toruslang::CompilationOptions;
|
|
|
|
#define CONCAT(a, b) CONCAT_INNER(a, b)
|
|
#define CONCAT_INNER(a, b) a##b
|
|
|
|
#define GET_OR_THROW_EXPECTED_(VARNAME, RESULT, MAYBE) \
|
|
auto MAYBE = RESULT; \
|
|
if (auto err = MAYBE.takeError()) { \
|
|
throw std::runtime_error(llvm::toString(std::move(err))); \
|
|
} \
|
|
VARNAME = std::move(*MAYBE);
|
|
|
|
#define GET_OR_THROW_EXPECTED(VARNAME, RESULT) \
|
|
GET_OR_THROW_EXPECTED_(VARNAME, RESULT, CONCAT(maybe, __COUNTER__))
|
|
|
|
#define GET_OR_THROW_RESULT_(VARNAME, RESULT, MAYBE) \
|
|
auto MAYBE = RESULT; \
|
|
if (MAYBE.has_failure()) { \
|
|
throw std::runtime_error(MAYBE.as_failure().error().mesg); \
|
|
} \
|
|
VARNAME = MAYBE.value();
|
|
|
|
#define GET_OR_THROW_RESULT(VARNAME, RESULT) \
|
|
GET_OR_THROW_RESULT_(VARNAME, RESULT, CONCAT(maybe, __COUNTER__))
|
|
|
|
#define EXPECTED_TRY_(lhs, rhs, maybe) \
|
|
auto maybe = rhs; \
|
|
if (auto err = maybe.takeError()) { \
|
|
return std::move(err); \
|
|
} \
|
|
lhs = *maybe;
|
|
|
|
#define EXPECTED_TRY(lhs, rhs) \
|
|
EXPECTED_TRY_(lhs, rhs, CONCAT(maybe, __COUNTER__))
|
|
|
|
template <typename T> llvm::Expected<T> outcomeToExpected(Result<T> outcome) {
|
|
if (outcome.has_failure()) {
|
|
return mlir::toruslang::StreamStringError(
|
|
outcome.as_failure().error().mesg);
|
|
} else {
|
|
return outcome.value();
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
class SignalGuard {
|
|
public:
|
|
SignalGuard() { previousHandler = signal(SIGINT, SignalGuard::handler); }
|
|
~SignalGuard() { signal(SIGINT, this->previousHandler); }
|
|
|
|
private:
|
|
void (*previousHandler)(int);
|
|
|
|
static void handler(int _signum) {
|
|
llvm::outs() << " Aborting... \n";
|
|
kill(getpid(), SIGKILL);
|
|
}
|
|
};
|
|
|
|
void terminateDataflowParallelization() { _dfr_terminate(); }
|
|
|
|
void initDataflowParallelization() {
|
|
mlir::toruslang::dfr::_dfr_set_required(true);
|
|
}
|
|
|
|
bool checkGPURuntimeEnabled() {
|
|
return mlir::toruslang::gpu_dfg::check_cuda_runtime_enabled();
|
|
}
|
|
|
|
bool checkCudaDeviceAvailable() {
|
|
return mlir::toruslang::gpu_dfg::check_cuda_device_available();
|
|
}
|
|
|
|
std::string roundTrip(const char *module) {
|
|
std::shared_ptr<mlir::toruslang::CompilationContext> ccx =
|
|
mlir::toruslang::CompilationContext::createShared();
|
|
mlir::toruslang::CompilerEngine ce{ccx};
|
|
|
|
std::string backingString;
|
|
llvm::raw_string_ostream os(backingString);
|
|
|
|
llvm::Expected<mlir::toruslang::CompilationResult> retOrErr =
|
|
ce.compile(module, mlir::toruslang::Target::ROUND_TRIP);
|
|
if (!retOrErr) {
|
|
os << "MLIR parsing failed: " << llvm::toString(retOrErr.takeError());
|
|
throw std::runtime_error(os.str());
|
|
}
|
|
|
|
retOrErr->mlirModuleRef->get().print(os);
|
|
return os.str();
|
|
}
|
|
|
|
// Every number sent by python through the API has a type `int64` that must be
|
|
// turned into the proper type expected by the ArgTransformers. This allows to
|
|
// get an extra transformer executed right before the ArgTransformer gets
|
|
// called.
|
|
std::function<Value(Value)>
|
|
getPythonTypeTransformer(const Message<torusprotocol::GateInfo> &info) {
|
|
if (info.asReader().getTypeInfo().hasIndex()) {
|
|
return [=](Value input) {
|
|
Tensor<int64_t> tensorInput = input.getTensor<int64_t>().value();
|
|
return Value{(Tensor<uint64_t>)tensorInput};
|
|
};
|
|
} else if (info.asReader().getTypeInfo().hasPlaintext()) {
|
|
if (info.asReader().getTypeInfo().getPlaintext().getIntegerPrecision() <=
|
|
8) {
|
|
return [=](Value input) {
|
|
Tensor<int64_t> tensorInput = input.getTensor<int64_t>().value();
|
|
return Value{(Tensor<uint8_t>)tensorInput};
|
|
};
|
|
}
|
|
if (info.asReader().getTypeInfo().getPlaintext().getIntegerPrecision() <=
|
|
16) {
|
|
return [=](Value input) {
|
|
Tensor<int64_t> tensorInput = input.getTensor<int64_t>().value();
|
|
return Value{(Tensor<uint16_t>)tensorInput};
|
|
};
|
|
}
|
|
if (info.asReader().getTypeInfo().getPlaintext().getIntegerPrecision() <=
|
|
32) {
|
|
return [=](Value input) {
|
|
Tensor<int64_t> tensorInput = input.getTensor<int64_t>().value();
|
|
return Value{(Tensor<uint32_t>)tensorInput};
|
|
};
|
|
}
|
|
if (info.asReader().getTypeInfo().getPlaintext().getIntegerPrecision() <=
|
|
64) {
|
|
return [=](Value input) {
|
|
Tensor<int64_t> tensorInput = input.getTensor<int64_t>().value();
|
|
return Value{(Tensor<uint64_t>)tensorInput};
|
|
};
|
|
}
|
|
assert(false);
|
|
} else if (info.asReader().getTypeInfo().hasLweCiphertext()) {
|
|
if (info.asReader()
|
|
.getTypeInfo()
|
|
.getLweCiphertext()
|
|
.getEncoding()
|
|
.hasInteger() &&
|
|
info.asReader()
|
|
.getTypeInfo()
|
|
.getLweCiphertext()
|
|
.getEncoding()
|
|
.getInteger()
|
|
.getIsSigned()) {
|
|
return [=](Value input) { return input; };
|
|
} else {
|
|
return [=](Value input) {
|
|
Tensor<int64_t> tensorInput = input.getTensor<int64_t>().value();
|
|
return Value{(Tensor<uint64_t>)tensorInput};
|
|
};
|
|
}
|
|
} else {
|
|
assert(false);
|
|
}
|
|
};
|
|
|
|
template <typename T> Tensor<T> arrayToTensor(pybind11::array &input) {
|
|
auto data_ptr = (const T *)input.data();
|
|
std::vector<T> data = std::vector(data_ptr, data_ptr + input.size());
|
|
auto dims = std::vector<size_t>(input.ndim(), 0);
|
|
for (ssize_t i = 0; i < input.ndim(); i++) {
|
|
dims[i] = input.shape(i);
|
|
}
|
|
return std::move(Tensor<T>(std::move(data), std::move(dims)));
|
|
}
|
|
|
|
template <typename T> pybind11::array tensorToArray(Tensor<T> input) {
|
|
return pybind11::array(pybind11::array::ShapeContainer(input.dimensions),
|
|
input.values.data());
|
|
}
|
|
} // namespace
|
|
|
|
/// Populate the compiler API python module.
|
|
void mlir::toruslang::python::populateCompilerAPISubmodule(
|
|
pybind11::module &m) {
|
|
|
|
using ::toruslang::csprng::EncryptionCSPRNG;
|
|
using ::toruslang::values::Value;
|
|
using pybind11::arg;
|
|
using pybind11::array;
|
|
using pybind11::init;
|
|
using Library = Library;
|
|
|
|
m.doc() = "Toruslang compiler python API";
|
|
|
|
m.def("round_trip",
|
|
[](std::string mlir_input) { return roundTrip(mlir_input.c_str()); });
|
|
|
|
m.def("set_llvm_debug_flag", [](bool enable) { llvm::DebugFlag = enable; });
|
|
|
|
m.def("set_compiler_logging",
|
|
[](bool enable) { mlir::toruslang::setupLogging(enable); });
|
|
|
|
m.def("terminate_df_parallelization", &terminateDataflowParallelization);
|
|
|
|
m.def("init_df_parallelization", &initDataflowParallelization);
|
|
m.def("check_gpu_runtime_enabled", &checkGPURuntimeEnabled);
|
|
m.def("check_cuda_device_available", &checkCudaDeviceAvailable);
|
|
|
|
pybind11::enum_<mlir::toruslang::Backend>(m, "Backend")
|
|
.value("CPU", mlir::toruslang::Backend::CPU,
|
|
"Circuit codegen targets cpu.")
|
|
.value("GPU", mlir::toruslang::Backend::GPU,
|
|
"Circuit codegen tartgets gpu.")
|
|
.export_values();
|
|
|
|
pybind11::enum_<optimizer::Strategy>(m, "OptimizerStrategy")
|
|
.value("V0", optimizer::Strategy::V0)
|
|
.value("DAG_MONO", optimizer::Strategy::DAG_MONO)
|
|
.value("DAG_MULTI", optimizer::Strategy::DAG_MULTI)
|
|
.export_values();
|
|
|
|
pybind11::enum_<torus_optimizer::MultiParamStrategy>(
|
|
m, "OptimizerMultiParameterStrategy")
|
|
.value("PRECISION", torus_optimizer::MultiParamStrategy::ByPrecision)
|
|
.value("PRECISION_AND_NORM2",
|
|
torus_optimizer::MultiParamStrategy::ByPrecisionAndNorm2)
|
|
.export_values();
|
|
|
|
pybind11::enum_<torus_optimizer::Encoding>(m, "Encoding")
|
|
.value("AUTO", torus_optimizer::Encoding::Auto)
|
|
.value("CRT", torus_optimizer::Encoding::Crt)
|
|
.value("NATIVE", torus_optimizer::Encoding::Native)
|
|
.export_values();
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// RANGE RESTRICTION //
|
|
// ------------------------------------------------------------------------------//
|
|
pybind11::class_<torus_optimizer::restriction::RangeRestriction>(
|
|
m, "RangeRestriction")
|
|
.def(pybind11::init(
|
|
[]() { return torus_optimizer::restriction::RangeRestriction(); }))
|
|
.def(
|
|
"add_available_glwe_log_polynomial_size",
|
|
[](torus_optimizer::restriction::RangeRestriction &restriction,
|
|
uint64_t v) {
|
|
restriction.glwe_log_polynomial_sizes.push_back(v);
|
|
},
|
|
"Add an available glwe log poly size to the restriction")
|
|
.def(
|
|
"add_available_glwe_dimension",
|
|
[](torus_optimizer::restriction::RangeRestriction &restriction,
|
|
uint64_t v) { restriction.glwe_dimensions.push_back(v); },
|
|
"Add an available glwe dimension to the restriction")
|
|
.def(
|
|
"add_available_internal_lwe_dimension",
|
|
[](torus_optimizer::restriction::RangeRestriction &restriction,
|
|
uint64_t v) { restriction.internal_lwe_dimensions.push_back(v); },
|
|
"Add an available internal lwe dimension to the restriction")
|
|
.def(
|
|
"add_available_pbs_level_count",
|
|
[](torus_optimizer::restriction::RangeRestriction &restriction,
|
|
uint64_t v) { restriction.pbs_level_count.push_back(v); },
|
|
"Add an available pbs level count to the restriction")
|
|
.def(
|
|
"add_available_pbs_base_log",
|
|
[](torus_optimizer::restriction::RangeRestriction &restriction,
|
|
uint64_t v) { restriction.pbs_base_log.push_back(v); },
|
|
"Add an available pbs base log to the restriction")
|
|
.def(
|
|
"add_available_ks_level_count",
|
|
[](torus_optimizer::restriction::RangeRestriction &restriction,
|
|
uint64_t v) { restriction.ks_level_count.push_back(v); },
|
|
"Add an available ks level count to the restriction")
|
|
.def(
|
|
"add_available_ks_base_log",
|
|
[](torus_optimizer::restriction::RangeRestriction &restriction,
|
|
uint64_t v) { restriction.ks_base_log.push_back(v); },
|
|
"Add an available ks base log to the restriction")
|
|
.def(
|
|
"from_json",
|
|
[](std::string input)
|
|
-> torus_optimizer::restriction::RangeRestriction {
|
|
return torus_optimizer::restriction::range_restriction_from_json(
|
|
input);
|
|
},
|
|
"Create a RangeRestriction from a json string.")
|
|
.def(
|
|
"to_json",
|
|
[](torus_optimizer::restriction::RangeRestriction &restriction)
|
|
-> std::string {
|
|
return std::string(restriction.range_restriction_to_json());
|
|
},
|
|
"Serialize a RangeRestriction to a json string.")
|
|
.doc() = "Allow to restrict the optimizer parameter search space to a "
|
|
"set of values.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// KEYSET RESTRICTION //
|
|
// ------------------------------------------------------------------------------//
|
|
pybind11::class_<torus_optimizer::restriction::KeysetRestriction>(
|
|
m, "KeysetRestriction")
|
|
.def(
|
|
"from_json",
|
|
[](std::string input)
|
|
-> torus_optimizer::restriction::KeysetRestriction {
|
|
return torus_optimizer::restriction::
|
|
keyset_restriction_from_json(input);
|
|
},
|
|
"Create a KeysetRestriction from a json string.")
|
|
.def(
|
|
"to_json",
|
|
[](torus_optimizer::restriction::KeysetRestriction &restriction)
|
|
-> std::string {
|
|
return std::string(restriction.keyset_restriction_to_json());
|
|
},
|
|
"Serialize a KeysetRestriction to a json string.")
|
|
|
|
.doc() = "Allow to restrict the optimizer search space to be compatible "
|
|
"with a keyset.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// OPTIMIZER OPTIONS //
|
|
// ------------------------------------------------------------------------------//
|
|
pybind11::class_<torus_optimizer::Options>(m, "OptimizerOptions")
|
|
.def(
|
|
"set_security_level",
|
|
[](torus_optimizer::Options &options, uint64_t security_level) {
|
|
options.security_level = security_level;
|
|
},
|
|
"Set option for security level.", arg("security_level"))
|
|
.def(
|
|
"set_maximum_acceptable_error_probability",
|
|
[](torus_optimizer::Options &options,
|
|
double maximum_acceptable_error_probability) {
|
|
options.maximum_acceptable_error_probability =
|
|
maximum_acceptable_error_probability;
|
|
},
|
|
"Set option for maximum acceptable error probability.",
|
|
arg("maximum_acceptable_error_probability"))
|
|
.def(
|
|
"set_key_sharing",
|
|
[](torus_optimizer::Options &options, bool key_sharing) {
|
|
options.key_sharing = key_sharing;
|
|
},
|
|
"Set option for key sharing.", arg("key_sharing"))
|
|
.def(
|
|
"set_multi_param_strategy_to_by_precision",
|
|
[](torus_optimizer::Options &options) {
|
|
options.multi_param_strategy =
|
|
torus_optimizer::MultiParamStrategy::ByPrecision;
|
|
},
|
|
"Set option for multi param strategy to by-precision.")
|
|
.def(
|
|
"set_multi_param_strategy_to_by_precision_and_norm_2",
|
|
[](torus_optimizer::Options &options) {
|
|
options.multi_param_strategy =
|
|
torus_optimizer::MultiParamStrategy::ByPrecisionAndNorm2;
|
|
},
|
|
"Set option for multi param strategy to by-precision-and-norm2.")
|
|
.def(
|
|
"set_default_log_norm2_woppbs",
|
|
[](torus_optimizer::Options &options,
|
|
double default_log_norm2_woppbs) {
|
|
options.default_log_norm2_woppbs = default_log_norm2_woppbs;
|
|
},
|
|
"Set option for default log norm2 woppbs.",
|
|
arg("default_log_norm2_woppbs"))
|
|
.def(
|
|
"set_use_gpu_constraints",
|
|
[](torus_optimizer::Options &options, bool use_gpu_constraints) {
|
|
options.use_gpu_constraints = use_gpu_constraints;
|
|
},
|
|
"Set option for use gpu constrints.", arg("use_gpu_constraints"))
|
|
.def(
|
|
"set_encoding_to_auto",
|
|
[](torus_optimizer::Options &options) {
|
|
options.encoding = torus_optimizer::Encoding::Auto;
|
|
},
|
|
"Set option for encoding to auto.")
|
|
.def(
|
|
"set_encoding_to_crt",
|
|
[](torus_optimizer::Options &options) {
|
|
options.encoding = torus_optimizer::Encoding::Crt;
|
|
},
|
|
"Set option for encoding to crt.")
|
|
.def(
|
|
"set_encoding_to_native",
|
|
[](torus_optimizer::Options &options) {
|
|
options.encoding = torus_optimizer::Encoding::Native;
|
|
},
|
|
"Set option for encoding to native.")
|
|
.def(
|
|
"set_cache_on_disk",
|
|
[](torus_optimizer::Options &options, bool cache_on_disk) {
|
|
options.cache_on_disk = cache_on_disk;
|
|
},
|
|
"Set option for cache on disk.", arg("cache_on_disk"))
|
|
.def(
|
|
"set_ciphertext_modulus_log",
|
|
[](torus_optimizer::Options &options,
|
|
uint32_t ciphertext_modulus_log) {
|
|
options.ciphertext_modulus_log = ciphertext_modulus_log;
|
|
},
|
|
"Set option for ciphertext modulus log.",
|
|
arg("ciphertext_modulus_log"))
|
|
.def(
|
|
"set_fft_precision",
|
|
[](torus_optimizer::Options &options, uint32_t fft_precision) {
|
|
options.fft_precision = fft_precision;
|
|
},
|
|
"Set option for fft precision.", arg("fft_precision"))
|
|
.def(
|
|
"set_fft_precision",
|
|
[](torus_optimizer::Options &options, uint32_t fft_precision) {
|
|
options.fft_precision = fft_precision;
|
|
},
|
|
"Set option for fft precision.", arg("fft_precision"))
|
|
.def(
|
|
"set_range_restriction",
|
|
[](torus_optimizer::Options &options,
|
|
torus_optimizer::restriction::RangeRestriction restriction) {
|
|
options.range_restriction = std::make_shared<
|
|
torus_optimizer::restriction::RangeRestriction>(restriction);
|
|
},
|
|
"Set option for range restriction", arg("restriction"))
|
|
.def(
|
|
"set_keyset_restriction",
|
|
[](torus_optimizer::Options &options,
|
|
torus_optimizer::restriction::KeysetRestriction restriction) {
|
|
options.keyset_restriction = std::make_shared<
|
|
torus_optimizer::restriction::KeysetRestriction>(
|
|
restriction);
|
|
},
|
|
"Set option for keyset restriction", arg("restriction"))
|
|
.doc() = "Options for the optimizer.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// COMPILATION OPTIONS //
|
|
// ------------------------------------------------------------------------------//
|
|
pybind11::class_<CompilationOptions>(m, "CompilationOptions")
|
|
.def(pybind11::init([](mlir::toruslang::Backend backend) {
|
|
return CompilationOptions(backend);
|
|
}),
|
|
arg("backend"))
|
|
.def(
|
|
"set_verify_diagnostics",
|
|
[](CompilationOptions &options, bool b) {
|
|
options.verifyDiagnostics = b;
|
|
},
|
|
"Set option for diagnostics verification.", arg("verify_diagnostics"))
|
|
.def(
|
|
"set_auto_parallelize",
|
|
[](CompilationOptions &options, bool b) {
|
|
options.autoParallelize = b;
|
|
},
|
|
"Set option for auto parallelization.", arg("auto_parallelize"))
|
|
.def(
|
|
"set_loop_parallelize",
|
|
[](CompilationOptions &options, bool b) {
|
|
options.loopParallelize = b;
|
|
},
|
|
"Set option for loop parallelization.", arg("loop_parallelize"))
|
|
.def(
|
|
"set_dataflow_parallelize",
|
|
[](CompilationOptions &options, bool b) {
|
|
options.dataflowParallelize = b;
|
|
},
|
|
"Set option for dataflow parallelization.",
|
|
arg("dataflow_parallelize"))
|
|
.def(
|
|
"set_compress_evaluation_keys",
|
|
[](CompilationOptions &options, bool b) {
|
|
options.compressEvaluationKeys = b;
|
|
},
|
|
"Set option for compression of evaluation keys.",
|
|
arg("compress_evaluation_keys"))
|
|
.def(
|
|
"set_compress_input_ciphertexts",
|
|
[](CompilationOptions &options, bool b) {
|
|
options.compressInputCiphertexts = b;
|
|
},
|
|
"Set option for compression of input ciphertexts.",
|
|
arg("compress_input_ciphertexts"))
|
|
.def(
|
|
"set_optimize_torus",
|
|
[](CompilationOptions &options, bool b) { options.optimizeTFHE = b; },
|
|
"Set flag to enable/disable optimization of torus intermediate "
|
|
"representation.",
|
|
arg("optimize"))
|
|
.def(
|
|
"set_p_error",
|
|
[](CompilationOptions &options, double p_error) {
|
|
options.optimizerConfig.p_error = p_error;
|
|
},
|
|
"Set error probability for shared by each pbs.", arg("p_error"))
|
|
.def(
|
|
"set_display_optimizer_choice",
|
|
[](CompilationOptions &options, bool display) {
|
|
options.optimizerConfig.display = display;
|
|
},
|
|
"Set display flag of optimizer choices.", arg("display"))
|
|
.def(
|
|
"set_optimizer_strategy",
|
|
[](CompilationOptions &options, optimizer::Strategy strategy) {
|
|
options.optimizerConfig.strategy = strategy;
|
|
},
|
|
"Set the strategy of the optimizer.", arg("strategy"))
|
|
.def(
|
|
"set_optimizer_multi_parameter_strategy",
|
|
[](CompilationOptions &options,
|
|
torus_optimizer::MultiParamStrategy strategy) {
|
|
options.optimizerConfig.multi_param_strategy = strategy;
|
|
},
|
|
"Set the strategy of the optimizer for multi-parameter.",
|
|
arg("strategy"))
|
|
.def(
|
|
"set_global_p_error",
|
|
[](CompilationOptions &options, double global_p_error) {
|
|
options.optimizerConfig.global_p_error = global_p_error;
|
|
},
|
|
"Set global error probability for the full circuit.",
|
|
arg("global_p_error"))
|
|
.def(
|
|
"add_composition",
|
|
[](CompilationOptions &options, std::string from_func,
|
|
size_t from_pos, std::string to_func, size_t to_pos) {
|
|
options.optimizerConfig.composition_rules.push_back(
|
|
{from_func, from_pos, to_func, to_pos});
|
|
},
|
|
"Add a composition rule.", arg("from_func"), arg("from_pos"),
|
|
arg("to_func"), arg("to_pos"))
|
|
.def(
|
|
"set_composable",
|
|
[](CompilationOptions &options, bool composable) {
|
|
options.optimizerConfig.composable = composable;
|
|
},
|
|
"Set composable flag.", arg("composable"))
|
|
.def(
|
|
"set_security_level",
|
|
[](CompilationOptions &options, int security_level) {
|
|
options.optimizerConfig.security = security_level;
|
|
},
|
|
"Set security level.", arg("security_level"))
|
|
.def("set_range_restriction",
|
|
[](CompilationOptions &options,
|
|
torus_optimizer::restriction::RangeRestriction restriction) {
|
|
options.optimizerConfig.range_restriction = std::make_shared<
|
|
torus_optimizer::restriction::RangeRestriction>(
|
|
restriction);
|
|
})
|
|
.def("set_keyset_restriction",
|
|
[](CompilationOptions &options,
|
|
torus_optimizer::restriction::KeysetRestriction restriction) {
|
|
options.optimizerConfig.keyset_restriction = std::make_shared<
|
|
torus_optimizer::restriction::KeysetRestriction>(
|
|
restriction);
|
|
})
|
|
.def(
|
|
"set_v0_parameter",
|
|
[](CompilationOptions &options, size_t glweDimension,
|
|
size_t logPolynomialSize, size_t nSmall, size_t brLevel,
|
|
size_t brLogBase, size_t ksLevel, size_t ksLogBase) {
|
|
options.v0Parameter = {glweDimension, logPolynomialSize, nSmall,
|
|
brLevel, brLogBase, ksLevel,
|
|
ksLogBase, std::nullopt};
|
|
},
|
|
"Set the basic V0 parameters.", arg("glwe_dimension"),
|
|
arg("log_poly_size"), arg("n_small"), arg("br_level"),
|
|
arg("br_log_base"), arg("ks_level"), arg("ks_log_base"))
|
|
.def(
|
|
"set_all_v0_parameter",
|
|
[](CompilationOptions &options, size_t glweDimension,
|
|
size_t logPolynomialSize, size_t nSmall, size_t brLevel,
|
|
size_t brLogBase, size_t ksLevel, size_t ksLogBase,
|
|
std::vector<int64_t> crtDecomposition, size_t cbsLevel,
|
|
size_t cbsLogBase, size_t pksLevel, size_t pksLogBase,
|
|
size_t pksInputLweDimension, size_t pksOutputPolynomialSize) {
|
|
mlir::toruslang::PackingKeySwitchParameter pksParam = {
|
|
pksInputLweDimension, pksOutputPolynomialSize, pksLevel,
|
|
pksLogBase};
|
|
mlir::toruslang::CitcuitBoostrapParameter crbParam = {
|
|
cbsLevel, cbsLogBase};
|
|
mlir::toruslang::WopPBSParameter wopPBSParam = {pksParam,
|
|
crbParam};
|
|
mlir::toruslang::LargeIntegerParameter largeIntegerParam = {
|
|
crtDecomposition, wopPBSParam};
|
|
options.v0Parameter = {glweDimension, logPolynomialSize, nSmall,
|
|
brLevel, brLogBase, ksLevel,
|
|
ksLogBase, largeIntegerParam};
|
|
},
|
|
"Set all the V0 parameters.", arg("glwe_dimension"),
|
|
arg("log_poly_size"), arg("n_small"), arg("br_level"),
|
|
arg("br_log_base"), arg("ks_level"), arg("ks_log_base"),
|
|
arg("crt_decomp"), arg("cbs_level"), arg("cbs_log_base"),
|
|
arg("pks_level"), arg("pks_log_base"), arg("pks_input_lwe_dim"),
|
|
arg("pks_output_poly_size"))
|
|
.def(
|
|
"force_encoding",
|
|
[](CompilationOptions &options,
|
|
torus_optimizer::Encoding encoding) {
|
|
options.optimizerConfig.encoding = encoding;
|
|
},
|
|
"Force the compiler to use a specific encoding.", arg("encoding"))
|
|
.def(
|
|
"simulation",
|
|
[](CompilationOptions &options, bool simulate) {
|
|
options.simulate = simulate;
|
|
},
|
|
"Enable or disable simulation.", arg("simulate"))
|
|
.def(
|
|
"set_emit_gpu_ops",
|
|
[](CompilationOptions &options, bool emit_gpu_ops) {
|
|
options.emitGPUOps = emit_gpu_ops;
|
|
},
|
|
"Set flag that allows gpu ops to be emitted.", arg("emit_gpu_ops"))
|
|
.def(
|
|
"set_batch_tfhe_ops",
|
|
[](CompilationOptions &options, bool batch_tfhe_ops) {
|
|
options.batchTFHEOps = batch_tfhe_ops;
|
|
},
|
|
"Set flag that triggers the batching of scalar TFHE operations.",
|
|
arg("batch_tfhe_ops"))
|
|
.def(
|
|
"set_enable_tlu_fusing",
|
|
[](CompilationOptions &options, bool enableTluFusing) {
|
|
options.enableTluFusing = enableTluFusing;
|
|
},
|
|
"Enable or disable tlu fusing.", arg("enable_tlu_fusing"))
|
|
.def(
|
|
"set_print_tlu_fusing",
|
|
[](CompilationOptions &options, bool printTluFusing) {
|
|
options.printTluFusing = printTluFusing;
|
|
},
|
|
"Enable or disable printing tlu fusing.", arg("print_tlu_fusing"))
|
|
.def(
|
|
"set_enable_overflow_detection_in_simulation",
|
|
[](CompilationOptions &options, bool enableOverflowDetection) {
|
|
options.enableOverflowDetectionInSimulation =
|
|
enableOverflowDetection;
|
|
},
|
|
"Enable or disable overflow detection during simulation.",
|
|
arg("enable_overflow_detection"))
|
|
.doc() = "Holds different flags and options of the compilation process.";
|
|
|
|
pybind11::enum_<mlir::toruslang::PrimitiveOperation>(m,
|
|
"PrimitiveOperation")
|
|
.value("PBS", mlir::toruslang::PrimitiveOperation::PBS)
|
|
.value("WOP_PBS", mlir::toruslang::PrimitiveOperation::WOP_PBS)
|
|
.value("KEY_SWITCH", mlir::toruslang::PrimitiveOperation::KEY_SWITCH)
|
|
.value("CLEAR_ADDITION",
|
|
mlir::toruslang::PrimitiveOperation::CLEAR_ADDITION)
|
|
.value("ENCRYPTED_ADDITION",
|
|
mlir::toruslang::PrimitiveOperation::ENCRYPTED_ADDITION)
|
|
.value("CLEAR_MULTIPLICATION",
|
|
mlir::toruslang::PrimitiveOperation::CLEAR_MULTIPLICATION)
|
|
.value("ENCRYPTED_NEGATION",
|
|
mlir::toruslang::PrimitiveOperation::ENCRYPTED_NEGATION)
|
|
.export_values();
|
|
|
|
pybind11::enum_<mlir::toruslang::KeyType>(m, "KeyType")
|
|
.value("SECRET", mlir::toruslang::KeyType::SECRET)
|
|
.value("BOOTSTRAP", mlir::toruslang::KeyType::BOOTSTRAP)
|
|
.value("KEY_SWITCH", mlir::toruslang::KeyType::KEY_SWITCH)
|
|
.value("PACKING_KEY_SWITCH",
|
|
mlir::toruslang::KeyType::PACKING_KEY_SWITCH)
|
|
.export_values();
|
|
|
|
pybind11::class_<mlir::toruslang::Statistic>(m, "Statistic")
|
|
.def_readonly("operation", &mlir::toruslang::Statistic::operation)
|
|
.def_readonly("location", &mlir::toruslang::Statistic::location)
|
|
.def_readonly("keys", &mlir::toruslang::Statistic::keys)
|
|
.def_readonly("count", &mlir::toruslang::Statistic::count);
|
|
|
|
pybind11::class_<mlir::toruslang::CircuitCompilationFeedback>(
|
|
m, "CircuitCompilationFeedback")
|
|
.def_readonly("name",
|
|
&mlir::toruslang::CircuitCompilationFeedback::name)
|
|
.def_readonly(
|
|
"total_inputs_size",
|
|
&mlir::toruslang::CircuitCompilationFeedback::totalInputsSize)
|
|
.def_readonly(
|
|
"total_output_size",
|
|
&mlir::toruslang::CircuitCompilationFeedback::totalOutputsSize)
|
|
.def_readonly("crt_decompositions_of_outputs",
|
|
&mlir::toruslang::CircuitCompilationFeedback::
|
|
crtDecompositionsOfOutputs)
|
|
.def_readonly("statistics",
|
|
&mlir::toruslang::CircuitCompilationFeedback::statistics)
|
|
.def_readonly(
|
|
"memory_usage_per_location",
|
|
&mlir::toruslang::CircuitCompilationFeedback::memoryUsagePerLoc)
|
|
.doc() = "Compilation feedback for a single circuit.";
|
|
|
|
pybind11::class_<mlir::toruslang::ProgramCompilationFeedback>(
|
|
m, "ProgramCompilationFeedback")
|
|
.def_readonly("complexity",
|
|
&mlir::toruslang::ProgramCompilationFeedback::complexity)
|
|
.def_readonly("p_error",
|
|
&mlir::toruslang::ProgramCompilationFeedback::pError)
|
|
.def_readonly(
|
|
"global_p_error",
|
|
&mlir::toruslang::ProgramCompilationFeedback::globalPError)
|
|
.def_readonly(
|
|
"total_secret_keys_size",
|
|
&mlir::toruslang::ProgramCompilationFeedback::totalSecretKeysSize)
|
|
.def_readonly("total_bootstrap_keys_size",
|
|
&mlir::toruslang::ProgramCompilationFeedback::
|
|
totalBootstrapKeysSize)
|
|
.def_readonly("total_keyswitch_keys_size",
|
|
&mlir::toruslang::ProgramCompilationFeedback::
|
|
totalKeyswitchKeysSize)
|
|
.def_readonly(
|
|
"circuit_feedbacks",
|
|
&mlir::toruslang::ProgramCompilationFeedback::circuitFeedbacks)
|
|
.def(
|
|
"get_circuit_feedback",
|
|
[](mlir::toruslang::ProgramCompilationFeedback &feedback,
|
|
std::string function) {
|
|
for (auto circuit : feedback.circuitFeedbacks) {
|
|
if (circuit.name == function) {
|
|
return circuit;
|
|
}
|
|
}
|
|
throw std::runtime_error(
|
|
"Circuit feedback not found fo passed function.");
|
|
},
|
|
"Return the circuit feedback for `function`.", arg("function"))
|
|
.doc() = "Compilation feedback for a whole program.";
|
|
|
|
pybind11::class_<mlir::toruslang::CompilationContext,
|
|
std::shared_ptr<mlir::toruslang::CompilationContext>>(
|
|
m, "CompilationContext")
|
|
.def(pybind11::init([]() {
|
|
return mlir::toruslang::CompilationContext::createShared();
|
|
}))
|
|
.def("mlir_context",
|
|
[](std::shared_ptr<mlir::toruslang::CompilationContext> cctx) {
|
|
auto mlirCtx = cctx->getMLIRContext();
|
|
return pybind11::reinterpret_steal<pybind11::object>(
|
|
mlirPythonContextToCapsule(wrap(mlirCtx)));
|
|
});
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// LWE SECRET KEY PARAM //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
struct LweSecretKeyParam {
|
|
Message<torusprotocol::LweSecretKeyInfo> info;
|
|
|
|
std::string toString() {
|
|
std::string output = "LweSecretKeyParam(dimension=";
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getLweDimension()));
|
|
output.append(")");
|
|
return output;
|
|
}
|
|
|
|
bool operator==(LweSecretKeyParam const &other) const {
|
|
capnp::AnyStruct::Reader left = this->info.asReader().getParams();
|
|
capnp::AnyStruct::Reader right = other.info.asReader().getParams();
|
|
return left == right;
|
|
}
|
|
|
|
bool operator!=(LweSecretKeyParam const &other) const {
|
|
capnp::AnyStruct::Reader left = this->info.asReader().getParams();
|
|
capnp::AnyStruct::Reader right = other.info.asReader().getParams();
|
|
return left != right;
|
|
}
|
|
};
|
|
pybind11::class_<LweSecretKeyParam>(m, "LweSecretKeyParam")
|
|
.def(
|
|
"dimension",
|
|
[](LweSecretKeyParam &key) {
|
|
return key.info.asReader().getParams().getLweDimension();
|
|
},
|
|
"Return the associated LWE dimension.")
|
|
.def("__str__", [](LweSecretKeyParam &key) { return key.toString(); })
|
|
.def("__repr__", [](LweSecretKeyParam &key) { return key.toString(); })
|
|
.def("__hash__",
|
|
[](pybind11::object key) {
|
|
return pybind11::hash(pybind11::repr(key));
|
|
})
|
|
.def(pybind11::self == pybind11::self)
|
|
.def(pybind11::self != pybind11::self)
|
|
.doc() = "Parameters of an LWE Secret Key.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// BOOTSTRAP KEY PARAM //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
struct BootstrapKeyParam {
|
|
Message<torusprotocol::LweBootstrapKeyInfo> info;
|
|
|
|
std::string toString() {
|
|
std::string output = "BootstrapKeyParam(";
|
|
output.append("polynomial_size=");
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getPolynomialSize()));
|
|
output.append(", glwe_dimension=");
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getGlweDimension()));
|
|
output.append(", input_lwe_dimension=");
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getInputLweDimension()));
|
|
output.append(", level=");
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getLevelCount()));
|
|
output.append(", base_log=");
|
|
output.append(std::to_string(info.asReader().getParams().getBaseLog()));
|
|
output.append(", variance=");
|
|
output.append(std::to_string(info.asReader().getParams().getVariance()));
|
|
output.append(")");
|
|
return output;
|
|
}
|
|
|
|
bool operator==(BootstrapKeyParam const &other) const {
|
|
capnp::AnyStruct::Reader left = this->info.asReader().getParams();
|
|
capnp::AnyStruct::Reader right = other.info.asReader().getParams();
|
|
return left == right;
|
|
}
|
|
|
|
bool operator!=(BootstrapKeyParam const &other) const {
|
|
capnp::AnyStruct::Reader left = this->info.asReader().getParams();
|
|
capnp::AnyStruct::Reader right = other.info.asReader().getParams();
|
|
return left != right;
|
|
}
|
|
};
|
|
pybind11::class_<BootstrapKeyParam>(m, "BootstrapKeyParam")
|
|
.def(
|
|
"input_secret_key_id",
|
|
[](BootstrapKeyParam &key) {
|
|
return key.info.asReader().getInputId();
|
|
},
|
|
"Return the key id of the associated input key.")
|
|
.def(
|
|
"output_secret_key_id",
|
|
[](BootstrapKeyParam &key) {
|
|
return key.info.asReader().getOutputId();
|
|
},
|
|
"Return the key id of the associated output key.")
|
|
.def(
|
|
"level",
|
|
[](BootstrapKeyParam &key) {
|
|
return key.info.asReader().getParams().getLevelCount();
|
|
},
|
|
"Return the associated number of levels.")
|
|
.def(
|
|
"base_log",
|
|
[](BootstrapKeyParam &key) {
|
|
return key.info.asReader().getParams().getBaseLog();
|
|
},
|
|
"Return the associated base log.")
|
|
.def(
|
|
"glwe_dimension",
|
|
[](BootstrapKeyParam &key) {
|
|
return key.info.asReader().getParams().getGlweDimension();
|
|
},
|
|
"Return the associated GLWE dimension.")
|
|
.def(
|
|
"variance",
|
|
[](BootstrapKeyParam &key) {
|
|
return key.info.asReader().getParams().getVariance();
|
|
},
|
|
"Return the associated noise variance.")
|
|
.def(
|
|
"polynomial_size",
|
|
[](BootstrapKeyParam &key) {
|
|
return key.info.asReader().getParams().getPolynomialSize();
|
|
},
|
|
"Return the associated polynomial size.")
|
|
.def(
|
|
"input_lwe_dimension",
|
|
[](BootstrapKeyParam &key) {
|
|
return key.info.asReader().getParams().getInputLweDimension();
|
|
},
|
|
"Return the associated input lwe dimension.")
|
|
.def("__str__", [](BootstrapKeyParam &key) { return key.toString(); })
|
|
.def("__repr__", [](BootstrapKeyParam &key) { return key.toString(); })
|
|
.def("__hash__",
|
|
[](pybind11::object key) {
|
|
return pybind11::hash(pybind11::repr(key));
|
|
})
|
|
.def(pybind11::self == pybind11::self)
|
|
.def(pybind11::self != pybind11::self)
|
|
.doc() = "Parameters of a Bootstrap key.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// KEYSWITCH KEY PARAM //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
struct KeyswitchKeyParam {
|
|
Message<torusprotocol::LweKeyswitchKeyInfo> info;
|
|
|
|
std::string toString() {
|
|
std::string output = "KeyswitchKeyParam(";
|
|
output.append("level=");
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getLevelCount()));
|
|
output.append(", base_log=");
|
|
output.append(std::to_string(info.asReader().getParams().getBaseLog()));
|
|
output.append(", variance=");
|
|
output.append(std::to_string(info.asReader().getParams().getVariance()));
|
|
output.append(")");
|
|
return output;
|
|
}
|
|
|
|
bool operator==(KeyswitchKeyParam const &other) const {
|
|
capnp::AnyStruct::Reader left = this->info.asReader().getParams();
|
|
capnp::AnyStruct::Reader right = other.info.asReader().getParams();
|
|
return left == right;
|
|
}
|
|
|
|
bool operator!=(KeyswitchKeyParam const &other) const {
|
|
capnp::AnyStruct::Reader left = this->info.asReader().getParams();
|
|
capnp::AnyStruct::Reader right = other.info.asReader().getParams();
|
|
return left != right;
|
|
}
|
|
};
|
|
pybind11::class_<KeyswitchKeyParam>(m, "KeyswitchKeyParam")
|
|
.def(
|
|
"input_secret_key_id",
|
|
[](KeyswitchKeyParam &key) {
|
|
return key.info.asReader().getInputId();
|
|
},
|
|
"Return the key id of the associated input key.")
|
|
.def(
|
|
"output_secret_key_id",
|
|
[](KeyswitchKeyParam &key) {
|
|
return key.info.asReader().getOutputId();
|
|
},
|
|
"Return the key id of the associated output key.")
|
|
.def(
|
|
"level",
|
|
[](KeyswitchKeyParam &key) {
|
|
return key.info.asReader().getParams().getLevelCount();
|
|
},
|
|
"Return the associated number of levels.")
|
|
.def(
|
|
"base_log",
|
|
[](KeyswitchKeyParam &key) {
|
|
return key.info.asReader().getParams().getBaseLog();
|
|
},
|
|
"Return the associated base log.")
|
|
.def(
|
|
"variance",
|
|
[](KeyswitchKeyParam &key) {
|
|
return key.info.asReader().getParams().getVariance();
|
|
},
|
|
"Return the associated noise variance.")
|
|
.def("__str__", [](KeyswitchKeyParam &key) { return key.toString(); })
|
|
.def("__repr__", [](KeyswitchKeyParam &key) { return key.toString(); })
|
|
.def("__hash__",
|
|
[](pybind11::object key) {
|
|
return pybind11::hash(pybind11::repr(key));
|
|
})
|
|
.def(pybind11::self == pybind11::self)
|
|
.def(pybind11::self != pybind11::self)
|
|
.doc() = "Parameters of a keyswitch key.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// PACKING KEYSWITCH KEY PARAM //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
struct PackingKeyswitchKeyParam {
|
|
Message<torusprotocol::PackingKeyswitchKeyInfo> info;
|
|
|
|
std::string toString() {
|
|
std::string output = "PackingKeyswitchKeyParam(";
|
|
output.append("polynomial_size=");
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getPolynomialSize()));
|
|
output.append(", glwe_dimension=");
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getGlweDimension()));
|
|
output.append(", input_lwe_dimension=");
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getInputLweDimension()));
|
|
output.append(", level=");
|
|
output.append(
|
|
std::to_string(info.asReader().getParams().getLevelCount()));
|
|
output.append(", base_log=");
|
|
output.append(std::to_string(info.asReader().getParams().getBaseLog()));
|
|
output.append(", variance=");
|
|
output.append(std::to_string(info.asReader().getParams().getVariance()));
|
|
output.append(")");
|
|
return output;
|
|
}
|
|
|
|
bool operator==(PackingKeyswitchKeyParam const &other) const {
|
|
capnp::AnyStruct::Reader left = this->info.asReader().getParams();
|
|
capnp::AnyStruct::Reader right = other.info.asReader().getParams();
|
|
return left == right;
|
|
}
|
|
|
|
bool operator!=(PackingKeyswitchKeyParam const &other) const {
|
|
capnp::AnyStruct::Reader left = this->info.asReader().getParams();
|
|
capnp::AnyStruct::Reader right = other.info.asReader().getParams();
|
|
return left != right;
|
|
}
|
|
};
|
|
pybind11::class_<PackingKeyswitchKeyParam>(m, "PackingKeyswitchKeyParam")
|
|
.def(
|
|
"input_secret_key_id",
|
|
[](PackingKeyswitchKeyParam &key) {
|
|
return key.info.asReader().getInputId();
|
|
},
|
|
"Return the key id of the associated input key.")
|
|
.def(
|
|
"output_secret_key_id",
|
|
[](PackingKeyswitchKeyParam &key) {
|
|
return key.info.asReader().getOutputId();
|
|
},
|
|
"Return the key id of the associated output key.")
|
|
.def(
|
|
"level",
|
|
[](PackingKeyswitchKeyParam &key) {
|
|
return key.info.asReader().getParams().getLevelCount();
|
|
},
|
|
"Return the associated number of levels.")
|
|
.def(
|
|
"base_log",
|
|
[](PackingKeyswitchKeyParam &key) {
|
|
return key.info.asReader().getParams().getBaseLog();
|
|
},
|
|
"Return the associated base log.")
|
|
.def(
|
|
"glwe_dimension",
|
|
[](PackingKeyswitchKeyParam &key) {
|
|
return key.info.asReader().getParams().getGlweDimension();
|
|
},
|
|
"Return the associated GLWE dimension.")
|
|
.def(
|
|
"polynomial_size",
|
|
[](PackingKeyswitchKeyParam &key) {
|
|
return key.info.asReader().getParams().getPolynomialSize();
|
|
},
|
|
"Return the associated polynomial size.")
|
|
.def(
|
|
"input_lwe_dimension",
|
|
[](PackingKeyswitchKeyParam &key) {
|
|
return key.info.asReader().getParams().getInputLweDimension();
|
|
},
|
|
"Return the associated input LWE dimension.")
|
|
.def(
|
|
"variance",
|
|
[](PackingKeyswitchKeyParam &key) {
|
|
return key.info.asReader().getParams().getVariance();
|
|
},
|
|
"Return the associated noise variance.")
|
|
.def("__str__",
|
|
[](PackingKeyswitchKeyParam &key) { return key.toString(); })
|
|
.def("__repr__",
|
|
[](PackingKeyswitchKeyParam &key) { return key.toString(); })
|
|
.def("__hash__",
|
|
[](pybind11::object key) {
|
|
return pybind11::hash(pybind11::repr(key));
|
|
})
|
|
.def(pybind11::self == pybind11::self)
|
|
.def(pybind11::self != pybind11::self)
|
|
.doc() = "Parameters of a packing keyswitch key.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// PARTITION DEFINITION //
|
|
// ------------------------------------------------------------------------------//
|
|
//
|
|
pybind11::class_<torus_optimizer::utils::PartitionDefinition>(
|
|
m, "PartitionDefinition")
|
|
.def(init([](uint8_t precision, double norm2)
|
|
-> torus_optimizer::utils::PartitionDefinition {
|
|
return torus_optimizer::utils::PartitionDefinition{precision,
|
|
norm2};
|
|
}),
|
|
arg("precision"), arg("norm2"))
|
|
.doc() = "Definition of a partition (in terms of precision in bits and "
|
|
"norm2 in value).";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// KEYSET INFO //
|
|
// ------------------------------------------------------------------------------//
|
|
typedef Message<torusprotocol::KeysetInfo> KeysetInfo;
|
|
pybind11::class_<KeysetInfo>(m, "KeysetInfo")
|
|
.def_static(
|
|
"generate_virtual",
|
|
[](std::vector<torus_optimizer::utils::PartitionDefinition>
|
|
partitions,
|
|
bool generateFks,
|
|
std::optional<torus_optimizer::Options> options) -> KeysetInfo {
|
|
if (partitions.size() < 2) {
|
|
throw std::runtime_error("Need at least two partition defs to "
|
|
"generate a virtual keyset info.");
|
|
}
|
|
return ::toruslang::keysets::keysetInfoFromVirtualCircuit(
|
|
partitions, generateFks, options);
|
|
},
|
|
arg("partition_defs"), arg("generate_fks"),
|
|
arg("options") = std::nullopt,
|
|
"Generate a generic keyset info for a set of partition definitions")
|
|
.def(
|
|
"secret_keys",
|
|
[](KeysetInfo &keysetInfo) {
|
|
auto secretKeys = std::vector<LweSecretKeyParam>();
|
|
for (auto key : keysetInfo.asReader().getLweSecretKeys()) {
|
|
secretKeys.push_back(LweSecretKeyParam{
|
|
(Message<torusprotocol::LweSecretKeyInfo>)key});
|
|
}
|
|
return secretKeys;
|
|
},
|
|
"Return the parameters of the secret keys for this keyset.")
|
|
.def(
|
|
"bootstrap_keys",
|
|
[](KeysetInfo &keysetInfo) {
|
|
auto bootstrapKeys = std::vector<BootstrapKeyParam>();
|
|
for (auto key : keysetInfo.asReader().getLweBootstrapKeys()) {
|
|
bootstrapKeys.push_back(BootstrapKeyParam{
|
|
(Message<torusprotocol::LweBootstrapKeyInfo>)key});
|
|
}
|
|
return bootstrapKeys;
|
|
},
|
|
"Return the parameters of the bootstrap keys for this keyset.")
|
|
.def(
|
|
"keyswitch_keys",
|
|
[](KeysetInfo &keysetInfo) {
|
|
auto keyswitchKeys = std::vector<KeyswitchKeyParam>();
|
|
for (auto key : keysetInfo.asReader().getLweKeyswitchKeys()) {
|
|
keyswitchKeys.push_back(KeyswitchKeyParam{
|
|
(Message<torusprotocol::LweKeyswitchKeyInfo>)key});
|
|
}
|
|
return keyswitchKeys;
|
|
},
|
|
"Return the parameters of the keyswitch keys for this keyset.")
|
|
.def(
|
|
"packing_keyswitch_keys",
|
|
[](KeysetInfo &keysetInfo) {
|
|
auto packingKeyswitchKeys = std::vector<PackingKeyswitchKeyParam>();
|
|
for (auto key : keysetInfo.asReader().getPackingKeyswitchKeys()) {
|
|
packingKeyswitchKeys.push_back(PackingKeyswitchKeyParam{
|
|
(Message<torusprotocol::PackingKeyswitchKeyInfo>)key});
|
|
}
|
|
return packingKeyswitchKeys;
|
|
},
|
|
"Return the parameters of the packing keyswitch keys for this "
|
|
"keyset.")
|
|
.def(
|
|
"get_restriction",
|
|
[](KeysetInfo &keysetInfo) {
|
|
torus_optimizer::restriction::KeysetInfo output;
|
|
for (auto key : keysetInfo.asReader().getLweSecretKeys()) {
|
|
output.lwe_secret_keys.push_back(
|
|
torus_optimizer::restriction::LweSecretKeyInfo{
|
|
key.getParams().getLweDimension()});
|
|
}
|
|
for (auto key : keysetInfo.asReader().getLweBootstrapKeys()) {
|
|
output.lwe_bootstrap_keys.push_back(
|
|
torus_optimizer::restriction::LweBootstrapKeyInfo{
|
|
key.getParams().getLevelCount(),
|
|
key.getParams().getBaseLog(),
|
|
key.getParams().getGlweDimension(),
|
|
key.getParams().getPolynomialSize(),
|
|
key.getParams().getInputLweDimension()});
|
|
}
|
|
for (auto key : keysetInfo.asReader().getLweKeyswitchKeys()) {
|
|
output.lwe_keyswitch_keys.push_back(
|
|
torus_optimizer::restriction::LweKeyswitchKeyInfo{
|
|
key.getParams().getLevelCount(),
|
|
key.getParams().getBaseLog(),
|
|
key.getParams().getInputLweDimension(),
|
|
key.getParams().getOutputLweDimension()});
|
|
}
|
|
return torus_optimizer::restriction::KeysetRestriction{output};
|
|
},
|
|
"Return the search space restriction associated to this keyset info.")
|
|
.def_static(
|
|
"deserialize",
|
|
[](const pybind11::bytes &buffer) {
|
|
auto keysetInfo = Message<torusprotocol::KeysetInfo>();
|
|
auto maybeError = keysetInfo.readBinaryFromString(
|
|
buffer, mlir::toruslang::python::DESER_OPTIONS);
|
|
if (maybeError.has_failure()) {
|
|
throw std::runtime_error("Failed to deserialize keyset info." +
|
|
maybeError.as_failure().error().mesg);
|
|
}
|
|
return keysetInfo;
|
|
},
|
|
"Deserialize a KeysetInfo from bytes.", arg("bytes"))
|
|
.def(
|
|
"serialize",
|
|
[](KeysetInfo &keySetInfo) {
|
|
auto maybeBuffer = keySetInfo.writeBinaryToString();
|
|
if (maybeBuffer.has_failure()) {
|
|
throw std::runtime_error("Failed to serialize keyset info.");
|
|
}
|
|
return pybind11::bytes(maybeBuffer.value());
|
|
},
|
|
"Serialize a KeysetInfo to bytes.")
|
|
.def(pybind11::self == pybind11::self)
|
|
.def(pybind11::self != pybind11::self)
|
|
.doc() = "Parameters of a complete keyset.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// TYPE INFO //
|
|
// ------------------------------------------------------------------------------//
|
|
typedef Message<torusprotocol::TypeInfo> TypeInfo;
|
|
pybind11::class_<TypeInfo>(m, "TypeInfo")
|
|
.def(
|
|
"is_plaintext",
|
|
[](TypeInfo &type) { return type.asReader().hasPlaintext(); },
|
|
"Return true if the type is plaintext")
|
|
.doc() = "Informations describing the type of a gate.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// RAW INFO //
|
|
// ------------------------------------------------------------------------------//
|
|
typedef Message<torusprotocol::RawInfo> RawInfo;
|
|
pybind11::class_<RawInfo>(m, "RawInfo")
|
|
.def(
|
|
"get_shape",
|
|
[](RawInfo &raw) {
|
|
auto output = std::vector<int64_t>();
|
|
for (auto dim : raw.asReader().getShape().getDimensions()) {
|
|
output.push_back({dim});
|
|
}
|
|
return output;
|
|
},
|
|
"Return the shape associated to the raw info.")
|
|
.def(
|
|
"get_integer_precision",
|
|
[](RawInfo &raw) { return raw.asReader().getIntegerPrecision(); },
|
|
"Return the integer precision associated to the raw info.")
|
|
.def(
|
|
"get_signedness",
|
|
[](RawInfo &raw) { return raw.asReader().getIsSigned(); },
|
|
"Return the signedness associated to the raw info.")
|
|
.doc() = "Informations describing a raw type of gate.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// GATE INFO //
|
|
// ------------------------------------------------------------------------------//
|
|
typedef Message<torusprotocol::GateInfo> GateInfo;
|
|
pybind11::class_<GateInfo>(m, "GateInfo")
|
|
.def(
|
|
"get_type_info",
|
|
[](GateInfo &gate) -> TypeInfo {
|
|
return {(TypeInfo)gate.asReader().getTypeInfo()};
|
|
},
|
|
"Return the type associated to the gate.")
|
|
.def(
|
|
"get_raw_info",
|
|
[](GateInfo &gate) -> RawInfo {
|
|
return {(RawInfo)gate.asReader().getRawInfo()};
|
|
},
|
|
"Return the raw type associated to the gate.")
|
|
.doc() = "Informations describing a circuit gate (input or output).";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// CIRCUIT INFO //
|
|
// ------------------------------------------------------------------------------//
|
|
typedef Message<torusprotocol::CircuitInfo> CircuitInfo;
|
|
pybind11::class_<CircuitInfo>(m, "CircuitInfo")
|
|
.def(
|
|
"get_name",
|
|
[](CircuitInfo &circuit) {
|
|
return circuit.asReader().getName().cStr();
|
|
},
|
|
"Return the name of the circuit")
|
|
.def(
|
|
"get_inputs",
|
|
[](CircuitInfo &circuit) -> std::vector<GateInfo> {
|
|
auto output = std::vector<GateInfo>();
|
|
for (auto gate : circuit.asReader().getInputs()) {
|
|
output.push_back({(Message<torusprotocol::GateInfo>)gate});
|
|
}
|
|
return output;
|
|
},
|
|
"Return the input gates")
|
|
.def(
|
|
"get_outputs",
|
|
[](CircuitInfo &circuit) -> std::vector<GateInfo> {
|
|
auto output = std::vector<GateInfo>();
|
|
for (auto gate : circuit.asReader().getOutputs()) {
|
|
output.push_back({(Message<torusprotocol::GateInfo>)gate});
|
|
}
|
|
return output;
|
|
},
|
|
"Return the output gates")
|
|
.doc() = "Informations describing a compiled circuit.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// PROGRAM INFO //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
struct ProgramInfo {
|
|
Message<torusprotocol::ProgramInfo> programInfo;
|
|
|
|
torusprotocol::LweCiphertextEncryptionInfo::Reader
|
|
inputEncryptionAt(size_t inputId, std::string circuitName) {
|
|
auto reader = programInfo.asReader();
|
|
if (!reader.hasCircuits()) {
|
|
throw std::runtime_error("can't get keyid: no circuit info");
|
|
}
|
|
auto circuits = reader.getCircuits();
|
|
for (auto circuit : circuits) {
|
|
if (circuit.hasName() &&
|
|
circuitName.compare(circuit.getName().cStr()) == 0) {
|
|
if (!circuit.hasInputs()) {
|
|
throw std::runtime_error("can't get keyid: no input");
|
|
}
|
|
auto inputs = circuit.getInputs();
|
|
if (inputId >= inputs.size()) {
|
|
throw std::runtime_error(
|
|
"can't get keyid: inputId bigger than number of inputs");
|
|
}
|
|
auto input = inputs[inputId];
|
|
if (!input.hasTypeInfo()) {
|
|
throw std::runtime_error(
|
|
"can't get keyid: input don't have typeInfo");
|
|
}
|
|
auto typeInfo = input.getTypeInfo();
|
|
if (!typeInfo.hasLweCiphertext()) {
|
|
throw std::runtime_error("can't get keyid: typeInfo don't "
|
|
"have lwe ciphertext info");
|
|
}
|
|
auto lweCt = typeInfo.getLweCiphertext();
|
|
if (!lweCt.hasEncryption()) {
|
|
throw std::runtime_error("can't get keyid: lwe ciphertext "
|
|
"don't have encryption info");
|
|
}
|
|
return lweCt.getEncryption();
|
|
}
|
|
}
|
|
|
|
throw std::runtime_error("can't get keyid: no circuit with name " +
|
|
circuitName);
|
|
}
|
|
};
|
|
pybind11::class_<ProgramInfo>(m, "ProgramInfo")
|
|
.def_static(
|
|
"deserialize",
|
|
[](const pybind11::bytes &buffer) {
|
|
auto programInfo = Message<torusprotocol::ProgramInfo>();
|
|
if (programInfo.readJsonFromString(buffer).has_failure()) {
|
|
throw std::runtime_error("Failed to deserialize program info");
|
|
}
|
|
return ProgramInfo{programInfo};
|
|
},
|
|
"Deserialize a ProgramInfo from bytes.", arg("bytes"))
|
|
.def(
|
|
"serialize",
|
|
[](ProgramInfo &programInfo) {
|
|
auto programInfoSerialize = [](ProgramInfo ¶ms) {
|
|
auto maybeJson = params.programInfo.writeJsonToString();
|
|
if (maybeJson.has_failure()) {
|
|
throw std::runtime_error("Failed to serialize program info");
|
|
}
|
|
return maybeJson.value();
|
|
};
|
|
return pybind11::bytes(programInfoSerialize(programInfo));
|
|
},
|
|
"Serialize a ProgramInfo to bytes.")
|
|
.def(
|
|
"input_keyid_at",
|
|
[](ProgramInfo &programInfo, size_t pos, std::string circuitName) {
|
|
auto encryption = programInfo.inputEncryptionAt(pos, circuitName);
|
|
return encryption.getKeyId();
|
|
},
|
|
"Return the key id associated to the argument `pos` of circuit "
|
|
"`circuit_name`.",
|
|
arg("pos"), arg("circuit_name"))
|
|
.def(
|
|
"input_variance_at",
|
|
[](ProgramInfo &programInfo, size_t pos, std::string circuitName) {
|
|
auto encryption = programInfo.inputEncryptionAt(pos, circuitName);
|
|
return encryption.getVariance();
|
|
},
|
|
"Return the noise variance associated to the argument `pos` of "
|
|
"circuit `circuit_name`.",
|
|
arg("pos"), arg("circuit_name"))
|
|
.def("function_list",
|
|
[](ProgramInfo &programInfo) {
|
|
std::vector<std::string> result;
|
|
for (auto circuit :
|
|
programInfo.programInfo.asReader().getCircuits()) {
|
|
result.push_back(circuit.getName());
|
|
}
|
|
return result;
|
|
})
|
|
.def(
|
|
"output_signs",
|
|
[](ProgramInfo &programInfo) {
|
|
std::vector<bool> result;
|
|
for (auto output : programInfo.programInfo.asReader()
|
|
.getCircuits()[0]
|
|
.getOutputs()) {
|
|
if (output.getTypeInfo().hasLweCiphertext() &&
|
|
output.getTypeInfo()
|
|
.getLweCiphertext()
|
|
.getEncoding()
|
|
.hasInteger()) {
|
|
result.push_back(output.getTypeInfo()
|
|
.getLweCiphertext()
|
|
.getEncoding()
|
|
.getInteger()
|
|
.getIsSigned());
|
|
} else {
|
|
result.push_back(true);
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
"Return the signedness of the output of the first circuit.")
|
|
.def(
|
|
"input_signs",
|
|
[](ProgramInfo &programInfo) {
|
|
std::vector<bool> result;
|
|
for (auto input : programInfo.programInfo.asReader()
|
|
.getCircuits()[0]
|
|
.getInputs()) {
|
|
if (input.getTypeInfo().hasLweCiphertext() &&
|
|
input.getTypeInfo()
|
|
.getLweCiphertext()
|
|
.getEncoding()
|
|
.hasInteger()) {
|
|
result.push_back(input.getTypeInfo()
|
|
.getLweCiphertext()
|
|
.getEncoding()
|
|
.getInteger()
|
|
.getIsSigned());
|
|
} else {
|
|
result.push_back(true);
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
"Return the signedness of the input of the first circuit.")
|
|
|
|
.def(
|
|
"get_keyset_info",
|
|
[](ProgramInfo &programInfo) -> KeysetInfo {
|
|
return (KeysetInfo)programInfo.programInfo.asReader().getKeyset();
|
|
},
|
|
"Return the keyset info associated to the program.")
|
|
.def(
|
|
"get_circuits",
|
|
[](ProgramInfo &programInfo) {
|
|
auto output = std::vector<CircuitInfo>();
|
|
for (auto circuit :
|
|
programInfo.programInfo.asReader().getCircuits()) {
|
|
output.push_back((CircuitInfo)circuit);
|
|
}
|
|
return output;
|
|
},
|
|
"Return the circuits associated to the program.")
|
|
.def(
|
|
"get_circuit",
|
|
[](ProgramInfo &programInfo, std::string &name) -> CircuitInfo {
|
|
for (auto circuit :
|
|
programInfo.programInfo.asReader().getCircuits()) {
|
|
if (circuit.getName() == name) {
|
|
return (CircuitInfo)circuit;
|
|
}
|
|
}
|
|
throw std::runtime_error("couldn't find circuit.");
|
|
},
|
|
"Return the circuit associated to the program with given name.")
|
|
.doc() = "Informations describing a compiled program.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// LWE SECRET KEY //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
pybind11::class_<LweSecretKey>(m, "LweSecretKey")
|
|
.def_static(
|
|
"deserialize",
|
|
[](pybind11::bytes buffer, LweSecretKeyParam ¶ms) {
|
|
std::string buffer_str = buffer;
|
|
auto lwe_dim = params.info.asReader().getParams().getLweDimension();
|
|
auto lwe_size = torus_cpu_lwe_secret_key_size_u64(lwe_dim);
|
|
std::vector<uint64_t> lwe_sk(lwe_size);
|
|
auto key_size = torus_cpu_unserialize_lwe_secret_key_u64(
|
|
(uint8_t *)buffer_str.data(), buffer_str.size(), lwe_sk.data(),
|
|
lwe_sk.size());
|
|
lwe_sk.resize(key_size);
|
|
return LweSecretKey(
|
|
std::make_shared<std::vector<uint64_t>>(std::move(lwe_sk)),
|
|
params.info);
|
|
},
|
|
"Deserialize an LweSecretKet from bytes and associated parameters.",
|
|
arg("buffer"), arg("params"))
|
|
.def(
|
|
"serialize",
|
|
[](LweSecretKey &lweSk) {
|
|
auto skBuffer = lweSk.getBuffer();
|
|
auto lwe_dimension =
|
|
lweSk.getInfo().asReader().getParams().getLweDimension();
|
|
auto buffer_size =
|
|
torus_cpu_lwe_secret_key_buffer_size_u64(lwe_dimension);
|
|
std::vector<uint8_t> buffer(buffer_size, 0);
|
|
buffer_size = torus_cpu_serialize_lwe_secret_key_u64(
|
|
skBuffer.data(), lwe_dimension, buffer.data(), buffer_size);
|
|
if (buffer_size == 0) {
|
|
throw std::runtime_error("couldn't serialize the secret key");
|
|
}
|
|
auto bytes = pybind11::bytes((char *)buffer.data(), buffer_size);
|
|
return bytes;
|
|
},
|
|
"Serialize an LweSecretKey to bytes.")
|
|
.def_static(
|
|
"deserialize_from_glwe",
|
|
[](pybind11::bytes buffer, LweSecretKeyParam ¶ms) {
|
|
std::string buffer_str = buffer;
|
|
auto lwe_dim = params.info.asReader().getParams().getLweDimension();
|
|
auto glwe_sk_size = torus_cpu_lwe_secret_key_size_u64(lwe_dim);
|
|
std::vector<uint64_t> glwe_sk(glwe_sk_size);
|
|
auto key_size = torus_cpu_unserialize_glwe_secret_key_u64(
|
|
(uint8_t *)buffer_str.data(), buffer_str.size(), glwe_sk.data(),
|
|
glwe_sk.size());
|
|
glwe_sk.resize(key_size);
|
|
return LweSecretKey(
|
|
std::make_shared<std::vector<uint64_t>>(std::move(glwe_sk)),
|
|
params.info);
|
|
},
|
|
"Deserialize an LweSecretKey from glwe encoded (Lux-FHE "
|
|
"compatible) "
|
|
"bytes and associated parameters.",
|
|
arg("buffer"), arg("params"))
|
|
.def(
|
|
"serialize_as_glwe",
|
|
[](LweSecretKey &lweSk, size_t glwe_dimension,
|
|
size_t polynomial_size) {
|
|
auto skBuffer = lweSk.getBuffer();
|
|
auto buffer_size = torus_cpu_glwe_secret_key_buffer_size_u64(
|
|
glwe_dimension, polynomial_size);
|
|
std::vector<uint8_t> buffer(buffer_size, 0);
|
|
buffer_size = torus_cpu_serialize_glwe_secret_key_u64(
|
|
skBuffer.data(), glwe_dimension, polynomial_size, buffer.data(),
|
|
buffer_size);
|
|
if (buffer_size == 0) {
|
|
throw std::runtime_error("couldn't serialize the secret key");
|
|
}
|
|
auto bytes = pybind11::bytes((char *)buffer.data(), buffer_size);
|
|
return bytes;
|
|
},
|
|
"Serialize an LweSecretKey to glwe encoded (Lux-FHE compatible) "
|
|
"bytes and associated parameters.",
|
|
arg("glwe_dimension"), arg("polynomial_size"))
|
|
.def_property_readonly(
|
|
"param",
|
|
[](LweSecretKey &lweSk) {
|
|
return LweSecretKeyParam{lweSk.getInfo()};
|
|
},
|
|
"Parameters associated to the key.")
|
|
.doc() = "Lwe secret key.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// KEYSET CACHE //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
pybind11::class_<KeysetCache>(m, "KeysetCache")
|
|
.def(pybind11::init<std::string &>(), arg("backing_directory_path"))
|
|
.doc() = "Local keysets cache.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// SERVER KEYSET //
|
|
// ------------------------------------------------------------------------------//
|
|
pybind11::class_<ServerKeyset>(m, "ServerKeyset")
|
|
.def_static(
|
|
"deserialize",
|
|
[](const pybind11::bytes &buffer) {
|
|
auto serverKeysetProto = Message<torusprotocol::ServerKeyset>();
|
|
auto maybeError = serverKeysetProto.readBinaryFromString(
|
|
buffer, mlir::toruslang::python::DESER_OPTIONS);
|
|
if (maybeError.has_failure()) {
|
|
throw std::runtime_error("Failed to deserialize server keyset." +
|
|
maybeError.as_failure().error().mesg);
|
|
}
|
|
return ServerKeyset::fromProto(serverKeysetProto.asReader());
|
|
},
|
|
"Deserialize a ServerKeyset from bytes.", arg("bytes"))
|
|
.def(
|
|
"serialize",
|
|
[](ServerKeyset &serverKeyset) {
|
|
auto serverKeysetSerialize = [](ServerKeyset &serverKeyset) {
|
|
auto serverKeysetProto = serverKeyset.toProto();
|
|
auto maybeBuffer = serverKeysetProto.writeBinaryToString();
|
|
if (maybeBuffer.has_failure()) {
|
|
throw std::runtime_error("Failed to serialize server keyset.");
|
|
}
|
|
return maybeBuffer.value();
|
|
};
|
|
return pybind11::bytes(serverKeysetSerialize(serverKeyset));
|
|
},
|
|
"Serialize a ServerKeyset to bytes.")
|
|
.doc() = "Server-side / Evaluation keyset";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// CLIENT KEYSET //
|
|
// ------------------------------------------------------------------------------//
|
|
pybind11::class_<ClientKeyset>(m, "ClientKeyset")
|
|
.def("get_secret_keys",
|
|
[](ClientKeyset &keyset) { return keyset.lweSecretKeys; })
|
|
.doc() = "Client-side / Encryption keyset";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// KEYSET //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
pybind11::class_<Keyset>(m, "Keyset")
|
|
.def(init([](ProgramInfo programInfo, std::optional<KeysetCache> cache,
|
|
uint64_t secretSeedMsb, uint64_t secretSeedLsb,
|
|
uint64_t encSeedMsb, uint64_t encSeedLsb,
|
|
std::optional<std::map<uint32_t, LweSecretKey>>
|
|
initialLweSecretKeys) {
|
|
SignalGuard const signalGuard;
|
|
|
|
auto secretSeed =
|
|
(((__uint128_t)secretSeedMsb) << 64) | secretSeedLsb;
|
|
auto encryptionSeed =
|
|
(((__uint128_t)encSeedMsb) << 64) | encSeedLsb;
|
|
|
|
if (!initialLweSecretKeys.has_value()) {
|
|
initialLweSecretKeys = std::map<uint32_t, LweSecretKey>();
|
|
}
|
|
|
|
if (cache) {
|
|
GET_OR_THROW_RESULT(
|
|
Keyset keyset,
|
|
(*cache).getKeyset(
|
|
(KeysetInfo)programInfo.programInfo.asReader()
|
|
.getKeyset(),
|
|
secretSeed, encryptionSeed,
|
|
initialLweSecretKeys.value()));
|
|
return std::make_unique<Keyset>(std::move(keyset));
|
|
} else {
|
|
::toruslang::csprng::SecretCSPRNG secCsprng(secretSeed);
|
|
::toruslang::csprng::EncryptionCSPRNG encCsprng(
|
|
encryptionSeed);
|
|
auto keyset = Keyset(
|
|
(KeysetInfo)programInfo.programInfo.asReader().getKeyset(),
|
|
secCsprng, encCsprng, initialLweSecretKeys.value());
|
|
return std::make_unique<Keyset>(std::move(keyset));
|
|
}
|
|
}),
|
|
arg("program_info"), arg("keyset_cache"), arg("secret_seed_msb") = 0,
|
|
arg("secret_seed_lsb") = 0, arg("encryption_seed_msb") = 0,
|
|
arg("encryption_seed_lsb") = 0,
|
|
arg("initial_lwe_secret_keys") = std::nullopt)
|
|
.def_static(
|
|
"deserialize",
|
|
[](const pybind11::bytes &buffer) {
|
|
auto keysetProto = Message<torusprotocol::Keyset>();
|
|
auto maybeError = keysetProto.readBinaryFromString(
|
|
buffer, mlir::toruslang::python::DESER_OPTIONS);
|
|
if (maybeError.has_failure()) {
|
|
throw std::runtime_error("Failed to deserialize keyset." +
|
|
maybeError.as_failure().error().mesg);
|
|
}
|
|
auto keyset = Keyset::fromProto(keysetProto);
|
|
return std::make_unique<Keyset>(std::move(keyset));
|
|
},
|
|
"Deserialize a Keyset from bytes.", arg("bytes"))
|
|
.def_static(
|
|
"deserialize_from_file",
|
|
[](const std::string path) {
|
|
std::ifstream ifs;
|
|
ifs.open(path);
|
|
if (!ifs.good()) {
|
|
throw std::runtime_error("Failed to open keyset file " + path);
|
|
}
|
|
|
|
auto keysetProto = Message<torusprotocol::Keyset>();
|
|
auto maybeError = keysetProto.readBinaryFromIstream(
|
|
ifs, mlir::toruslang::python::DESER_OPTIONS);
|
|
if (maybeError.has_failure()) {
|
|
throw std::runtime_error("Failed to deserialize keyset." +
|
|
maybeError.as_failure().error().mesg);
|
|
}
|
|
auto keyset = Keyset::fromProto(std::move(keysetProto));
|
|
return std::make_unique<Keyset>(std::move(keyset));
|
|
},
|
|
"Deserialize a Keyset from a file.", arg("path"))
|
|
.def(
|
|
"serialize",
|
|
[](Keyset &keySet) {
|
|
auto keySetSerialize = [](Keyset &keyset) {
|
|
auto keysetProto = keyset.toProto();
|
|
auto maybeBuffer = keysetProto.writeBinaryToString();
|
|
if (maybeBuffer.has_failure()) {
|
|
throw std::runtime_error("Failed to serialize keys.");
|
|
}
|
|
return maybeBuffer.value();
|
|
};
|
|
return pybind11::bytes(keySetSerialize(keySet));
|
|
},
|
|
"Serialize a Keyset to bytes.")
|
|
.def(
|
|
"serialize_to_file",
|
|
[](Keyset &keySet, const std::string path) {
|
|
std::ofstream ofs;
|
|
ofs.open(path);
|
|
if (!ofs.good()) {
|
|
throw std::runtime_error("Failed to open keyset file " + path);
|
|
}
|
|
auto keysetProto = keySet.toProto();
|
|
auto maybeBuffer = keysetProto.writeBinaryToOstream(ofs);
|
|
if (maybeBuffer.has_failure()) {
|
|
throw std::runtime_error("Failed to serialize keys.");
|
|
}
|
|
},
|
|
"Serialize a Keyset to bytes.")
|
|
.def(
|
|
"serialize_lwe_secret_key_as_glwe",
|
|
[](Keyset &keyset, size_t keyIndex, size_t glwe_dimension,
|
|
size_t polynomial_size) {
|
|
auto secretKeys = keyset.client.lweSecretKeys;
|
|
if (keyIndex >= secretKeys.size()) {
|
|
throw std::runtime_error(
|
|
"keyIndex is bigger than the number of keys");
|
|
}
|
|
auto secretKey = secretKeys[keyIndex];
|
|
auto skBuffer = secretKey.getBuffer();
|
|
auto buffer_size = torus_cpu_glwe_secret_key_buffer_size_u64(
|
|
glwe_dimension, polynomial_size);
|
|
std::vector<uint8_t> buffer(buffer_size, 0);
|
|
buffer_size = torus_cpu_serialize_glwe_secret_key_u64(
|
|
skBuffer.data(), glwe_dimension, polynomial_size, buffer.data(),
|
|
buffer_size);
|
|
if (buffer_size == 0) {
|
|
throw std::runtime_error("couldn't serialize the secret key");
|
|
}
|
|
auto bytes = pybind11::bytes((char *)buffer.data(), buffer_size);
|
|
return bytes;
|
|
},
|
|
"Serialize the `key_id` secret key as a Lux-FHE GLWE key with "
|
|
"parameters `glwe_dim` and `poly_size`.",
|
|
arg("key_id"), arg("glwe_dim"), arg("poly_size"))
|
|
.def(
|
|
"get_server_keys", [](Keyset &keyset) { return keyset.server; },
|
|
"Return the associated ServerKeyset.")
|
|
.def(
|
|
"get_client_keys", [](Keyset &keyset) { return keyset.client; },
|
|
"Return the associated ClientKeyset.")
|
|
.doc() =
|
|
"Complete keyset containing both client-side and server-side keys.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// LIBRARY //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
pybind11::class_<Library>(m, "Library")
|
|
.def(init([](std::string output_dir_path) -> Library {
|
|
return Library(output_dir_path);
|
|
}),
|
|
arg("output_dir_path"))
|
|
.def(
|
|
"get_program_info",
|
|
[](Library &library) {
|
|
GET_OR_THROW_RESULT(auto pi, library.getProgramInfo());
|
|
return ProgramInfo{pi};
|
|
},
|
|
"Return the program info associated to the library.")
|
|
.def(
|
|
"get_output_dir_path",
|
|
[](Library &library) { return library.getOutputDirPath(); },
|
|
"Return the path to library output directory.")
|
|
.def(
|
|
"get_shared_lib_path",
|
|
[](Library &library) { return library.getSharedLibraryPath(); },
|
|
"Return the path to the shared library.")
|
|
.def(
|
|
"get_program_info_path",
|
|
[](Library &library) { return library.getProgramInfoPath(); },
|
|
"Return the path to the program info file.")
|
|
.def(
|
|
"get_program_compilation_feedback",
|
|
[](Library &library) {
|
|
auto path = library.getCompilationFeedbackPath();
|
|
GET_OR_THROW_RESULT(auto feedback,
|
|
ProgramCompilationFeedback::load(path));
|
|
return feedback;
|
|
},
|
|
"Return the associated program compilation feedback.")
|
|
.doc() = "Library object representing the output of a compilation.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// COMPILER //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
struct Compiler {
|
|
std::string outputPath;
|
|
std::string runtimeLibraryPath;
|
|
bool generateSharedLib;
|
|
bool generateStaticLib;
|
|
bool generateClientParameters;
|
|
bool generateCompilationFeedback;
|
|
};
|
|
pybind11::class_<Compiler>(m, "Compiler")
|
|
.def(init([](std::string outputPath, std::string runtimeLibraryPath,
|
|
bool generateSharedLib, bool generateStaticLib,
|
|
bool generateProgramInfo, bool generateCompilationFeedback) {
|
|
if (!std::filesystem::exists(outputPath)) {
|
|
std::filesystem::create_directory(outputPath);
|
|
}
|
|
return Compiler{outputPath.c_str(), runtimeLibraryPath.c_str(),
|
|
generateSharedLib, generateStaticLib,
|
|
generateProgramInfo, generateCompilationFeedback};
|
|
}),
|
|
arg("output_path"), arg("runtime_lib_path"),
|
|
arg("generate_shared_lib") = true, arg("generate_static_lib") = true,
|
|
arg("generate_program_info") = true,
|
|
arg("generate_compilation_feedback") = true)
|
|
.def(
|
|
"compile",
|
|
[](Compiler &support, std::string mlir_program,
|
|
mlir::toruslang::CompilationOptions options) {
|
|
SignalGuard signalGuard;
|
|
llvm::SourceMgr sm;
|
|
sm.AddNewSourceBuffer(
|
|
llvm::MemoryBuffer::getMemBuffer(mlir_program.c_str()),
|
|
llvm::SMLoc());
|
|
|
|
// Setup the compiler engine
|
|
auto context = CompilationContext::createShared();
|
|
toruslang::CompilerEngine engine(context);
|
|
engine.setCompilationOptions(options);
|
|
|
|
// Compile to a library
|
|
GET_OR_THROW_EXPECTED(
|
|
auto library,
|
|
engine.compile(
|
|
sm, support.outputPath, support.runtimeLibraryPath,
|
|
support.generateSharedLib, support.generateStaticLib,
|
|
support.generateClientParameters,
|
|
support.generateCompilationFeedback));
|
|
return library;
|
|
},
|
|
"Compile `mlir_program` using the `options` compilation options.",
|
|
arg("mlir_program"), arg("options"))
|
|
.def(
|
|
"compile",
|
|
[](Compiler &support, pybind11::object mlir_module,
|
|
mlir::toruslang::CompilationOptions options,
|
|
std::shared_ptr<mlir::toruslang::CompilationContext> context) {
|
|
SignalGuard signalGuard;
|
|
mlir::ModuleOp module =
|
|
unwrap(mlirPythonCapsuleToModule(mlir_module.ptr())).clone();
|
|
|
|
// Setup the compiler engine
|
|
toruslang::CompilerEngine engine(context);
|
|
engine.setCompilationOptions(options);
|
|
|
|
// Compile to a library
|
|
GET_OR_THROW_EXPECTED(
|
|
auto library,
|
|
engine.compile(
|
|
module, support.outputPath, support.runtimeLibraryPath,
|
|
support.generateSharedLib, support.generateStaticLib,
|
|
support.generateClientParameters,
|
|
support.generateCompilationFeedback));
|
|
return library;
|
|
},
|
|
"Compile the `mlir_module` module with `options` compilation "
|
|
"options, under the `context` compilation context.",
|
|
arg("mlir_module"), arg("options"), arg("context").none(false))
|
|
.doc() = "Provides compilation facility.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// TRANSPORT VALUE //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
pybind11::class_<TransportValue>(m, "TransportValue")
|
|
.def_static(
|
|
"deserialize",
|
|
[](const pybind11::bytes &buffer) {
|
|
auto inner = TransportValue();
|
|
if (inner
|
|
.readBinaryFromString(
|
|
buffer, mlir::toruslang::python::DESER_OPTIONS)
|
|
.has_failure()) {
|
|
throw std::runtime_error("Failed to deserialize TransportValue");
|
|
}
|
|
return TransportValue{inner};
|
|
},
|
|
"Deserialize a TransportValue from bytes.", arg("bytes"))
|
|
.def(
|
|
"serialize",
|
|
[](const TransportValue &value) {
|
|
auto valueSerialize = [](const TransportValue &value) {
|
|
auto maybeString = value.writeBinaryToString();
|
|
if (maybeString.has_failure()) {
|
|
throw std::runtime_error("Failed to serialize TransportValue");
|
|
}
|
|
return maybeString.value();
|
|
};
|
|
return pybind11::bytes(valueSerialize(value));
|
|
},
|
|
"Serialize a TransportValue to bytes")
|
|
.doc() = "Public/Transportable value.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// VALUE //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
typedef std::variant<int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t,
|
|
uint32_t, uint64_t, array>
|
|
PyValType;
|
|
|
|
pybind11::class_<Value>(m, "Value")
|
|
.def(init([](int64_t scalar) { return Value{Tensor<int64_t>(scalar)}; }),
|
|
arg("input"))
|
|
.def(
|
|
init([](uint64_t scalar) { return Value{Tensor<uint64_t>(scalar)}; }),
|
|
arg("input"))
|
|
.def(init([](int32_t scalar) { return Value{Tensor<int32_t>(scalar)}; }),
|
|
arg("input"))
|
|
.def(
|
|
init([](uint32_t scalar) { return Value{Tensor<uint32_t>(scalar)}; }),
|
|
arg("input"))
|
|
.def(init([](int16_t scalar) { return Value{Tensor<int16_t>(scalar)}; }),
|
|
arg("input"))
|
|
.def(
|
|
init([](uint16_t scalar) { return Value{Tensor<uint16_t>(scalar)}; }),
|
|
arg("input"))
|
|
.def(init([](int8_t scalar) { return Value{Tensor<int8_t>(scalar)}; }),
|
|
arg("input"))
|
|
.def(init([](uint8_t scalar) { return Value{Tensor<uint8_t>(scalar)}; }),
|
|
arg("input"))
|
|
.def(init([](array input) -> Value {
|
|
if (input.dtype().kind() == 'i') {
|
|
if (input.dtype().itemsize() == 1) {
|
|
return Value{::arrayToTensor<int8_t>(input)};
|
|
}
|
|
if (input.dtype().itemsize() == 2) {
|
|
return Value{::arrayToTensor<int16_t>(input)};
|
|
}
|
|
if (input.dtype().itemsize() == 4) {
|
|
return Value{::arrayToTensor<int32_t>(input)};
|
|
}
|
|
if (input.dtype().itemsize() == 8) {
|
|
return Value{::arrayToTensor<int64_t>(input)};
|
|
}
|
|
}
|
|
if (input.dtype().kind() == 'u') {
|
|
if (input.dtype().itemsize() == 1) {
|
|
return Value{::arrayToTensor<uint8_t>(input)};
|
|
}
|
|
if (input.dtype().itemsize() == 2) {
|
|
return Value{::arrayToTensor<uint16_t>(input)};
|
|
}
|
|
if (input.dtype().itemsize() == 4) {
|
|
return Value{::arrayToTensor<uint32_t>(input)};
|
|
}
|
|
if (input.dtype().itemsize() == 8) {
|
|
return Value{::arrayToTensor<uint64_t>(input)};
|
|
}
|
|
}
|
|
throw std::runtime_error(
|
|
"Values can only be constructed from arrays "
|
|
"of signed and unsigned integers.");
|
|
}),
|
|
arg("input"))
|
|
.def(init([](pybind11::object object) -> Value {
|
|
std::string message =
|
|
"Failed to create value from input. Incompatible type: ";
|
|
message.append(std::string{pybind11::str(object.get_type())});
|
|
message.append(" . Expected int or np.ndarray.");
|
|
throw std::runtime_error(message);
|
|
}),
|
|
arg("input"))
|
|
.def(
|
|
"to_py_val",
|
|
[](Value &value) -> PyValType {
|
|
if (value.isScalar()) {
|
|
if (value.hasElementType<int8_t>()) {
|
|
return {value.getTensor<int8_t>()->values[0]};
|
|
}
|
|
if (value.hasElementType<int16_t>()) {
|
|
return {value.getTensor<int16_t>()->values[0]};
|
|
}
|
|
if (value.hasElementType<int32_t>()) {
|
|
return {value.getTensor<int32_t>()->values[0]};
|
|
}
|
|
if (value.hasElementType<int64_t>()) {
|
|
return {value.getTensor<int64_t>()->values[0]};
|
|
}
|
|
if (value.hasElementType<uint8_t>()) {
|
|
return {value.getTensor<uint8_t>()->values[0]};
|
|
}
|
|
if (value.hasElementType<uint16_t>()) {
|
|
return {value.getTensor<uint16_t>()->values[0]};
|
|
}
|
|
if (value.hasElementType<uint32_t>()) {
|
|
return {value.getTensor<uint32_t>()->values[0]};
|
|
}
|
|
if (value.hasElementType<uint64_t>()) {
|
|
return {value.getTensor<uint64_t>()->values[0]};
|
|
}
|
|
} else {
|
|
if (value.hasElementType<int8_t>()) {
|
|
return {tensorToArray(value.getTensor<int8_t>().value())};
|
|
}
|
|
if (value.hasElementType<int16_t>()) {
|
|
return {tensorToArray(value.getTensor<int16_t>().value())};
|
|
}
|
|
if (value.hasElementType<int32_t>()) {
|
|
return {tensorToArray(value.getTensor<int32_t>().value())};
|
|
}
|
|
if (value.hasElementType<int64_t>()) {
|
|
return {tensorToArray(value.getTensor<int64_t>().value())};
|
|
}
|
|
if (value.hasElementType<uint8_t>()) {
|
|
return {tensorToArray(value.getTensor<uint8_t>().value())};
|
|
}
|
|
if (value.hasElementType<uint16_t>()) {
|
|
return {tensorToArray(value.getTensor<uint16_t>().value())};
|
|
}
|
|
if (value.hasElementType<uint32_t>()) {
|
|
return {tensorToArray(value.getTensor<uint32_t>().value())};
|
|
}
|
|
if (value.hasElementType<uint64_t>()) {
|
|
return {tensorToArray(value.getTensor<uint64_t>().value())};
|
|
}
|
|
}
|
|
throw std::invalid_argument("Value has insupported scalar type.");
|
|
},
|
|
"Return the inner value as a python type.")
|
|
.def(
|
|
"is_scalar", [](Value &val) { return val.isScalar(); },
|
|
"Return whether the value is a scalar.")
|
|
.def(
|
|
"is_tensor", [](Value &val) { return !val.isScalar(); },
|
|
"Return whether the value is a tensor.")
|
|
.def(
|
|
"get_shape", [](Value &val) { return val.getDimensions(); },
|
|
"Return the shape of the value.")
|
|
.doc() = "Private / Runtime value.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// SERVER CIRCUIT //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
pybind11::class_<ServerCircuit>(m, "ServerCircuit")
|
|
.def(
|
|
"call",
|
|
[](ServerCircuit &circuit, std::vector<TransportValue> args,
|
|
ServerKeyset keyset) {
|
|
SignalGuard signalGuard;
|
|
pybind11::gil_scoped_release release;
|
|
GET_OR_THROW_RESULT(auto output, circuit.call(keyset, args));
|
|
return output;
|
|
},
|
|
"Perform circuit call with `args` arguments using the `keyset` "
|
|
"ServerKeyset.",
|
|
arg("args"), arg("keyset"))
|
|
.def(
|
|
"simulate",
|
|
[](ServerCircuit &circuit, std::vector<TransportValue> &args) {
|
|
pybind11::gil_scoped_release release;
|
|
GET_OR_THROW_RESULT(auto output, circuit.simulate(args));
|
|
return output;
|
|
},
|
|
"Perform circuit simulation with `args` arguments.", arg("args"))
|
|
.doc() = "Server-side / Evaluation circuit.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// SERVER PROGRAM //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
pybind11::class_<ServerProgram>(m, "ServerProgram")
|
|
.def(init([](Library &library, bool useSimulation) {
|
|
auto sharedLibPath = library.getSharedLibraryPath();
|
|
|
|
GET_OR_THROW_RESULT(auto pi, library.getProgramInfo());
|
|
GET_OR_THROW_RESULT(
|
|
auto result,
|
|
ServerProgram::load(
|
|
(Message<torusprotocol::ProgramInfo>)pi.asReader(),
|
|
sharedLibPath, useSimulation));
|
|
return result;
|
|
}),
|
|
arg("library"), arg("use_simulation"))
|
|
.def(
|
|
"get_server_circuit",
|
|
[](ServerProgram &program, const std::string &circuitName) {
|
|
GET_OR_THROW_RESULT(auto result,
|
|
program.getServerCircuit(circuitName));
|
|
return result;
|
|
},
|
|
"Return the `circuit` ServerCircuit.", arg("circuit"))
|
|
.doc() = "Server-side / Evaluation program.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// CLIENT CIRCUIT //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
pybind11::class_<ClientCircuit>(m, "ClientCircuit")
|
|
.def(
|
|
"prepare_input",
|
|
[](ClientCircuit &circuit, Value arg, size_t pos) {
|
|
if (pos > circuit.getCircuitInfo().asReader().getInputs().size()) {
|
|
throw std::runtime_error("Unknown position.");
|
|
}
|
|
auto info = circuit.getCircuitInfo().asReader().getInputs()[pos];
|
|
auto typeTransformer = getPythonTypeTransformer((GateInfo)info);
|
|
GET_OR_THROW_RESULT(
|
|
auto ok, circuit.prepareInput(typeTransformer(arg), pos));
|
|
return ok;
|
|
},
|
|
"Prepare a `pos` positional arguments `arg` to be sent to server. ",
|
|
arg("arg"), arg("pos"))
|
|
.def(
|
|
"process_output",
|
|
[](ClientCircuit &circuit, TransportValue result, size_t pos) {
|
|
GET_OR_THROW_RESULT(auto ok, circuit.processOutput(result, pos));
|
|
return ok;
|
|
},
|
|
"Process a `pos` positional result `result` retrieved from "
|
|
"server. ",
|
|
arg("result"), arg("pos"))
|
|
.def(
|
|
"simulate_prepare_input",
|
|
[](ClientCircuit &circuit, Value arg, size_t pos) {
|
|
if (pos > circuit.getCircuitInfo().asReader().getInputs().size()) {
|
|
throw std::runtime_error("Unknown position.");
|
|
}
|
|
auto info = circuit.getCircuitInfo().asReader().getInputs()[pos];
|
|
auto typeTransformer = getPythonTypeTransformer((GateInfo)info);
|
|
GET_OR_THROW_RESULT(auto ok, circuit.simulatePrepareInput(
|
|
typeTransformer(arg), pos));
|
|
return ok;
|
|
},
|
|
"SIMULATE preparation of `pos` positional argument `arg` to be "
|
|
"sent "
|
|
"to server. DOES NOT NCRYPT.",
|
|
arg("arg"), arg("pos"))
|
|
.def(
|
|
"simulate_process_output",
|
|
[](ClientCircuit &circuit, TransportValue result, size_t pos) {
|
|
GET_OR_THROW_RESULT(auto ok,
|
|
circuit.simulateProcessOutput(result, pos));
|
|
return ok;
|
|
},
|
|
"SIMULATE processing of `pos` positional result `result` retrieved "
|
|
"from server.",
|
|
arg("result"), arg("pos"))
|
|
.doc() = "Client-side / Encryption circuit.";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
// CLIENT PROGRAM //
|
|
// ------------------------------------------------------------------------------//
|
|
|
|
pybind11::class_<ClientProgram>(m, "ClientProgram")
|
|
.def_static(
|
|
"create_encrypted",
|
|
[](ProgramInfo programInfo, Keyset keyset) {
|
|
GET_OR_THROW_RESULT(
|
|
auto clientProgram,
|
|
ClientProgram::createEncrypted(
|
|
programInfo.programInfo, keyset.client,
|
|
std::make_shared<EncryptionCSPRNG>(EncryptionCSPRNG(0))));
|
|
return clientProgram;
|
|
},
|
|
"Create an encrypted (as opposed to simulated) ClientProgram.",
|
|
arg("program_info"), arg("keyset"))
|
|
.def_static(
|
|
"create_simulated",
|
|
[](ProgramInfo &programInfo) {
|
|
GET_OR_THROW_RESULT(
|
|
auto clientProgram,
|
|
ClientProgram::createSimulated(
|
|
programInfo.programInfo,
|
|
std::make_shared<EncryptionCSPRNG>(EncryptionCSPRNG(0))));
|
|
return clientProgram;
|
|
},
|
|
"Create a simulated (as opposed to encrypted) ClientProgram. DOES "
|
|
"NOT PERFORM ENCRYPTION OF VALUES.",
|
|
arg("program_info"))
|
|
.def(
|
|
"get_client_circuit",
|
|
[](ClientProgram &program,
|
|
const std::string &circuitName) -> ClientCircuit {
|
|
GET_OR_THROW_RESULT(auto result,
|
|
program.getClientCircuit(circuitName));
|
|
return result;
|
|
},
|
|
"Return the `circuit` ClientCircuit.", arg("circuit"))
|
|
.doc() = "Client-side / Encryption program";
|
|
|
|
// ------------------------------------------------------------------------------//
|
|
}
|