diff --git a/README.md b/README.md index a9fe272..2f7999c 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,11 @@ Among various PSI protocols that have been developed in academia and industry, E Privacy-Preserving Ads Measurement (PPAM) leveraging DPCA-PSI enables private ad measurement, offering advertisers the ability to measure the effectiveness of their ads while ensuring user privacy protection. This is achieved through the implementation of key privacy-preserving features, such as encrypted match keys and differential privacy (DP) guaranteed matched group size. These features ensure that user interaction between ad provider and advertiser for ad measurement computation cannot be traced back to individual users. For more detailed information, please refer to [this folder](./ppam). +## MPC-DualDP +Secure multiparty computation (MPC) is a desired tool to provide privacy to the input data and intermediate results during secure computation. However, MPC can not help if the computation results leak information about the input data. To bound information leakage in outputs of protocols, we can apply differential privacy such that the MPC outputs are perturbed by the addition of noise before the outputs are revealed. Therefore, we need a mechanism that allows MPC servers to collaboratively generate random noise in a secret fashion. + +MPC-DualDP is a distributed protocol for generating shared differential privacy noise in a two-server setting. MPC-DualDP leverages MPC to sample random noise according to specific distributions, and outputs the noise in the form of secret sharing. For more detailed information, please refer to [this folder](./mpc-dualdp). + ## Contribution Please check [Contributing](CONTRIBUTING.md) for more details. diff --git a/mpc-dualdp/CMakeLists.txt b/mpc-dualdp/CMakeLists.txt new file mode 100644 index 0000000..2e2bb8f --- /dev/null +++ b/mpc-dualdp/CMakeLists.txt @@ -0,0 +1,369 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.15) + +######################################################### +# Project MPC_DUALDP includes the following components: # +# 1. MPC_DUALDP C++ library # +# 2. MPC_DUALDP C++ examples # +# 3. MPC_DUALDP C++ tests # +######################################################### + +# [OPTION] CMAKE_BUILD_TYPE (DEFAULT: "Release") +# Select from Release, Debug, MiniSizeRel, or RelWithDebInfo. +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY + STRINGS "Release" "Debug" "MinSizeRel" "RelWithDebInfo") +endif() +message(STATUS "Build type (CMAKE_BUILD_TYPE): ${CMAKE_BUILD_TYPE}") + +project(MPC_DUALDP VERSION 0.1.0 LANGUAGES CXX) + +######################## +# Global configuration # +######################## + +# CMake modules +include(CMakeDependentOption) +include(CMakePushCheckState) +include(CheckIncludeFiles) +include(CheckCXXSourceCompiles) +include(CheckCXXSourceRuns) + +# Extra modules +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) +include(MPC_DualDPCustomMacros) + +# In Debug mode, define MPC_DUALDP_DEBUG. +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(MPC_DUALDP_DEBUG ON) +else() + set(MPC_DUALDP_DEBUG OFF) +endif() +message(STATUS "MPC_DUALDP debug mode: ${MPC_DUALDP_DEBUG}") + +# In Debug mode, enable extra compiler flags. +include(EnableDebugFlags) + +# Build position-independent-code +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +# Make the install target depend on the all target +set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY OFF) + +# [OPTION] MPC_DUALDP_USE_CXX17 (default: OFF) +# Use C++17, use C++14 otherwise. +set(MPC_DUALDP_USE_CXX17_OPTION_STR "Use C++17") +option(MPC_DUALDP_USE_CXX17 ${MPC_DUALDP_USE_CXX17_OPTION_STR} OFF) +message(STATUS "MPC_DUALDP_USE_CXX17: ${MPC_DUALDP_USE_CXX17}") +# Enable features from C++17 if available, disable features if set to OFF. +include(EnableCXX17) + +# Required files and directories +include(GNUInstallDirs) + +# Runtime path +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +# Source Tree +set(MPC_DUALDP_INCLUDES_DIR ${CMAKE_CURRENT_LIST_DIR}/src) +set(MPC_DUALDP_CONFIG_IN_FILENAME ${CMAKE_CURRENT_LIST_DIR}/cmake/MPC_DualDPConfig.cmake.in) +set(MPC_DUALDP_CONFIG_H_IN_FILENAME ${MPC_DUALDP_INCLUDES_DIR}/mpc-dualdp/utils/config.h.in) + +# Build tree +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) +set(MPC_DUALDP_THIRDPARTY_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty) +set(MPC_DUALDP_TARGETS_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/cmake/MPC_DualDPTargets.cmake) +set(MPC_DUALDP_CONFIG_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/cmake/MPC_DualDPConfig.cmake) +set(MPC_DUALDP_CONFIG_VERSION_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/cmake/MPC_DualDPConfigVersion.cmake) +set(MPC_DUALDP_CONFIG_H_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/src/mpc-dualdp/utils/config.h) + +# Install +set(MPC_DUALDP_CONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/MPC_DualDP-${MPC_DUALDP_VERSION_MAJOR}.${MPC_DUALDP_VERSION_MINOR}) +set(MPC_DUALDP_INCLUDES_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}/MPC_DualDP-${MPC_DUALDP_VERSION_MAJOR}.${MPC_DUALDP_VERSION_MINOR}) +set(MPC_DUALDP_THIRDPARTY_INCLUDES_INSTALL_DIR ${MPC_DUALDP_INCLUDES_INSTALL_DIR}/thirdparty) + +# Supported target operating systems are Linux and macOS. +if (NOT DEFINED LINUX) + if (UNIX AND NOT APPLE AND NOT CYGWIN AND NOT MINGW) + set(LINUX ON) + endif() +endif() +if (UNIX AND APPLE) + set(MACOS ON) +endif() +if (NOT LINUX AND NOT MACOS) + message(FATAL_ERROR "Supported target operating systems are Linux and macOS") +endif() + +# Only support x86_64 and arm64 +set(CMAKE_REQUIRED_QUIET_OLD ${CMAKE_REQUIRED_QUIET}) +set(CMAKE_REQUIRED_QUIET ON) +check_cxx_source_runs(" + #if defined(__aarch64__) + int main() { + return 0; + } + #else + #error + #endif + " + MPC_DUALDP_ARM64 +) +check_cxx_source_runs(" + #if defined(__amd64) + int main() { + return 0; + } + #else + #error + #endif + " + MPC_DUALDP_AMD64 +) +set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_OLD}) +if (NOT MPC_DUALDP_AMD64 AND NOT MPC_DUALDP_ARM64) + message(FATAL_ERROR "Supported target architectures are x86_64 and arm64") +endif() + +add_compile_options(-msse4.2 -maes -mavx -Wno-ignored-attributes) + +# Enable test coverage +set(MPC_DUALDP_ENABLE_GCOV_STR "Enable gcov") +option(MPC_DUALDP_ENABLE_GCOV ${MPC_DUALDP_ENABLE_GCOV_STR} OFF) +message(STATUS "MPC_DUALDP_ENABLE_GCOV: ${MPC_DUALDP_ENABLE_GCOV}") +if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND MPC_DUALDP_ENABLE_GCOV) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -fprofile-arcs -ftest-coverage -lgcov") +endif() + +set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -ldl -lrt") + +######################### +# External dependencies # +######################### + +# [OPTION] MPC_DUALDP_BUILD_DEPS (DEFAULT: ON) +# Download and build dependencies if set to ON. +# Look for dependencies using find_package, otherwise. +set(MPC_DUALDP_BUILD_DEPS_OPTION_STR "Automatically download and build unmet dependencies") +option(MPC_DUALDP_BUILD_DEPS ${MPC_DUALDP_BUILD_DEPS_OPTION_STR} ON) +message(STATUS "MPC_DUALDP_BUILD_DEPS: ${MPC_DUALDP_BUILD_DEPS}") + +if(MPC_DUALDP_BUILD_DEPS) + include(FetchContent) + mark_as_advanced(FETCHCONTENT_BASE_DIR) + mark_as_advanced(FETCHCONTENT_FULLY_DISCONNECTED) + mark_as_advanced(FETCHCONTENT_UPDATES_DISCONNECTED) + mark_as_advanced(FETCHCONTENT_QUIET) +endif() + +# [OPTION] MPC_DUALDP_BUILD_SHARED_LIBS (DEFAULT: OFF) +# Build a shared library if set to ON. +set(MPC_DUALDP_BUILD_SHARED_LIBS_STR "Build shared library") +option(MPC_DUALDP_BUILD_SHARED_LIBS ${MPC_DUALDP_BUILD_SHARED_LIBS_STR} OFF) +message(STATUS "MPC_DUALDP_BUILD_SHARED_LIBS: ${MPC_DUALDP_BUILD_SHARED_LIBS}") + +# PPAM:ppam +if(NOT TARGET PPAM::ppam AND NOT TARGET PPAM::ppam_shared) + find_package(PPAM 0.1 QUIET CONFIG) + if(PPAM_FOUND) + message(STATUS "PPAM found") + if(PPAM_STATIC_FOUND) + set(ppam "PPAM::ppam") + else() + set(ppam "PPAM::ppam_shared") + endif() + else() + if(MPC_DUALDP_BUILD_DEPS) + message(STATUS "PPAM fetching internal...") + include(PPAM) + if(TARGET ppam) + set(ppam "PPAM::ppam") + else() + set(ppam "PPAM::ppam_shared") + endif() + set(MPC_DUALDP_BUILD_PPAM TRUE CACHE BOOL "" FORCE) + else() + message(FATAL_ERROR "PPAM: not found, please download and install manually") + endif() + endif() +endif() + +########################## +# MPC_DUALDP C++ library # +########################## + +# Add source files to library and header files to install +set(MPC_DUALDP_SOURCE_FILES "") +add_subdirectory(src/mpc-dualdp) + +# Create the config file +configure_file(${MPC_DUALDP_CONFIG_H_IN_FILENAME} ${MPC_DUALDP_CONFIG_H_FILENAME}) +install( + FILES ${MPC_DUALDP_CONFIG_H_FILENAME} + DESTINATION ${MPC_DUALDP_INCLUDES_INSTALL_DIR}/mpc-dualdp/utils) + +# Build only a static library +if(NOT MPC_DUALDP_BUILD_SHARED_LIBS) + add_library(mpc_dualdp STATIC ${MPC_DUALDP_SOURCE_FILES}) + if(MPC_DUALDP_USE_CXX17) + target_compile_features(mpc_dualdp PUBLIC cxx_std_17) + else() + target_compile_features(mpc_dualdp PUBLIC cxx_std_14) + endif() + target_include_directories(mpc_dualdp PUBLIC + $ + $) + target_include_directories(mpc_dualdp PUBLIC + $) + set_target_properties(mpc_dualdp PROPERTIES OUTPUT_NAME mpc_dualdp-${MPC_DUALDP_VERSION_MAJOR}.${MPC_DUALDP_VERSION_MINOR}) + set_target_properties(mpc_dualdp PROPERTIES VERSION ${MPC_DUALDP_VERSION}) + + if(MPC_DUALDP_BUILD_PPAM) + add_dependencies(mpc_dualdp ${ppam}) + target_include_directories(mpc_dualdp PUBLIC + $> + $) + endif() + set(MPC_DUALDP_CARRY_PPAM FALSE) + target_link_libraries(mpc_dualdp PUBLIC ${ppam}) + + install(TARGETS mpc_dualdp + EXPORT MPC_DualDPTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +# Build only a shared library +else() + add_library(mpc_dualdp_shared SHARED ${MPC_DUALDP_SOURCE_FILES}) + if(MPC_DUALDP_USE_CXX17) + target_compile_features(mpc_dualdp_shared PUBLIC cxx_std_17) + else() + target_compile_features(mpc_dualdp_shared PUBLIC cxx_std_14) + endif() + target_include_directories(mpc_dualdp_shared PUBLIC + $ + $) + target_include_directories(mpc_dualdp_shared PUBLIC + $) + set_target_properties(mpc_dualdp_shared PROPERTIES OUTPUT_NAME mpc_dualdp) + set_target_properties(mpc_dualdp_shared PROPERTIES VERSION ${MPC_DUALDP_VERSION}) + set_target_properties(mpc_dualdp_shared PROPERTIES SOVERSION ${MPC_DUALDP_VERSION_MAJOR}.${MPC_DUALDP_VERSION_MINOR}) + + if(MPC_DUALDP_BUILD_PPAM) + add_dependencies(mpc_dualdp_shared ${ppam}) + target_include_directories(mpc_dualdp_shared PUBLIC + $> + $) + endif() + set(MPC_DUALDP_CARRY_PPAM FALSE) + target_link_libraries(mpc_dualdp_shared PUBLIC ${ppam}) + + install(TARGETS mpc_dualdp_shared + EXPORT MPC_DualDPTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() + +# Add standard alias targets for MPC_DualDP::mpc_dualdp and MPC_DualDP::mpc_dualdp_shared +if(TARGET mpc_dualdp) + add_library(MPC_DualDP::mpc_dualdp ALIAS mpc_dualdp) +endif() +if(TARGET mpc_dualdp_shared) + add_library(MPC_DualDP::mpc_dualdp_shared ALIAS mpc_dualdp_shared) +endif() + +################################# +# Installation and CMake config # +################################# + +# Create the CMake config file +include(CMakePackageConfigHelpers) +configure_package_config_file( + ${MPC_DUALDP_CONFIG_IN_FILENAME} ${MPC_DUALDP_CONFIG_FILENAME} + INSTALL_DESTINATION ${MPC_DUALDP_CONFIG_INSTALL_DIR} +) + +# Install the export +install( + EXPORT MPC_DualDPTargets + NAMESPACE MPC_DualDP:: + DESTINATION ${MPC_DUALDP_CONFIG_INSTALL_DIR}) + +# Version file; we require exact version match for downstream +write_basic_package_version_file( + ${MPC_DUALDP_CONFIG_VERSION_FILENAME} + VERSION ${MPC_DUALDP_VERSION} + COMPATIBILITY SameMinorVersion) + +# Install config and module files +install( + FILES + ${MPC_DUALDP_CONFIG_FILENAME} + ${MPC_DUALDP_CONFIG_VERSION_FILENAME} + DESTINATION ${MPC_DUALDP_CONFIG_INSTALL_DIR}) + +# We export MPC_DualDPTargets from the build tree so it can be used by other projects +# without requiring an install. +export( + EXPORT MPC_DualDPTargets + NAMESPACE MPC_DualDP:: + FILE ${MPC_DUALDP_TARGETS_FILENAME}) + +# Install header files of dependencies if MPC_DUALDP_BUILD_DEPS is ON +if(MPC_DUALDP_BUILD_DEPS) + # Insert dependencies here + if(MPC_DUALDP_BUILD_PPAM) + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} --build ${PPAM_BUILD_DIR} -t install)") + endif() +endif() + +########################### +# MPC_DUALDP C++ examples # +########################### + +# [option] MPC_DUALDP_BUILD_EXAMPLE +set(MPC_DUALDP_BUILD_EXAMPLE_OPTION_STR "Build C++ example for MPC_DUALDP") +option(MPC_DUALDP_BUILD_EXAMPLE ${MPC_DUALDP_BUILD_EXAMPLE_OPTION_STR} ON) +message(STATUS "MPC_DUALDP_BUILD_EXAMPLE: ${MPC_DUALDP_BUILD_EXAMPLE}") + +if(MPC_DUALDP_BUILD_EXAMPLE) + add_subdirectory(example) +endif() + +######################## +# MPC_DUALDP C++ tests # +######################## + +# [option] MPC_DUALDP_BUILD_TEST +set(MPC_DUALDP_BUILD_TEST_OPTION_STR "Build C++ test for MPC_DUALDP") +option(MPC_DUALDP_BUILD_TEST ${MPC_DUALDP_BUILD_TEST_OPTION_STR} TRUE) +message(STATUS "MPC_DUALDP_BUILD_TEST: ${MPC_DUALDP_BUILD_TEST}") + +if(MPC_DUALDP_BUILD_TEST) + add_subdirectory(test) + if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND MPC_DUALDP_ENABLE_GCOV) + add_custom_target(test_coverage + COMMAND gcovr -r ${CMAKE_CURRENT_LIST_DIR} -f \"src\" -e \".+\(test\\.cpp\)\" --xml-pretty -o "${CMAKE_CURRENT_BINARY_DIR}/report/coverage.xml" + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) + endif() +endif() diff --git a/mpc-dualdp/README.md b/mpc-dualdp/README.md new file mode 100644 index 0000000..9a81e3c --- /dev/null +++ b/mpc-dualdp/README.md @@ -0,0 +1,87 @@ +# MPC-DualDP +[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE) + +Secure multiparty computation (MPC) is a desired tool to provide privacy to the input data and intermediate results during secure computation. However, MPC can not help if the computation results leak information about the input data. To bound information leakage in outputs of protocols, we can apply differential privacy such that the MPC outputs are perturbed by the addition of noise before the outputs are revealed. Therefore, we need a mechanism that allows MPC servers to collaboratively generate random noise in a secret fashion. + +MPC-DualDP is a distributed protocol for generating shared differential privacy noise in a two-server setting. MPC-DualDP leverages MPC to sample random noise according to specific distributions, and outputs the noise in the form of secret sharing. + +Currently, we support the generation of noise following binomial distribution, and more distributions might be supported in the future. As for the security model, our protocol and implementation provide security and privacy against two semi-honest servers. The round complexity of our protocol is 1, and the communication complexity is $O(n)$ if we consider a binomial distribution $Bin(n,p = 0.5)$. + +## How to use MPC-DualDP + +### Requirements + +- Linux +- CMake (>=3.15) +- GNU G++ (>=5.5) or Clang++ (>= 5.0) +- Python 3 + +### Building MPC-DualDP + +MPC-DualDP depends on [PPAM](../ppam/README.md). You need to build the dependencies of PPAM first, and then build MPC-DualDP. + +First, install NASM with `apt install nasm`, or build and install NASM from source code downloaded from [NASM's official page](https://www.nasm.us/). Assume that you are working in the root directory of NASM source code. +```shell +./configure +make -j +make install +``` + +Second, build and install IPCL using the following scripts. +Assume that IPCL is cloned into the directory `${IPCL}` and will be installed to the directory `${IPCL_INSTALL_DIR}`. +```shell +cmake -B ${IPCL}/build -S ${IPCL} -DCMAKE_INSTALL_PREFIX=${IPCL_INSTALL_DIR} -DCMAKE_BUILD_TYPE=Release -DIPCL_TEST=OFF -DIPCL_BENCHMARK=OFF +cmake --build ${IPCL}/build -j +cmake --build ${IPCL}/build --target install +``` + +Third, build [JSON for Modern C++ (JSON)](https://github.com/nlohmann/json) using the following scripts. +Assume that JSON is cloned into the directory `${JSON}`. +```shell +cmake -B ${JSON}/build -S ${JSON} +cmake --build ${JSON}/build -j +``` + +At last, build MPC-DualDP using the following scripts. +Assume that MPC-DualDP is cloned into the directory `${MPC-DualDP}`. +```shell +cmake -B ${MPC-DualDP}/build -S ${MPC-DualDP} -DCMAKE_BUILD_TYPE=Release -DIPCL_DIR=${IPCL_INSTALL_DIR}/lib/cmake/ipcl-2.0.0 -Dnlohmann_json_DIR=${JSON}/build +cmake --build ${MPC-DualDP}/build -j +``` + +Output binaries can be found in `${MPC-DualDP}/build/lib/` and `${MPC-DualDP}/build/bin/` directories. + +| Compile Options | Values | Default | Description | +|--------------------------------|---------------|---------|-----------------------------------------------------| +| `CMAKE_BUILD_TYPE` | Release/Debug | Release | The build type. | +| `MPC-DUALDP_BUILD_SHARED_LIBS` | ON/OFF | OFF | Build a shared library if set to ON. | +| `MPC-DUALDP_BUILD_EXAMPLE` | ON/OFF | ON | Build C++ example if set to ON. | +| `MPC-DUALDP_BUILD_TEST` | ON/OFF | ON | Build C++ test if set to ON. | +| `MPC-DUALDP_BUILD_DEPS` | ON/OFF | ON | Download and build unmet dependencies if set to ON. | + +MPC-DualDP further depends on [Google Test](https://github.com/google/googletest). +The build system will try to find these dependencies if they exist or will otherwise automatically download and build them. + +### Running the MPC-DualDP protocol + +Here we give a simple example to run our protocol. + +To run Party A +```shell +cd ${MPC-DualDP}/build/bin +./mpc_dualdp_example 127.0.0.1 8899 127.0.0.1 8890 0 +``` + +To run Party B +```shell +cd ${MPC-DualDP}/build/bin +./mpc_dualdp_example 127.0.0.1 8890 127.0.0.1 8899 1 +``` + +## License + +MPC-DualDP is Apache-2.0 License licensed, as found in the [LICENSE](../LICENSE) file. + +## Disclaimers + +This software is not an officially supported product of TikTok. It is provided as-is, without any guarantees or warranties, whether express or implied. diff --git a/mpc-dualdp/cmake/EnableCXX17.cmake b/mpc-dualdp/cmake/EnableCXX17.cmake new file mode 100644 index 0000000..35f63fe --- /dev/null +++ b/mpc-dualdp/cmake/EnableCXX17.cmake @@ -0,0 +1,49 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set(DP_USE_STD_BYTE ${DP_USE_CXX17}) +set(DP_USE_SHARED_MUTEX ${DP_USE_CXX17}) +set(DP_USE_IF_CONSTEXPR ${DP_USE_CXX17}) +set(DP_USE_MAYBE_UNUSED ${DP_USE_CXX17}) +set(DP_USE_NODISCARD ${DP_USE_CXX17}) + +if(DP_USE_CXX17) + set(DP_LANG_FLAG "-std=c++17") +else() + set(DP_LANG_FLAG "-std=c++14") +endif() + +set(DP_USE_STD_FOR_EACH_N ${DP_USE_CXX17}) +# In some non-MSVC compilers std::for_each_n is not available even when compiling as C++17 +if(DP_USE_STD_FOR_EACH_N) + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_QUIET TRUE) + if(NOT MSVC) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -O0 ${DP_LANG_FLAG}") + check_cxx_source_compiles(" + #include + int main() { + int a[1]{ 0 }; + volatile auto fun = std::for_each_n(a, 1, [](auto b) {}); + return 0; + }" + USE_STD_FOR_EACH_N + ) + if(NOT USE_STD_FOR_EACH_N EQUAL 1) + set(DP_USE_STD_FOR_EACH_N OFF) + endif() + unset(USE_STD_FOR_EACH_N CACHE) + endif() + cmake_pop_check_state() +endif() diff --git a/mpc-dualdp/cmake/EnableDebugFlags.cmake b/mpc-dualdp/cmake/EnableDebugFlags.cmake new file mode 100644 index 0000000..0b9eb14 --- /dev/null +++ b/mpc-dualdp/cmake/EnableDebugFlags.cmake @@ -0,0 +1,33 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +include(CheckCXXCompilerFlag) +function(mpc_dualdp_add_compiler_flag flag) + string(FIND "${CMAKE_CXX_FLAGS}" "${flag}" flag_already_set) + if(flag_already_set EQUAL -1) + message(STATUS "Adding CXX compiler flag: ${flag} ...") + check_cxx_compiler_flag("${flag}" flag_supported) + if(flag_supported) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE) + endif() + unset(flag_supported CACHE) + endif() +endfunction() +if(NOT MSVC AND DP_DEBUG) + mpc_dualdp_add_compiler_flag("-Wall") + mpc_dualdp_add_compiler_flag("-Wextra") + mpc_dualdp_add_compiler_flag("-Wconversion") + mpc_dualdp_add_compiler_flag("-Wshadow") + mpc_dualdp_add_compiler_flag("-pedantic") +endif() diff --git a/mpc-dualdp/cmake/ExternalGTest.cmake b/mpc-dualdp/cmake/ExternalGTest.cmake new file mode 100644 index 0000000..20b4a9e --- /dev/null +++ b/mpc-dualdp/cmake/ExternalGTest.cmake @@ -0,0 +1,37 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG 58d77fa8070e8cec2dc1ed015d66b454c8d78850 # 1.12.1 +) +FetchContent_GetProperties(googletest) + +if(NOT googletest_POPULATED) + FetchContent_Populate(googletest) + + set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) + set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + mark_as_advanced(BUILD_GMOCK) + mark_as_advanced(INSTALL_GTEST) + mark_as_advanced(FETCHCONTENT_SOURCE_DIR_GOOGLETEST) + mark_as_advanced(FETCHCONTENT_UPDATES_DISCONNECTED_GOOGLETEST) + + add_subdirectory( + ${googletest_SOURCE_DIR} + ${THIRDPARTY_BINARY_DIR}/googletest-src + EXCLUDE_FROM_ALL) +endif() diff --git a/mpc-dualdp/cmake/MPC_DualDPConfig.cmake.in b/mpc-dualdp/cmake/MPC_DualDPConfig.cmake.in new file mode 100644 index 0000000..2c58732 --- /dev/null +++ b/mpc-dualdp/cmake/MPC_DualDPConfig.cmake.in @@ -0,0 +1,95 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Exports target MPC_DualDP::mpc_dualdp +# +# Creates variables: +# MPC_DualDP_FOUND : If MPC_DualDP was found +# MPC_DualDP_VERSION : the full version number +# MPC_DualDP_VERSION_MAJOR : the major version number +# MPC_DualDP_VERSION_MINOR : the minor version number +# MPC_DualDP_VERSION_PATCH : the patch version number +# MPC_DualDP_BUILD_TYPE : The build type (e.g., "Release" or "Debug") + +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +macro(mpc_dualdp_find_dependency dep) + find_dependency(${dep}) + if(NOT ${dep}_FOUND) + if(NOT MPC_DualDP_FIND_QUIETLY) + message(WARNING "Could not find dependency `${dep}` required by this configuration") + endif() + set(MPC_DualDP_FOUND FALSE) + return() + endif() +endmacro() + +set(MPC_DualDP_FOUND FALSE) +set(MPC_DualDP_STATIC_FOUND FALSE) +set(MPC_DualDP_SHARED_FOUND FALSE) + +set(MPC_DUALDP_DEBUG @MPC_DUALDP_DEBUG@) + +set(MPC_DUALDP_VERSION @MPC_DUALDP_VERSION@) +set(MPC_DUALDP_VERSION_MAJOR @MPC_DUALDP_VERSION_MAJOR@) +set(MPC_DUALDP_VERSION_MINOR @MPC_DUALDP_VERSION_MINOR@) +set(MPC_DUALDP_VERSION_PATCH @MPC_DUALDP_VERSION_PATCH@) +set(MPC_DUALDP_BUILD_TYPE @CMAKE_BUILD_TYPE@) + +set(MPC_DUALDP_CARRY_PPAM @MPC_DUALDP_CARRY_PPAM@) + +if(NOT MPC_DUALDP_CARRY_PPAM) + mpc_dualdp_find_dependency(PPAM REQUIRED) +endif() + +# Add the current directory to the module search path +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(${CMAKE_CURRENT_LIST_DIR}/MPC_DualDPTargets.cmake) + +if(TARGET MPC_DualDP::mpc_dualdp) + set(MPC_DualDP_FOUND TRUE) + set(MPC_DualDP_STATIC_FOUND TRUE) +endif() + +if(TARGET MPC_DualDP::mpc_dualdp_shared) + set(MPC_DualDP_FOUND TRUE) + set(MPC_DualDP_SHARED_FOUND TRUE) +endif() + +if(MPC_DualDP_FOUND) + if(NOT MPC_DualDP_FIND_QUIETLY) + message(STATUS "MPC_DualDP -> Version ${MPC_DualDP_VERSION} detected") + endif() + if(MPC_DUALDP_DEBUG AND NOT MPC_DualDP_FIND_QUIETLY) + message(STATUS "Performance warning: MPC_DualDP compiled in debug mode") + endif() + + set(MPC_DualDP_TARGETS_AVAILABLE "MPC_DualDP -> Targets available:") + if(MPC_DualDP_STATIC_FOUND) + string(APPEND MPC_DualDP_TARGETS_AVAILABLE " MPC_DualDP::mpc_dualdp") + endif() + if(MPC_DualDP_SHARED_FOUND) + string(APPEND MPC_DualDP_TARGETS_AVAILABLE " MPC_DualDP::mpc_dualdp_shared") + endif() + if(NOT MPC_DualDP_FIND_QUIETLY) + message(STATUS ${MPC_DualDP_TARGETS_AVAILABLE}) + endif() +else() + if(NOT MPC_DualDP_FIND_QUIETLY) + message(STATUS "MPC_DualDP -> NOT FOUND") + endif() +endif() diff --git a/mpc-dualdp/cmake/MPC_DualDPCustomMacros.cmake b/mpc-dualdp/cmake/MPC_DualDPCustomMacros.cmake new file mode 100644 index 0000000..66371ad --- /dev/null +++ b/mpc-dualdp/cmake/MPC_DualDPCustomMacros.cmake @@ -0,0 +1,53 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Manually combine archives, using ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} to keep temporary files. +macro(mpc_dualdp_combine_archives target dependency) + if(MSVC) + add_custom_command(TARGET ${target} POST_BUILD + COMMAND lib.exe /OUT:$ $ $ + DEPENDS $ $ + WORKING_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) + else() + if(CMAKE_HOST_WIN32) + get_filename_component(CXX_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) + set(AR_CMD_PATH "${CXX_DIR}/llvm-ar.exe") + file(TO_NATIVE_PATH "${AR_CMD_PATH}" AR_CMD_PATH) + set(DEL_CMD "del") + set(DEL_CMD_OPTS "") + else() + set(AR_CMD_PATH "ar") + set(DEL_CMD "rm") + set(DEL_CMD_OPTS "-rf") + endif() + if(EMSCRIPTEN) + set(AR_CMD_PATH "emar") + endif() + add_custom_command(TARGET ${target} POST_BUILD + COMMAND "${AR_CMD_PATH}" x $ + COMMAND "${AR_CMD_PATH}" x $ + COMMAND "${AR_CMD_PATH}" rcs $ *.o + COMMAND ${DEL_CMD} ${DEL_CMD_OPTS} *.o + WORKING_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) + endif() +endmacro() + +# Fetch thirdparty content specified by content_file +macro(mpc_dualdp_fetch_thirdparty_content content_file) + set(MPC_DUALDP_FETCHCONTENT_BASE_DIR_OLD ${FETCHCONTENT_BASE_DIR}) + set(FETCHCONTENT_BASE_DIR ${MPC_DUALDP_THIRDPARTY_DIR} CACHE STRING "" FORCE) + include(${content_file}) + set(FETCHCONTENT_BASE_DIR ${MPC_DUALDP_FETCHCONTENT_BASE_DIR_OLD} CACHE STRING "" FORCE) + unset(MPC_DUALDP_FETCHCONTENT_BASE_DIR_OLD) +endmacro() diff --git a/mpc-dualdp/cmake/PPAM.cmake b/mpc-dualdp/cmake/PPAM.cmake new file mode 100644 index 0000000..981faba --- /dev/null +++ b/mpc-dualdp/cmake/PPAM.cmake @@ -0,0 +1,24 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set(PPAM_BUILD_TEST OFF CACHE BOOL "" FORCE) +set(PPAM_BUILD_EXAMPLE OFF CACHE BOOL "" FORCE) +set(PPAM_BUILD_SHARED_LIBS ${MPC_DUALDP_BUILD_SHARED_LIBS} CACHE BOOL "" FORCE) + +set(PPAM_BUILD_DIR ${MPC_DUALDP_THIRDPARTY_DIR}/ppam-build CACHE STRING "" FORCE) + +add_subdirectory( + ${PROJECT_SOURCE_DIR}/../ppam + ${PPAM_BUILD_DIR} + EXCLUDE_FROM_ALL) diff --git a/mpc-dualdp/example/CMakeLists.txt b/mpc-dualdp/example/CMakeLists.txt new file mode 100644 index 0000000..b38870e --- /dev/null +++ b/mpc-dualdp/example/CMakeLists.txt @@ -0,0 +1,69 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.15) + +project(MPC_DUALDPExamples VERSION 0.1.0 LANGUAGES CXX) + +# If not called from root CMakeLists.txt +if(NOT DEFINED MPC_DUALDP_BUILD_EXAMPLE) + set(MPC_DUALDP_BUILD_EXAMPLE ON) + + # Import MPC_DUALDP + find_package(MPC_DualDP 0.1.0 EXACT REQUIRED) + + add_compile_options(-msse4.2 -maes -mavx -Wno-ignored-attributes) + + # Must define these variables and include macros + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) + set(MPC_DUALDP_THIRDPARTY_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty) + set(THIRDPARTY_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty) + include(FetchContent) + mark_as_advanced(FETCHCONTENT_BASE_DIR) + mark_as_advanced(FETCHCONTENT_FULLY_DISCONNECTED) + mark_as_advanced(FETCHCONTENT_UPDATES_DISCONNECTED) + mark_as_advanced(FETCHCONTENT_QUIET) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../cmake) + include(MPC_DualDPCustomMacros) +else() + set(THIRDPARTY_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../thirdparty) +endif() + +if(NOT DEFINED MPC_DUALDP_BUILD_DEPS) + # [option] MPC_DUALDP_BUILD_DEPS (default: ON) + # Download and build missing dependencies, throw error if disabled. + set(MPC_DUALDP_BUILD_DEPS_OPTION_STR "Automatically download and build unmet dependencies") + option(MPC_DUALDP_BUILD_DEPS ${MPC_DUALDP_BUILD_DEPS_OPTION_STR} ON) +endif() + +if(MPC_DUALDP_BUILD_EXAMPLE) + # Add source files to example + set(MPC_DUALDP_EXAMPLE_FILES "") + # Test files in this directory + set(MPC_DUALDP_EXAMPLE_FILES ${MPC_DUALDP_EXAMPLE_FILES} + ${CMAKE_CURRENT_LIST_DIR}/mpc_dualdp_example.cpp + ) + + set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -ldl -lrt") + add_executable(mpc_dualdp_example ${MPC_DUALDP_EXAMPLE_FILES}) + + if(TARGET MPC_DualDP::mpc_dualdp) + target_link_libraries(mpc_dualdp_example PRIVATE MPC_DualDP::mpc_dualdp) + elseif(TARGET MPC_DualDP::mpc_dualdp_shared) + target_link_libraries(mpc_dualdp_example PRIVATE MPC_DualDP::mpc_dualdp_shared) + else() + message(FATAL_ERROR "Cannot find target MPC_DualDP::mpc_dualdp or MPC_DualDP::mpc_dualdp_shared") + endif() +endif() diff --git a/mpc-dualdp/example/mpc_dualdp_example.cpp b/mpc-dualdp/example/mpc_dualdp_example.cpp new file mode 100644 index 0000000..7c59ee8 --- /dev/null +++ b/mpc-dualdp/example/mpc_dualdp_example.cpp @@ -0,0 +1,62 @@ +// Copyright 2023 TikTok Pte. Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "mpc-dualdp/mpc_dualdp.h" + +#include "dpca-psi/dp_cardinality_psi.h" +#include "dpca-psi/network/two_channel_net_io.h" + +void mpc_dualdp_example(std::size_t party, std::string local_addr, std::size_t local_port, std::string remote_addr, + std::size_t remote_port) { + auto net = std::make_shared(remote_addr, remote_port, local_port); + + auto aby_test = privacy_go::ppam::AbyProtocol::Instance(); + aby_test->initialize(party, net); + + auto dual_dp_test = std::make_shared(); + dual_dp_test->initialize(party, net); + + std::size_t batch_n = 16; + double epsilon = 1.0; + double delta = 0.00001; + double sensitivity = 1.0; + std::vector noise; + + dual_dp_test->binomial_sampling(batch_n, epsilon, delta, sensitivity, noise); + + privacy_go::ppam::CryptoMatrix cipher_share(noise.size(), 1); + cipher_share.shares = Eigen::Map>(noise.data(), noise.size(), 1); + + privacy_go::ppam::eMatrix plain(noise.size(), 1); + + aby_test->reveal(0, cipher_share, plain); + aby_test->reveal(1, cipher_share, plain); + + for (std::size_t i = 0; i < plain.size(); i++) { + std::cout << plain(i, 0) << " "; + } + std::cout << std::endl; + + return; +} + +// ./build/bin/mpc_dualdp_example 127.0.0.1 8899 127.0.0.1 8890 0 +// ./build/bin/mpc_dualdp_example 127.0.0.1 8890 127.0.0.1 8899 1 +int main(int argc, char* argv[]) { + mpc_dualdp_example(atoi(argv[5]), std::string(argv[1]), atoi(argv[2]), std::string(argv[3]), atoi(argv[4])); + return 0; +} diff --git a/mpc-dualdp/src/mpc-dualdp/CMakeLists.txt b/mpc-dualdp/src/mpc-dualdp/CMakeLists.txt new file mode 100644 index 0000000..a26cea3 --- /dev/null +++ b/mpc-dualdp/src/mpc-dualdp/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Source files in this directory +set(MPC_DUALDP_SOURCE_FILES ${DP_SOURCE_FMPC_DUALDP_SOURCE_FILESILES} + ${CMAKE_CURRENT_LIST_DIR}/mpc_dualdp.cpp +) + +# Add header files for installation +install( + FILES + ${CMAKE_CURRENT_LIST_DIR}/mpc_dualdp.h + DESTINATION + ${MPC_DUALDP_INCLUDES_INSTALL_DIR}/mpc-dualdp +) + +set(MPC_DUALDP_SOURCE_FILES ${MPC_DUALDP_SOURCE_FILES} PARENT_SCOPE) diff --git a/mpc-dualdp/src/mpc-dualdp/mpc_dualdp.cpp b/mpc-dualdp/src/mpc-dualdp/mpc_dualdp.cpp new file mode 100644 index 0000000..775252e --- /dev/null +++ b/mpc-dualdp/src/mpc-dualdp/mpc_dualdp.cpp @@ -0,0 +1,134 @@ +// Copyright 2023 TikTok Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "mpc-dualdp/mpc_dualdp.h" + +#include + +namespace privacy_go { +namespace mpc_dualdp { + +void MPCDualDP::initialize(const std::size_t party_id, const std::shared_ptr& net) { + party_id_ = party_id; + net_ = net; + + ppam::block data_from_recv; + auto data_to_send = ppam::read_block_from_dev_urandom(); + + if (party_id_ == 0) { + net_->send_block(&data_to_send, 1); + net_->recv_block(&data_from_recv, 1); + } else { + net_->recv_block(&data_from_recv, 1); + net_->send_block(&data_to_send, 1); + } + + rand_generator_ = std::make_shared(data_to_send ^ data_from_recv); + + auto common_seed = _mm_set_epi64x(rand_generator_->get_common_rand(), rand_generator_->get_common_rand()); + auto unique_seed = _mm_set_epi64x(rand_generator_->get_unique_rand(), rand_generator_->get_unique_rand()); + oblivious_transfer_ = std::make_shared(party_id_, net_, common_seed, unique_seed); + oblivious_transfer_->initialize(); + + return; +} + +void MPCDualDP::binomial_sampling(const std::size_t n, const double epsilon, const double delta, + const double sensitivity, std::vector& noise) { + std::size_t binomial_n = std::ceil(8 * sensitivity * sensitivity * std::log(2 / delta) / (epsilon * epsilon)); + std::size_t rows = n; + std::size_t cols = binomial_n; + + ppam::CryptoMatrix x(rows, cols); + ppam::CryptoMatrix r(rows, cols); + ppam::CryptoMatrix s0(rows, cols); + ppam::CryptoMatrix s1(rows, cols); + + for (std::size_t i = 0; i < x.size(); i++) { + x.shares(i) = rand_generator_->get_unique_rand() & 0x1; + } + + if (party_id_ == 0) { + for (std::size_t i = 0; i < r.size(); i++) { + r.shares(i) = rand_generator_->get_unique_rand(); + } + for (int i = 0; i < x.size(); i++) { + s0.shares(i) = x.shares(i) - r.shares(i); + s1.shares(i) = 1 - x.shares(i) - r.shares(i); + } + } + + std::size_t size = rows * cols; + bool* k = new bool[size]; + ppam::CryptoMatrix y0(rows, cols); + ppam::CryptoMatrix y1(rows, cols); + ppam::CryptoMatrix rb(rows, cols); + if (party_id_ == 1) { + for (std::size_t i = 0; i < size; i++) { + auto msg = oblivious_transfer_->get_ot_instance(1 - party_id_); + k[i] = msg[1] ^ x.shares(i); + rb.shares(i) = msg[0]; + } + net_->send_bool(k, size); + ppam::recv_matrix(net_, &y0, 1); + ppam::recv_matrix(net_, &y1, 1); + for (std::size_t i = 0; i < size; i++) { + if (x.shares(i) == 0) { + r.shares(i) = y0.shares(i) ^ rb.shares(i); + } else { + r.shares(i) = y1.shares(i) ^ rb.shares(i); + } + } + } else { + for (std::size_t i = 0; i < size; i++) { + auto msg = oblivious_transfer_->get_ot_instance(party_id_); + y0.shares(i) = msg[0]; + y1.shares(i) = msg[1]; + } + net_->recv_bool(k, size); + for (std::size_t i = 0; i < size; i++) { + if (k[i] == 0) { + y0.shares(i) ^= s0.shares(i); + y1.shares(i) ^= s1.shares(i); + + } else { + auto t = s0.shares(i) ^ y1.shares(i); + y1.shares(i) = s1.shares(i) ^ y0.shares(i); + y0.shares(i) = t; + } + } + ppam::send_matrix(net_, &y0, 1); + ppam::send_matrix(net_, &y1, 1); + } + delete[] k; + + auto binomial_sum = r.shares.rowwise().sum(); + double mean = static_cast(binomial_n) / 2.0; + + if (party_id_ == 0) { + for (std::size_t i = 0; i < n; i++) { + noise.push_back(binomial_sum(i) << 16); + } + } else { + std::int64_t fix_mean = static_cast(mean * static_cast(1UL << 16)); + for (std::size_t i = 0; i < n; i++) { + noise.push_back((binomial_sum(i) << 16) - fix_mean); + } + } + + return; +} + +} // namespace mpc_dualdp +} // namespace privacy_go diff --git a/mpc-dualdp/src/mpc-dualdp/mpc_dualdp.h b/mpc-dualdp/src/mpc-dualdp/mpc_dualdp.h new file mode 100644 index 0000000..ba96055 --- /dev/null +++ b/mpc-dualdp/src/mpc-dualdp/mpc_dualdp.h @@ -0,0 +1,73 @@ +// Copyright 2023 TikTok Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "dpca-psi/network/io_base.h" +#include "ppam/ppam.h" + +namespace privacy_go { +namespace mpc_dualdp { + +using IOBase = dpca_psi::IOBase; + +class MPCDualDP { +public: + MPCDualDP() { + aby_op_ = std::make_shared(); + } + + MPCDualDP(const MPCDualDP& other) = delete; + + MPCDualDP& operator=(const MPCDualDP& other) = delete; + + ~MPCDualDP() = default; + + /** + * @brief Initialize psi and mpc protocol. + * @param[in] party_id The id of party. + * @param[in] net Net io channel. + * @return None. + */ + void initialize(const std::size_t party_id, const std::shared_ptr& net); + + /** + * @brief MPC-DualDP protocol. + * @param[in] n Amount of noise to be generated. + * @param[in] epsilon DP parameter $epsilon$. + * @param[in] delta DP parameter $delta$. + * @param[in] sensitivity DP parameter $sensitivity$. + * @param[out] noise DP noise secret shares. + * @return none + */ + void binomial_sampling(const std::size_t n, const double epsilon, const double delta, const double sensitivity, + std::vector& noise); + +private: + std::size_t party_id_ = 0; + + std::shared_ptr net_ = nullptr; + + std::shared_ptr aby_op_ = nullptr; + + std::shared_ptr rand_generator_ = nullptr; + + std::shared_ptr oblivious_transfer_ = nullptr; +}; + +} // namespace mpc_dualdp +} // namespace privacy_go diff --git a/mpc-dualdp/src/mpc-dualdp/utils/config.h.in b/mpc-dualdp/src/mpc-dualdp/utils/config.h.in new file mode 100644 index 0000000..c1418c9 --- /dev/null +++ b/mpc-dualdp/src/mpc-dualdp/utils/config.h.in @@ -0,0 +1,31 @@ +// Copyright 2023 TikTok Pte. Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#define MPC_DUALDP_VERSION "@MPC_DUALDP_VERSION@" +#define MPC_DUALDP_VERSION_MAJOR @MPC_DUALDP_VERSION_MAJOR@ +#define MPC_DUALDP_VERSION_MINOR @MPC_DUALDP_VERSION_MINOR@ +#define MPC_DUALDP_VERSION_PATCH @MPC_DUALDP_VERSION_PATCH@ + +// Are we in debug mode? +#cmakedefine MPC_DUALDP_DEBUG + +// C++17 features +#cmakedefine MPC_DUALDP_USE_STD_BYTE +#cmakedefine MPC_DUALDP_USE_SHARED_MUTEX +#cmakedefine MPC_DUALDP_USE_IF_CONSTEXPR +#cmakedefine MPC_DUALDP_USE_MAYBE_UNUSED +#cmakedefine MPC_DUALDP_USE_NODISCARD +#cmakedefine MPC_DUALDP_USE_STD_FOR_EACH_N diff --git a/mpc-dualdp/test/CMakeLists.txt b/mpc-dualdp/test/CMakeLists.txt new file mode 100644 index 0000000..94be3a7 --- /dev/null +++ b/mpc-dualdp/test/CMakeLists.txt @@ -0,0 +1,103 @@ +# Copyright 2023 TikTok Pte. Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.15) + +project(MPC_DUALDPTest VERSION 0.1.0 LANGUAGES CXX C) + +# If not called from root CMakeLists.txt +if(NOT DEFINED MPC_DUALDP_BUILD_TEST) + set(MPC_DUALDP_BUILD_TEST ON) + + find_package(MPC_DUALDP 0.1.0 EXACT REQUIRED) + + add_compile_options(-msse4.2 -maes -mavx -Wno-ignored-attributes) + + # Must define these variables and include macros + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) + set(MPC_DUALDP_THIRDPARTY_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty) + set(THIRDPARTY_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty) + include(FetchContent) + mark_as_advanced(FETCHCONTENT_BASE_DIR) + mark_as_advanced(FETCHCONTENT_FULLY_DISCONNECTED) + mark_as_advanced(FETCHCONTENT_UPDATES_DISCONNECTED) + mark_as_advanced(FETCHCONTENT_QUIET) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../cmake) + include(MPC_DualDPCustomMacros) +else() + set(THIRDPARTY_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../thirdparty) +endif() + +if(NOT DEFINED MPC_DUALDP_BUILD_DEPS) + # [option] MPC_DUALDP_BUILD_DEPS (default: ON) + # Download and build missing dependencies, throw error if disabled. + set(MPC_DUALDP_BUILD_DEPS_OPTION_STR "Automatically download and build unmet dependencies") + option(MPC_DUALDP_BUILD_DEPS ${MPC_DUALDP_BUILD_DEPS_OPTION_STR} ON) +endif() + +# if MPC_DUALDP_BUILD_TEST is ON, use GoogleTest +if(MPC_DUALDP_BUILD_TEST) + find_package(GTest 1 CONFIG) + if(GTest_FOUND) + message(STATUS "GoogleTest: found") + else() + if(MPC_DUALDP_BUILD_DEPS) + message(STATUS "GoogleTest: downloading ...") + mpc_dualdp_fetch_thirdparty_content(ExternalGTest) + add_library(GTest::gtest ALIAS gtest) + else() + message(FATAL_ERROR "GoogleTest: not found, please download and install manually") + endif() + endif() + + # Add source files to test + set(MPC_DUALDP_TEST_FILES + ${CMAKE_CURRENT_LIST_DIR}/mpc_dualdp_test.cpp + ${CMAKE_CURRENT_LIST_DIR}/test_runner.cpp + ) + + # CMAKE_CXX_LINK_EXECUTABLE + set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -ldl -lrt") + if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND MPC_DUALDP_ENABLE_GCOV) + set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -fprofile-arcs -ftest-coverage -lgcov") + endif() + + add_executable(mpc_dualdp_test ${MPC_DUALDP_TEST_FILES}) + + if(TARGET MPC_DualDP::mpc_dualdp) + target_link_libraries(mpc_dualdp_test PRIVATE MPC_DualDP::mpc_dualdp GTest::gtest) + elseif(TARGET MPC_DualDP::mpc_dualdp_shared) + target_link_libraries(mpc_dualdp_test PRIVATE MPC_DualDP::mpc_dualdp_shared GTest::gtest) + else() + message(FATAL_ERROR "Cannot find target MPC_DualDP::mpc_dualdp or MPC_DualDP::mpc_dualdp_shared") + endif() + + # In Debug mode, enable AddressSanitizer (and LeakSanitizer) on Unix-like platforms. + if(MPC_DUALDP_DEBUG AND UNIX) + # On macOS, only AddressSanitizer is enabled. + # On Linux, LeakSanitizer is enabled by default. + target_compile_options(mpc_dualdp_test PUBLIC -fsanitize=address) + target_link_options(mpc_dualdp_test PUBLIC -fsanitize=address) + if(NOT APPLE) + message(STATUS "Sanitizers enabled: address, leak") + else() + message(STATUS "Sanitizers enabled: address") + endif() + endif() + + add_custom_target(test_report + COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mpc_dualdp_test --gtest_output="xml:${CMAKE_CURRENT_BINARY_DIR}/../report/mpc_dualdp_test.xml" + DEPENDS mpc_dualdp_test) +endif() diff --git a/mpc-dualdp/test/mpc_dualdp_test.cpp b/mpc-dualdp/test/mpc_dualdp_test.cpp new file mode 100644 index 0000000..d93e258 --- /dev/null +++ b/mpc-dualdp/test/mpc_dualdp_test.cpp @@ -0,0 +1,98 @@ +// Copyright 2023 TikTok Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "mpc-dualdp/mpc_dualdp.h" + +#include "gtest/gtest.h" + +#include "ppam/mpc/aby/aby_protocol.h" +#include "ppam/mpc/common/defines.h" + +namespace privacy_go { +namespace mpc_dualdp { + +class MPCDualDPTest : public ::testing::Test { +public: + void SetUp() { + mpc_party0_ = 0; + mpc_party1_ = 1; + } + + void gen_noise_test(std::size_t& party) { + std::uint16_t remote_port = (party == mpc_party0_) ? 9989 : 9990; + std::uint16_t local_port = (party == mpc_party0_) ? 9990 : 9989; + auto net = std::make_shared("127.0.0.1", remote_port, local_port); + + auto aby_test = ppam::AbyProtocol::Instance(); + aby_test->initialize(party, net); + + auto dual_dp_test = std::make_shared(); + dual_dp_test->initialize(party, net); + + std::size_t batch_n = 16; + double epsilon = 1.0; + double delta = 0.00001; + double sensitivity = 1.0; + std::vector noise; + + auto binomial_n = ceil(8 * sensitivity * sensitivity * log(2 / delta) / (epsilon * epsilon)); + sigma_4 = 4 * sqrt(static_cast(binomial_n) / 4); + + dual_dp_test->binomial_sampling(batch_n, epsilon, delta, sensitivity, noise); + + ppam::CryptoMatrix cipher_share(noise.size(), 1); + cipher_share.shares = Eigen::Map>(noise.data(), noise.size(), 1); + + plain_.resize(noise.size(), 1); + aby_test->reveal(0, cipher_share, plain_); + + return; + } + +public: + std::size_t mpc_party0_ = 0; + std::size_t mpc_party1_ = 1; + double sigma_4 = 0; + ppam::eMatrix plain_{}; +}; + +TEST_F(MPCDualDPTest, gen_noise_test) { + pid_t pid; + int status; + + pid = fork(); + if (pid < 0) { + status = -1; + exit(EXIT_FAILURE); + } else if (pid == 0) { + gen_noise_test(mpc_party1_); + exit(EXIT_SUCCESS); + } else { + gen_noise_test(mpc_party0_); + while (waitpid(pid, &status, 0) < 0) { + if (errno != EINTR) { + status = -1; + break; + } + } + for (std::size_t i = 0; i < plain_.size(); i++) { + ASSERT_LT(plain_(i, 0), sigma_4); + } + + return; + } +} + +} // namespace mpc_dualdp +} // namespace privacy_go diff --git a/mpc-dualdp/test/test_runner.cpp b/mpc-dualdp/test/test_runner.cpp new file mode 100644 index 0000000..288bbd2 --- /dev/null +++ b/mpc-dualdp/test/test_runner.cpp @@ -0,0 +1,23 @@ +// Copyright 2023 TikTok Pte. Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" + +/** +Main entry point for Google Test unit tests. +*/ +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}