diff --git a/.gitignore b/.gitignore index 38818e6ab8..bec3896a5c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ blspy.*.so .mypy_cache/ .pytest_chache/ .eggs/ +cmake-build-debug/ js_build node_modules @@ -67,6 +68,8 @@ yarn-error.log .vs/ out/ +target + Makefile.in /ar-lib /mdate-sh diff --git a/CMakeLists.txt b/CMakeLists.txt index f730426e1f..f413f97cc7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ endif() project(BLS) +set(BUILD_BLS_JS_BINDINGS "1" CACHE STRING "") set(BUILD_BLS_PYTHON_BINDINGS "1" CACHE STRING "") set(BUILD_BLS_TESTS "1" CACHE STRING "") set(BUILD_BLS_BENCHMARKS "1" CACHE STRING "") @@ -110,10 +111,36 @@ set(MI_OVERRIDE "off" CACHE STRING "") add_subdirectory(depends/relic) add_subdirectory(depends/mimalloc) +#message(STATUS "Patching Relic to make setjmp.h inclusion conditional") +# +#execute_process( +# COMMAND bash -c "git apply ${CMAKE_SOURCE_DIR}/setjmp_patch.diff" +# WORKING_DIRECTORY ${RELIC_SRC} +#) + add_subdirectory(src) + +# Write include paths for rust binding if(EMSCRIPTEN) - add_subdirectory(js-bindings) + file(APPEND "${CMAKE_CURRENT_LIST_DIR}/build/include_paths.txt" "${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}/c++/v1/;") +endif() + +file(APPEND "${CMAKE_CURRENT_LIST_DIR}/build/include_paths.txt" "${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES};") + +if(GMP_INCLUDES) + file(APPEND "${CMAKE_CURRENT_LIST_DIR}/build/include_paths.txt" "${GMP_INCLUDES};") +endif() + +# Write gmp library path for rust binding +if(GMP_LIBRARIES) + file(APPEND "${CMAKE_CURRENT_LIST_DIR}/build/gmp_libraries.txt" "${GMP_LIBRARIES}") +endif() + +if(EMSCRIPTEN) + if(BUILD_BLS_JS_BINDINGS) + add_subdirectory(js-bindings) + endif() else() # emscripten can't build python bindings, it produces only javascript # add_subdirectory(contrib/pybind11) diff --git a/apple.rust.deps.sh b/apple.rust.deps.sh new file mode 100755 index 0000000000..7d3b8de22f --- /dev/null +++ b/apple.rust.deps.sh @@ -0,0 +1,373 @@ +#!/bin/sh +set -x +# "x86_64-apple-ios" +# "aarch64-apple-ios" +# "aarch64-apple-ios-sim" +# "x86_64-apple-darwin" +# "aarch64-apple-darwin" +# TODO: it's probably needs to be optimized in order to increase better build velocity +# TODO: so we need to combine multiple targets +TARGET=$1 +git submodule update --init +MIN_IOS="13.0" +MIN_WATCHOS="5.0" +MIN_TVOS=$MIN_IOS +MIN_MACOS="10.15" + +IPHONEOS=iphoneos +IPHONESIMULATOR=iphonesimulator +WATCHOS=watchos +WATCHSIMULATOR=watchsimulator +TVOS=appletvos +TVSIMULATOR=appletvsimulator +MACOS=macosx + +LOGICALCPU_MAX=$(sysctl -n hw.logicalcpu_max) +BUILD=build + +version_min_flag() { + PLATFORM=$1 + FLAG="" + # shellcheck disable=SC2039 + # shellcheck disable=SC2053 + if [[ $PLATFORM = $IPHONEOS ]]; then + FLAG="-miphoneos-version-min=${MIN_IOS}" + elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then + FLAG="-mios-simulator-version-min=${MIN_IOS}" + elif [[ $PLATFORM = $WATCHOS ]]; then + FLAG="-mwatchos-version-min=${MIN_WATCHOS}" + elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then + FLAG="-mwatchos-simulator-version-min=${MIN_WATCHOS}" + elif [[ $PLATFORM = $TVOS ]]; then + FLAG="-mtvos-version-min=${MIN_TVOS}" + elif [[ $PLATFORM = $TVSIMULATOR ]]; then + FLAG="-mtvos-simulator-version-min=${MIN_TVOS}" + elif [[ $PLATFORM = $MACOS ]]; then + FLAG="-mmacosx-version-min=${MIN_MACOS}" + fi + echo $FLAG +} + + +prepare() { + download_gmp() { + GMP_VERSION="6.2.1" + CURRENT_DIR=$(pwd) + echo "$CURRENT_DIR" + # shellcheck disable=SC2039,SC2164 + pushd ${BUILD} + mkdir -p "contrib" + if [ ! -s "contrib/gmp-${GMP_VERSION}.tar.bz2" ]; then + curl -L -o "contrib/gmp-${GMP_VERSION}.tar.bz2" https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.bz2 + fi + rm -rf "contrib/gmp" + # shellcheck disable=SC2039,SC2164 + pushd contrib + tar xfj "gmp-${GMP_VERSION}.tar.bz2" + mv gmp-${GMP_VERSION} gmp + rm gmp/compat.c && cp ../../contrib/gmp-patch-6.2.1/compat.c gmp/compat.c + rm gmp/longlong.h && cp ../../contrib/gmp-patch-6.2.1/longlong.h gmp/longlong.h + # shellcheck disable=SC2039,SC2164 + popd #contrib + # shellcheck disable=SC2039,SC2164 + popd #build + } + + download_cmake_toolchain() { + if [ ! -s "${BUILD}/ios.toolchain.cmake" ]; then + SHA256_HASH="d02857ff6bd64f1d7109ca59c3e4f3b2f89d0663c412146e6977c679801b3243" + curl -o "${BUILD}/ios.toolchain.cmake" https://raw.githubusercontent.com/leetal/ios-cmake/c55677a4445b138c9ef2650d3c21f22cc78c2357/ios.toolchain.cmake + DOWNLOADED_HASH=$(shasum -a 256 ${BUILD}/ios.toolchain.cmake | cut -f 1 -d " ") + if [ $SHA256_HASH != "$DOWNLOADED_HASH" ]; then + echo "Error: sha256 checksum of ios.toolchain.cmake mismatch" >&2 + exit 1 + fi + fi + } + + download_relic() { + CURRENT_DIR=$(pwd) + echo "$CURRENT_DIR" + mkdir -p "${CURRENT_DIR}/${BUILD}/contrib" + if [ ! -s "${CURRENT_DIR}/${BUILD}/contrib/relic" ]; then + # shellcheck disable=SC2039,SC2164 + pushd "${CURRENT_DIR}/${BUILD}/contrib" + git clone --depth 1 --branch "feat/ios-support" https://github.com/pankcuf/relic + # shellcheck disable=SC2039,SC2164 + pushd relic + git fetch --depth 1 origin 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae + git checkout 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae + # shellcheck disable=SC2039,SC2164 + popd #relic + # shellcheck disable=SC2039,SC2164 + popd #contrib + fi + } + rm -rf ${BUILD} + mkdir -p ${BUILD} + download_relic + download_gmp + download_cmake_toolchain +} + +build_gmp_arch() { + PLATFORM=$1 + ARCH=$2 + PFX=${PLATFORM}-${ARCH} + # why this works with this host only? + HOST=arm-apple-darwin + # shellcheck disable=SC2039,SC2164 + pushd ${BUILD} + SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path) + PLATFORM_PATH=$(xcrun --sdk "$PLATFORM" --show-sdk-platform-path) + CLANG=$(xcrun --sdk "$PLATFORM" --find clang) + DEVELOPER=$(xcode-select --print-path) + CURRENT_DIR=$(pwd) + export PATH="${PLATFORM_PATH}/Developer/usr/bin:${DEVELOPER}/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin" + mkdir gmplib-"${PLATFORM}"-"${ARCH}" + CFLAGS="-Wno-unused-value -fembed-bitcode -arch ${ARCH} --sysroot=${SDK} $(version_min_flag "$PLATFORM")" + CONFIGURESCRIPT="gmp_configure_script.sh" + # shellcheck disable=SC2039,SC2164 + pushd contrib + # shellcheck disable=SC2039,SC2164 + pushd gmp + make clean || true + make distclean || true + echo "HOST: $HOST" + echo "PREFIX: ${CURRENT_DIR}/gmplib-${PFX}" + + cat >"$CONFIGURESCRIPT" << EOF +#!/bin/sh +./configure \ +CC="$CLANG" CFLAGS="$CFLAGS" CPPFLAGS="$CFLAGS" LDFLAGS="$CFLAGS" \ +--host=${HOST} --prefix="${CURRENT_DIR}/gmplib-${PFX}" \ +--disable-shared --enable-static --disable-assembly -v +EOF + + chmod a+x "$CONFIGURESCRIPT" + sh "$CONFIGURESCRIPT" + rm "$CONFIGURESCRIPT" + + # shellcheck disable=SC2039 + mkdir -p "${CURRENT_DIR}/log" + # shellcheck disable=SC2039 + make -j "$LOGICALCPU_MAX" &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-build.log + # shellcheck disable=SC2039 + make install &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-install.log + # shellcheck disable=SC2039,SC2164 + popd # gmp + # shellcheck disable=SC2039,SC2164 + popd # contrib + # shellcheck disable=SC2039,SC2164 + popd # build +} + +build_relic_arch() { + PLATFORM=$1 + ARCH=$2 + PFX=${PLATFORM}-${ARCH} + + # shellcheck disable=SC2039,SC2164 + pushd ${BUILD} + + SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path) + + BUILDDIR=relic-"${PFX}" + TOOLCHAIN=$(pwd)/ios.toolchain.cmake + GMP_PFX=$(pwd)/gmplib-${PFX} + rm -rf "$BUILDDIR" + mkdir "$BUILDDIR" + # shellcheck disable=SC2039,SC2164 + pushd "$BUILDDIR" + + unset CC + # shellcheck disable=SC2155 + export CC=$(xcrun --sdk "${PLATFORM}" --find clang) + + WSIZE=0 + IOS_PLATFORM="" + OPTIMIZATIONFLAGS="" + DEPLOYMENT_TARGET="" + + # shellcheck disable=SC2039 + # shellcheck disable=SC2053 + if [[ $PLATFORM = $IPHONEOS ]]; then + if [[ $ARCH = "arm64" ]] || [[ $ARCH = "arm64e" ]]; then + IOS_PLATFORM=OS64 + DEPLOYMENT_TARGET=$MIN_IOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + else + IOS_PLATFORM=OS + WSIZE=32 + fi + elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then + if [[ $ARCH = "x86_64" ]]; then + IOS_PLATFORM=SIMULATOR64 + DEPLOYMENT_TARGET=$MIN_IOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + elif [[ $ARCH = "arm64" ]]; then + IOS_PLATFORM=SIMULATORARM64 + DEPLOYMENT_TARGET=$MIN_IOS + WSIZE=64 + else + IOS_PLATFORM=SIMULATOR + WSIZE=32 + fi + elif [[ $PLATFORM = $WATCHOS ]]; then + IOS_PLATFORM=WATCHOS + DEPLOYMENT_TARGET=$MIN_WATCHOS + WSIZE=32 + elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then + IOS_PLATFORM=SIMULATOR_WATCHOS + DEPLOYMENT_TARGET=$MIN_WATCHOS + WSIZE=32 + elif [[ $PLATFORM = $TVOS ]]; then + IOS_PLATFORM=TVOS + DEPLOYMENT_TARGET=$MIN_TVOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + elif [[ $PLATFORM = $TVSIMULATOR ]]; then + IOS_PLATFORM=SIMULATOR_TVOS + #TODO + if [[ $ARCH = "arm64" ]] + then + IOS_PLATFORM=OS64 + fi + DEPLOYMENT_TARGET=$MIN_TVOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + elif [[ $PLATFORM = $MACOS ]]; then + WSIZE=64 + IOS_PLATFORM=MAC + if [[ $ARCH = "arm64" ]] + then + IOS_PLATFORM=MAC_ARM64 + fi + DEPLOYMENT_TARGET=$MIN_MACOS + OPTIMIZATIONFLAGS=-fomit-frame-pointer + fi + + COMPILER_ARGS="$(version_min_flag "$PLATFORM") -Wno-unused-functions" + + EXTRA_ARGS="-DOPSYS=NONE -DPLATFORM=$IOS_PLATFORM -DDEPLOYMENT_TARGET=$DEPLOYMENT_TARGET -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN" + + # shellcheck disable=SC2039 + if [[ $ARCH = "i386" ]]; then + EXTRA_ARGS+=" -DARCH=X86" + elif [[ $ARCH = "x86_64" ]]; then + EXTRA_ARGS+=" -DARCH=X64" + else + EXTRA_ARGS+=" -DARCH=ARM" + if [[ $ARCH = "armv7s" ]]; then + EXTRA_ARGS+=" -DIOS_ARCH=armv7s" + elif [[ $ARCH = "armv7k" ]]; then + EXTRA_ARGS+=" -DIOS_ARCH=armv7k" + elif [[ $ARCH = "arm64_32" ]]; then + EXTRA_ARGS+=" -DIOS_ARCH=arm64_32" + fi + fi + + CURRENT_DIR=$(pwd) + cmake -DCMAKE_PREFIX_PATH:PATH="${GMP_PFX}" -DTESTS=0 -DBENCH=0 -DBUILD_BLS_JS_BINDINGS=0 -DBUILD_BLS_PYTHON_BINDINGS=0 \ + -DBUILD_BLS_BENCHMARKS=0 -DBUILD_BLS_TESTS=0 -DCHECK=off -DARITH=gmp -DTIMER=HPROC -DFP_PRIME=381 -DMULTI=PTHREAD \ + -DFP_QNRES=on -DFP_METHD="INTEG;INTEG;INTEG;MONTY;EXGCD;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" \ + -DCOMP_FLAGS="-pipe -std=c99 -O3 -funroll-loops $OPTIMIZATIONFLAGS -isysroot $SDK -arch $ARCH -fembed-bitcode ${COMPILER_ARGS}" \ + -DWSIZE=$WSIZE -DVERBS=off -DSHLIB=off -DALLOC="AUTO" -DEP_PLAIN=off -DEP_SUPER=off -DPP_EXT="LAZYR" \ + -DWITH="DV;BN;MD;FP;EP;FPX;EPX;PP;PC;CP" -DBN_METHD="COMBA;COMBA;MONTY;SLIDE;STEIN;BASIC" ${EXTRA_ARGS} ../../ + + make -j "$LOGICALCPU_MAX" + # shellcheck disable=SC2039,SC2164 + popd # "$BUILDDIR" + # shellcheck disable=SC2039,SC2164 + popd # contrib/relic +} + +build_bls_arch() { + # shellcheck disable=SC2039 + BLS_FILES=( "bls" "chaincode" "elements" "extendedprivatekey" "extendedpublickey" "legacy" "privatekey" "schemes" "threshold" ) + # shellcheck disable=SC2039 + ALL_BLS_OBJ_FILES=$(printf "%s.o " "${BLS_FILES[@]}") + + PLATFORM=$1 + ARCH=$2 + PFX=${PLATFORM}-${ARCH} + SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path) + + BUILDDIR=${BUILD}/bls-"${PFX}" + rm -rf "$BUILDDIR" + mkdir "$BUILDDIR" + # shellcheck disable=SC2039,SC2164 + pushd "$BUILDDIR" + + EXTRA_ARGS="$(version_min_flag "$PLATFORM")" + + CURRENT_DIR=$(pwd) + + # shellcheck disable=SC2039 + for F in "${BLS_FILES[@]}" + do + clang -I"../contrib/relic/include" \ + -I"../../depends/relic/include" \ + -I"../../include/dashbls" \ + -I"../relic-${PFX}/_deps/relic-build/include" \ + -I"../../src/" \ + -I"../gmplib-${PFX}/include" \ + -x c++ -std=c++14 -stdlib=libc++ -fembed-bitcode -arch "${ARCH}" -isysroot "${SDK}" "${EXTRA_ARGS}" \ + -c "../../src/${F}.cpp" -o "${F}.o" + done + + # shellcheck disable=SC2086 + xcrun -sdk "$PLATFORM" ar -cvq libbls.a $ALL_BLS_OBJ_FILES + + # shellcheck disable=SC2039,SC2164 + popd # "$BUILDDIR" +} + +build_all_arch() { + PLATFORM=$1 + ARCH=$2 + build_gmp_arch "$PLATFORM" "$ARCH" + build_relic_arch "$PLATFORM" "$ARCH" + build_bls_arch "$PLATFORM" "$ARCH" +} + +build_target() { + BUILD_IN=$1 + echo "Build target: $BUILD_IN" + ARCH="" + PLATFORM="" + # shellcheck disable=SC2039 + if [[ $BUILD_IN = "x86_64-apple-ios" ]]; then + ARCH=x86_64 + PLATFORM=$IPHONESIMULATOR + elif [[ $BUILD_IN = "aarch64-apple-ios" ]]; then + ARCH=arm64 + PLATFORM=$IPHONEOS + elif [[ $BUILD_IN = "aarch64-apple-ios-sim" ]]; then + ARCH=arm64 + PLATFORM=$IPHONESIMULATOR + elif [[ $BUILD_IN = "x86_64-apple-darwin" ]]; then + ARCH=x86_64 + PLATFORM=$MACOS + elif [[ $BUILD_IN = "aarch64-apple-darwin" ]]; then + ARCH=arm64 + PLATFORM=$MACOS + fi + build_all_arch "$PLATFORM" "$ARCH" + PFX="${PLATFORM}"-"${ARCH}" + rm -rf "build/artefacts/${BUILD_IN}" + mkdir -p "build/artefacts/${BUILD_IN}" + cp "build/gmplib-${PFX}/lib/libgmp.a" "build/artefacts/${BUILD_IN}" + cp "build/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" "build/artefacts/${BUILD_IN}" + cp "build/relic-${PFX}/_deps/sodium-build/libsodium.a" "build/artefacts/${BUILD_IN}" + cp "build/bls-${PFX}/libbls.a" "build/artefacts/${BUILD_IN}" +# cp -rf build/bls-"${PFX}"/*.o build/artefacts/"${BUILD_IN}"/include +# cp -rf src/*.hpp build/artefacts/"${BUILD_IN}"/include +# cp -rf build/gmplib-"${PFX}"/include/gmp.h build/artefacts/"${BUILD_IN}"/include +# cp -rf build/relic-"${PFX}"/_deps/relic-build/include/*.h build/artefacts/"${BUILD_IN}"/include +} + +prepare +build_target "$TARGET" diff --git a/apple.rust.sh b/apple.rust.sh new file mode 100755 index 0000000000..e105c3ce6c --- /dev/null +++ b/apple.rust.sh @@ -0,0 +1,458 @@ +#!/bin/sh +set -x + +git submodule update --init + +MIN_IOS="13.0" +MIN_WATCHOS="5.0" +MIN_TVOS=$MIN_IOS +MIN_MACOS="10.15" + +IPHONEOS=iphoneos +IPHONESIMULATOR=iphonesimulator +WATCHOS=watchos +WATCHSIMULATOR=watchsimulator +TVOS=appletvos +TVSIMULATOR=appletvsimulator +MACOS=macosx + +LOGICALCPU_MAX=$(sysctl -n hw.logicalcpu_max) +BUILD=build + +version_min_flag() { + PLATFORM=$1 + FLAG="" + # shellcheck disable=SC2039 + # shellcheck disable=SC2053 + if [[ $PLATFORM = $IPHONEOS ]]; then + FLAG="-miphoneos-version-min=${MIN_IOS}" + elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then + FLAG="-mios-simulator-version-min=${MIN_IOS}" + elif [[ $PLATFORM = $WATCHOS ]]; then + FLAG="-mwatchos-version-min=${MIN_WATCHOS}" + elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then + FLAG="-mwatchos-simulator-version-min=${MIN_WATCHOS}" + elif [[ $PLATFORM = $TVOS ]]; then + FLAG="-mtvos-version-min=${MIN_TVOS}" + elif [[ $PLATFORM = $TVSIMULATOR ]]; then + FLAG="-mtvos-simulator-version-min=${MIN_TVOS}" + elif [[ $PLATFORM = $MACOS ]]; then + FLAG="-mmacosx-version-min=${MIN_MACOS}" + fi + echo $FLAG +} + + +prepare() { + download_gmp() { + GMP_VERSION="6.2.1" + CURRENT_DIR=$(pwd) + echo "$CURRENT_DIR" + # shellcheck disable=SC2039,SC2164 + pushd ${BUILD} + mkdir -p "contrib" + if [ ! -s "contrib/gmp-${GMP_VERSION}.tar.bz2" ]; then + curl -L -o "contrib/gmp-${GMP_VERSION}.tar.bz2" https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.bz2 + fi + rm -rf "contrib/gmp" + # shellcheck disable=SC2039,SC2164 + pushd contrib + tar xfj "gmp-${GMP_VERSION}.tar.bz2" + mv gmp-${GMP_VERSION} gmp + rm gmp/compat.c && cp ../../contrib/gmp-patch-6.2.1/compat.c gmp/compat.c + rm gmp/longlong.h && cp ../../contrib/gmp-patch-6.2.1/longlong.h gmp/longlong.h + # shellcheck disable=SC2039,SC2164 + popd #contrib + # shellcheck disable=SC2039,SC2164 + popd #build + } + + download_cmake_toolchain() { + if [ ! -s "${BUILD}/ios.toolchain.cmake" ]; then + SHA256_HASH="d02857ff6bd64f1d7109ca59c3e4f3b2f89d0663c412146e6977c679801b3243" + curl -o "${BUILD}/ios.toolchain.cmake" https://raw.githubusercontent.com/leetal/ios-cmake/c55677a4445b138c9ef2650d3c21f22cc78c2357/ios.toolchain.cmake + DOWNLOADED_HASH=$(shasum -a 256 ${BUILD}/ios.toolchain.cmake | cut -f 1 -d " ") + if [ $SHA256_HASH != "$DOWNLOADED_HASH" ]; then + echo "Error: sha256 checksum of ios.toolchain.cmake mismatch" >&2 + exit 1 + fi + fi + } + + download_relic() { + CURRENT_DIR=$(pwd) + echo "$CURRENT_DIR" + mkdir -p "${CURRENT_DIR}/${BUILD}/contrib" + if [ ! -s "${CURRENT_DIR}/${BUILD}/contrib/relic" ]; then + # shellcheck disable=SC2039,SC2164 + pushd "${CURRENT_DIR}/${BUILD}/contrib" + git clone --depth 1 --branch "feat/ios-support" https://github.com/pankcuf/relic + # shellcheck disable=SC2039,SC2164 + pushd relic + git fetch --depth 1 origin 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae + git checkout 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae + # shellcheck disable=SC2039,SC2164 + popd #relic + # shellcheck disable=SC2039,SC2164 + popd #contrib + fi + } + rm -rf ${BUILD} + mkdir -p ${BUILD} + download_relic + download_gmp + download_cmake_toolchain + mkdir -p ${BUILD}/artefacts/include +} + +build_gmp_arch() { + PLATFORM=$1 + ARCH=$2 + PFX=${PLATFORM}-${ARCH} + # why this works with this host only? + HOST=arm-apple-darwin + # shellcheck disable=SC2039,SC2164 + pushd ${BUILD} + SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path) + PLATFORM_PATH=$(xcrun --sdk "$PLATFORM" --show-sdk-platform-path) + CLANG=$(xcrun --sdk "$PLATFORM" --find clang) + DEVELOPER=$(xcode-select --print-path) + CURRENT_DIR=$(pwd) + export PATH="${PLATFORM_PATH}/Developer/usr/bin:${DEVELOPER}/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin" + mkdir gmplib-"${PLATFORM}"-"${ARCH}" + CFLAGS="-Wno-unused-value -fembed-bitcode -arch ${ARCH} --sysroot=${SDK} $(version_min_flag "$PLATFORM")" + CONFIGURESCRIPT="gmp_configure_script.sh" + # shellcheck disable=SC2039,SC2164 + pushd contrib + # shellcheck disable=SC2039,SC2164 + pushd gmp + make clean || true + make distclean || true + echo "HOST: $HOST" + echo "PREFIX: ${CURRENT_DIR}/gmplib-${PFX}" + + cat >"$CONFIGURESCRIPT" << EOF +#!/bin/sh +./configure \ +CC="$CLANG" CFLAGS="$CFLAGS" CPPFLAGS="$CFLAGS" LDFLAGS="$CFLAGS" \ +--host=${HOST} --prefix="${CURRENT_DIR}/gmplib-${PFX}" \ +--disable-shared --enable-static --disable-assembly -v +EOF + + chmod a+x "$CONFIGURESCRIPT" + sh "$CONFIGURESCRIPT" + rm "$CONFIGURESCRIPT" + + # shellcheck disable=SC2039 + mkdir -p "${CURRENT_DIR}/log" + # shellcheck disable=SC2039 + make -j "$LOGICALCPU_MAX" &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-build.log + # shellcheck disable=SC2039 + make install &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-install.log + # shellcheck disable=SC2039,SC2164 + popd # gmp + # shellcheck disable=SC2039,SC2164 + popd # contrib + # shellcheck disable=SC2039,SC2164 + popd # build +} + +build_relic_arch() { + PLATFORM=$1 + ARCH=$2 + PFX=${PLATFORM}-${ARCH} + + # shellcheck disable=SC2039,SC2164 + pushd ${BUILD} + + SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path) + + BUILDDIR=relic-"${PFX}" + TOOLCHAIN=$(pwd)/ios.toolchain.cmake + GMP_PFX=$(pwd)/gmplib-${PFX} + rm -rf "$BUILDDIR" + mkdir "$BUILDDIR" + # shellcheck disable=SC2039,SC2164 + pushd "$BUILDDIR" + + unset CC + # shellcheck disable=SC2155 + export CC=$(xcrun --sdk "${PLATFORM}" --find clang) + + WSIZE=0 + IOS_PLATFORM="" + OPTIMIZATIONFLAGS="" + DEPLOYMENT_TARGET="" + + # shellcheck disable=SC2039 + # shellcheck disable=SC2053 + if [[ $PLATFORM = $IPHONEOS ]]; then + if [[ $ARCH = "arm64" ]] || [[ $ARCH = "arm64e" ]]; then + IOS_PLATFORM=OS64 + DEPLOYMENT_TARGET=$MIN_IOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + else + IOS_PLATFORM=OS + WSIZE=32 + fi + elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then + if [[ $ARCH = "x86_64" ]]; then + IOS_PLATFORM=SIMULATOR64 + DEPLOYMENT_TARGET=$MIN_IOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + elif [[ $ARCH = "arm64" ]]; then + IOS_PLATFORM=SIMULATORARM64 + DEPLOYMENT_TARGET=$MIN_IOS + WSIZE=64 + else + IOS_PLATFORM=SIMULATOR + WSIZE=32 + fi + elif [[ $PLATFORM = $WATCHOS ]]; then + IOS_PLATFORM=WATCHOS + DEPLOYMENT_TARGET=$MIN_WATCHOS + WSIZE=32 + elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then + IOS_PLATFORM=SIMULATOR_WATCHOS + DEPLOYMENT_TARGET=$MIN_WATCHOS + WSIZE=32 + elif [[ $PLATFORM = $TVOS ]]; then + IOS_PLATFORM=TVOS + DEPLOYMENT_TARGET=$MIN_TVOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + elif [[ $PLATFORM = $TVSIMULATOR ]]; then + IOS_PLATFORM=SIMULATOR_TVOS + #TODO + if [[ $ARCH = "arm64" ]] + then + IOS_PLATFORM=OS64 + fi + DEPLOYMENT_TARGET=$MIN_TVOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + elif [[ $PLATFORM = $MACOS ]]; then + WSIZE=64 + IOS_PLATFORM=MAC + if [[ $ARCH = "arm64" ]] + then + IOS_PLATFORM=MAC_ARM64 + fi + DEPLOYMENT_TARGET=$MIN_MACOS + OPTIMIZATIONFLAGS=-fomit-frame-pointer + fi + + COMPILER_ARGS="$(version_min_flag "$PLATFORM") -Wno-unused-functions" + + EXTRA_ARGS="-DOPSYS=NONE -DPLATFORM=$IOS_PLATFORM -DDEPLOYMENT_TARGET=$DEPLOYMENT_TARGET -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN" + + # shellcheck disable=SC2039 + if [[ $ARCH = "i386" ]]; then + EXTRA_ARGS+=" -DARCH=X86" + elif [[ $ARCH = "x86_64" ]]; then + EXTRA_ARGS+=" -DARCH=X64" + else + EXTRA_ARGS+=" -DARCH=ARM" + if [[ $ARCH = "armv7s" ]]; then + EXTRA_ARGS+=" -DIOS_ARCH=armv7s" + elif [[ $ARCH = "armv7k" ]]; then + EXTRA_ARGS+=" -DIOS_ARCH=armv7k" + elif [[ $ARCH = "arm64_32" ]]; then + EXTRA_ARGS+=" -DIOS_ARCH=arm64_32" + fi + fi + + CURRENT_DIR=$(pwd) + cmake -DCMAKE_PREFIX_PATH:PATH="${GMP_PFX}" -DTESTS=0 -DBENCH=0 -DBUILD_BLS_JS_BINDINGS=0 -DBUILD_BLS_PYTHON_BINDINGS=0 \ + -DBUILD_BLS_BENCHMARKS=0 -DBUILD_BLS_TESTS=0 -DCHECK=off -DARITH=gmp -DTIMER=HPROC -DFP_PRIME=381 -DMULTI=PTHREAD \ + -DFP_QNRES=on -DFP_METHD="INTEG;INTEG;INTEG;MONTY;EXGCD;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" \ + -DCOMP_FLAGS="-pipe -std=c99 -O3 -funroll-loops $OPTIMIZATIONFLAGS -isysroot $SDK -arch $ARCH -fembed-bitcode ${COMPILER_ARGS}" \ + -DWSIZE=$WSIZE -DVERBS=off -DSHLIB=off -DALLOC="AUTO" -DEP_PLAIN=off -DEP_SUPER=off -DPP_EXT="LAZYR" \ + -DWITH="DV;BN;MD;FP;EP;FPX;EPX;PP;PC;CP" -DBN_METHD="COMBA;COMBA;MONTY;SLIDE;STEIN;BASIC" ${EXTRA_ARGS} ../../ + + make -j "$LOGICALCPU_MAX" + # shellcheck disable=SC2039,SC2164 + popd # "$BUILDDIR" + # shellcheck disable=SC2039,SC2164 + popd # contrib/relic +} + +build_bls_arch() { + # shellcheck disable=SC2039 + BLS_FILES=( "bls" "chaincode" "elements" "extendedprivatekey" "extendedpublickey" "legacy" "privatekey" "schemes" "threshold" ) + # shellcheck disable=SC2039 + ALL_BLS_OBJ_FILES=$(printf "%s.o " "${BLS_FILES[@]}") + + PLATFORM=$1 + ARCH=$2 + PFX=${PLATFORM}-${ARCH} + SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path) + + BUILDDIR=${BUILD}/bls-"${PFX}" + rm -rf "$BUILDDIR" + mkdir "$BUILDDIR" + # shellcheck disable=SC2039,SC2164 + pushd "$BUILDDIR" + + EXTRA_ARGS="$(version_min_flag "$PLATFORM")" + + CURRENT_DIR=$(pwd) + + # shellcheck disable=SC2039 + for F in "${BLS_FILES[@]}" + do + clang -I"../contrib/relic/include" \ + -I"../relic-${PFX}/_deps/relic-build/include" \ + -I"../../src/" \ + -I"../gmplib-${PFX}/include" \ + -x c++ -std=c++14 -stdlib=libc++ -fembed-bitcode -arch "${ARCH}" -isysroot "${SDK}" "${EXTRA_ARGS}" \ + -c "../../src/${F}.cpp" -o "${F}.o" + done + + # shellcheck disable=SC2086 + xcrun -sdk "$PLATFORM" ar -cvq libbls.a $ALL_BLS_OBJ_FILES + + # shellcheck disable=SC2039,SC2164 + popd # "$BUILDDIR" +} + +build_all_arch() { + PLATFORM=$1 + ARCH=$2 + build_gmp_arch "$PLATFORM" "$ARCH" + build_relic_arch "$PLATFORM" "$ARCH" + build_bls_arch "$PLATFORM" "$ARCH" +} + +build_all() { + BUILD_IN=$1 + TARGET_DIR=build/artefacts + # shellcheck disable=SC2039 + IFS='|' read -ra BUILD_PAIRS <<< "$BUILD_IN" + # shellcheck disable=SC2039 + for BUILD_PAIR in "${BUILD_PAIRS[@]}" + do + # shellcheck disable=SC2039 + IFS=';' read -ra PARSED_PAIR <<< "$BUILD_PAIR" + # shellcheck disable=SC2039 + PLATFORM=${PARSED_PAIR[0]} + # shellcheck disable=SC2039 + ARCH=${PARSED_PAIR[1]} + + GMP_LIPOARGS="" + RELIC_LIPOARGS="" + BLS_LIPOARGS="" + + # shellcheck disable=SC2039 + local NEED_LIPO=0 + # shellcheck disable=SC2039 + IFS='+' read -ra ARCHS <<< "$ARCH" + # shellcheck disable=SC2039 + for i in "${!ARCHS[@]}" + do + # shellcheck disable=SC2039 + local SINGLEARCH=${ARCHS[i]} + + # build for every platform+arch + build_all_arch "$PLATFORM" "$SINGLEARCH" + + PFX="${PLATFORM}"-"${SINGLEARCH}" + ARCH_TARGET_DIR=${TARGET_DIR}/${PFX} + rm -rf "${ARCH_TARGET_DIR}" + mkdir -p "${ARCH_TARGET_DIR}" + #mv "${BUILD}/gmplib-${PFX}/lib/libgmp.a" "${ARCH_TARGET_DIR}/libgmp.a" + #mv "${BUILD}/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" "${ARCH_TARGET_DIR}/librelic.a" + #mv "${BUILD}/bls-${PFX}/libbls.a" "${ARCH_TARGET_DIR}/libbls.a" + + libtool -static -o "${ARCH_TARGET_DIR}/libbls.a" \ + "${BUILD}/gmplib-${PFX}/lib/libgmp.a" \ + "${BUILD}/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" \ + "${BUILD}/bls-${PFX}/libbls.a" + + # shellcheck disable=SC2039 + GMP_LIPOARGS+="${ARCH_TARGET_DIR}/libgmp.a " + # shellcheck disable=SC2039 + RELIC_LIPOARGS+="${ARCH_TARGET_DIR}/librelic.a " + # shellcheck disable=SC2039 + BLS_LIPOARGS+="${ARCH_TARGET_DIR}/libbls.a " + + NEED_LIPO=i + done + + # Do lipo if we need https://developer.apple.com/forums/thread/666335?answerId=645963022#645963022 +# if [[ $NEED_LIPO -gt 0 ]] +# then +# FAT_TARGET_DIR=${TARGET_DIR}/${PLATFORM}-fat +# rm -rf "${FAT_TARGET_DIR}" +# mkdir -p "${FAT_TARGET_DIR}" +# # shellcheck disable=SC2086 +# xcrun lipo $GMP_LIPOARGS -create -output "${FAT_TARGET_DIR}/libgmp.a" +# # shellcheck disable=SC2086 +# xcrun lipo $RELIC_LIPOARGS -create -output "${FAT_TARGET_DIR}/librelic.a" +# # shellcheck disable=SC2086 +# xcrun lipo $BLS_LIPOARGS -create -output "${FAT_TARGET_DIR}/libbls.a" +# libtool -static -o "${FAT_TARGET_DIR}/libbls_combined.a" "${FAT_TARGET_DIR}/libgmp.a" "${FAT_TARGET_DIR}/librelic.a" "${FAT_TARGET_DIR}/libbls.a" +# rm "${FAT_TARGET_DIR}/libgmp.a" +# rm "${FAT_TARGET_DIR}/librelic.a" +# rm "${FAT_TARGET_DIR}/libbls.a" +# mv "${FAT_TARGET_DIR}/libbls_combined.a" "${FAT_TARGET_DIR}/libbls.a" +# # clean up +# # shellcheck disable=SC2039 +# for i in "${!ARCHS[@]}" +# do +# local SINGLEARCH=${ARCHS[i]} +# rm -rf "${TARGET_DIR}-${SINGLEARCH}" +# done +# fi + done +} + +#make_relic_headers_universal() { +# RELIC_TARGET_DIR=relic-iphoneos-arm64 +# perl -p -e 's/#define WSIZE.*/#ifdef __LP64__\n#define WSIZE 64\n#else\n#define WSIZE 32\n#endif/' \ +# "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h" \ +# > "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h.new" +# +# rm "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h" +# mv "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h.new" "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h" +#} + +#copy_headers() { +# mkdir build/artefacts/include +# # Copy all headers we will need +# cp -rf src/*.hpp build/artefacts/include +# cp -rf build/gmp/include/gmp.h build/artefacts/include +# cp -rf build/contrib/relic/include/*.h build/artefacts/include +# cp -rf build/contrib/relic/include/low/*.h build/artefacts/include +# cp -rf build/contrib/relic/relic-iphoneos-arm64/include/*.h build/artefacts/include +# rm -rf build/artefacts/include/test-utils.hpp +#} + +#function make_fat_binary() +#{ +# pushd artefacts +# +# XCFRAMEWORK_ARGS="" +# +# for dir in */; do +# if [ -d "$dir" ]; then +# if [[ "$dir" != "include/" ]]; then +# libtool -static -o "${dir}libbls_combined.a" "${dir}libgmp.a" "${dir}librelic.a" "${dir}libbls.a" +# +# XCFRAMEWORK_ARGS+="-library ${dir}libbls_combined.a -headers include " +# fi +# fi +# done +# +# #xcodebuild -create-xcframework $XCFRAMEWORK_ARGS -output "libbls.xcframework" +#} + +prepare +build_all "${MACOS};x86_64+arm64" +build_all "${IPHONEOS};arm64|${IPHONESIMULATOR};arm64+x86_64" + +#make_relic_headers_universal +#copy_headers +#make_fat_binary diff --git a/apple.rust.single.sh b/apple.rust.single.sh new file mode 100755 index 0000000000..d99722bf02 --- /dev/null +++ b/apple.rust.single.sh @@ -0,0 +1,404 @@ +#!/bin/sh +set -x +# "x86_64-apple-ios" +# "x86_64-apple-ios-sim" +# "aarch64-apple-ios" +# "aarch64-apple-ios-sim" +# "x86_64-apple-darwin" +# "aarch64-apple-darwin" +# TODO: it's probably needs to be optimized in order to increase better build velocity +# TODO: so we need to combine multiple targets +TARGET=$1 +git submodule update --init +MIN_IOS="13.0" +MIN_WATCHOS="5.0" +MIN_TVOS=$MIN_IOS +MIN_MACOS="10.15" + +IPHONEOS=iphoneos +IPHONESIMULATOR=iphonesimulator +WATCHOS=watchos +WATCHSIMULATOR=watchsimulator +TVOS=appletvos +TVSIMULATOR=appletvsimulator +MACOS=macosx + +LOGICALCPU_MAX=$(sysctl -n hw.logicalcpu_max) +BUILD=build + +version_min_flag() { + PLATFORM=$1 + FLAG="" + # shellcheck disable=SC2039 + # shellcheck disable=SC2053 + if [[ $PLATFORM = $IPHONEOS ]]; then + FLAG="-miphoneos-version-min=${MIN_IOS}" + elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then + FLAG="-mios-simulator-version-min=${MIN_IOS}" + elif [[ $PLATFORM = $WATCHOS ]]; then + FLAG="-mwatchos-version-min=${MIN_WATCHOS}" + elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then + FLAG="-mwatchos-simulator-version-min=${MIN_WATCHOS}" + elif [[ $PLATFORM = $TVOS ]]; then + FLAG="-mtvos-version-min=${MIN_TVOS}" + elif [[ $PLATFORM = $TVSIMULATOR ]]; then + FLAG="-mtvos-simulator-version-min=${MIN_TVOS}" + elif [[ $PLATFORM = $MACOS ]]; then + FLAG="-mmacosx-version-min=${MIN_MACOS}" + fi + echo $FLAG +} + + +prepare() { + download_gmp() { + GMP_VERSION="6.2.1" + CURRENT_DIR=$(pwd) + echo "$CURRENT_DIR" + # shellcheck disable=SC2039,SC2164 + pushd ${BUILD} + mkdir -p "contrib" + if [ ! -s "contrib/gmp-${GMP_VERSION}.tar.bz2" ]; then + curl -L -o "contrib/gmp-${GMP_VERSION}.tar.bz2" https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.bz2 + fi + rm -rf "contrib/gmp" + # shellcheck disable=SC2039,SC2164 + pushd contrib + tar xfj "gmp-${GMP_VERSION}.tar.bz2" + mv gmp-${GMP_VERSION} gmp + rm gmp/compat.c && cp ../../contrib/gmp-patch-6.2.1/compat.c gmp/compat.c + rm gmp/longlong.h && cp ../../contrib/gmp-patch-6.2.1/longlong.h gmp/longlong.h + # shellcheck disable=SC2039,SC2164 + popd #contrib + # shellcheck disable=SC2039,SC2164 + popd #build + } + + download_cmake_toolchain() { + if [ ! -s "${BUILD}/ios.toolchain.cmake" ]; then + SHA256_HASH="d02857ff6bd64f1d7109ca59c3e4f3b2f89d0663c412146e6977c679801b3243" + curl -o "${BUILD}/ios.toolchain.cmake" https://raw.githubusercontent.com/leetal/ios-cmake/c55677a4445b138c9ef2650d3c21f22cc78c2357/ios.toolchain.cmake + DOWNLOADED_HASH=$(shasum -a 256 ${BUILD}/ios.toolchain.cmake | cut -f 1 -d " ") + if [ $SHA256_HASH != "$DOWNLOADED_HASH" ]; then + echo "Error: sha256 checksum of ios.toolchain.cmake mismatch" >&2 + exit 1 + fi + fi + } + + download_relic() { + CURRENT_DIR=$(pwd) + echo "$CURRENT_DIR" + mkdir -p "${CURRENT_DIR}/${BUILD}/contrib" + if [ ! -s "${CURRENT_DIR}/${BUILD}/contrib/relic" ]; then + # shellcheck disable=SC2039,SC2164 + pushd "${CURRENT_DIR}/${BUILD}/contrib" + git clone --depth 1 --branch "feat/ios-support" https://github.com/pankcuf/relic + # shellcheck disable=SC2039,SC2164 + pushd relic + git fetch --depth 1 origin 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae + git checkout 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae + # shellcheck disable=SC2039,SC2164 + popd #relic + # shellcheck disable=SC2039,SC2164 + popd #contrib + fi + } + rm -rf ${BUILD} + mkdir -p ${BUILD} + download_relic + download_gmp + download_cmake_toolchain +} + +build_gmp_arch() { + PLATFORM=$1 + ARCH=$2 + PFX=${PLATFORM}-${ARCH} + # why this works with this host only? + HOST=arm-apple-darwin + # shellcheck disable=SC2039,SC2164 + pushd ${BUILD} + SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path) + PLATFORM_PATH=$(xcrun --sdk "$PLATFORM" --show-sdk-platform-path) + CLANG=$(xcrun --sdk "$PLATFORM" --find clang) + DEVELOPER=$(xcode-select --print-path) + CURRENT_DIR=$(pwd) + export PATH="${PLATFORM_PATH}/Developer/usr/bin:${DEVELOPER}/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin" + mkdir gmplib-"${PLATFORM}"-"${ARCH}" + CFLAGS="-Wno-unused-value -fembed-bitcode -arch ${ARCH} --sysroot=${SDK} $(version_min_flag "$PLATFORM")" + CONFIGURESCRIPT="gmp_configure_script.sh" + # shellcheck disable=SC2039,SC2164 + pushd contrib + # shellcheck disable=SC2039,SC2164 + pushd gmp + make clean || true + make distclean || true + echo "HOST: $HOST" + echo "PREFIX: ${CURRENT_DIR}/gmplib-${PFX}" + + cat >"$CONFIGURESCRIPT" << EOF +#!/bin/sh +./configure \ +CC="$CLANG" CFLAGS="$CFLAGS" CPPFLAGS="$CFLAGS" LDFLAGS="$CFLAGS" \ +--host=${HOST} --prefix="${CURRENT_DIR}/gmplib-${PFX}" \ +--disable-shared --enable-static --disable-assembly -v +EOF + + chmod a+x "$CONFIGURESCRIPT" + sh "$CONFIGURESCRIPT" + rm "$CONFIGURESCRIPT" + + # shellcheck disable=SC2039 + mkdir -p "${CURRENT_DIR}/log" + # shellcheck disable=SC2039 + make -j "$LOGICALCPU_MAX" &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-build.log + # shellcheck disable=SC2039 + make install &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-install.log + # shellcheck disable=SC2039,SC2164 + popd # gmp + # shellcheck disable=SC2039,SC2164 + popd # contrib + # shellcheck disable=SC2039,SC2164 + popd # build +} + +build_relic_arch() { + PLATFORM=$1 + ARCH=$2 + PFX=${PLATFORM}-${ARCH} + + # shellcheck disable=SC2039,SC2164 + pushd ${BUILD} + + SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path) + + BUILDDIR=relic-"${PFX}" + TOOLCHAIN=$(pwd)/ios.toolchain.cmake + GMP_PFX=$(pwd)/gmplib-${PFX} + rm -rf "$BUILDDIR" + mkdir "$BUILDDIR" + # shellcheck disable=SC2039,SC2164 + pushd "$BUILDDIR" + + unset CC + # shellcheck disable=SC2155 + export CC=$(xcrun --sdk "${PLATFORM}" --find clang) + + WSIZE=0 + IOS_PLATFORM="" + OPTIMIZATIONFLAGS="" + DEPLOYMENT_TARGET="" + + # shellcheck disable=SC2039 + # shellcheck disable=SC2053 + if [[ $PLATFORM = $IPHONEOS ]]; then + if [[ $ARCH = "arm64" ]] || [[ $ARCH = "arm64e" ]]; then + IOS_PLATFORM=OS64 + DEPLOYMENT_TARGET=$MIN_IOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + else + IOS_PLATFORM=OS + WSIZE=32 + fi + elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then + if [[ $ARCH = "x86_64" ]]; then + IOS_PLATFORM=SIMULATOR64 + DEPLOYMENT_TARGET=$MIN_IOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + elif [[ $ARCH = "arm64" ]]; then + IOS_PLATFORM=SIMULATORARM64 + DEPLOYMENT_TARGET=$MIN_IOS + WSIZE=64 + else + IOS_PLATFORM=SIMULATOR + WSIZE=32 + fi + elif [[ $PLATFORM = $WATCHOS ]]; then + IOS_PLATFORM=WATCHOS + DEPLOYMENT_TARGET=$MIN_WATCHOS + WSIZE=32 + elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then + IOS_PLATFORM=SIMULATOR_WATCHOS + DEPLOYMENT_TARGET=$MIN_WATCHOS + WSIZE=32 + elif [[ $PLATFORM = $TVOS ]]; then + IOS_PLATFORM=TVOS + DEPLOYMENT_TARGET=$MIN_TVOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + elif [[ $PLATFORM = $TVSIMULATOR ]]; then + IOS_PLATFORM=SIMULATOR_TVOS + #TODO + if [[ $ARCH = "arm64" ]] + then + IOS_PLATFORM=OS64 + fi + DEPLOYMENT_TARGET=$MIN_TVOS + WSIZE=64 + OPTIMIZATIONFLAGS=-fomit-frame-pointer + elif [[ $PLATFORM = $MACOS ]]; then + WSIZE=64 + IOS_PLATFORM=MAC + if [[ $ARCH = "arm64" ]] + then + IOS_PLATFORM=MAC_ARM64 + fi + DEPLOYMENT_TARGET=$MIN_MACOS + OPTIMIZATIONFLAGS=-fomit-frame-pointer + fi + + COMPILER_ARGS="$(version_min_flag "$PLATFORM") -Wno-unused-functions" + + EXTRA_ARGS="-DOPSYS=NONE -DPLATFORM=$IOS_PLATFORM -DDEPLOYMENT_TARGET=$DEPLOYMENT_TARGET -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN" + + # shellcheck disable=SC2039 + if [[ $ARCH = "i386" ]]; then + EXTRA_ARGS+=" -DARCH=X86" + elif [[ $ARCH = "x86_64" ]]; then + EXTRA_ARGS+=" -DARCH=X64" + else + EXTRA_ARGS+=" -DARCH=ARM" + if [[ $ARCH = "armv7s" ]]; then + EXTRA_ARGS+=" -DIOS_ARCH=armv7s" + elif [[ $ARCH = "armv7k" ]]; then + EXTRA_ARGS+=" -DIOS_ARCH=armv7k" + elif [[ $ARCH = "arm64_32" ]]; then + EXTRA_ARGS+=" -DIOS_ARCH=arm64_32" + fi + fi + + CURRENT_DIR=$(pwd) + cmake -DCMAKE_PREFIX_PATH:PATH="${GMP_PFX}" -DTESTS=0 -DBENCH=0 -DBUILD_BLS_JS_BINDINGS=0 -DBUILD_BLS_PYTHON_BINDINGS=0 \ + -DBUILD_BLS_BENCHMARKS=0 -DBUILD_BLS_TESTS=0 -DCHECK=off -DARITH=gmp -DTIMER=HPROC -DFP_PRIME=381 -DMULTI=PTHREAD \ + -DFP_QNRES=on -DFP_METHD="INTEG;INTEG;INTEG;MONTY;EXGCD;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" \ + -DCOMP_FLAGS="-pipe -std=c99 -O3 -funroll-loops $OPTIMIZATIONFLAGS -isysroot $SDK -arch $ARCH -fembed-bitcode ${COMPILER_ARGS}" \ + -DWSIZE=$WSIZE -DVERBS=off -DSHLIB=off -DALLOC="AUTO" -DEP_PLAIN=off -DEP_SUPER=off -DPP_EXT="LAZYR" \ + -DWITH="DV;BN;MD;FP;EP;FPX;EPX;PP;PC;CP" -DBN_METHD="COMBA;COMBA;MONTY;SLIDE;STEIN;BASIC" ${EXTRA_ARGS} ../../ + + make -j "$LOGICALCPU_MAX" + # shellcheck disable=SC2039,SC2164 + popd # "$BUILDDIR" + # shellcheck disable=SC2039,SC2164 + popd # contrib/relic +} + +build_bls_arch() { + # shellcheck disable=SC2039 + BLS_FILES=( "bls" "chaincode" "elements" "extendedprivatekey" "extendedpublickey" "legacy" "privatekey" "schemes" "threshold" ) + # shellcheck disable=SC2039 + ALL_BLS_OBJ_FILES=$(printf "%s.o " "${BLS_FILES[@]}") + + PLATFORM=$1 + ARCH=$2 + PFX=${PLATFORM}-${ARCH} + SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path) + + BUILDDIR=${BUILD}/bls-"${PFX}" + rm -rf "$BUILDDIR" + mkdir "$BUILDDIR" + # shellcheck disable=SC2039,SC2164 + pushd "$BUILDDIR" + + EXTRA_ARGS="$(version_min_flag "$PLATFORM")" + + CURRENT_DIR=$(pwd) + + # shellcheck disable=SC2039 + for F in "${BLS_FILES[@]}" + do + clang -I"../contrib/relic/include" \ + -I"../relic-${PFX}/_deps/relic-build/include" \ + -I"../../src/" \ + -I"../gmplib-${PFX}/include" \ + -x c++ -std=c++14 -stdlib=libc++ -fembed-bitcode -arch "${ARCH}" -isysroot "${SDK}" "${EXTRA_ARGS}" \ + -c "../../src/${F}.cpp" -o "${F}.o" + done + + # shellcheck disable=SC2086 + xcrun -sdk "$PLATFORM" ar -cvq libbls.a $ALL_BLS_OBJ_FILES + + # shellcheck disable=SC2039,SC2164 + popd # "$BUILDDIR" +} + +build_all_arch() { + PLATFORM=$1 + ARCH=$2 + build_gmp_arch "$PLATFORM" "$ARCH" + build_relic_arch "$PLATFORM" "$ARCH" + build_bls_arch "$PLATFORM" "$ARCH" +} + +build_target() { + BUILD_IN=$1 + echo "Build target: $BUILD_IN" + ARCH="" + PLATFORM="" + # shellcheck disable=SC2039 + if [[ $BUILD_IN = "x86_64-apple-ios" ]]; then + ARCH=x86_64 + PLATFORM=$IPHONESIMULATOR + elif [[ $BUILD_IN = "aarch64-apple-ios" ]]; then + ARCH=arm64 + PLATFORM=$IPHONEOS + elif [[ $BUILD_IN = "aarch64-apple-ios-sim" ]]; then + ARCH=arm64 + PLATFORM=$IPHONESIMULATOR + elif [[ $BUILD_IN = "x86_64-apple-darwin" ]]; then + ARCH=x86_64 + PLATFORM=$MACOS + elif [[ $BUILD_IN = "aarch64-apple-darwin" ]]; then + ARCH=arm64 + PLATFORM=$MACOS + fi + build_all_arch "$PLATFORM" "$ARCH" + PFX="${PLATFORM}"-"${ARCH}" + rm -rf "build/artefacts/${BUILD_IN}" + mkdir -p "build/artefacts/${BUILD_IN}/include" +# libtool -static -o "build/artefacts/${BUILD_IN}/libbls.a" \ +# "build/gmplib-${PFX}/lib/libgmp.a" \ +# "build/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" \ +# "build/bls-${PFX}/libbls.a" + cp "build/gmplib-${PFX}/lib/libgmp.a" "build/artefacts/${BUILD_IN}" + cp "build/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" "build/artefacts/${BUILD_IN}" + cp "build/relic-${PFX}/_deps/sodium-build/libsodium.a" "build/artefacts/${BUILD_IN}" + cp "build/bls-${PFX}/libbls.a" "build/artefacts/${BUILD_IN}" + cp -rf build/bls-"${PFX}"/*.o build/artefacts/"${BUILD_IN}"/include + cp -rf src/*.hpp build/artefacts/"${BUILD_IN}"/include + cp -rf build/gmplib-"${PFX}"/include/gmp.h build/artefacts/"${BUILD_IN}"/include + cp -rf build/relic-"${PFX}"/_deps/relic-build/include/*.h build/artefacts/"${BUILD_IN}"/include +} + +#make_relic_headers_universal() { +# RELIC_TARGET_DIR=relic-iphoneos-arm64 +# perl -p -e 's/#define WSIZE.*/#ifdef __LP64__\n#define WSIZE 64\n#else\n#define WSIZE 32\n#endif/' \ +# "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h" \ +# > "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h.new" +# +# rm "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h" +# mv "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h.new" "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h" +#} +# +#copy_headers() { +## mkdir build/artefacts/include +# # Copy all headers we will need +# cp -rf src/*.hpp ${BUILD}/artefacts/include +# cp -rf ${BUILD}/contrib/gmp/include/gmp.h ${BUILD}/artefacts/include +# cp -rf ${BUILD}/contrib/relic/include/*.h ${BUILD}/artefacts/include +# cp -rf ${BUILD}/contrib/relic/include/low/*.h ${BUILD}/artefacts/include +# #cp -rf ${BUILD}/contrib/relic/relic-iphoneos-arm64/include/*.h ${BUILD}/artefacts/include +# rm -rf ${BUILD}/artefacts/include/test-utils.hpp +#} + +prepare +build_target "$TARGET" +#copy_headers +#build_all "${MACOS};x86_64+arm64" +#build_all "${IPHONEOS};arm64|${IPHONESIMULATOR};arm64+x86_64" + +#make_relic_headers_universal +#copy_headers +#make_fat_binary diff --git a/configure.ac b/configure.ac index 32900bb14f..23b61ec455 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.60]) -AC_INIT([libdashbls],[1.2.4]) +AC_INIT([libdashbls],[1.3.0]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) @@ -783,3 +783,4 @@ AC_OUTPUT dnl Peplace conflict-prone PACKAGE-prefixed macros with DASHBLS sed -i.old 's/PACKAGE/DASHBLS/g' depends/relic/include/relic_conf.h +sed -i.old 's/PACKAGE/DASHBLS/g' config.status diff --git a/include/dashbls/elements.hpp b/include/dashbls/elements.hpp index a147115907..6832b31f3a 100644 --- a/include/dashbls/elements.hpp +++ b/include/dashbls/elements.hpp @@ -59,6 +59,7 @@ public: GTElement Pair(const G2Element &b) const; uint32_t GetFingerprint(bool fLegacy = false) const; std::vector Serialize(bool fLegacy = false) const; + G1Element Copy(); friend bool operator==(const G1Element &a, const G1Element &b); friend bool operator!=(const G1Element &a, const G1Element &b); @@ -101,6 +102,7 @@ public: G2Element Negate() const; GTElement Pair(const G1Element &a) const; std::vector Serialize(bool fLegacy = false) const; + G2Element Copy(); friend bool operator==(G2Element const &a, G2Element const &b); friend bool operator!=(G2Element const &a, G2Element const &b); diff --git a/include/dashbls/schemes.hpp b/include/dashbls/schemes.hpp index 456ae749af..31e6b1a1b7 100644 --- a/include/dashbls/schemes.hpp +++ b/include/dashbls/schemes.hpp @@ -39,6 +39,7 @@ class CoreMPL { public: CoreMPL() = delete; CoreMPL(const std::string& strId) : strCiphersuiteId(strId) {} + virtual ~CoreMPL() {} // Generates a private key from a seed, similar to HD key generation // (hashes the seed), and reduces it mod the group order virtual PrivateKey KeyGen(const vector& seed); @@ -112,7 +113,7 @@ protected: bool fLegacy); }; -class BasicSchemeMPL : public CoreMPL { +class BasicSchemeMPL final : public CoreMPL { public: static const std::string CIPHERSUITE_ID; BasicSchemeMPL() : CoreMPL(BasicSchemeMPL::CIPHERSUITE_ID) {} @@ -133,7 +134,7 @@ public: const G2Element& signature) override; }; -class AugSchemeMPL : public CoreMPL { +class AugSchemeMPL final : public CoreMPL { public: static const std::string CIPHERSUITE_ID; @@ -186,7 +187,7 @@ public: const G2Element& signature) override; }; -class PopSchemeMPL : public CoreMPL { +class PopSchemeMPL final : public CoreMPL { public: static const std::string CIPHERSUITE_ID; @@ -221,7 +222,7 @@ public: /** * This scheme reflects the Sign/Verify behaviour of older bls-signatures library versions (<0.1.29). */ -class LegacySchemeMPL : public CoreMPL { +class LegacySchemeMPL final : public CoreMPL { public: LegacySchemeMPL() : CoreMPL(std::string{}) {} diff --git a/js-bindings/CMakeLists.txt b/js-bindings/CMakeLists.txt index 55de66444a..03da706af7 100644 --- a/js-bindings/CMakeLists.txt +++ b/js-bindings/CMakeLists.txt @@ -34,5 +34,5 @@ foreach(file ${JS_BINDINGS_TESTS}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/${file} tests/${file} COPYONLY) endforeach() -set_target_properties(blsjstmp PROPERTIES LINK_FLAGS "--bind -Oz --closure 1 -s MODULARIZE=1 -s NODEJS_CATCH_EXIT=1 -s NODEJS_CATCH_REJECTION=1") +set_target_properties(blsjstmp PROPERTIES LINK_FLAGS "--bind -Oz --closure 1 -s MODULARIZE=1") add_custom_command(TARGET blsjstmp POST_BUILD COMMAND npm run build:web) diff --git a/js-bindings/blsjs.d.ts b/js-bindings/blsjs.d.ts index 4cd30bc621..95cb05962a 100644 --- a/js-bindings/blsjs.d.ts +++ b/js-bindings/blsjs.d.ts @@ -21,6 +21,7 @@ export declare class BasicSchemeMPL { static deriveChildSk(sk: PrivateKey, index: number): PrivateKey; static deriveChildSkUnhardened(sk: PrivateKey, index: number): PrivateKey; static deriveChildPkUnhardened(pk: G1Element, index: number): G1Element; + static verifySecure(pk: G1Element, sig: G2Element, msg: Uint8Array): boolean; } export declare class PopSchemeMPL { diff --git a/js-bindings/jsbindings.cpp b/js-bindings/jsbindings.cpp index f390923eb8..81daa4abc7 100644 --- a/js-bindings/jsbindings.cpp +++ b/js-bindings/jsbindings.cpp @@ -42,7 +42,8 @@ EMSCRIPTEN_BINDINGS(blsjs) { .class_function("aggregateVerify", &SchemeMPLWrapper::AggregateVerify) .class_function("deriveChildSk", &SchemeMPLWrapper::DeriveChildSk) .class_function("deriveChildSkUnhardened", &SchemeMPLWrapper::DeriveChildSkUnhardened) - .class_function("deriveChildPkUnhardened", &SchemeMPLWrapper::DeriveChildPkUnhardened); + .class_function("deriveChildPkUnhardened", &SchemeMPLWrapper::DeriveChildPkUnhardened) + .class_function("verifySecure", &SchemeMPLWrapper::VerifySecure); class_("PopSchemeMPL") .class_function("skToG1", &PopSchemeMPLWrapper::SkToG1) diff --git a/js-bindings/wrappers/SchemeMPLWrapper.h b/js-bindings/wrappers/SchemeMPLWrapper.h index 972d7e3a76..e5a4ae5ef8 100644 --- a/js-bindings/wrappers/SchemeMPLWrapper.h +++ b/js-bindings/wrappers/SchemeMPLWrapper.h @@ -81,6 +81,15 @@ template class SchemeMPLWrapper : public JSWrapper pubkeys = G1ElementWrapper::Unwrap + (helpers::toVectorFromJSArray(pubkeyArray)); + + std::vector message = helpers::toVector(messageVal); + + return mpl.VerifySecure(pubkeys, signature.GetWrappedInstance(), message); + } + protected: static inline SchemeMPL mpl; }; diff --git a/python-impl/op_swu_g2.py b/python-impl/op_swu_g2.py index 2872611215..afdb40cf71 100644 --- a/python-impl/op_swu_g2.py +++ b/python-impl/op_swu_g2.py @@ -21,6 +21,7 @@ from bls12381 import h_eff, q from ec import JacobianPoint, default_ec_twist, eval_iso from fields import Fq, Fq2, roots_of_unity from hash_to_field import Hp2 +from typing import Union def sgn0(x: Fq2) -> int: @@ -198,7 +199,7 @@ def iso3(P): # # map from Fq2 element(s) to point in G2 subgroup of Ell2 # -def opt_swu2_map(t: Fq2, t2: Fq2 = None) -> JacobianPoint: +def opt_swu2_map(t: Fq2, t2: Union[Fq2, None] = None) -> JacobianPoint: Pp = iso3(osswu2_help(t)) if t2 is not None: Pp2 = iso3(osswu2_help(t2)) diff --git a/rust-bindings/.gitignore b/rust-bindings/.gitignore new file mode 100644 index 0000000000..cb117fd6ee --- /dev/null +++ b/rust-bindings/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target \ No newline at end of file diff --git a/rust-bindings/bls-dash-sys/.rustfmt.toml b/rust-bindings/bls-dash-sys/.rustfmt.toml new file mode 100644 index 0000000000..f5fe8f3188 --- /dev/null +++ b/rust-bindings/bls-dash-sys/.rustfmt.toml @@ -0,0 +1,17 @@ +unstable_features = true + +blank_lines_lower_bound = 0 +condense_wildcard_suffixes = true +error_on_line_overflow = true +error_on_unformatted = true +format_code_in_doc_comments = true +format_macro_matchers = true +format_strings = true +imports_granularity = "Crate" +normalize_comments = true +normalize_doc_attributes = true +reorder_impl_items = true +group_imports = "StdExternalCrate" +use_field_init_shorthand = true +use_try_shorthand = true +wrap_comments = true diff --git a/rust-bindings/bls-dash-sys/Cargo.toml b/rust-bindings/bls-dash-sys/Cargo.toml new file mode 100644 index 0000000000..c5a04be4de --- /dev/null +++ b/rust-bindings/bls-dash-sys/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "bls-dash-sys" +description = "" +version = "1.2.5" +build = "build.rs" +edition = "2021" + +[features] +default = [] +apple = [] + +[build-dependencies] +cc = "1.0" +bindgen = "0.65.1" +glob ="0.3" diff --git a/rust-bindings/bls-dash-sys/bindings.rs b/rust-bindings/bls-dash-sys/bindings.rs new file mode 100644 index 0000000000..b90527e85f --- /dev/null +++ b/rust-bindings/bls-dash-sys/bindings.rs @@ -0,0 +1,435 @@ +pub type G1Element = *mut ::std::os::raw::c_void; +pub type G2Element = *mut ::std::os::raw::c_void; +pub type PrivateKey = *mut ::std::os::raw::c_void; +pub type CoreMPL = *mut ::std::os::raw::c_void; +pub type BasicSchemeMPL = CoreMPL; +pub type AugSchemeMPL = CoreMPL; +pub type PopSchemeMPL = CoreMPL; +pub type LegacySchemeMPL = CoreMPL; +pub type BIP32ExtendedPrivateKey = *mut ::std::os::raw::c_void; +pub type BIP32ExtendedPublicKey = *mut ::std::os::raw::c_void; +pub type BIP32ChainCode = *mut ::std::os::raw::c_void; + +extern "C" { + pub fn G1ElementSize() -> ::std::os::raw::c_int; + + pub fn G1ElementFromBytes( + data: *const ::std::os::raw::c_void, + legacy: bool, + didErr: *mut bool, + ) -> G1Element; + + pub fn G1ElementGenerator() -> G1Element; + + pub fn G1ElementIsValid(el: G1Element) -> bool; + + pub fn G1ElementGetFingerprint(el: G1Element, legacy: bool) -> u32; + + pub fn G1ElementIsEqual(el1: G1Element, el2: G1Element) -> bool; + + pub fn G1ElementAdd(el1: G1Element, el2: G1Element) -> G1Element; + + pub fn G1ElementMul(el: G1Element, sk: PrivateKey) -> G1Element; + + pub fn G1ElementNegate(el: G1Element) -> G1Element; + + pub fn G1ElementCopy(el: G1Element) -> G1Element; + + pub fn G1ElementSerialize(el: G1Element, legacy: bool) -> *mut ::std::os::raw::c_void; + + pub fn G1ElementFree(el: G1Element); + + pub fn G2ElementSize() -> ::std::os::raw::c_int; + + pub fn G2ElementFromBytes( + data: *const ::std::os::raw::c_void, + legacy: bool, + didErr: *mut bool, + ) -> G2Element; + + pub fn G2ElementGenerator() -> G2Element; + + pub fn G2ElementIsValid(el: G2Element) -> bool; + + pub fn G2ElementIsEqual(el1: G2Element, el2: G2Element) -> bool; + + pub fn G2ElementAdd(el1: G2Element, el2: G2Element) -> G2Element; + + pub fn G2ElementMul(el: G2Element, sk: PrivateKey) -> G2Element; + + pub fn G2ElementNegate(el: G2Element) -> G2Element; + + pub fn G2ElementCopy(el: G2Element) -> G2Element; + + pub fn G2ElementSerialize(el: G2Element, legacy: bool) -> *mut ::std::os::raw::c_void; + + pub fn G2ElementFree(el: G2Element); + + pub fn PrivateKeyFromBytes( + data: *const ::std::os::raw::c_void, + modOrder: bool, + didErr: *mut bool, + ) -> PrivateKey; + + pub fn PrivateKeyFromSeedBIP32(data: *const ::std::os::raw::c_void, len: usize) -> PrivateKey; + + pub fn PrivateKeyAggregate(sks: *mut *mut ::std::os::raw::c_void, len: usize) -> PrivateKey; + + pub fn PrivateKeyGetG1Element(sk: PrivateKey, didErr: *mut bool) -> G1Element; + + pub fn PrivateKeyGetG2Element(sk: PrivateKey, didErr: *mut bool) -> G2Element; + + pub fn PrivateKeyGetG2Power(sk: PrivateKey, el: G2Element) -> G2Element; + + pub fn PrivateKeyIsEqual(sk1: PrivateKey, sk2: PrivateKey) -> bool; + + pub fn PrivateKeySerialize(sk: PrivateKey) -> *mut ::std::os::raw::c_void; + + pub fn PrivateKeyFree(sk: PrivateKey); + + pub fn PrivateKeySizeBytes() -> usize; + + pub fn SecFree(p: *mut ::std::os::raw::c_void); + + pub fn AllocPtrArray(len: usize) -> *mut *mut ::std::os::raw::c_void; + + pub fn SetPtrArray( + arrPtr: *mut *mut ::std::os::raw::c_void, + elemPtr: *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ); + + pub fn FreePtrArray(inPtr: *mut *mut ::std::os::raw::c_void); + + pub fn GetPtrAtIndex( + arrPtr: *mut *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; + + pub fn SecAllocBytes(len: usize) -> *mut u8; + + pub fn GetAddressAtIndex( + ptr: *mut u8, + index: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; + + pub fn GetLastErrorMsg() -> *const ::std::os::raw::c_char; + + pub fn CoreMPLKeyGen( + scheme: CoreMPL, + seed: *const ::std::os::raw::c_void, + seedLen: usize, + didErr: *mut bool, + ) -> PrivateKey; + + pub fn CoreMPLSkToG1(scheme: CoreMPL, sk: PrivateKey) -> G1Element; + + pub fn CoreMPLSign( + scheme: CoreMPL, + sk: PrivateKey, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + ) -> G2Element; + + pub fn CoreMPLVerify( + scheme: BasicSchemeMPL, + pk: G1Element, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + sig: G2Element, + ) -> bool; + + pub fn CoreMPLVerifySecure( + scheme: CoreMPL, + pks: *mut *mut ::std::os::raw::c_void, + pksLen: usize, + sig: G2Element, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + ) -> bool; + + pub fn CoreMPLAggregatePubKeys( + scheme: CoreMPL, + pubKeys: *mut *mut ::std::os::raw::c_void, + pkLen: usize, + ) -> G1Element; + + pub fn CoreMPLAggregateSigs( + scheme: CoreMPL, + sigs: *mut *mut ::std::os::raw::c_void, + sigLen: usize, + ) -> G2Element; + + pub fn CoreMPLDeriveChildSk(scheme: CoreMPL, sk: PrivateKey, index: u32) -> PrivateKey; + + pub fn CoreMPLDeriveChildSkUnhardened( + scheme: CoreMPL, + sk: PrivateKey, + index: u32, + ) -> PrivateKey; + + pub fn CoreMPLDeriveChildPkUnhardened(scheme: CoreMPL, sk: G1Element, index: u32) -> G1Element; + + pub fn CoreMPLAggregateVerify( + scheme: CoreMPL, + pks: *mut *mut ::std::os::raw::c_void, + pkLen: usize, + msgs: *mut *mut ::std::os::raw::c_void, + msgLens: *const ::std::os::raw::c_void, + msgLen: usize, + sig: G2Element, + ) -> bool; + + pub fn NewBasicSchemeMPL() -> BasicSchemeMPL; + + pub fn BasicSchemeMPLAggregateVerify( + scheme: BasicSchemeMPL, + pks: *mut *mut ::std::os::raw::c_void, + pksLen: usize, + msgs: *mut *mut ::std::os::raw::c_void, + msgsLens: *const ::std::os::raw::c_void, + msgsLen: usize, + sig: G2Element, + ) -> bool; + + pub fn BasicSchemeMPLFree(scheme: BasicSchemeMPL); + + pub fn NewAugSchemeMPL() -> AugSchemeMPL; + + pub fn AugSchemeMPLSign( + scheme: AugSchemeMPL, + sk: PrivateKey, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + ) -> G2Element; + + pub fn AugSchemeMPLSignPrepend( + scheme: AugSchemeMPL, + sk: PrivateKey, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + prepPk: G1Element, + ) -> G2Element; + + pub fn AugSchemeMPLVerify( + scheme: AugSchemeMPL, + pk: G1Element, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + sig: G2Element, + ) -> bool; + + pub fn AugSchemeMPLAggregateVerify( + scheme: AugSchemeMPL, + pks: *mut *mut ::std::os::raw::c_void, + pksLen: usize, + msgs: *mut *mut ::std::os::raw::c_void, + msgsLens: *const ::std::os::raw::c_void, + msgsLen: usize, + sig: G2Element, + ) -> bool; + + pub fn AugSchemeMPLFree(scheme: AugSchemeMPL); + + pub fn NewPopSchemeMPL() -> PopSchemeMPL; + + pub fn PopSchemeMPLPopProve(scheme: PopSchemeMPL, sk: PrivateKey) -> G2Element; + + pub fn PopSchemeMPLPopVerify(scheme: PopSchemeMPL, pk: G1Element, sig: G2Element) -> bool; + + pub fn PopSchemeMPLFastAggregateVerify( + scheme: PopSchemeMPL, + pks: *mut *mut ::std::os::raw::c_void, + pksLen: usize, + msgs: *const ::std::os::raw::c_void, + msgsLen: usize, + sig: G2Element, + ) -> bool; + + pub fn PopSchemeMPLFree(scheme: PopSchemeMPL); + + pub fn NewLegacySchemeMPL() -> LegacySchemeMPL; + + pub fn LegacySchemeMPLSign( + scheme: LegacySchemeMPL, + sk: PrivateKey, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + ) -> G2Element; + + pub fn LegacySchemeMPLSignPrepend( + scheme: LegacySchemeMPL, + sk: PrivateKey, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + prepPk: G1Element, + ) -> G2Element; + + pub fn LegacySchemeMPLVerify( + scheme: LegacySchemeMPL, + pk: G1Element, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + sig: G2Element, + ) -> bool; + + pub fn LegacySchemeMPLVerifySecure( + scheme: LegacySchemeMPL, + pks: *mut *mut ::std::os::raw::c_void, + pksLen: usize, + sig: G2Element, + msg: *const ::std::os::raw::c_void, + msgLen: usize, + ) -> bool; + + pub fn LegacySchemeMPLAggregateVerify( + scheme: LegacySchemeMPL, + pks: *mut *mut ::std::os::raw::c_void, + pksLen: usize, + msgs: *mut *mut ::std::os::raw::c_void, + msgsLens: *const ::std::os::raw::c_void, + msgsLen: usize, + sig: G2Element, + ) -> bool; + + pub fn LegacySchemeMPLFree(scheme: LegacySchemeMPL); + + pub fn ThresholdPrivateKeyShare( + sks: *mut *mut ::std::os::raw::c_void, + sksLen: usize, + hash: *const ::std::os::raw::c_void, + didErr: *mut bool, + ) -> PrivateKey; + + pub fn ThresholdPrivateKeyRecover( + sks: *mut *mut ::std::os::raw::c_void, + sksLen: usize, + hashes: *mut *mut ::std::os::raw::c_void, + hashesLen: usize, + didErr: *mut bool, + ) -> PrivateKey; + + pub fn ThresholdPublicKeyShare( + pks: *mut *mut ::std::os::raw::c_void, + pksLen: usize, + hash: *const ::std::os::raw::c_void, + didErr: *mut bool, + ) -> G1Element; + + pub fn ThresholdPublicKeyRecover( + pks: *mut *mut ::std::os::raw::c_void, + pksLen: usize, + hashes: *mut *mut ::std::os::raw::c_void, + hashesLen: usize, + didErr: *mut bool, + ) -> G1Element; + + pub fn ThresholdSignatureShare( + sigs: *mut *mut ::std::os::raw::c_void, + sigsLen: usize, + hash: *const ::std::os::raw::c_void, + didErr: *mut bool, + ) -> G2Element; + + pub fn ThresholdSignatureRecover( + sigs: *mut *mut ::std::os::raw::c_void, + sigsLen: usize, + hashes: *mut *mut ::std::os::raw::c_void, + hashesLen: usize, + didErr: *mut bool, + ) -> G2Element; + + pub fn ThresholdSign(sk: PrivateKey, hash: *const ::std::os::raw::c_void) -> G2Element; + + pub fn ThresholdVerify( + pk: G1Element, + hash: *const ::std::os::raw::c_void, + sig: G2Element, + ) -> bool; + + pub fn BIP32ChainCodeSerialize(cc: BIP32ChainCode) -> *mut ::std::os::raw::c_void; + + pub fn BIP32ChainCodeIsEqual(cc1: BIP32ChainCode, cc2: BIP32ChainCode) -> bool; + + pub fn BIP32ChainCodeFree(cc: BIP32ChainCode); + + pub fn BIP32ExtendedPublicKeyFromBytes( + data: *const ::std::os::raw::c_void, + legacy: bool, + didErr: *mut bool, + ) -> BIP32ExtendedPublicKey; + + pub fn BIP32ExtendedPublicKeyPublicChild( + pk: BIP32ExtendedPublicKey, + index: u32, + legacy: bool, + ) -> BIP32ExtendedPublicKey; + + pub fn BIP32ExtendedPublicKeyGetChainCode(pk: BIP32ExtendedPublicKey) -> BIP32ChainCode; + + pub fn BIP32ExtendedPublicKeySerialize( + pk: BIP32ExtendedPublicKey, + legacy: bool, + ) -> *mut ::std::os::raw::c_void; + + pub fn BIP32ExtendedPublicKeyIsEqual( + pk1: BIP32ExtendedPublicKey, + pk2: BIP32ExtendedPublicKey, + ) -> bool; + + pub fn BIP32ExtendedPublicKeyGetPublicKey( + pk: BIP32ExtendedPublicKey, + ) -> *mut ::std::os::raw::c_void; + + pub fn BIP32ExtendedPublicKeyFree(pk: BIP32ExtendedPublicKey); + + pub fn BIP32ExtendedPrivateKeyFromBytes( + data: *const ::std::os::raw::c_void, + didErr: *mut bool, + ) -> BIP32ExtendedPrivateKey; + + pub fn BIP32ExtendedPrivateKeyFromSeed( + data: *const ::std::os::raw::c_void, + len: usize, + didErr: *mut bool, + ) -> BIP32ExtendedPrivateKey; + + pub fn BIP32ExtendedPrivateKeyPrivateChild( + sk: BIP32ExtendedPrivateKey, + index: u32, + legacy: bool, + ) -> BIP32ExtendedPrivateKey; + + pub fn BIP32ExtendedPrivateKeyPublicChild( + sk: BIP32ExtendedPrivateKey, + index: u32, + ) -> BIP32ExtendedPublicKey; + + pub fn BIP32ExtendedPrivateKeyGetChainCode(sk: BIP32ExtendedPrivateKey) -> BIP32ChainCode; + + pub fn BIP32ExtendedPrivateKeySerialize( + sk: BIP32ExtendedPrivateKey, + ) -> *mut ::std::os::raw::c_void; + + pub fn BIP32ExtendedPrivateKeyIsEqual( + sk1: BIP32ExtendedPrivateKey, + sk2: BIP32ExtendedPrivateKey, + ) -> bool; + + pub fn BIP32ExtendedPrivateKeyGetPrivateKey( + sk: BIP32ExtendedPrivateKey, + ) -> *mut ::std::os::raw::c_void; + + pub fn BIP32ExtendedPrivateKeyGetExtendedPublicKey( + sk: BIP32ExtendedPrivateKey, + legacy: bool, + didErr: *mut bool, + ) -> BIP32ExtendedPublicKey; + + pub fn BIP32ExtendedPrivateKeyGetPublicKey( + sk: BIP32ExtendedPrivateKey, + didErr: *mut bool, + ) -> *mut ::std::os::raw::c_void; + + pub fn BIP32ExtendedPrivateKeyFree(sk: BIP32ExtendedPrivateKey); +} diff --git a/rust-bindings/bls-dash-sys/build.rs b/rust-bindings/bls-dash-sys/build.rs new file mode 100644 index 0000000000..cc7cdd2d44 --- /dev/null +++ b/rust-bindings/bls-dash-sys/build.rs @@ -0,0 +1,374 @@ +use std::{env, fs, io, io::Write, path::{Path, PathBuf}, process::{Command, Output}}; + +#[cfg(not(feature = "apple"))] +fn create_cross_cmake_command() -> Command { + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + + let mut command = if target_arch.eq("wasm32") { + Command::new("emcmake") + } else { + Command::new("cmake") + }; + + if target_arch.eq("wasm32") { + command.arg("cmake"); + } + + command +} + +fn handle_command_output(output: Output) { + io::stdout() + .write_all(&output.stdout) + .expect("should write output"); + + io::stderr() + .write_all(&output.stderr) + .expect("should write output"); + + assert!(output.status.success()); +} + +#[cfg(not(feature = "apple"))] +fn main() { + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + + // TODO: fix build for wasm32 on MacOS + // errors with `error: linking with `rust-lld` failed: exit status: 1` + if target_arch.eq("wasm32") { + println!("Build for wasm32 is not fully supported"); + return; + } + + let root_path = Path::new("../..") + .canonicalize() + .expect("can't get abs path"); + + let bls_dash_build_path = root_path.join("build"); + let bls_dash_src_path = root_path.join("src"); + let c_bindings_path = root_path.join("rust-bindings/bls-dash-sys/c-bindings"); + + println!("root {}", root_path.display()); + println!("bls_dash_build_path {}", bls_dash_build_path.display()); + println!("bls_dash_src_path {}", bls_dash_src_path.display()); + // println!("c_bindings_path {}", c_bindings_path.display()); + + // Run cmake + + println!("Run cmake:"); + + if bls_dash_build_path.exists() { + fs::remove_dir_all(&bls_dash_build_path).expect("can't clean build directory"); + } + + fs::create_dir_all(&bls_dash_build_path).expect("can't create build directory"); + + let cmake_output = create_cross_cmake_command() + .current_dir(&bls_dash_build_path) + .arg("-DBUILD_BLS_PYTHON_BINDINGS=0") + .arg("-DBUILD_BLS_TESTS=0") + .arg("-DBUILD_BLS_BENCHMARKS=0") + .arg("-DBUILD_BLS_JS_BINDINGS=0") + .arg("..") + .output() + .expect("can't run cmake"); + + handle_command_output(cmake_output); + + // Build deps for bls-signatures + + println!("Build dependencies:"); + + let build_output = Command::new("cmake") + .args(["--build", ".", "--", "-j", "6"]) + .current_dir(&bls_dash_build_path) + .output() + .expect("can't build bls-signatures deps"); + + handle_command_output(build_output); + + // Collect include paths + let include_paths_file_path = bls_dash_build_path.join("include_paths.txt"); + + let include_paths = + fs::read_to_string(include_paths_file_path).expect("should read include paths from file"); + + let mut include_paths: Vec<_> = include_paths + .split(';') + .filter(|path| !path.is_empty()) + .map(|path| PathBuf::from(path)) + .collect(); + + include_paths.extend([ + bls_dash_build_path.join("_deps/relic-src/include"), + bls_dash_build_path.join("_deps/relic-build/include"), + bls_dash_build_path.join("src"), + root_path.join("include/dashbls"), + bls_dash_build_path.join("depends/relic/include"), + bls_dash_build_path.join("depends/mimalloc/include"), + root_path.join("depends/relic/include"), + root_path.join("depends/mimalloc/include"), + bls_dash_src_path.clone(), + ]); + + // Build c binding + + println!("Build C binding:"); + + let mut cc = cc::Build::new(); + + let cpp_files_mask = c_bindings_path.join("**/*.cpp"); + + let cpp_files: Vec<_> = glob::glob(cpp_files_mask.to_str().unwrap()) + .expect("can't get list of cpp files") + .filter_map(Result::ok) + .collect(); + + cc.files(cpp_files) + .includes(&include_paths) + .cpp(true) + .flag_if_supported("-std=c++14"); + + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + + // Fix homebrew LLVM installation issue + if env::consts::OS == "macos" && target_arch == "wasm32" { + cc.archiver("llvm-ar"); + } + + if target_arch.eq("wasm32") { + cc.flag_if_supported("-ffreestanding") + .define("_LIBCPP_HAS_NO_THREADS", Some("1")); + } + + if !cfg!(debug_assertions) { + cc.opt_level(2); + } + + cc.compile("bls-dash-sys"); + + // // Link dependencies + // println!( + // "cargo:rustc-link-search={}", + // bls_dash_build_path.join("_deps/sodium-build").display() + // ); + + // println!("cargo:rustc-link-lib=static=sodium"); + + println!( + "cargo:rustc-link-search={}", + root_path.join("build/depends/relic/lib").display() + ); + + println!("cargo:rustc-link-lib=static=relic_s"); + + println!( + "cargo:rustc-link-search={}", + root_path.join("build/depends/mimalloc").display() + ); + + println!("cargo:rustc-link-lib=static=mimalloc-secure"); + + println!( + "cargo:rustc-link-search={}", + bls_dash_build_path.join("src").display() + ); + + println!("cargo:rustc-link-lib=static=dashbls"); + + // Link GMP if exists + let gmp_libraries_file_path = bls_dash_build_path.join("gmp_libraries.txt"); + + if gmp_libraries_file_path.exists() { + let gmp_libraries_path = PathBuf::from( + fs::read_to_string(gmp_libraries_file_path) + .expect("should read gmp includes from file"), + ); + + let gmp_libraries_parent_path = gmp_libraries_path + .parent() + .expect("can't get gmp libraries parent dir"); + + println!( + "cargo:rustc-link-search={}", + gmp_libraries_parent_path.display() + ); + + println!("cargo:rustc-link-lib=static=gmp"); + } + + // Generate rust code for c binding to src/lib.rs + // println!("Generate C binding for rust:"); + + // let mut builder = bindgen::Builder::default() + // // .trust_clang_mangling(true) + // // .wasm_import_module_name() + // .size_t_is_usize(true) + // .parse_callbacks(Box::new(bindgen::CargoCallbacks)); + + // let headers_to_process = [ + // "blschia.h", + // "elements.h", + // "privatekey.h", + // "schemes.h", + // "threshold.h", + // "bip32/chaincode.h", + // "bip32/extendedprivatekey.h", + // "bip32/extendedpublickey.h", + // ]; + + // for header in headers_to_process { + // builder = builder.header(c_bindings_path.join(header).to_str().unwrap()) + // } + + // if target_arch == "wasm32" { + // builder = builder.clang_args( + // include_paths + // .iter() + // .map(|path| format!("-I{}", path.display())), + // ); + // } + + // let bindings = builder.generate().expect("Unable to generate bindings"); + + // let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + + // bindings + // .write_to_file(out_path.join("bindings.rs")) + // .expect("couldn't write bindings"); + + // // Rerun build if files changed + // println!("cargo:rerun-if-changed={}", c_bindings_path.display()); + println!("cargo:rerun-if-changed={}", bls_dash_src_path.display()); +} + +// fn main() { +// let target = env::var("TARGET").unwrap(); +// println!("Building bls-signatures for apple target: {}", target); +// let root_path = Path::new("../..") +// .canonicalize() +// .expect("can't get abs path"); +// let bls_dash_build_path = root_path.join("build"); +// let bls_dash_src_path = root_path.join("src"); +// let artefacts_path = bls_dash_build_path.join("artefacts"); +// let target_path = artefacts_path.join(&target); +// let script = root_path.join("apple.rust.single.sh"); +// if bls_dash_build_path.exists() { +// fs::remove_dir_all(&bls_dash_build_path).expect("can't clean build directory"); +// } +// fs::create_dir_all(&bls_dash_build_path).expect("can't create build directory"); +// let output = Command::new("sh") +// .current_dir(&root_path) +// .arg(script) +// .arg(target) +// .output() +// .expect("Failed to execute the shell script"); +// handle_command_output(output); +// let library_path = target_path.join("libbls.a"); +// if !fs::metadata(&library_path).is_ok() { +// panic!("Library file not found: {}", library_path.display()); +// } +// println!("cargo:rustc-link-search={}", target_path.display()); +// println!("cargo:rustc-link-lib=static=gmp"); +// println!("cargo:rustc-link-lib=static=sodium"); +// println!("cargo:rustc-link-lib=static=relic_s"); +// println!("cargo:rustc-link-search={}", bls_dash_build_path.join("src").display()); +// println!("cargo:rustc-link-lib=static=bls"); +// println!("cargo:rerun-if-changed={}", bls_dash_src_path.display()); +// } + +#[cfg(feature = "apple")] +fn main() { + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + + // TODO: fix build for wasm32 on MacOS + // errors with `error: linking with `rust-lld` failed: exit status: 1` + if target_arch.eq("wasm32") { + println!("Build for wasm32 is not fully supported"); + return; + } + + + let target = env::var("TARGET").unwrap(); + println!("Building bls-signatures for apple target: {}", target); + let root_path = Path::new("../..") + .canonicalize() + .expect("can't get abs path"); + let bls_dash_build_path = root_path.join("build"); + let bls_dash_src_path = root_path.join("src"); + let bls_dash_src_include_path = root_path.join("include/dashbls"); + let c_bindings_path = root_path.join("rust-bindings/bls-dash-sys/c-bindings"); + let artefacts_path = bls_dash_build_path.join("artefacts"); + let target_path = artefacts_path.join(&target); + let script = root_path.join("apple.rust.deps.sh"); + if bls_dash_build_path.exists() { + fs::remove_dir_all(&bls_dash_build_path).expect("can't clean build directory"); + } + fs::create_dir_all(&bls_dash_build_path).expect("can't create build directory"); + let output = Command::new("sh") + .current_dir(&root_path) + .arg(script) + .arg(target.as_str()) + .output() + .expect("Failed to execute the shell script"); + handle_command_output(output); + let (arch, platform) = match target.as_str() { + "x86_64-apple-ios" => ("x86_64", "iphonesimulator"), + "aarch64-apple-ios" => ("arm64", "iphoneos"), + "aarch64-apple-ios-sim" => ("arm64", "iphonesimulator"), + "x86_64-apple-darwin" => ("x86_64", "macosx"), + "aarch64-apple-darwin" => ("arm64", "macosx"), + _ => panic!("Target {} not supported", target.as_str()) + }; + env::set_var("IPHONEOS_DEPLOYMENT_TARGET", "13.0"); + + // Collect include paths + let include_paths_file_path = bls_dash_build_path.join("include_paths.txt"); + + let include_paths = + fs::read_to_string(include_paths_file_path).expect("should read include paths from file"); + + let mut include_paths: Vec<_> = include_paths + .split(';') + .filter(|path| !path.is_empty()) + .map(|path| PathBuf::from(path)) + .collect(); + + include_paths.extend([ + bls_dash_build_path.join(format!("relic-{}-{}/_deps/relic-src/include", platform, arch)), + bls_dash_build_path.join(format!("relic-{}-{}/_deps/relic-build/include", platform, arch)), + bls_dash_build_path.join("contrib/relic/src"), + root_path.join("src"), + root_path.join("include/dashbls"), + root_path.join("depends/relic/include"), + root_path.join("depends/mimalloc/include"), + root_path.join("depends/catch2/include"), + bls_dash_src_path.clone(), + bls_dash_src_include_path.clone() + ]); + + let cpp_files: Vec<_> = glob::glob(c_bindings_path.join("**/*.cpp").to_str().unwrap()) + .expect("can't get list of cpp files") + .filter_map(Result::ok) + .collect(); + + let mut cc = cc::Build::new(); + cc.files(cpp_files) + .includes(&include_paths) + .cpp(true) + .flag("-Wno-unused-parameter") + .flag("-Wno-sign-compare") + .flag("-Wno-delete-non-abstract-non-virtual-dtor") + .flag("-std=c++14"); + + cc.compile("dashbls"); + + println!("cargo:rustc-link-search={}", target_path.display()); + println!("cargo:rustc-link-lib=static=gmp"); + // println!("cargo:rustc-link-lib=static=sodium"); + // println!("cargo:rustc-link-lib=static=relic_s"); + println!("cargo:rustc-link-lib=static=bls"); + println!("cargo:rustc-link-search={}", bls_dash_src_path.display()); + println!("cargo:rustc-link-lib=static=dashbls"); + println!("cargo:rerun-if-changed={}", bls_dash_src_path.display()); +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.cpp b/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.cpp new file mode 100644 index 0000000000..177c4d7371 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.cpp @@ -0,0 +1,25 @@ +#include +#include "bls.hpp" +#include "chaincode.h" + +void* BIP32ChainCodeSerialize(const BIP32ChainCode cc) +{ + const bls::ChainCode* ccPtr = (bls::ChainCode*)cc; + const std::vector serialized = ccPtr->Serialize(); + uint8_t* buffer = (uint8_t*)malloc(bls::ChainCode::SIZE); + memcpy(buffer, serialized.data(), bls::ChainCode::SIZE); + return (void*)buffer; +} + +bool BIP32ChainCodeIsEqual(const BIP32ChainCode cc1, const BIP32ChainCode cc2) +{ + const bls::ChainCode* cc1Ptr = (bls::ChainCode*)cc1; + const bls::ChainCode* cc2Ptr = (bls::ChainCode*)cc2; + return *cc1Ptr == *cc2Ptr; +} + +void BIP32ChainCodeFree(const BIP32ChainCode cc) +{ + const bls::ChainCode* ccPtr = (bls::ChainCode*)cc; + delete ccPtr; +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.h b/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.h new file mode 100644 index 0000000000..688cf3f51e --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.h @@ -0,0 +1,21 @@ +#ifndef BIP32CHAINCODE_H_ +#define BIP32CHAINCODE_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* BIP32ChainCode; + +void* BIP32ChainCodeSerialize(const BIP32ChainCode cc); +bool BIP32ChainCodeIsEqual(const BIP32ChainCode cc1, const BIP32ChainCode cc2); +void BIP32ChainCodeFree(const BIP32ChainCode cc); + +#ifdef __cplusplus +} +#endif +#endif // BIP32CHAINCODE_H_ \ No newline at end of file diff --git a/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.cpp b/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.cpp new file mode 100644 index 0000000000..541f5f992c --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.cpp @@ -0,0 +1,128 @@ +#include "extendedprivatekey.h" + +#include + +#include "../blschia.h" +#include "../error.h" +#include "bls.hpp" + +BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromBytes(const void* data, bool* didErr) +{ + bls::ExtendedPrivateKey* el = nullptr; + try { + el = new bls::ExtendedPrivateKey(bls::ExtendedPrivateKey::FromBytes( + bls::Bytes((uint8_t*)(data), bls::ExtendedPrivateKey::SIZE))); + } catch (const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return el; +} + +BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromSeed(const void* data, const size_t len, bool* didErr) +{ + bls::ExtendedPrivateKey* el = nullptr; + try { + el = new bls::ExtendedPrivateKey(bls::ExtendedPrivateKey::FromSeed( + bls::Bytes((uint8_t*)(data), len))); + } catch (const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return el; +} + +BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyPrivateChild( + const BIP32ExtendedPrivateKey sk, + const uint32_t index, + const bool legacy) +{ + const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk; + return new bls::ExtendedPrivateKey(skPtr->PrivateChild(index, legacy)); +} + +BIP32ExtendedPublicKey BIP32ExtendedPrivateKeyPublicChild( + const BIP32ExtendedPrivateKey sk, + const uint32_t index) +{ + const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk; + return new bls::ExtendedPublicKey(skPtr->PublicChild(index)); +} + +BIP32ChainCode BIP32ExtendedPrivateKeyGetChainCode(const BIP32ExtendedPrivateKey sk) +{ + const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk; + return new bls::ChainCode(skPtr->GetChainCode()); +} + +void* BIP32ExtendedPrivateKeySerialize(const BIP32ExtendedPrivateKey sk) +{ + const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk; + uint8_t* buffer = + bls::Util::SecAlloc(bls::ExtendedPrivateKey::SIZE); + skPtr->Serialize(buffer); + + return (void*)buffer; +} + +bool BIP32ExtendedPrivateKeyIsEqual( + const BIP32ExtendedPrivateKey sk1, + const BIP32ExtendedPrivateKey sk2) +{ + const bls::ExtendedPrivateKey* sk1Ptr = (bls::ExtendedPrivateKey*)sk1; + const bls::ExtendedPrivateKey* sk2Ptr = (bls::ExtendedPrivateKey*)sk2; + return *sk1Ptr == *sk2Ptr; +} + +void* BIP32ExtendedPrivateKeyGetPrivateKey(const BIP32ExtendedPrivateKey sk) +{ + bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk; + return new bls::PrivateKey(skPtr->GetPrivateKey()); +} + +void* BIP32ExtendedPrivateKeyGetPublicKey( + const BIP32ExtendedPrivateKey sk, + bool* didErr) +{ + bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk; + bls::G1Element* el = nullptr; + try { + el = new bls::G1Element(skPtr->GetPublicKey()); + *didErr = false; + } catch (const std::exception& ex) { + // set err + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + return el; +} + +BIP32ExtendedPublicKey BIP32ExtendedPrivateKeyGetExtendedPublicKey( + const BIP32ExtendedPrivateKey sk, + const bool legacy, + bool* didErr) +{ + bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk; + bls::ExtendedPublicKey* pk = nullptr; + try { + pk = new bls::ExtendedPublicKey(skPtr->GetExtendedPublicKey(legacy)); + *didErr = false; + } catch (const std::exception& ex) { + // set err + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + return pk; +} + +void BIP32ExtendedPrivateKeyFree(const BIP32ExtendedPrivateKey sk) +{ + const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk; + delete skPtr; +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.h b/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.h new file mode 100644 index 0000000000..18ca3c28f3 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.h @@ -0,0 +1,48 @@ +#ifndef BIP32EXTENDEDPRIVATEKEY_H_ +#define BIP32EXTENDEDPRIVATEKEY_H_ + +#include +#include +#include + +#include "extendedpublickey.h" +#include "chaincode.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* BIP32ExtendedPrivateKey; + +// ExtendedPrivateKey +BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromBytes( + const void* data, + bool* didErr); +BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromSeed(const void* data, const size_t len, bool* didErr); +BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyPrivateChild( + const BIP32ExtendedPrivateKey sk, + const uint32_t index, + const bool legacy); +BIP32ExtendedPublicKey BIP32ExtendedPrivateKeyPublicChild( + const BIP32ExtendedPrivateKey sk, + const uint32_t index); +BIP32ChainCode BIP32ExtendedPrivateKeyGetChainCode(const BIP32ExtendedPrivateKey sk); +void* BIP32ExtendedPrivateKeySerialize(const BIP32ExtendedPrivateKey sk); +bool BIP32ExtendedPrivateKeyIsEqual( + const BIP32ExtendedPrivateKey sk1, + const BIP32ExtendedPrivateKey sk2); +void* BIP32ExtendedPrivateKeyGetPrivateKey(const BIP32ExtendedPrivateKey sk); +BIP32ExtendedPublicKey BIP32ExtendedPrivateKeyGetExtendedPublicKey( + const BIP32ExtendedPrivateKey sk, + const bool legacy, + bool* didErr); +void* BIP32ExtendedPrivateKeyGetPublicKey( + const BIP32ExtendedPrivateKey sk, + bool* didErr); +void BIP32ExtendedPrivateKeyFree(const BIP32ExtendedPrivateKey sk); + +#ifdef __cplusplus +} +#endif +#endif // BIP32EXTENDEDPRIVATEKEY_H_ diff --git a/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.cpp b/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.cpp new file mode 100644 index 0000000000..703c32e021 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.cpp @@ -0,0 +1,72 @@ +#include "extendedpublickey.h" + +#include + +#include "../blschia.h" +#include "../error.h" +#include "bls.hpp" + +BIP32ExtendedPublicKey BIP32ExtendedPublicKeyFromBytes( + const void* data, + const bool legacy, + bool* didErr) +{ + bls::ExtendedPublicKey* el = nullptr; + try { + el = new bls::ExtendedPublicKey(bls::ExtendedPublicKey::FromBytes( + bls::Bytes((uint8_t*)(data), bls::ExtendedPublicKey::SIZE), + legacy)); + } catch (const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return el; +} + +BIP32ExtendedPublicKey BIP32ExtendedPublicKeyPublicChild( + const BIP32ExtendedPublicKey pk, + const uint32_t index, + const bool legacy) +{ + const bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk; + return new bls::ExtendedPublicKey(pkPtr->PublicChild(index, legacy)); +} + +BIP32ChainCode BIP32ExtendedPublicKeyGetChainCode(const BIP32ExtendedPublicKey pk) +{ + const bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk; + return new bls::ChainCode(pkPtr->GetChainCode()); +} + +void* BIP32ExtendedPublicKeyGetPublicKey(const BIP32ExtendedPublicKey pk) { + bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk; + return new bls::G1Element(pkPtr->GetPublicKey()); +} + +void* BIP32ExtendedPublicKeySerialize( + const BIP32ExtendedPublicKey pk, + const bool legacy) +{ + const bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk; + const std::vector serialized = pkPtr->Serialize(legacy); + uint8_t* buffer = (uint8_t*)malloc(bls::ExtendedPublicKey::SIZE); + memcpy(buffer, serialized.data(), bls::ExtendedPublicKey::SIZE); + return (void*)buffer; +} + +bool BIP32ExtendedPublicKeyIsEqual( + const BIP32ExtendedPublicKey pk1, + const BIP32ExtendedPublicKey pk2) +{ + const bls::ExtendedPublicKey* pk1Ptr = (bls::ExtendedPublicKey*)pk1; + const bls::ExtendedPublicKey* pk2Ptr = (bls::ExtendedPublicKey*)pk2; + return *pk1Ptr == *pk2Ptr; +} + +void BIP32ExtendedPublicKeyFree(const BIP32ExtendedPublicKey pk) +{ + const bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk; + delete pkPtr; +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.h b/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.h new file mode 100644 index 0000000000..51465cae03 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.h @@ -0,0 +1,38 @@ +#ifndef BIP32EXTENDEDPUBLICKEY_H_ +#define BIP32EXTENDEDPUBLICKEY_H_ + +#include +#include +#include + +#include "chaincode.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* BIP32ExtendedPublicKey; + +// ExtendedPublicKey +BIP32ExtendedPublicKey BIP32ExtendedPublicKeyFromBytes( + const void* data, + const bool legacy, + bool* didErr); +BIP32ExtendedPublicKey BIP32ExtendedPublicKeyPublicChild( + const BIP32ExtendedPublicKey pk, + const uint32_t index, + const bool legacy); +BIP32ChainCode BIP32ExtendedPublicKeyGetChainCode(const BIP32ExtendedPublicKey pk); +void* BIP32ExtendedPublicKeyGetPublicKey(const BIP32ExtendedPublicKey pk); +void* BIP32ExtendedPublicKeySerialize( + const BIP32ExtendedPublicKey pk, + const bool legacy); +bool BIP32ExtendedPublicKeyIsEqual( + const BIP32ExtendedPublicKey pk1, + const BIP32ExtendedPublicKey pk2); +void BIP32ExtendedPublicKeyFree(const BIP32ExtendedPublicKey pk); + +#ifdef __cplusplus +} +#endif +#endif // BIP32EXTENDEDPUBLICKEY_H_ diff --git a/rust-bindings/bls-dash-sys/c-bindings/blschia.cpp b/rust-bindings/bls-dash-sys/c-bindings/blschia.cpp new file mode 100644 index 0000000000..2b3c274dc4 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/blschia.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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 "bls.hpp" +#include "error.h" +#include "blschia.h" + +// TODO: Revisit + +std::string gErrMsg; + +void SecFree(void *p) { + bls::Util::SecFree(p); +} + +void** AllocPtrArray(size_t len) { + // caller to free + return (void**)bls::Util::SecAlloc(sizeof(void*) * len); +} + +void SetPtrArray(void** arrPtr, void* elemPtr, int index) { + arrPtr[index] = elemPtr; +} + +void FreePtrArray(void** inPtr) { + bls::Util::SecFree(inPtr); +} + +void* GetPtrAtIndex(void** arrPtr, int index) { + return arrPtr[index]; +} + +uint8_t* SecAllocBytes(size_t len) { + return (uint8_t*)bls::Util::SecAlloc(sizeof(uint8_t) * len); +} + +void* GetAddressAtIndex(uint8_t* ptr, int index) { + return (void*)&ptr[index]; +} + +const char* GetLastErrorMsg() { + return gErrMsg.c_str(); +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/blschia.h b/rust-bindings/bls-dash-sys/c-bindings/blschia.h new file mode 100644 index 0000000000..ebc3b518dc --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/blschia.h @@ -0,0 +1,46 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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. + +#ifndef BLSCHIA_H_ +#define BLSCHIA_H_ +#include +#include +#include "privatekey.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Export the BLS SecFree method +void SecFree(void *p); + +typedef void** carr; + +// Additional C++ helper funcs for allocations +void** AllocPtrArray(size_t len); +void SetPtrArray(void **arrPtr, void *elemPtr, int index); +void FreePtrArray(void **inPtr); +void* GetPtrAtIndex(void **arrPtr, int index); + +// Allocates an array of bytes with size of passed in len argument +uint8_t* SecAllocBytes(size_t len); + +void* GetAddressAtIndex(uint8_t *ptr, int index); + +const char* GetLastErrorMsg(); + +#ifdef __cplusplus +} +#endif +#endif // BLSCHIA_H_ diff --git a/rust-bindings/bls-dash-sys/c-bindings/elements.cpp b/rust-bindings/bls-dash-sys/c-bindings/elements.cpp new file mode 100644 index 0000000000..5214bc4fc9 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/elements.cpp @@ -0,0 +1,162 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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 "bls.hpp" +#include "blschia.h" +#include "error.h" +#include "elements.h" + +// G1Element +int G1ElementSize() { + return bls::G1Element::SIZE; +} + +G1Element G1ElementFromBytes(const void* data, bool legacy, bool* didErr) { + bls::G1Element* el = nullptr; + try { + el = new bls::G1Element( + bls::G1Element::FromBytes(bls::Bytes((uint8_t*)(data), bls::G1Element::SIZE), legacy) + ); + } catch(const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return el; +} + +G1Element G1ElementGenerator() { + return new bls::G1Element(bls::G1Element::Generator()); +} + +bool G1ElementIsValid(const G1Element el) { + const bls::G1Element* elPtr = (bls::G1Element*)el; + return elPtr->IsValid(); +} + +uint32_t G1ElementGetFingerprint(const G1Element el, const bool legacy) { + const bls::G1Element* elPtr = (bls::G1Element*)el; + return elPtr->GetFingerprint(legacy); +} + +void* G1ElementSerialize(const G1Element el, const bool legacy) { + const bls::G1Element* elPtr = (bls::G1Element*)el; + const std::vector serialized = elPtr->Serialize(legacy); + uint8_t* buffer = (uint8_t*)malloc(bls::G1Element::SIZE); + memcpy(buffer, serialized.data(), bls::G1Element::SIZE); + return (void*)buffer; +} + +bool G1ElementIsEqual(const G1Element el1, const G1Element el2) { + const bls::G1Element* el1Ptr = (bls::G1Element*)el1; + const bls::G1Element* el2Ptr = (bls::G1Element*)el2; + return *el1Ptr == *el2Ptr; +} + +G1Element G1ElementAdd(const G1Element el1, const G1Element el2) { + const bls::G1Element* el1Ptr = (bls::G1Element*)el1; + const bls::G1Element* el2Ptr = (bls::G1Element*)el2; + return new bls::G1Element((*el1Ptr) + (*el2Ptr)); +} + +G1Element G1ElementMul(const G1Element el, const PrivateKey sk) { + const bls::G1Element* elPtr = (bls::G1Element*)el; + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::G1Element(*elPtr * *skPtr); +} + +G1Element G1ElementNegate(const G1Element el) { + const bls::G1Element* elPtr = (bls::G1Element*)el; + return new bls::G1Element(elPtr->Negate()); +} + +G1Element G1ElementCopy(const G1Element el) { + return new bls::G1Element(((bls::G1Element*)el)->Copy()); +} + +void G1ElementFree(const G1Element el) { + const bls::G1Element* elPtr = (bls::G1Element*)el; + delete elPtr; +} + +// G2Element +int G2ElementSize() { + return bls::G2Element::SIZE; +} + +G2Element G2ElementFromBytes(const void* data, const bool legacy, bool* didErr) { + bls::G2Element* el = nullptr; + try { + el = new bls::G2Element( + bls::G2Element::FromBytes(bls::Bytes((uint8_t*)data, bls::G2Element::SIZE), legacy) + ); + *didErr = false; + } catch(const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + return el; +} + +G2Element G2ElementGenerator() { + return new bls::G2Element(bls::G2Element::Generator()); +} + +bool G2ElementIsValid(const G2Element el) { + const bls::G2Element* elPtr = (bls::G2Element*)el; + return elPtr->IsValid(); +} + +void* G2ElementSerialize(const G2Element el, const bool legacy) { + const bls::G2Element* elPtr = (bls::G2Element*)el; + const std::vector serialized = elPtr->Serialize(legacy); + uint8_t* buffer = (uint8_t*)malloc(bls::G2Element::SIZE); + memcpy(buffer, serialized.data(), bls::G2Element::SIZE); + return (void*)buffer; +} + +bool G2ElementIsEqual(const G2Element el1, const G2Element el2) { + const bls::G2Element* el1Ptr = (bls::G2Element*)el1; + const bls::G2Element* el2Ptr = (bls::G2Element*)el2; + return *el1Ptr == *el2Ptr; +} + +G2Element G2ElementAdd(const G2Element el1, const G2Element el2) { + bls::G2Element* el1Ptr = (bls::G2Element*)el1; + bls::G2Element* el2Ptr = (bls::G2Element*)el2; + return new bls::G2Element(*el1Ptr + *el2Ptr); +} + +G2Element G2ElementMul(const G2Element el, const PrivateKey sk) { + const bls::G2Element* elPtr = (bls::G2Element*)el; + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::G2Element(*elPtr * *skPtr); +} + +G2Element G2ElementNegate(const G2Element el) { + const bls::G2Element* elPtr = (bls::G2Element*)el; + return new bls::G2Element(elPtr->Negate()); +} + +G2Element G2ElementCopy(const G1Element el) { + return new bls::G2Element(((bls::G2Element*)el)->Copy()); +} + +void G2ElementFree(const G2Element el) { + bls::G2Element* elPtr = (bls::G2Element*)el; + delete elPtr; +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/elements.h b/rust-bindings/bls-dash-sys/c-bindings/elements.h new file mode 100644 index 0000000000..fa1b5ae581 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/elements.h @@ -0,0 +1,58 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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. + +#ifndef ELEMENTS_H_ +#define ELEMENTS_H_ +#include +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* G1Element; +typedef void* G2Element; +typedef void* PrivateKey; + +// G1Element +int G1ElementSize(); +G1Element G1ElementFromBytes(const void* data, const bool legacy, bool* didErr); +G1Element G1ElementGenerator(); +bool G1ElementIsValid(const G1Element el); +uint32_t G1ElementGetFingerprint(const G1Element el, const bool legacy); +bool G1ElementIsEqual(const G1Element el1, const G1Element el2); +G1Element G1ElementAdd(const G1Element el1, const G1Element el2); +G1Element G1ElementMul(const G1Element el, const PrivateKey sk); +G1Element G1ElementNegate(const G1Element el); +G1Element G1ElementCopy(const G1Element el); +void* G1ElementSerialize(const G1Element el, const bool legacy); +void G1ElementFree(const G1Element el); + +// G2Element +int G2ElementSize(); +G2Element G2ElementFromBytes(const void* data, const bool legacy, bool* didErr); +G2Element G2ElementGenerator(); +bool G2ElementIsValid(const G2Element el); +bool G2ElementIsEqual(const G2Element el1, const G2Element el2); +G2Element G2ElementAdd(const G2Element el1, const G2Element el2); +G2Element G2ElementMul(const G2Element el, const PrivateKey sk); +G2Element G2ElementNegate(const G2Element el); +G2Element G2ElementCopy(const G2Element el); +void* G2ElementSerialize(const G2Element el, const bool legacy); +void G2ElementFree(const G2Element el); + +#ifdef __cplusplus +} +#endif +#endif // ELEMENTS_H_ diff --git a/rust-bindings/bls-dash-sys/c-bindings/error.h b/rust-bindings/bls-dash-sys/c-bindings/error.h new file mode 100644 index 0000000000..57525b77fa --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/error.h @@ -0,0 +1,21 @@ +// Copyright (c) 2020 The Dash Core developers + +// 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. + +#ifndef ERROR_H_ +#define ERROR_H_ +#include + +extern std::string gErrMsg; + +#endif // ERROR_H_ diff --git a/rust-bindings/bls-dash-sys/c-bindings/privatekey.cpp b/rust-bindings/bls-dash-sys/c-bindings/privatekey.cpp new file mode 100644 index 0000000000..4e1d0df346 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/privatekey.cpp @@ -0,0 +1,120 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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 "bls.hpp" +#include "privatekey.h" +#include "blschia.h" +#include "error.h" +#include "utils.hpp" + +// private key bindings implementation +PrivateKey PrivateKeyFromBytes(const void* data, const bool modOrder, bool* didErr) { + bls::PrivateKey* skPtr = nullptr; + try { + skPtr = new bls::PrivateKey( + bls::PrivateKey::FromBytes( + bls::Bytes((uint8_t*)data, bls::PrivateKey::PRIVATE_KEY_SIZE), + modOrder + ) + ); + } catch (const std::exception& ex) { + // set err + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return skPtr; +} + +PrivateKey PrivateKeyFromSeedBIP32(const void* data, const size_t len) { + return new bls::PrivateKey( + bls::PrivateKey::FromSeedBIP32(bls::Bytes((uint8_t*)data, len)) + ); +} + +PrivateKey PrivateKeyAggregate(void** sks, const size_t len) { + return new bls::PrivateKey( + bls::PrivateKey::Aggregate(toBLSVector(sks, len)) + ); +} + +void* PrivateKeySerialize(const PrivateKey sk) { + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + uint8_t* buffer = bls::Util::SecAlloc(bls::PrivateKey::PRIVATE_KEY_SIZE); + skPtr->Serialize(buffer); + + return (void*)buffer; +} + +size_t PrivateKeySizeBytes() { + return bls::PrivateKey::PRIVATE_KEY_SIZE; +} + +bool PrivateKeyIsEqual(const PrivateKey sk1, const PrivateKey sk2) { + const bls::PrivateKey* sk1Ptr = (bls::PrivateKey*)sk1; + const bls::PrivateKey* sk2Ptr = (bls::PrivateKey*)sk2; + return *sk1Ptr == *sk2Ptr; +} + +G1Element PrivateKeyGetG1Element(const PrivateKey sk, bool* didErr) { + bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + bls::G1Element* el = nullptr; + try { + el = new bls::G1Element(skPtr->GetG1Element()); + *didErr = false; + } catch (const std::exception& ex) { + // set err + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + return el; +} + +G2Element PrivateKeyGetG2Element(const PrivateKey sk, bool* didErr) { + bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + bls::G2Element* el = nullptr; + try { + el = new bls::G2Element(skPtr->GetG2Element()); + *didErr = false; + } catch (const std::exception& ex) { + // set err + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + return el; +} + +G2Element PrivateKeyGetG2Power(const PrivateKey sk, const G2Element el) { + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + const bls::G2Element* elPtr = (bls::G2Element*)el; + return new bls::G2Element(skPtr->GetG2Power(*elPtr)); +} + +G2Element PrivateKeySignG2(const PrivateKey sk, + uint8_t* msg, + const size_t len, + const uint8_t* dst, + const size_t dstLen) { + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::G2Element(skPtr->SignG2(msg, len, dst, dstLen)); +} + +void PrivateKeyFree(PrivateKey sk) { + bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + delete skPtr; +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/privatekey.h b/rust-bindings/bls-dash-sys/c-bindings/privatekey.h new file mode 100644 index 0000000000..147e1a618f --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/privatekey.h @@ -0,0 +1,40 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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. + +#ifndef PRIVATEKEY_H_ +#define PRIVATEKEY_H_ +#include +#include +#include "elements.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* PrivateKey; + +PrivateKey PrivateKeyFromBytes(const void* data, const bool modOrder, bool* didErr); +PrivateKey PrivateKeyFromSeedBIP32(const void* data, const size_t len); +PrivateKey PrivateKeyAggregate(void** sks, const size_t len); +G1Element PrivateKeyGetG1Element(const PrivateKey sk, bool* didErr); +G2Element PrivateKeyGetG2Element(const PrivateKey sk, bool* didErr); +G2Element PrivateKeyGetG2Power(const PrivateKey sk, const G2Element el); +bool PrivateKeyIsEqual(const PrivateKey sk1, const PrivateKey sk2); +void* PrivateKeySerialize(const PrivateKey sk); +void PrivateKeyFree(const PrivateKey sk); +size_t PrivateKeySizeBytes(); + +#ifdef __cplusplus +} +#endif +#endif // PRIVATEKEY_H_ diff --git a/rust-bindings/bls-dash-sys/c-bindings/schemes.cpp b/rust-bindings/bls-dash-sys/c-bindings/schemes.cpp new file mode 100644 index 0000000000..bc2e632c80 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/schemes.cpp @@ -0,0 +1,388 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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 "schemes.h" + +#include + +#include "bls.hpp" +#include "blschia.h" +#include "elements.h" +#include "error.h" +#include "privatekey.h" +#include "utils.hpp" + +// Implementation of bindings for CoreMPL class + +PrivateKey CoreMPLKeyGen( + const CoreMPL scheme, + const void* seed, + const size_t seedLen, + bool* didErr) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + bls::PrivateKey* sk = nullptr; + try { + sk = new bls::PrivateKey( + schemePtr->KeyGen(bls::Bytes((uint8_t*)seed, seedLen))); + } catch (const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return sk; +} + +G1Element CoreMPLSkToG1(const CoreMPL scheme, const PrivateKey sk) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::G1Element(schemePtr->SkToG1(*skPtr)); +} + +G2Element CoreMPLSign( + CoreMPL scheme, + const PrivateKey sk, + const void* msg, + const size_t msgLen) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::G2Element( + schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen))); +} + +bool CoreMPLVerify( + const CoreMPL scheme, + const G1Element pk, + const void* msg, + const size_t msgLen, + const G2Element sig) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + const bls::G1Element* pkPtr = (bls::G1Element*)pk; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + return schemePtr->Verify( + *pkPtr, bls::Bytes((uint8_t*)msg, msgLen), *sigPtr); +} + +bool CoreMPLVerifySecure( + const CoreMPL scheme, + void** pks, + const size_t pksLen, + const G2Element sig, + const void* msg, + const size_t msgLen) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + const std::vector vecPubKeys = + toBLSVector(pks, pksLen); + const uint8_t* msgPtr = (uint8_t*)msg; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + return schemePtr->VerifySecure( + vecPubKeys, *sigPtr, bls::Bytes(msgPtr, msgLen)); +} + +G1Element CoreMPLAggregatePubKeys( + const CoreMPL scheme, + void** pks, + const size_t pksLen) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + return new bls::G1Element( + schemePtr->Aggregate(toBLSVector(pks, pksLen))); +} + +G2Element CoreMPLAggregateSigs( + const CoreMPL scheme, + void** sigs, + const size_t sigsLen) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + return new bls::G2Element( + schemePtr->Aggregate(toBLSVector(sigs, sigsLen))); +} + +PrivateKey CoreMPLDeriveChildSk( + const CoreMPL scheme, + const PrivateKey sk, + const uint32_t index) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::PrivateKey(schemePtr->DeriveChildSk(*skPtr, index)); +} + +PrivateKey CoreMPLDeriveChildSkUnhardened( + CoreMPL scheme, + PrivateKey sk, + uint32_t index) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::PrivateKey( + schemePtr->DeriveChildSkUnhardened(*skPtr, index)); +} + +G1Element CoreMPLDeriveChildPkUnhardened( + CoreMPL scheme, + G1Element el, + uint32_t index) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + bls::G1Element* elPtr = (bls::G1Element*)el; + return new bls::G1Element( + schemePtr->DeriveChildPkUnhardened(*elPtr, index)); +} + +bool CoreMPLAggregateVerify( + const CoreMPL scheme, + void** pks, + const size_t pksLen, + void** msgs, + const void* msgsLens, + const size_t msgsLen, + const G2Element sig) +{ + bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme; + const size_t* msgLensPtr = (size_t*)msgsLens; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + const std::vector vecPubKeys = + toBLSVector(pks, pksLen); + const std::vector vecMsgsLens = + std::vector(msgLensPtr, msgLensPtr + msgsLen); + const std::vector vecMsgs = + toVectorBytes(msgs, msgsLen, vecMsgsLens); + return schemePtr->AggregateVerify(vecPubKeys, vecMsgs, *sigPtr); +} + +// BasicSchemeMPL +BasicSchemeMPL NewBasicSchemeMPL() { return new bls::BasicSchemeMPL(); } + +bool BasicSchemeMPLAggregateVerify( + BasicSchemeMPL scheme, + void** pks, + const size_t pksLen, + void** msgs, + const void* msgsLens, + const size_t msgsLen, + const G2Element sig) +{ + bls::BasicSchemeMPL* schemePtr = (bls::BasicSchemeMPL*)scheme; + const size_t* msgLensPtr = (size_t*)msgsLens; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + const std::vector vecPubKeys = + toBLSVector(pks, pksLen); + const std::vector vecMsgsLens = + std::vector(msgLensPtr, msgLensPtr + msgsLen); + const std::vector vecMsgs = + toVectorBytes(msgs, msgsLen, vecMsgsLens); + return schemePtr->AggregateVerify(vecPubKeys, vecMsgs, *sigPtr); +} + +void BasicSchemeMPLFree(BasicSchemeMPL scheme) +{ + bls::BasicSchemeMPL* schemePtr = (bls::BasicSchemeMPL*)scheme; + delete schemePtr; +} + +// AugSchemeMPL +AugSchemeMPL NewAugSchemeMPL() { return new bls::AugSchemeMPL(); } + +G2Element AugSchemeMPLSign( + const AugSchemeMPL scheme, + const PrivateKey sk, + const void* msg, + const size_t msgLen) +{ + bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme; + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::G2Element( + schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen))); +} + +G2Element AugSchemeMPLSignPrepend( + const AugSchemeMPL scheme, + const PrivateKey sk, + const void* msg, + const size_t msgLen, + const G1Element prepPk) +{ + bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme; + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + const bls::G1Element* prepPkPtr = (bls::G1Element*)prepPk; + return new bls::G2Element( + schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen), *prepPkPtr)); +} + +bool AugSchemeMPLVerify( + const AugSchemeMPL scheme, + const G1Element pk, + const void* msg, + const size_t msgLen, + const G2Element sig) +{ + bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme; + const bls::G1Element* pkPtr = (bls::G1Element*)pk; + const uint8_t* msgPtr = (uint8_t*)msg; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + return schemePtr->Verify(*pkPtr, bls::Bytes(msgPtr, msgLen), *sigPtr); +} + +bool AugSchemeMPLAggregateVerify( + const AugSchemeMPL scheme, + void** pks, + const size_t pksLen, + void** msgs, + const void* msgsLens, + const size_t msgsLen, + const G2Element sig) +{ + bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme; + const size_t* msgLensPtr = (size_t*)msgsLens; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + const std::vector vecPubKeys = + toBLSVector(pks, pksLen); + const std::vector vecMsgsLens = + std::vector(msgLensPtr, msgLensPtr + msgsLen); + const std::vector vecMsgs = + toVectorBytes(msgs, msgsLen, vecMsgsLens); + return schemePtr->AggregateVerify(vecPubKeys, vecMsgs, *sigPtr); +} + +void AugSchemeMPLFree(AugSchemeMPL scheme) +{ + bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme; + delete schemePtr; +} + +// PopSchemeMPL +PopSchemeMPL NewPopSchemeMPL() { return new bls::PopSchemeMPL(); } + +G2Element PopSchemeMPLPopProve( + const PopSchemeMPL scheme, + const PrivateKey sk) +{ + bls::PopSchemeMPL* schemePtr = (bls::PopSchemeMPL*)scheme; + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::G2Element(schemePtr->PopProve(*skPtr)); +} + +bool PopSchemeMPLPopVerify( + const PopSchemeMPL scheme, + const G1Element pk, + const G2Element sig) +{ + bls::PopSchemeMPL* schemePtr = (bls::PopSchemeMPL*)scheme; + const bls::G1Element* pkPtr = (bls::G1Element*)pk; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + return schemePtr->PopVerify(*pkPtr, *sigPtr); +} + +bool PopSchemeMPLFastAggregateVerify( + const PopSchemeMPL scheme, + void** pks, + const size_t pksLen, + const void* msg, + const size_t msgLen, + const G2Element sig) +{ + bls::PopSchemeMPL* schemePtr = (bls::PopSchemeMPL*)scheme; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + const std::vector vecPubKeys = + toBLSVector(pks, pksLen); + return schemePtr->FastAggregateVerify( + vecPubKeys, bls::Bytes((uint8_t*)msg, msgLen), *sigPtr); +} + +void PopSchemeMPLFree(PopSchemeMPL scheme) +{ + bls::PopSchemeMPL* schemePtr = (bls::PopSchemeMPL*)scheme; + delete schemePtr; +} + +// LegacySchemeMPL +LegacySchemeMPL NewLegacySchemeMPL() { return new bls::LegacySchemeMPL(); } + +G2Element LegacySchemeMPLSign( + const LegacySchemeMPL scheme, + const PrivateKey sk, + const void* msg, + const size_t msgLen) +{ + bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme; + const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::G2Element( + schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen))); +} + +bool LegacySchemeMPLVerify( + const LegacySchemeMPL scheme, + const G1Element pk, + const void* msg, + const size_t msgLen, + const G2Element sig) +{ + bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme; + const bls::G1Element* pkPtr = (bls::G1Element*)pk; + const uint8_t* msgPtr = (uint8_t*)msg; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + return schemePtr->Verify(*pkPtr, bls::Bytes(msgPtr, msgLen), *sigPtr); +} + +bool LegacySchemeMPLVerifySecure( + const LegacySchemeMPL scheme, + void** pks, + const size_t pksLen, + const G2Element sig, + const void* msg, + const size_t msgLen) +{ + bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme; + const std::vector vecPubKeys = + toBLSVector(pks, pksLen); + const uint8_t* msgPtr = (uint8_t*)msg; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + // Because of scheme pointer it will call CoreMPL::VerifySecure with 'legacy' flag variant + return schemePtr->VerifySecure( + vecPubKeys, *sigPtr, bls::Bytes(msgPtr, msgLen)); +} + +bool LegacySchemeMPLAggregateVerify( + const LegacySchemeMPL scheme, + void** pks, + const size_t pksLen, + void** msgs, + const void* msgsLens, + const size_t msgsLen, + const G2Element sig) +{ + bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme; + const size_t* msgLensPtr = (size_t*)msgsLens; + const bls::G2Element* sigPtr = (bls::G2Element*)sig; + const std::vector vecPubKeys = + toBLSVector(pks, pksLen); + const std::vector vecMsgsLens = + std::vector(msgLensPtr, msgLensPtr + msgsLen); + const std::vector vecMsgs = + toVectorBytes(msgs, msgsLen, vecMsgsLens); + return schemePtr->AggregateVerify(vecPubKeys, vecMsgs, *sigPtr); +} + +void LegacySchemeMPLFree(LegacySchemeMPL scheme) +{ + bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme; + delete schemePtr; +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/schemes.h b/rust-bindings/bls-dash-sys/c-bindings/schemes.h new file mode 100644 index 0000000000..41b39a6103 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/schemes.h @@ -0,0 +1,184 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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. + +#ifndef SCHEMES_H_ +#define SCHEMES_H_ +#include +#include + +#include "elements.h" +#include "privatekey.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* CoreMPL; +typedef CoreMPL BasicSchemeMPL; +typedef CoreMPL AugSchemeMPL; +typedef CoreMPL PopSchemeMPL; +typedef CoreMPL LegacySchemeMPL; + +// CoreMPL +PrivateKey CoreMPLKeyGen( + const CoreMPL scheme, + const void* seed, + const size_t seedLen, + bool* didErr); +G1Element CoreMPLSkToG1(const CoreMPL scheme, const PrivateKey sk); +G2Element CoreMPLSign( + const CoreMPL scheme, + const PrivateKey sk, + const void* msg, + const size_t msgLen); +bool CoreMPLVerify( + const BasicSchemeMPL scheme, + const G1Element pk, + const void* msg, + const size_t msgLen, + const G2Element sig); +bool CoreMPLVerifySecure( + const CoreMPL scheme, + void** pks, + const size_t pksLen, + const G2Element sig, + const void* msg, + const size_t msgLen); +G1Element CoreMPLAggregatePubKeys( + const CoreMPL scheme, + void** pubKeys, + const size_t pkLen); +G2Element CoreMPLAggregateSigs( + const CoreMPL scheme, + void** sigs, + const size_t sigLen); +PrivateKey CoreMPLDeriveChildSk( + const CoreMPL scheme, + const PrivateKey sk, + const uint32_t index); +PrivateKey CoreMPLDeriveChildSkUnhardened( + const CoreMPL scheme, + const PrivateKey sk, + const uint32_t index); +G1Element CoreMPLDeriveChildPkUnhardened( + const CoreMPL scheme, + const G1Element sk, + const uint32_t index); +bool CoreMPLAggregateVerify( + const CoreMPL scheme, + void** pks, + const size_t pkLen, + void** msgs, + const void* msgLens, + const size_t msgLen, + const G2Element sig); + +// BasicSchemeMPL +BasicSchemeMPL NewBasicSchemeMPL(); +bool BasicSchemeMPLAggregateVerify( + BasicSchemeMPL scheme, + void** pks, + const size_t pksLen, + void** msgs, + const void* msgsLens, + const size_t msgsLen, + const G2Element sig); +void BasicSchemeMPLFree(BasicSchemeMPL scheme); + +// AugSchemeMPL +AugSchemeMPL NewAugSchemeMPL(); +G2Element AugSchemeMPLSign( + const AugSchemeMPL scheme, + const PrivateKey sk, + const void* msg, + const size_t msgLen); +G2Element AugSchemeMPLSignPrepend( + const AugSchemeMPL scheme, + const PrivateKey sk, + const void* msg, + const size_t msgLen, + const G1Element prepPk); +bool AugSchemeMPLVerify( + const AugSchemeMPL scheme, + const G1Element pk, + const void* msg, + const size_t msgLen, + const G2Element sig); +bool AugSchemeMPLAggregateVerify( + const AugSchemeMPL scheme, + void** pks, + const size_t pksLen, + void** msgs, + const void* msgsLens, + const size_t msgsLen, + const G2Element sig); +void AugSchemeMPLFree(AugSchemeMPL scheme); + +// PopSchemeMPL +PopSchemeMPL NewPopSchemeMPL(); +G2Element PopSchemeMPLPopProve( + const PopSchemeMPL scheme, + const PrivateKey sk); +bool PopSchemeMPLPopVerify( + const PopSchemeMPL scheme, + const G1Element pk, + const G2Element sig); +bool PopSchemeMPLFastAggregateVerify( + const PopSchemeMPL scheme, + void** pks, + const size_t pksLen, + const void* msgs, + const size_t msgsLen, + const G2Element sig); +void PopSchemeMPLFree(PopSchemeMPL scheme); + +// LegacySchemeMPL +LegacySchemeMPL NewLegacySchemeMPL(); +G2Element LegacySchemeMPLSign( + const LegacySchemeMPL scheme, + const PrivateKey sk, + const void* msg, + const size_t msgLen); +G2Element LegacySchemeMPLSignPrepend( + const LegacySchemeMPL scheme, + const PrivateKey sk, + const void* msg, + const size_t msgLen, + const G1Element prepPk); +bool LegacySchemeMPLVerify( + const LegacySchemeMPL scheme, + const G1Element pk, + const void* msg, + const size_t msgLen, + const G2Element sig); +bool LegacySchemeMPLVerifySecure( + const LegacySchemeMPL scheme, + void** pks, + const size_t pksLen, + const G2Element sig, + const void* msg, + const size_t msgLen); +bool LegacySchemeMPLAggregateVerify( + const LegacySchemeMPL scheme, + void** pks, + const size_t pksLen, + void** msgs, + const void* msgsLens, + const size_t msgsLen, + const G2Element sig); +void LegacySchemeMPLFree(LegacySchemeMPL scheme); + +#ifdef __cplusplus +} +#endif +#endif // SCHEMES_H_ diff --git a/rust-bindings/bls-dash-sys/c-bindings/threshold.cpp b/rust-bindings/bls-dash-sys/c-bindings/threshold.cpp new file mode 100644 index 0000000000..2bb668483d --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/threshold.cpp @@ -0,0 +1,168 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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 "bls.hpp" +#include "privatekey.h" +#include "elements.h" +#include "blschia.h" +#include "threshold.h" +#include "utils.hpp" +#include "error.h" + +std::vector toVectorHashes(void** elems, const size_t len) { + std::vector vec; + vec.reserve(len); + for (int i = 0 ; i < len; ++i) { + vec.push_back( + bls::Bytes((uint8_t*)elems[i], HashSize) + ); + } + return vec; +} + +PrivateKey ThresholdPrivateKeyShare(void** sks, const size_t sksLen, const void* hash, bool* didErr) { + bls::PrivateKey* sk = nullptr; + try { + sk = new bls::PrivateKey( + bls::Threshold::PrivateKeyShare( + toBLSVector(sks, sksLen), + bls::Bytes((uint8_t*)hash, HashSize) + ) + ); + } catch(const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return sk; +} + +PrivateKey ThresholdPrivateKeyRecover(void** sks, + const size_t sksLen, + void** hashes, + const size_t hashesLen, + bool* didErr) { + bls::PrivateKey* sk = nullptr; + std::vector pop = toVectorHashes(hashes, hashesLen); + try { + sk = new bls::PrivateKey( + bls::Threshold::PrivateKeyRecover( + toBLSVector(sks, sksLen), + toVectorHashes(hashes, hashesLen) + ) + ); + } catch(const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return sk; +} + +G1Element ThresholdPublicKeyShare(void** pks, const size_t pksLen, const void* hash, bool* didErr) { + bls::G1Element* el = nullptr; + try { + el = new bls::G1Element( + bls::Threshold::PublicKeyShare( + toBLSVector(pks, pksLen), + bls::Bytes((uint8_t*)hash, HashSize) + ) + ); + } catch(const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return el; +} + +G1Element ThresholdPublicKeyRecover(void** pks, + const size_t pksLen, + void** hashes, + const size_t hashesLen, + bool* didErr) { + bls::G1Element* el = nullptr; + try { + el = new bls::G1Element( + bls::Threshold::PublicKeyRecover( + toBLSVector(pks, pksLen), + toVectorHashes(hashes, hashesLen) + ) + ); + } catch(const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return el; +} + +G2Element ThresholdSignatureShare(void** sigs, const size_t sigsLen, const void* hash, bool* didErr) { + bls::G2Element* el = nullptr; + try { + el = new bls::G2Element( + bls::Threshold::SignatureShare( + toBLSVector(sigs, sigsLen), + bls::Bytes((uint8_t*)hash, HashSize) + ) + ); + } catch(const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return el; +} + +G2Element ThresholdSignatureRecover(void** sigs, + const size_t sigsLen, + void** hashes, + const size_t hashesLen, + bool* didErr) { + bls::G2Element* el = nullptr; + try { + el = new bls::G2Element( + bls::Threshold::SignatureRecover( + toBLSVector(sigs, sigsLen), + toVectorHashes(hashes, hashesLen) + ) + ); + } catch(const std::exception& ex) { + gErrMsg = ex.what(); + *didErr = true; + return nullptr; + } + *didErr = false; + return el; +} + +G2Element ThresholdSign(const PrivateKey sk, const void* hash) { + bls::PrivateKey* skPtr = (bls::PrivateKey*)sk; + return new bls::G2Element( + bls::Threshold::Sign(*skPtr, bls::Bytes((uint8_t*)hash, HashSize)) + ); +} + +bool ThresholdVerify(const G1Element pk, const void* hash, const G2Element sig) { + bls::G1Element* pkPtr = (bls::G1Element*)pk; + bls::G2Element* sigPtr = (bls::G2Element*)sig; + return bls::Threshold::Verify(*pkPtr, bls::Bytes((uint8_t*)hash, HashSize), *sigPtr); +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/threshold.h b/rust-bindings/bls-dash-sys/c-bindings/threshold.h new file mode 100644 index 0000000000..054ddffcd8 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/threshold.h @@ -0,0 +1,55 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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. + +#ifndef THRESHOLD_H_ +#define THRESHOLD_H_ +#include +#include +#include +#include "privatekey.h" +#include "elements.h" +#ifdef __cplusplus +extern "C" { +#endif + +const int HashSize = 32; + +PrivateKey ThresholdPrivateKeyShare(void** sks, const size_t sksLen, const void* hash, bool* didErr); +PrivateKey ThresholdPrivateKeyRecover(void** sks, + const size_t sksLen, + void** hashes, + const size_t hashesLen, + bool* didErr); + +G1Element ThresholdPublicKeyShare(void** pks, const size_t pksLen, const void* hash, bool* didErr); +G1Element ThresholdPublicKeyRecover(void** pks, + const size_t pksLen, + void** hashes, + const size_t hashesLen, + bool* didErr); + +G2Element ThresholdSignatureShare(void** sigs, const size_t sigsLen, const void* hash, bool* didErr); +G2Element ThresholdSignatureRecover(void** sigs, + const size_t sigsLen, + void** hashes, + const size_t hashesLen, + bool* didErr); + +G2Element ThresholdSign(const PrivateKey sk, const void* hash); +bool ThresholdVerify(const G1Element pk, const void* hash, const G2Element sig); + +#ifdef __cplusplus +} +#endif +#endif // THRESHOLD_H_ diff --git a/rust-bindings/bls-dash-sys/c-bindings/utils.cpp b/rust-bindings/bls-dash-sys/c-bindings/utils.cpp new file mode 100644 index 0000000000..85ad174c84 --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/utils.cpp @@ -0,0 +1,40 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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 "bls.hpp" +#include "privatekey.h" +#include "elements.h" + +// helper functions +template +std::vector toBLSVector(void** elems, const size_t len) { + std::vector vec; + vec.reserve(len); + for (int i = 0 ; i < len; ++i) { + T* el = (T*)elems[i]; + vec.push_back(*el); + } + return vec; +} + +std::vector toVectorBytes(void** elems, const size_t len, const std::vector vecElemsLens) { + std::vector vec; + vec.reserve(len); + for (int i = 0 ; i < len; ++i) { + uint8_t* elPtr = (uint8_t*)elems[i]; + vec.push_back(bls::Bytes(elPtr, vecElemsLens[i])); + } + return vec; +} diff --git a/rust-bindings/bls-dash-sys/c-bindings/utils.hpp b/rust-bindings/bls-dash-sys/c-bindings/utils.hpp new file mode 100644 index 0000000000..42e7898a3f --- /dev/null +++ b/rust-bindings/bls-dash-sys/c-bindings/utils.hpp @@ -0,0 +1,34 @@ +// Copyright (c) 2021 The Dash Core developers + +// 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 "bls.hpp" +#include "privatekey.h" +#include "elements.h" + +// helper functions +template +std::vector toBLSVector(void** elems, const size_t len) { + std::vector vec; + vec.reserve(len); + for (int i = 0 ; i < (int)len; ++i) { + const T* el = (T*)elems[i]; + vec.push_back(*el); + } + return vec; +} + +std::vector toVectorBytes(void** elems, const size_t len, const std::vector vecElemsLens); diff --git a/rust-bindings/bls-dash-sys/include.h b/rust-bindings/bls-dash-sys/include.h new file mode 100644 index 0000000000..4189a0748c --- /dev/null +++ b/rust-bindings/bls-dash-sys/include.h @@ -0,0 +1,8 @@ +#include "c-bindings/blschia.h" +#include "c-bindings/elements.h" +#include "c-bindings/privatekey.h" +#include "c-bindings/schemes.h" +#include "c-bindings/threshold.h" +#include "c-bindings/bip32/chaincode.h" +#include "c-bindings/bip32/extendedprivatekey.h" +#include "c-bindings/bip32/extendedpublickey.h" diff --git a/rust-bindings/bls-dash-sys/src/lib.rs b/rust-bindings/bls-dash-sys/src/lib.rs new file mode 100644 index 0000000000..a24bad5d77 --- /dev/null +++ b/rust-bindings/bls-dash-sys/src/lib.rs @@ -0,0 +1,6 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +// include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +include!("../bindings.rs"); diff --git a/rust-bindings/bls-dash-sys/tests/sign_and_verify.rs b/rust-bindings/bls-dash-sys/tests/sign_and_verify.rs new file mode 100644 index 0000000000..6ceee4961c --- /dev/null +++ b/rust-bindings/bls-dash-sys/tests/sign_and_verify.rs @@ -0,0 +1,79 @@ +use bls_dash_sys as sys; + +#[test] +fn sign_and_verify() { + let seed = b"seedweedseedweedseedweedseedweed"; + let bad_seed = b"weedseedweedseedweedseedweedseed"; + + unsafe { + let scheme = sys::NewAugSchemeMPL(); + let mut did_err = false; + + let sk = sys::CoreMPLKeyGen( + scheme, + seed.as_ptr() as *const _, + seed.len(), + &mut did_err as *mut _, + ); + assert!(!did_err); + + let pk = sys::PrivateKeyGetG1Element(sk, &mut did_err as *mut _); + assert!(!did_err); + + let sk2 = sys::CoreMPLKeyGen( + scheme, + bad_seed.as_ptr() as *const _, + bad_seed.len(), + &mut did_err as *mut _, + ); + assert!(!did_err); + + let pk2 = sys::PrivateKeyGetG1Element(sk2, &mut did_err as *mut _); + assert!(!did_err); + + let message = b"Evgeny owns 1337 dash no cap"; + let sig = sys::CoreMPLSign(scheme, sk, message.as_ptr() as *const _, message.len()); + + let verify = + sys::CoreMPLVerify(scheme, pk, message.as_ptr() as *const _, message.len(), sig); + assert!(verify); + + let verify_bad = sys::CoreMPLVerify( + scheme, + pk2, + message.as_ptr() as *const _, + message.len(), + sig, + ); + assert!(!verify_bad); + + sys::G2ElementFree(sig); + sys::G1ElementFree(pk2); + sys::PrivateKeyFree(sk2); + sys::G1ElementFree(pk); + sys::PrivateKeyFree(sk); + sys::AugSchemeMPLFree(scheme); + } +} + +#[test] +fn test_private_key_from_bip32() { + use std::slice; + let long_seed: [u8; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2]; + let long_private_key_test_data: [u8; 32] = [50, 67, 148, 112, 207, 6, 210, 118, 137, 125, 27, 144, 105, 189, 214, 228, 68, 83, 144, 205, 80, 105, 133, 222, 14, 26, 28, 136, 167, 111, 241, 118]; + let short_seed: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let short_private_key_test_data: [u8; 32] = [70, 137, 28, 44, 236, 73, 89, 60, 129, 146, 30, 71, 61, 183, 72, 0, 41, 224, 252, 30, 185, 51, 198, 185, 61, 129, 245, 55, 14, 177, 159, 189]; + unsafe { + let c_private_key = sys::PrivateKeyFromSeedBIP32(long_seed.as_ptr() as *const _, long_seed.len()); + let serialized = sys::PrivateKeySerialize(c_private_key) as *const u8; + let data = slice::from_raw_parts(serialized, sys::PrivateKeySizeBytes()); + assert_eq!(data, &long_private_key_test_data); + sys::PrivateKeyFree(c_private_key); + + let c_private_key = sys::PrivateKeyFromSeedBIP32(short_seed.as_ptr() as *const _, short_seed.len()); + let serialized = sys::PrivateKeySerialize(c_private_key) as *const u8; + let data = slice::from_raw_parts(serialized, sys::PrivateKeySizeBytes()); + assert_eq!(data, &short_private_key_test_data); + sys::PrivateKeyFree(c_private_key); + } +} diff --git a/rust-bindings/bls-signatures/.rustfmt.toml b/rust-bindings/bls-signatures/.rustfmt.toml new file mode 100644 index 0000000000..f5fe8f3188 --- /dev/null +++ b/rust-bindings/bls-signatures/.rustfmt.toml @@ -0,0 +1,17 @@ +unstable_features = true + +blank_lines_lower_bound = 0 +condense_wildcard_suffixes = true +error_on_line_overflow = true +error_on_unformatted = true +format_code_in_doc_comments = true +format_macro_matchers = true +format_strings = true +imports_granularity = "Crate" +normalize_comments = true +normalize_doc_attributes = true +reorder_impl_items = true +group_imports = "StdExternalCrate" +use_field_init_shorthand = true +use_try_shorthand = true +wrap_comments = true diff --git a/rust-bindings/bls-signatures/Cargo.toml b/rust-bindings/bls-signatures/Cargo.toml new file mode 100644 index 0000000000..8c6f1e3c1d --- /dev/null +++ b/rust-bindings/bls-signatures/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "bls-signatures" +description = "" +version = "1.2.5" +edition = "2021" + +[features] +legacy = [] +bip32 = [] +use_serde = ["serde"] +dash_helpers = ["rand"] +default = [ "legacy", "bip32", "dash_helpers", "use_serde"] +apple = ["bls-dash-sys/apple"] + +[dependencies] +bls-dash-sys = { path = "../bls-dash-sys" } +serde = { version= "1.0.160", features = ["derive"], optional = true} +rand = { version= "0.8.5", optional = true} diff --git a/rust-bindings/bls-signatures/src/bip32/chain_code.rs b/rust-bindings/bls-signatures/src/bip32/chain_code.rs new file mode 100644 index 0000000000..f5271cc45b --- /dev/null +++ b/rust-bindings/bls-signatures/src/bip32/chain_code.rs @@ -0,0 +1,33 @@ +use std::ffi::c_void; + +use bls_dash_sys::{BIP32ChainCodeFree, BIP32ChainCodeIsEqual, BIP32ChainCodeSerialize}; + +pub const BIP32_CHAIN_CODE_SIZE: usize = 32; + +#[derive(Debug)] +pub struct ChainCode { + pub(crate) c_chain_code: *mut c_void, +} + +impl ChainCode { + pub fn serialize(&self) -> Box<[u8; BIP32_CHAIN_CODE_SIZE]> { + unsafe { + let malloc_ptr = BIP32ChainCodeSerialize(self.c_chain_code); + Box::from_raw(malloc_ptr as *mut _) + } + } +} + +impl PartialEq for ChainCode { + fn eq(&self, other: &Self) -> bool { + unsafe { BIP32ChainCodeIsEqual(self.c_chain_code, other.c_chain_code) } + } +} + +impl Eq for ChainCode {} + +impl Drop for ChainCode { + fn drop(&mut self) { + unsafe { BIP32ChainCodeFree(self.c_chain_code) } + } +} diff --git a/rust-bindings/bls-signatures/src/bip32/mod.rs b/rust-bindings/bls-signatures/src/bip32/mod.rs new file mode 100644 index 0000000000..6b3a64326e --- /dev/null +++ b/rust-bindings/bls-signatures/src/bip32/mod.rs @@ -0,0 +1,7 @@ +mod chain_code; +mod private_key; +mod public_key; + +pub use chain_code::*; +pub use private_key::*; +pub use public_key::*; diff --git a/rust-bindings/bls-signatures/src/bip32/private_key.rs b/rust-bindings/bls-signatures/src/bip32/private_key.rs new file mode 100644 index 0000000000..af4394f179 --- /dev/null +++ b/rust-bindings/bls-signatures/src/bip32/private_key.rs @@ -0,0 +1,205 @@ +use std::ffi::c_void; + +use bls_dash_sys::{ + BIP32ExtendedPrivateKeyFree, BIP32ExtendedPrivateKeyFromBytes, BIP32ExtendedPrivateKeyFromSeed, + BIP32ExtendedPrivateKeyGetChainCode, BIP32ExtendedPrivateKeyGetExtendedPublicKey, + BIP32ExtendedPrivateKeyGetPrivateKey, BIP32ExtendedPrivateKeyGetPublicKey, + BIP32ExtendedPrivateKeyIsEqual, BIP32ExtendedPrivateKeyPrivateChild, + BIP32ExtendedPrivateKeyPublicChild, BIP32ExtendedPrivateKeySerialize, +}; + +use crate::{ + bip32::{chain_code::ChainCode, ExtendedPublicKey}, + utils::{c_err_to_result, SecureBox}, + BlsError, G1Element, PrivateKey, +}; + +pub const BIP32_EXTENDED_PRIVATE_KEY_SIZE: usize = 77; + +#[derive(Debug)] +pub struct ExtendedPrivateKey { + c_extended_private_key: *mut c_void, +} + +impl PartialEq for ExtendedPrivateKey { + fn eq(&self, other: &Self) -> bool { + unsafe { + BIP32ExtendedPrivateKeyIsEqual( + self.c_extended_private_key, + other.c_extended_private_key, + ) + } + } +} + +impl Eq for ExtendedPrivateKey {} + +impl ExtendedPrivateKey { + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != BIP32_EXTENDED_PRIVATE_KEY_SIZE { + return Err(BlsError { + msg: format!( + "Extended Private Key size must be {}, got {}", + BIP32_EXTENDED_PRIVATE_KEY_SIZE, + bytes.len() + ), + }); + } + Ok(ExtendedPrivateKey { + c_extended_private_key: c_err_to_result(|did_err| unsafe { + BIP32ExtendedPrivateKeyFromBytes(bytes.as_ptr() as *const _, did_err) + })?, + }) + } + + pub fn from_seed(bytes: &[u8]) -> Result { + Ok(ExtendedPrivateKey { + c_extended_private_key: c_err_to_result(|did_err| unsafe { + BIP32ExtendedPrivateKeyFromSeed(bytes.as_ptr() as *const _, bytes.len(), did_err) + })?, + }) + } + + pub(crate) fn private_child_with_legacy_flag(&self, index: u32, legacy: bool) -> Self { + ExtendedPrivateKey { + c_extended_private_key: unsafe { + BIP32ExtendedPrivateKeyPrivateChild(self.c_extended_private_key, index, legacy) + }, + } + } + + pub fn private_child(&self, index: u32) -> Self { + self.private_child_with_legacy_flag(index, false) + } + + pub fn public_child(&self, index: u32) -> ExtendedPublicKey { + ExtendedPublicKey { + c_extended_public_key: unsafe { + BIP32ExtendedPrivateKeyPublicChild(self.c_extended_private_key, index) + }, + } + } + + pub(crate) fn extended_public_key_with_legacy_flag( + &self, + legacy: bool, + ) -> Result { + Ok(ExtendedPublicKey { + c_extended_public_key: c_err_to_result(|did_err| unsafe { + BIP32ExtendedPrivateKeyGetExtendedPublicKey( + self.c_extended_private_key, + legacy, + did_err, + ) + })?, + }) + } + + pub fn extended_public_key(&self) -> Result { + self.extended_public_key_with_legacy_flag(false) + } + + pub fn public_key(&self) -> Result { + Ok(G1Element { + c_element: c_err_to_result(|did_err| unsafe { + BIP32ExtendedPrivateKeyGetPublicKey(self.c_extended_private_key, did_err) + })?, + }) + } + + pub fn private_key(&self) -> PrivateKey { + PrivateKey { + c_private_key: unsafe { + BIP32ExtendedPrivateKeyGetPrivateKey(self.c_extended_private_key) + }, + } + } + + pub fn serialize(&self) -> SecureBox { + unsafe { + let secalloc_ptr = BIP32ExtendedPrivateKeySerialize(self.c_extended_private_key); + SecureBox::from_ptr(secalloc_ptr as *mut u8, BIP32_EXTENDED_PRIVATE_KEY_SIZE) + } + } + + pub fn chain_code(&self) -> ChainCode { + ChainCode { + c_chain_code: unsafe { + BIP32ExtendedPrivateKeyGetChainCode(self.c_extended_private_key) + }, + } + } +} + +impl Drop for ExtendedPrivateKey { + fn drop(&mut self) { + unsafe { BIP32ExtendedPrivateKeyFree(self.c_extended_private_key) } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn serialize_deserialize() { + let seed = b"seedweedseedweedseedweedseedweed"; + let private_key = + ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key"); + + let private_key_bytes = private_key.serialize(); + let private_key_2 = ExtendedPrivateKey::from_bytes(private_key_bytes.as_ref()) + .expect("cannot deserialize extended private key"); + + assert_eq!(private_key, private_key_2); + assert_eq!(private_key.private_key(), private_key_2.private_key()); + assert_eq!(private_key.public_key(), private_key_2.public_key()); + } + + #[test] + fn hierarchical_deterministic_keys() { + let seed = b"seedweedseedweedseedweedseedweed"; + let private_key = + ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key"); + let public_key = private_key + .extended_public_key() + .expect("cannot get extended public key"); + + let private_child = private_key.private_child(1337); + let private_grandchild = private_child.private_child(420); + + let public_child = public_key.public_child(1337); + let public_grandchild = public_child.public_child(420); + + assert_eq!( + public_grandchild, + private_grandchild + .extended_public_key() + .expect("cannot get extended public key") + ); + } + + #[test] + fn public_keys_match() { + let seed = b"seedweedseedweedseedweedseedweed"; + let private_key = + ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key"); + let public_key = private_key + .extended_public_key() + .expect("cannot get extended public key"); + + assert_eq!(private_key.public_key(), Ok(public_key.public_key())); + } + + #[test] + fn fingerprint_for_short_bip32_seed() { + assert_eq!( + ExtendedPrivateKey::from_seed(&[1u8, 50, 6, 244, 24, 199, 1, 25]) + .expect("cannot generate extended private key") + .public_key() + .expect("cannot get public key from extended private key") + .fingerprint_legacy(), + 0xa4700b27 + ); + } +} diff --git a/rust-bindings/bls-signatures/src/bip32/public_key.rs b/rust-bindings/bls-signatures/src/bip32/public_key.rs new file mode 100644 index 0000000000..43fa484f0c --- /dev/null +++ b/rust-bindings/bls-signatures/src/bip32/public_key.rs @@ -0,0 +1,119 @@ +use std::ffi::c_void; + +use bls_dash_sys::{ + BIP32ExtendedPublicKeyFree, BIP32ExtendedPublicKeyFromBytes, + BIP32ExtendedPublicKeyGetChainCode, BIP32ExtendedPublicKeyGetPublicKey, + BIP32ExtendedPublicKeyIsEqual, BIP32ExtendedPublicKeyPublicChild, + BIP32ExtendedPublicKeySerialize, +}; + +use crate::{bip32::chain_code::ChainCode, utils::c_err_to_result, BlsError, G1Element}; + +pub const BIP32_EXTENDED_PUBLIC_KEY_SIZE: usize = 93; + +#[derive(Debug)] +pub struct ExtendedPublicKey { + pub(crate) c_extended_public_key: *mut c_void, +} + +impl PartialEq for ExtendedPublicKey { + fn eq(&self, other: &Self) -> bool { + unsafe { + BIP32ExtendedPublicKeyIsEqual(self.c_extended_public_key, other.c_extended_public_key) + } + } +} + +impl Eq for ExtendedPublicKey {} + +impl ExtendedPublicKey { + pub(crate) fn from_bytes_with_legacy_flag( + bytes: &[u8], + legacy: bool, + ) -> Result { + if bytes.len() != BIP32_EXTENDED_PUBLIC_KEY_SIZE { + return Err(BlsError { + msg: format!( + "Extended Public Key size must be {}, got {}", + BIP32_EXTENDED_PUBLIC_KEY_SIZE, + bytes.len() + ), + }); + } + Ok(ExtendedPublicKey { + c_extended_public_key: c_err_to_result(|did_err| unsafe { + BIP32ExtendedPublicKeyFromBytes(bytes.as_ptr() as *const _, legacy, did_err) + })?, + }) + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + Self::from_bytes_with_legacy_flag(bytes, false) + } + + pub(crate) fn public_child_with_legacy_flag(&self, index: u32, legacy: bool) -> Self { + ExtendedPublicKey { + c_extended_public_key: unsafe { + BIP32ExtendedPublicKeyPublicChild(self.c_extended_public_key, index, legacy) + }, + } + } + + pub fn public_child(&self, index: u32) -> Self { + self.public_child_with_legacy_flag(index, false) + } + + pub(crate) fn serialize_with_legacy_flag( + &self, + legacy: bool, + ) -> Box<[u8; BIP32_EXTENDED_PUBLIC_KEY_SIZE]> { + unsafe { + let malloc_ptr = BIP32ExtendedPublicKeySerialize(self.c_extended_public_key, legacy); + Box::from_raw(malloc_ptr as *mut _) + } + } + + pub fn serialize(&self) -> Box<[u8; BIP32_EXTENDED_PUBLIC_KEY_SIZE]> { + self.serialize_with_legacy_flag(false) + } + + pub fn chain_code(&self) -> ChainCode { + ChainCode { + c_chain_code: unsafe { BIP32ExtendedPublicKeyGetChainCode(self.c_extended_public_key) }, + } + } + + pub fn public_key(&self) -> G1Element { + G1Element { + c_element: unsafe { BIP32ExtendedPublicKeyGetPublicKey(self.c_extended_public_key) }, + } + } +} + +impl Drop for ExtendedPublicKey { + fn drop(&mut self) { + unsafe { BIP32ExtendedPublicKeyFree(self.c_extended_public_key) } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::bip32::ExtendedPrivateKey; + + #[test] + fn serialize_deserialize() { + let seed = b"seedweedseedweedseedweedseedweed"; + let private_key = + ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key"); + let public_key = private_key + .extended_public_key() + .expect("cannot get extended public key"); + + let public_key_bytes = public_key.serialize(); + let public_key_2 = ExtendedPublicKey::from_bytes(public_key_bytes.as_ref()) + .expect("cannot deserialize extended public key"); + + assert_eq!(public_key, public_key_2); + } +} diff --git a/rust-bindings/bls-signatures/src/elements.rs b/rust-bindings/bls-signatures/src/elements.rs new file mode 100644 index 0000000000..3388ce022a --- /dev/null +++ b/rust-bindings/bls-signatures/src/elements.rs @@ -0,0 +1,368 @@ +use std::ffi::c_void; + +use bls_dash_sys::{CoreMPLDeriveChildPkUnhardened, G1ElementFree, G1ElementFromBytes, G1ElementGenerator, G1ElementGetFingerprint, G1ElementIsEqual, G1ElementSerialize, G1ElementCopy, G2ElementCopy, G2ElementFree, G2ElementFromBytes, G2ElementIsEqual, G2ElementSerialize, ThresholdPublicKeyRecover, ThresholdSignatureRecover}; +#[cfg(feature = "use_serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::{schemes::Scheme, utils::c_err_to_result, BlsError, BasicSchemeMPL}; + +// TODO Split into modules + +pub const G1_ELEMENT_SIZE: usize = 48; // TODO somehow extract it from bls library +pub const G2_ELEMENT_SIZE: usize = 96; // TODO somehow extract it from bls library + +#[cfg(feature = "dash_helpers")] +pub type PublicKey = G1Element; + +#[cfg(feature = "dash_helpers")] +pub type Signature = G2Element; + +#[derive(Debug)] +pub struct G1Element { + pub(crate) c_element: *mut c_void, +} + +impl PartialEq for G1Element { + fn eq(&self, other: &Self) -> bool { + unsafe { G1ElementIsEqual(self.c_element, other.c_element) } + } +} + +impl Eq for G1Element {} + +impl G1Element { + pub fn generate() -> Self { + let c_element = unsafe { G1ElementGenerator() }; + + G1Element { c_element } + } + + #[cfg(feature = "dash_helpers")] + pub fn verify(&self, signature: &G2Element, message: &[u8]) -> bool { + self.verify_basic(signature, message) + } + + pub fn verify_basic(&self, signature: &G2Element, message: &[u8]) -> bool { + let basic_scheme = BasicSchemeMPL::new(); + basic_scheme.verify(self, message, signature) + } + + pub(crate) fn from_bytes_with_legacy_flag( + bytes: &[u8], + legacy: bool, + ) -> Result { + if bytes.len() != G1_ELEMENT_SIZE { + return Err(BlsError { + msg: format!( + "G1 Element size must be {}, got {}", + G1_ELEMENT_SIZE, + bytes.len() + ), + }); + } + Ok(G1Element { + c_element: c_err_to_result(|did_err| unsafe { + G1ElementFromBytes(bytes.as_ptr() as *const _, legacy, did_err) + })?, + }) + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + Self::from_bytes_with_legacy_flag(bytes, false) + } + + pub(crate) fn to_bytes_with_legacy_flag(&self, legacy: bool) -> Box<[u8; G1_ELEMENT_SIZE]> { + unsafe { + let malloc_ptr = G1ElementSerialize(self.c_element, legacy); + Box::from_raw(malloc_ptr as *mut _) + } + } + + pub fn to_bytes(&self) -> Box<[u8; G1_ELEMENT_SIZE]> { + self.to_bytes_with_legacy_flag(false) + } + + pub fn derive_child_public_key_unhardened( + &self, + scheme: &impl Scheme, + index: u32, + ) -> G1Element { + G1Element { + c_element: unsafe { + CoreMPLDeriveChildPkUnhardened(scheme.as_mut_ptr(), self.c_element, index) + }, + } + } + + pub(crate) fn fingerprint_with_legacy_flag(&self, legacy: bool) -> u32 { + unsafe { G1ElementGetFingerprint(self.c_element, legacy) } + } + + pub fn fingerprint(&self) -> u32 { + self.fingerprint_with_legacy_flag(false) + } + + pub fn threshold_recover( + bls_ids_with_elements: &[(Vec, G1Element)], + ) -> Result { + unsafe { + let len = bls_ids_with_elements.len(); + let (c_hashes, c_elements): (Vec<_>, Vec<_>) = bls_ids_with_elements + .iter() + .map(|(hash, element)| { + ( + hash.as_ptr() as *mut c_void, + element.c_element as *mut c_void, + ) + }) + .unzip(); + let c_hashes_ptr = c_hashes.as_ptr() as *mut *mut c_void; + let c_elements_ptr = c_elements.as_ptr() as *mut *mut c_void; + Ok(G1Element { + c_element: c_err_to_result(|did_err| { + ThresholdPublicKeyRecover(c_elements_ptr, len, c_hashes_ptr, len, did_err) + })?, + }) + } + } +} + +impl Clone for G1Element { + fn clone(&self) -> Self { + unsafe { + G1Element{c_element: G1ElementCopy(self.c_element)} + } + } +} + +#[cfg(feature = "use_serde")] +// Implement Serialize trait for G1Element +impl Serialize for G1Element { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let bytes = *self.to_bytes(); + serializer.serialize_bytes(&bytes) + } +} + +#[cfg(feature = "use_serde")] +// Implement Deserialize trait for G1Element +impl<'de> Deserialize<'de> for G1Element { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct G1ElementVisitor; + + impl<'de> serde::de::Visitor<'de> for G1ElementVisitor { + type Value = G1Element; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a byte array representing a G1Element") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: serde::de::Error, + { + G1Element::from_bytes(bytes).map_err(serde::de::Error::custom) + } + } + + deserializer.deserialize_bytes(G1ElementVisitor) + } +} + +impl Drop for G1Element { + fn drop(&mut self) { + unsafe { G1ElementFree(self.c_element) } + } +} + +#[derive(Debug)] +pub struct G2Element { + pub(crate) c_element: *mut c_void, +} + +impl PartialEq for G2Element { + fn eq(&self, other: &Self) -> bool { + unsafe { G2ElementIsEqual(self.c_element, other.c_element) } + } +} + +impl Eq for G2Element {} + +impl G2Element { + pub(crate) fn from_bytes_with_legacy_flag( + bytes: &[u8], + legacy: bool, + ) -> Result { + if bytes.len() != G2_ELEMENT_SIZE { + return Err(BlsError { + msg: format!( + "G2 Element size must be {}, got {}", + G2_ELEMENT_SIZE, + bytes.len() + ), + }); + } + Ok(G2Element { + c_element: c_err_to_result(|did_err| unsafe { + G2ElementFromBytes(bytes.as_ptr() as *const _, legacy, did_err) + })?, + }) + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + Self::from_bytes_with_legacy_flag(bytes, false) + } + + pub(crate) fn to_bytes_with_legacy_flag(&self, legacy: bool) -> Box<[u8; G2_ELEMENT_SIZE]> { + unsafe { + let malloc_ptr = G2ElementSerialize(self.c_element, legacy); + Box::from_raw(malloc_ptr as *mut _) + } + } + + pub fn to_bytes(&self) -> Box<[u8; G2_ELEMENT_SIZE]> { + self.to_bytes_with_legacy_flag(false) + } + + pub fn threshold_recover( + bls_ids_with_elements: &[(Vec, G2Element)], + ) -> Result { + unsafe { + let len = bls_ids_with_elements.len(); + let (c_hashes, c_elements): (Vec<_>, Vec<_>) = bls_ids_with_elements + .iter() + .map(|(hash, element)| { + ( + hash.as_ptr() as *mut c_void, + element.c_element as *mut c_void, + ) + }) + .unzip(); + let c_hashes_ptr = c_hashes.as_ptr() as *mut *mut c_void; + let c_elements_ptr = c_elements.as_ptr() as *mut *mut c_void; + Ok(G2Element { + c_element: c_err_to_result(|did_err| { + ThresholdSignatureRecover(c_elements_ptr, len, c_hashes_ptr, len, did_err) + })?, + }) + } + } +} + +impl Clone for G2Element { + fn clone(&self) -> Self { + unsafe { + G2Element{c_element: G2ElementCopy(self.c_element)} + } + } +} + +#[cfg(feature = "use_serde")] +// Implement Serialize trait for G1Element +impl Serialize for G2Element { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let bytes = *self.to_bytes(); + serializer.serialize_bytes(&bytes) + } +} + +#[cfg(feature = "use_serde")] +// Implement Deserialize trait for G1Element +impl<'de> Deserialize<'de> for G2Element { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct G2ElementVisitor; + + impl<'de> serde::de::Visitor<'de> for G2ElementVisitor { + type Value = G2Element; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a byte array representing a G2Element") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: serde::de::Error, + { + G2Element::from_bytes(bytes).map_err(serde::de::Error::custom) + } + } + + deserializer.deserialize_bytes(G2ElementVisitor) + } +} + +impl Drop for G2Element { + fn drop(&mut self) { + unsafe { G2ElementFree(self.c_element) } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + schemes::{AugSchemeMPL, Scheme}, + PrivateKey, + }; + + #[test] + fn g1_serialize_deserialize() { + let seed = b"seedweedseedweedseedweedseedweed"; + let scheme = AugSchemeMPL::new(); + let sk = PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key"); + + let g1 = sk.g1_element().expect("cannot get G1 element"); + let g1_bytes = g1.to_bytes(); + let g1_2 = + G1Element::from_bytes(g1_bytes.as_ref()).expect("cannot build G1 element from bytes"); + + assert_eq!(g1, g1_2); + } + + #[test] + fn g2_serialize_deserialize() { + let seed = b"seedweedseedweedseedweedseedweed"; + let scheme = AugSchemeMPL::new(); + let sk = PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key"); + + let g2 = scheme.sign(&sk, b"ayy"); + let g2_bytes = g2.to_bytes(); + let g2_2 = + G2Element::from_bytes(g2_bytes.as_ref()).expect("cannot build G2 element from bytes"); + + assert_eq!(g2, g2_2); + } + + #[test] + fn should_generate_new_g1_element() { + let g1_element = G1Element::generate(); + + assert_eq!(g1_element.to_bytes().len(), 48); + } + + #[test] + fn should_return_fingerprint() { + let bytes = [ + 151, 241, 211, 167, 49, 151, 215, 148, 38, 149, 99, 140, 79, 169, 172, 15, 195, 104, + 140, 79, 151, 116, 185, 5, 161, 78, 58, 63, 23, 27, 172, 88, 108, 85, 232, 63, 249, + 122, 26, 239, 251, 58, 240, 10, 219, 34, 198, 187, + ]; + + let g1_element = + G1Element::from_bytes(&bytes).expect("should create g1 element from bytes"); + + assert_eq!(g1_element.fingerprint(), 2093959050); + } +} diff --git a/rust-bindings/bls-signatures/src/legacy/bip32/mod.rs b/rust-bindings/bls-signatures/src/legacy/bip32/mod.rs new file mode 100644 index 0000000000..5426eac84a --- /dev/null +++ b/rust-bindings/bls-signatures/src/legacy/bip32/mod.rs @@ -0,0 +1,2 @@ +mod private_key; +mod public_key; diff --git a/rust-bindings/bls-signatures/src/legacy/bip32/private_key.rs b/rust-bindings/bls-signatures/src/legacy/bip32/private_key.rs new file mode 100644 index 0000000000..c818c37214 --- /dev/null +++ b/rust-bindings/bls-signatures/src/legacy/bip32/private_key.rs @@ -0,0 +1,58 @@ +use crate::{ + bip32::{ExtendedPrivateKey, ExtendedPublicKey}, + BlsError, +}; + +impl ExtendedPrivateKey { + pub fn private_child_legacy(&self, index: u32) -> Self { + self.private_child_with_legacy_flag(index, true) + } + + pub fn extended_public_key_legacy(&self) -> Result { + self.extended_public_key_with_legacy_flag(true) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn serialize_deserialize_legacy() { + let seed = b"seedweedseedweedseedweedseedweed"; + let private_key = + ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key"); + let public_key = private_key + .extended_public_key_legacy() + .expect("cannot get extended public key"); + + let public_key_bytes = public_key.serialize_legacy(); + let public_key_2 = ExtendedPublicKey::from_bytes_legacy(public_key_bytes.as_ref()) + .expect("cannot deserialize extended public key"); + + assert_eq!(public_key, public_key_2); + } + + #[test] + fn hierarchical_deterministic_keys_legacy() { + let seed = b"seedweedseedweedseedweedseedweed"; + let private_key = + ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key"); + let public_key = private_key + .extended_public_key_legacy() + .expect("cannot get extended public key"); + + let private_child = private_key.private_child_legacy(1337); + let private_grandchild = private_child.private_child_legacy(420); + + let public_child = public_key.public_child_legacy(1337); + let public_grandchild = public_child.public_child_legacy(420); + + assert_eq!( + public_grandchild, + private_grandchild + .extended_public_key_legacy() + .expect("cannot get extended public key") + ); + } +} diff --git a/rust-bindings/bls-signatures/src/legacy/bip32/public_key.rs b/rust-bindings/bls-signatures/src/legacy/bip32/public_key.rs new file mode 100644 index 0000000000..eb0bda8513 --- /dev/null +++ b/rust-bindings/bls-signatures/src/legacy/bip32/public_key.rs @@ -0,0 +1,40 @@ +use crate::{ + bip32::{ExtendedPublicKey, BIP32_EXTENDED_PUBLIC_KEY_SIZE}, + BlsError, +}; + +impl ExtendedPublicKey { + pub fn from_bytes_legacy(bytes: &[u8]) -> Result { + Self::from_bytes_with_legacy_flag(bytes, true) + } + + pub fn public_child_legacy(&self, index: u32) -> Self { + self.public_child_with_legacy_flag(index, true) + } + + pub fn serialize_legacy(&self) -> Box<[u8; BIP32_EXTENDED_PUBLIC_KEY_SIZE]> { + self.serialize_with_legacy_flag(true) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::bip32::ExtendedPrivateKey; + + #[test] + fn serialize_deserialize_legacy() { + let seed = b"seedweedseedweedseedweedseedweed"; + let private_key = + ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key"); + let public_key = private_key + .extended_public_key_legacy() + .expect("cannot get extended public key"); + + let public_key_bytes = public_key.serialize_legacy(); + let public_key_2 = ExtendedPublicKey::from_bytes_legacy(public_key_bytes.as_ref()) + .expect("cannot deserialize extended public key"); + + assert_eq!(public_key, public_key_2); + } +} diff --git a/rust-bindings/bls-signatures/src/legacy/elements.rs b/rust-bindings/bls-signatures/src/legacy/elements.rs new file mode 100644 index 0000000000..ca205a8073 --- /dev/null +++ b/rust-bindings/bls-signatures/src/legacy/elements.rs @@ -0,0 +1,25 @@ +use crate::{BlsError, G1Element, G2Element, G1_ELEMENT_SIZE, G2_ELEMENT_SIZE}; + +impl G1Element { + pub fn serialize_legacy(&self) -> Box<[u8; G1_ELEMENT_SIZE]> { + self.to_bytes_with_legacy_flag(true) + } + + pub fn from_bytes_legacy(bytes: &[u8]) -> Result { + Self::from_bytes_with_legacy_flag(bytes, true) + } + + pub fn fingerprint_legacy(&self) -> u32 { + self.fingerprint_with_legacy_flag(true) + } +} + +impl G2Element { + pub fn from_bytes_legacy(bytes: &[u8]) -> Result { + Self::from_bytes_with_legacy_flag(bytes, true) + } + + pub fn serialize_legacy(&self) -> Box<[u8; G2_ELEMENT_SIZE]> { + self.to_bytes_with_legacy_flag(true) + } +} diff --git a/rust-bindings/bls-signatures/src/legacy/mod.rs b/rust-bindings/bls-signatures/src/legacy/mod.rs new file mode 100644 index 0000000000..d84ab9d025 --- /dev/null +++ b/rust-bindings/bls-signatures/src/legacy/mod.rs @@ -0,0 +1,2 @@ +mod bip32; +mod elements; diff --git a/rust-bindings/bls-signatures/src/lib.rs b/rust-bindings/bls-signatures/src/lib.rs new file mode 100644 index 0000000000..e6d76b8149 --- /dev/null +++ b/rust-bindings/bls-signatures/src/lib.rs @@ -0,0 +1,104 @@ +mod elements; +mod private_key; +mod schemes; +mod utils; + +#[cfg(feature = "legacy")] +mod legacy; + +#[cfg(feature = "bip32")] +pub mod bip32; + +use std::{error::Error, fmt::Display}; + +pub use elements::{G1Element, G2Element, G1_ELEMENT_SIZE, G2_ELEMENT_SIZE}; +#[cfg(feature = "dash_helpers")] +pub use elements::{PublicKey, Signature}; +pub use private_key::{PrivateKey, PRIVATE_KEY_SIZE}; +pub use schemes::{AugSchemeMPL, BasicSchemeMPL, LegacySchemeMPL, Scheme}; + +#[derive(Debug, PartialEq)] +pub struct BlsError { + // Need to use owned version as each time BLS has an error its binding glue overwrites error + // message variable. + msg: String, +} + +impl Display for BlsError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.msg) + } +} + +impl Error for BlsError {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::schemes::{AugSchemeMPL, Scheme}; + + #[test] + fn basic_sign() { + let seed = b"seedweedseedweedseedweedseedweed"; + let bad_seed = b"weedseedweedseedweedseedweedseed"; + + let scheme = AugSchemeMPL::new(); + + let private_key_before = + PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key"); + + // Also test private key serialization + let private_key_bytes = private_key_before.to_bytes(); + let private_key = PrivateKey::from_bytes(private_key_bytes.as_slice(), false) + .expect("cannot build private key from bytes"); + drop(private_key_bytes); + + let public_key = private_key.g1_element().expect("unable to get public key"); + + let private_key_bad = + PrivateKey::key_gen(&scheme, bad_seed).expect("unable to generate private key"); + let public_key_bad = private_key_bad + .g1_element() + .expect("unable to get public key"); + + let message = b"Evgeny owns 1337 dash no cap"; + + let signature = scheme.sign(&private_key, message); + let verify = scheme.verify(&public_key, message, &signature); + assert!(verify); + let verify_bad = scheme.verify(&public_key_bad, message, &signature); + assert!(!verify_bad); + } + + #[test] + fn bad_seed() { + let seed = b"lol"; + let scheme = AugSchemeMPL::new(); + let private_key = PrivateKey::key_gen(&scheme, seed); + + assert!(matches!( + private_key, + Err(BlsError { msg }) if msg == "Seed size must be at least 32 bytes" + )); + } + + #[test] + fn hd_keys_deterministic() { + let seed = b"seedweedseedweedseedweedseedweed"; + let scheme = AugSchemeMPL::new(); + + let master_sk = PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key"); + let master_pk = master_sk.g1_element().expect("unable to get public key"); + + let child_sk_u = master_sk.derive_child_private_key_unhardened(&scheme, 22); + let grandchild_sk_u = child_sk_u.derive_child_private_key_unhardened(&scheme, 0); + + let child_pk_u = master_pk.derive_child_public_key_unhardened(&scheme, 22); + let grandchild_pk_u = child_pk_u.derive_child_public_key_unhardened(&scheme, 0); + + assert_eq!( + grandchild_pk_u, + grandchild_sk_u.g1_element().expect("cannot get public key") + ); + } +} diff --git a/rust-bindings/bls-signatures/src/private_key.rs b/rust-bindings/bls-signatures/src/private_key.rs new file mode 100755 index 0000000000..bc74d710f3 --- /dev/null +++ b/rust-bindings/bls-signatures/src/private_key.rs @@ -0,0 +1,315 @@ +use std::{ffi::c_void, ops::Mul}; + +use bls_dash_sys::{ + CoreMPLDeriveChildSk, CoreMPLDeriveChildSkUnhardened, CoreMPLKeyGen, G1ElementMul, + PrivateKeyFree, PrivateKeyFromBytes, PrivateKeyFromSeedBIP32, PrivateKeyGetG1Element, + PrivateKeyIsEqual, PrivateKeySerialize, ThresholdPrivateKeyRecover, +}; +use rand::{prelude::StdRng, Rng}; +#[cfg(feature = "use_serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::{schemes::Scheme, utils::{c_err_to_result, SecureBox}, BasicSchemeMPL, BlsError, G1Element, G2Element}; + +pub const PRIVATE_KEY_SIZE: usize = 32; // TODO somehow extract it from bls library + +#[derive(Debug)] +pub struct PrivateKey { + pub(crate) c_private_key: *mut c_void, +} + +impl PartialEq for PrivateKey { + fn eq(&self, other: &Self) -> bool { + unsafe { PrivateKeyIsEqual(self.c_private_key, other.c_private_key) } + } +} + +impl Eq for PrivateKey {} + +impl Mul for PrivateKey { + type Output = Result; + + fn mul(self, rhs: G1Element) -> Self::Output { + Ok(G1Element { + c_element: c_err_to_result(|_| unsafe { + G1ElementMul(rhs.c_element, self.c_private_key) + })?, + }) + } +} + +impl Mul for G1Element { + type Output = Result; + + fn mul(self, rhs: PrivateKey) -> Self::Output { + rhs * self + } +} + +impl PrivateKey { + pub(crate) fn as_mut_ptr(&self) -> *mut c_void { + self.c_private_key + } + + // TODO Rename to from_seed + pub fn key_gen(scheme: &impl Scheme, seed: &[u8]) -> Result { + Ok(PrivateKey { + c_private_key: c_err_to_result(|did_err| unsafe { + CoreMPLKeyGen( + scheme.as_mut_ptr(), + seed.as_ptr() as *const _, + seed.len(), + did_err, + ) + })?, + }) + } + + #[cfg(feature = "dash_helpers")] + pub fn generate_dash(rng: &mut StdRng) -> Result { + let seed = rng.gen::<[u8; 32]>(); + let scheme = BasicSchemeMPL::new(); + Ok(PrivateKey { + c_private_key: c_err_to_result(|did_err| unsafe { + CoreMPLKeyGen( + scheme.as_mut_ptr(), + seed.as_ptr() as *const _, + seed.len(), + did_err, + ) + })?, + }) + } + + #[cfg(feature = "dash_helpers")] + pub fn sign(&self, message: &[u8]) -> G2Element { + self.sign_basic(message) + } + + pub fn sign_basic(&self, message: &[u8]) -> G2Element { + let scheme = BasicSchemeMPL::new(); + scheme.sign(self, message) + } + + #[cfg(feature = "dash_helpers")] + pub fn generate_dash_many(count: usize, rng: &mut StdRng) -> Result, BlsError> { + (0..count) + .into_iter() + .map(|_| Self::generate_dash(rng)) + .collect() + } + + pub fn g1_element(&self) -> Result { + Ok(G1Element { + c_element: c_err_to_result(|did_err| unsafe { + PrivateKeyGetG1Element(self.c_private_key, did_err) + })?, + }) + } + + pub fn to_bytes(&self) -> SecureBox { + // `PrivateKeySerialize` internally securely allocates memory which we have to + // wrap safely + unsafe { + SecureBox::from_ptr( + PrivateKeySerialize(self.c_private_key) as *mut u8, + PRIVATE_KEY_SIZE, + ) + } + } + + pub fn from_bytes(bytes: &[u8], mod_order: bool) -> Result { + if bytes.len() != PRIVATE_KEY_SIZE { + return Err(BlsError { + msg: format!( + "Private key size must be {}, got {}", + PRIVATE_KEY_SIZE, + bytes.len() + ), + }); + } + + let c_private_key = c_err_to_result(|did_err| unsafe { + PrivateKeyFromBytes(bytes.as_ptr() as *const c_void, mod_order, did_err) + })?; + + Ok(PrivateKey { c_private_key }) + } + + pub fn from_bip32_seed(bytes: &[u8]) -> Self { + let c_private_key = + unsafe { PrivateKeyFromSeedBIP32(bytes.as_ptr() as *const c_void, bytes.len()) }; + + PrivateKey { c_private_key } + } + + pub fn derive_child_private_key(&self, scheme: &impl Scheme, index: u32) -> PrivateKey { + PrivateKey { + c_private_key: unsafe { + CoreMPLDeriveChildSk(scheme.as_mut_ptr(), self.c_private_key, index) + }, + } + } + + pub fn derive_child_private_key_unhardened( + &self, + scheme: &impl Scheme, + index: u32, + ) -> PrivateKey { + PrivateKey { + c_private_key: unsafe { + CoreMPLDeriveChildSkUnhardened(scheme.as_mut_ptr(), self.c_private_key, index) + }, + } + } + + pub fn threshold_recover( + bls_ids_with_private_keys: &[(Vec, PrivateKey)], + ) -> Result { + unsafe { + let len = bls_ids_with_private_keys.len(); + let (c_hashes, c_elements): (Vec<_>, Vec<_>) = bls_ids_with_private_keys + .iter() + .map(|(hash, element)| (hash.as_ptr() as *mut c_void, element.c_private_key)) + .unzip(); + let c_hashes_ptr = c_hashes.as_ptr() as *mut *mut c_void; + let c_elements_ptr = c_elements.as_ptr() as *mut *mut c_void; + Ok(PrivateKey { + c_private_key: c_err_to_result(|did_err| { + ThresholdPrivateKeyRecover(c_elements_ptr, len, c_hashes_ptr, len, did_err) + })?, + }) + } + } +} + +impl Clone for PrivateKey { + fn clone(&self) -> Self { + // Serialize the element + let bytes = self.to_bytes(); + // We can panic + PrivateKey::from_bytes(bytes.as_slice(), false).expect("expected bytes to be valid") + } +} + +#[cfg(feature = "use_serde")] +// Implement Serialize trait for G1Element +impl Serialize for PrivateKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(self.to_bytes().as_slice()) + } +} + +#[cfg(feature = "use_serde")] +// Implement Deserialize trait for G1Element +impl<'de> Deserialize<'de> for PrivateKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PrivateKeyElementVisitor; + + impl<'de> serde::de::Visitor<'de> for PrivateKeyElementVisitor { + type Value = PrivateKey; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a byte array representing a Private Key") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: serde::de::Error, + { + PrivateKey::from_bytes(bytes, false).map_err(serde::de::Error::custom) + } + } + + deserializer.deserialize_bytes(PrivateKeyElementVisitor) + } +} + +impl Drop for PrivateKey { + fn drop(&mut self) { + unsafe { PrivateKeyFree(self.c_private_key) } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::schemes::AugSchemeMPL; + + #[test] + fn serialize_deserialize() { + let seed = b"seedweedseedweedseedweedseedweed"; + let scheme = AugSchemeMPL::new(); + let sk1 = PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key"); + let sk1_bytes = sk1.to_bytes(); + let sk2 = PrivateKey::from_bytes(sk1_bytes.as_slice(), false) + .expect("cannot build private key from bytes"); + + assert_eq!(sk1, sk2); + } + + #[test] + fn should_return_private_key_from_bip32_bytes() { + let long_seed = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 1, 2, + ]; + let long_private_key_test_data = [ + 50, 67, 148, 112, 207, 6, 210, 118, 137, 125, 27, 144, 105, 189, 214, 228, 68, 83, 144, + 205, 80, 105, 133, 222, 14, 26, 28, 136, 167, 111, 241, 118, + ]; + let long_private_key = PrivateKey::from_bip32_seed(&long_seed); + assert_eq!(*long_private_key.to_bytes(), long_private_key_test_data); + + // Previously didn't work with seed with length != 32 + let short_seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let short_private_key_test_data = [ + 70, 137, 28, 44, 236, 73, 89, 60, 129, 146, 30, 71, 61, 183, 72, 0, 41, 224, 252, 30, + 185, 51, 198, 185, 61, 129, 245, 55, 14, 177, 159, 189, + ]; + let short_private_key = PrivateKey::from_bip32_seed(&short_seed); + assert_eq!(*short_private_key.to_bytes(), short_private_key_test_data); + } + + #[test] + fn test_keys_multiplication() { + // 46891c2cec49593c81921e473db7480029e0fc1eb933c6b93d81f5370eb19fbd + let private_key_data = [ + 70, 137, 28, 44, 236, 73, 89, 60, 129, 146, 30, 71, 61, 183, 72, 0, 41, 224, 252, 30, + 185, 51, 198, 185, 61, 129, 245, 55, 14, 177, 159, 189, + ]; + // 0e2f9055c17eb13221d8b41833468ab49f7d4e874ddf4b217f5126392a608fd48ccab3510548f1da4f397c1ad4f8e01a + let public_key_data = [ + 14, 47, 144, 85, 193, 126, 177, 50, 33, 216, 180, 24, 51, 70, 138, 180, 159, 125, 78, + 135, 77, 223, 75, 33, 127, 81, 38, 57, 42, 96, 143, 212, 140, 202, 179, 81, 5, 72, 241, + 218, 79, 57, 124, 26, 212, 248, 224, 26, + ]; + // 03fd387c4d4c66ec9dcdb31ef0c08ad881090dcda13d4b2c9cbc5ef264ff4dc7 + let expected_data = [ + 3, 253, 56, 124, 77, 76, 102, 236, 157, 205, 179, 30, 240, 192, 138, 216, 129, 9, 13, + 205, 161, 61, 75, 44, 156, 188, 94, 242, 100, 255, 77, 199, + ]; + let private_key = PrivateKey::from_bytes(&private_key_data, false).unwrap(); + let public_key = G1Element::from_bytes_legacy(&public_key_data).unwrap(); + let result = (private_key * public_key).unwrap(); + assert_eq!( + &result.serialize_legacy()[..32], + &expected_data, + "should match" + ); + let private_key = PrivateKey::from_bytes(&private_key_data, false).unwrap(); + let public_key = G1Element::from_bytes_legacy(&public_key_data).unwrap(); + let result = (public_key * private_key).unwrap(); + assert_eq!( + &result.serialize_legacy()[..32], + &expected_data, + "should match" + ); + } +} diff --git a/rust-bindings/bls-signatures/src/schemes.rs b/rust-bindings/bls-signatures/src/schemes.rs new file mode 100644 index 0000000000..3019bc0b4a --- /dev/null +++ b/rust-bindings/bls-signatures/src/schemes.rs @@ -0,0 +1,434 @@ +use std::ffi::c_void; + +use bls_dash_sys::{ + AugSchemeMPLAggregateVerify, AugSchemeMPLFree, AugSchemeMPLSign, AugSchemeMPLVerify, + BasicSchemeMPLAggregateVerify, BasicSchemeMPLFree, CoreMPLAggregatePubKeys, + CoreMPLAggregateSigs, CoreMPLSign, CoreMPLVerify, CoreMPLVerifySecure, + LegacySchemeMPLAggregateVerify, LegacySchemeMPLSign, LegacySchemeMPLVerify, + LegacySchemeMPLVerifySecure, NewAugSchemeMPL, NewBasicSchemeMPL, NewLegacySchemeMPL, +}; + +// TODO Split into modules +use crate::{private_key::PrivateKey, G1Element, G2Element}; + +pub trait Scheme { + fn as_mut_ptr(&self) -> *mut c_void; + + fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element; + + fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool; + + fn verify_secure<'a>( + &self, + public_keys: impl IntoIterator, + message: &[u8], + signature: &G2Element, + ) -> bool { + let mut g1_pointers = public_keys + .into_iter() + .map(|g1| g1.c_element) + .collect::>(); + + unsafe { + CoreMPLVerifySecure( + self.as_mut_ptr(), + g1_pointers.as_mut_ptr(), + g1_pointers.len(), + signature.c_element, + message.as_ptr() as *const _, + message.len(), + ) + } + } + + fn aggregate_public_keys<'a>( + &self, + public_keys: impl IntoIterator, + ) -> G1Element { + let mut g1_pointers = public_keys + .into_iter() + .map(|g1| g1.c_element) + .collect::>(); + G1Element { + c_element: unsafe { + CoreMPLAggregatePubKeys( + self.as_mut_ptr(), + g1_pointers.as_mut_ptr(), + g1_pointers.len(), + ) + }, + } + } + + fn aggregate_sigs<'a>(&self, sigs: impl IntoIterator) -> G2Element { + let mut g2_pointers = sigs.into_iter().map(|g2| g2.c_element).collect::>(); + G2Element { + c_element: unsafe { + CoreMPLAggregateSigs( + self.as_mut_ptr(), + g2_pointers.as_mut_ptr(), + g2_pointers.len(), + ) + }, + } + } + + fn aggregate_verify<'a>( + &self, + public_keys: impl IntoIterator, + messages: impl IntoIterator, + signature: &G2Element, + ) -> bool; +} + +struct AggregateVerifyArgs { + g1_pointers: Vec<*mut c_void>, + messages_pointers: Vec<*const u8>, + messages_lengths: Vec, +} + +// TODO put constructor inside struct? +fn prepare_aggregate_verify_args<'a>( + public_keys: impl IntoIterator, + messages: impl IntoIterator, +) -> AggregateVerifyArgs { + let g1_pointers = public_keys + .into_iter() + .map(|g1| g1.c_element) + .collect::>(); + + let mut messages_pointers = Vec::new(); + let mut messages_lengths = Vec::new(); + + for m in messages.into_iter() { + messages_pointers.push(m.as_ptr()); + messages_lengths.push(m.len()); + } + + AggregateVerifyArgs { + g1_pointers, + messages_pointers, + messages_lengths, + } +} + +pub struct BasicSchemeMPL { + scheme: *mut c_void, +} + +impl BasicSchemeMPL { + pub fn new() -> Self { + BasicSchemeMPL { + scheme: unsafe { NewBasicSchemeMPL() }, + } + } +} + +impl Scheme for BasicSchemeMPL { + fn as_mut_ptr(&self) -> *mut c_void { + self.scheme + } + + fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element { + G2Element { + c_element: unsafe { + CoreMPLSign( + self.scheme, + private_key.as_mut_ptr(), + message.as_ptr() as *const _, + message.len(), + ) + }, + } + } + + fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool { + unsafe { + CoreMPLVerify( + self.scheme, + public_key.c_element, + message.as_ptr() as *const _, + message.len(), + signature.c_element, + ) + } + } + + fn aggregate_verify<'a>( + &self, + public_keys: impl IntoIterator, + messages: impl IntoIterator, + signature: &G2Element, + ) -> bool { + let AggregateVerifyArgs { + mut g1_pointers, + mut messages_pointers, + messages_lengths: mut messages_lengthes, + } = prepare_aggregate_verify_args(public_keys, messages); + + unsafe { + BasicSchemeMPLAggregateVerify( + self.as_mut_ptr(), + g1_pointers.as_mut_ptr(), + g1_pointers.len(), + messages_pointers.as_mut_ptr() as *mut _, + messages_lengthes.as_mut_ptr() as *mut _, + messages_pointers.len(), + signature.c_element, + ) + } + } +} + +pub struct LegacySchemeMPL { + scheme: *mut c_void, +} + +impl LegacySchemeMPL { + pub fn new() -> Self { + LegacySchemeMPL { + scheme: unsafe { NewLegacySchemeMPL() }, + } + } +} + +impl Scheme for LegacySchemeMPL { + fn as_mut_ptr(&self) -> *mut c_void { + self.scheme + } + + fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element { + G2Element { + c_element: unsafe { + LegacySchemeMPLSign( + self.scheme, + private_key.as_mut_ptr(), + message.as_ptr() as *const _, + message.len(), + ) + }, + } + } + + fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool { + unsafe { + LegacySchemeMPLVerify( + self.scheme, + public_key.c_element, + message.as_ptr() as *const _, + message.len(), + signature.c_element, + ) + } + } + + fn verify_secure<'a>( + &self, + public_keys: impl IntoIterator, + message: &[u8], + signature: &G2Element, + ) -> bool { + let mut g1_pointers = public_keys + .into_iter() + .map(|g1| g1.c_element) + .collect::>(); + + unsafe { + LegacySchemeMPLVerifySecure( + self.as_mut_ptr(), + g1_pointers.as_mut_ptr(), + g1_pointers.len(), + signature.c_element, + message.as_ptr() as *const _, + message.len(), + ) + } + } + + fn aggregate_verify<'a>( + &self, + public_keys: impl IntoIterator, + messages: impl IntoIterator, + signature: &G2Element, + ) -> bool { + let AggregateVerifyArgs { + mut g1_pointers, + mut messages_pointers, + messages_lengths: mut messages_lengthes, + } = prepare_aggregate_verify_args(public_keys, messages); + + unsafe { + LegacySchemeMPLAggregateVerify( + self.as_mut_ptr(), + g1_pointers.as_mut_ptr(), + g1_pointers.len(), + messages_pointers.as_mut_ptr() as *mut _, + messages_lengthes.as_mut_ptr() as *mut _, + messages_pointers.len(), + signature.c_element, + ) + } + } +} + +impl Drop for BasicSchemeMPL { + fn drop(&mut self) { + unsafe { BasicSchemeMPLFree(self.scheme) } + } +} + +pub struct AugSchemeMPL { + scheme: *mut c_void, +} + +impl AugSchemeMPL { + pub fn new() -> Self { + AugSchemeMPL { + scheme: unsafe { NewAugSchemeMPL() }, + } + } +} + +impl Scheme for AugSchemeMPL { + fn as_mut_ptr(&self) -> *mut c_void { + self.scheme + } + + fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element { + G2Element { + c_element: unsafe { + AugSchemeMPLSign( + self.scheme, + private_key.as_mut_ptr(), + message.as_ptr() as *const _, + message.len(), + ) + }, + } + } + + fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool { + unsafe { + AugSchemeMPLVerify( + self.scheme, + public_key.c_element, + message.as_ptr() as *const _, + message.len(), + signature.c_element, + ) + } + } + + fn aggregate_verify<'a>( + &self, + public_keys: impl IntoIterator, + messages: impl IntoIterator, + signature: &G2Element, + ) -> bool { + let AggregateVerifyArgs { + mut g1_pointers, + mut messages_pointers, + mut messages_lengths, + } = prepare_aggregate_verify_args(public_keys, messages); + + unsafe { + AugSchemeMPLAggregateVerify( + self.as_mut_ptr(), + g1_pointers.as_mut_ptr(), + g1_pointers.len(), + messages_pointers.as_mut_ptr() as *mut _, + messages_lengths.as_mut_ptr() as *mut _, + messages_pointers.len(), + signature.c_element, + ) + } + } +} + +impl Drop for AugSchemeMPL { + fn drop(&mut self) { + unsafe { AugSchemeMPLFree(self.scheme) } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn verify_aggregate(scheme: impl Scheme) { + let seed1 = b"seedweedseedweedseedweedseedweed"; + let seed2 = b"weedseedweedseedweedseedweedseed"; + let seed3 = b"seedseedseedseedweedweedweedweed"; + let seed4 = b"weedweedweedweedweedweedweedweed"; + + let private_key_1 = + PrivateKey::key_gen(&scheme, seed1).expect("unable to generate private key"); + let private_key_2 = + PrivateKey::key_gen(&scheme, seed2).expect("unable to generate private key"); + let private_key_3 = + PrivateKey::key_gen(&scheme, seed3).expect("unable to generate private key"); + let private_key_4 = + PrivateKey::key_gen(&scheme, seed4).expect("unable to generate private key"); + + let public_key_1 = private_key_1 + .g1_element() + .expect("unable to get public key"); + let public_key_2 = private_key_2 + .g1_element() + .expect("unable to get public key"); + let public_key_3 = private_key_3 + .g1_element() + .expect("unable to get public key"); + let public_key_4 = private_key_4 + .g1_element() + .expect("unable to get public key"); + + let message_1 = b"ayya"; + let message_2 = b"ayyb"; + let message_3 = b"ayyc"; + let message_4 = b"ayyd"; + + let signature_1 = scheme.sign(&private_key_1, message_1); + let signature_2 = scheme.sign(&private_key_2, message_2); + let signature_3 = scheme.sign(&private_key_3, message_3); + let signature_4 = scheme.sign(&private_key_4, message_4); + + let signature_agg = scheme.aggregate_sigs([&signature_1, &signature_2, &signature_3]); + + let verify = scheme.aggregate_verify( + [&public_key_1, &public_key_2, &public_key_3], + [message_1.as_ref(), message_2.as_ref(), message_3.as_ref()], + &signature_agg, + ); + assert!(verify); + + // Arbitrary trees of aggregates + let signature_agg_final = scheme.aggregate_sigs([&signature_agg, &signature_4]); + let verify_final = scheme.aggregate_verify( + [&public_key_1, &public_key_2, &public_key_3, &public_key_4], + [ + message_1.as_ref(), + message_2.as_ref(), + message_3.as_ref(), + message_4.as_ref(), + ], + &signature_agg_final, + ); + assert!(verify_final); + } + + #[test] + fn verify_aggregate_aug() { + verify_aggregate(AugSchemeMPL::new()); + } + + #[test] + fn verify_aggregate_basic() { + verify_aggregate(BasicSchemeMPL::new()); + } + + #[test] + fn verify_aggregate_legacy() { + verify_aggregate(LegacySchemeMPL::new()); + } +} diff --git a/rust-bindings/bls-signatures/src/utils.rs b/rust-bindings/bls-signatures/src/utils.rs new file mode 100644 index 0000000000..8461e25e93 --- /dev/null +++ b/rust-bindings/bls-signatures/src/utils.rs @@ -0,0 +1,71 @@ +use core::slice; +use std::{ + ffi::{c_void, CStr}, + ops::Deref, +}; + +use bls_dash_sys::{GetLastErrorMsg, SecAllocBytes, SecFree}; + +use crate::BlsError; + +pub(crate) fn c_err_to_result(f: F) -> Result +where + F: FnOnce(&mut bool) -> T, +{ + let mut did_error = false; + let result = f(&mut did_error); + + if did_error { + let error_message = unsafe { CStr::from_ptr(GetLastErrorMsg()) }; + Err(BlsError { + msg: String::from_utf8_lossy(error_message.to_bytes()).into_owned(), + }) + } else { + Ok(result) + } +} + +pub struct SecureBox { + c_sec_alloc: *mut u8, + len: usize, +} + +impl SecureBox { + #[allow(dead_code)] + pub(crate) fn new(len: usize) -> Self { + SecureBox { + c_sec_alloc: unsafe { SecAllocBytes(len) }, + len, + } + } + + pub(crate) unsafe fn from_ptr(ptr: *mut u8, len: usize) -> Self { + SecureBox { + c_sec_alloc: ptr, + len, + } + } + + // Somewhere it returns *mut c_void + pub(crate) fn as_mut_ptr(&mut self) -> *mut c_void { + self.c_sec_alloc as *mut c_void + } + + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.c_sec_alloc, self.len) } + } +} + +impl Deref for SecureBox { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +impl Drop for SecureBox { + fn drop(&mut self) { + unsafe { SecFree(self.as_mut_ptr()) } + } +} diff --git a/rust-bindings/example/Cargo.toml b/rust-bindings/example/Cargo.toml new file mode 100644 index 0000000000..8cbc6b7d91 --- /dev/null +++ b/rust-bindings/example/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "example" +version = "0.1.0" +edition = "2021" + +[dependencies] +bls-signatures = { path = "../bls-signatures" } diff --git a/rust-bindings/example/src/main.rs b/rust-bindings/example/src/main.rs new file mode 100644 index 0000000000..afc7c27cbb --- /dev/null +++ b/rust-bindings/example/src/main.rs @@ -0,0 +1,51 @@ +use bls_signatures::{bip32::ExtendedPrivateKey, LegacySchemeMPL, Scheme}; + +const SEED: &'static [u8] = b"seedweedseedweedseedweedseedweed"; + +fn check_bip32_hd_keys() { + println!("Check BIP32 hierarchical deterministic keys work"); + + let private_key = + ExtendedPrivateKey::from_seed(SEED).expect("cannot generate extended private key"); + let public_key = private_key + .extended_public_key() + .expect("cannot get extended public key"); + + let private_child = private_key.private_child(1337); + let private_grandchild = private_child.private_child(420); + + let public_child = public_key.public_child(1337); + let public_grandchild = public_child.public_child(420); + + assert_eq!( + public_grandchild, + private_grandchild + .extended_public_key() + .expect("cannot get extended public key") + ); +} + +fn check_bip32_legacy_scheme() { + println!("Check BIP32 signing works"); + + let private_key = + ExtendedPrivateKey::from_seed(SEED).expect("cannot generate extended private key"); + let public_key = private_key + .extended_public_key() + .expect("cannot get extended public key"); + + let scheme = LegacySchemeMPL::new(); + let message = b"dash is og"; + let signature = scheme.sign(&private_key.private_key(), message); + + assert!(scheme.verify(&public_key.public_key(), message, &signature)); +} + +fn main() { + println!("Run some checks to see if everything is linked up to original BLS library:"); + + check_bip32_hd_keys(); + check_bip32_legacy_scheme(); + + println!("All checks passed!"); +} diff --git a/setjmp_patch.diff b/setjmp_patch.diff new file mode 100644 index 0000000000..f4a5c80f1c --- /dev/null +++ b/setjmp_patch.diff @@ -0,0 +1,41 @@ +diff --git a/include/relic_err.h b/include/relic_err.h +index e16f71fe..a4adb107 100644 +--- a/include/relic_err.h ++++ b/include/relic_err.h +@@ -33,7 +33,6 @@ + #define RLC_ERR_H + + #include +-#include + #include + #include + #include +@@ -43,6 +42,10 @@ + #include "relic_util.h" + #include "relic_label.h" + ++#ifdef CHECK ++#include ++#endif ++ + /*============================================================================*/ + /* Constant definitions */ + /*============================================================================*/ +@@ -94,6 +97,8 @@ enum errors { + */ + typedef int err_t; + ++#ifdef CHECK ++ + /** + * Type that describes an error status, including the error code and the program + * location where the error occurred. +@@ -107,6 +112,8 @@ typedef struct _sts_t { + int block; + } sts_t; + ++#endif ++ + /*============================================================================*/ + /* Macro definitions */ + /*============================================================================*/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a021e7894f..c3c1abd759 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,8 +11,7 @@ add_library(dashbls ${CMAKE_CURRENT_SOURCE_DIR}/extendedpublickey.cpp ${CMAKE_CURRENT_SOURCE_DIR}/legacy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/schemes.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/threshold.cpp -) + ${CMAKE_CURRENT_SOURCE_DIR}/threshold.cpp) target_include_directories(dashbls PUBLIC diff --git a/src/elements.cpp b/src/elements.cpp index d53426da02..278af8cd8f 100644 --- a/src/elements.cpp +++ b/src/elements.cpp @@ -98,6 +98,14 @@ G1Element G1Element::FromNative(const g1_t element) return ele; } +G1Element G1Element::Copy() { + G1Element ele; + g1_copy(ele.p, this->p); + + return ele; +} + + G1Element G1Element::FromMessage(const std::vector& message, const uint8_t* dst, int dst_len) @@ -246,6 +254,7 @@ G2Element G2Element::FromBytesUnchecked(Bytes const bytes, const bool fLegacy) if (fLegacy) { std::memcpy(buffer + 1, bytes.begin(), G2Element::SIZE); + buffer[0] = 0x00; } else { std::memcpy(buffer + 1, bytes.begin() + G2Element::SIZE / 2, G2Element::SIZE / 2); std::memcpy(buffer + 1 + G2Element::SIZE / 2, bytes.begin(), G2Element::SIZE / 2); @@ -358,6 +367,14 @@ void G2Element::ToNative(g2_t output) const { g2_copy(output, (g2_st*)q); } +G2Element G2Element::Copy() { + G2Element ele; + g2_copy(ele.q, this->q); + + return ele; +} + + G2Element G2Element::Negate() const { G2Element ans; diff --git a/src/test.cpp b/src/test.cpp index 3102c7eeae..51d84706a8 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -56,7 +56,7 @@ void TestHKDF(string ikm_hex, string salt_hex, string info_hex, string prk_expec TEST_CASE("class PrivateKey") { uint8_t buffer[PrivateKey::PRIVATE_KEY_SIZE]; - memcmp(buffer, getRandomSeed().data(), PrivateKey::PRIVATE_KEY_SIZE); + memcpy(buffer, getRandomSeed().data(), PrivateKey::PRIVATE_KEY_SIZE); SECTION("Copy {constructor|assignment operator}") { PrivateKey pk1 = PrivateKey::RandomPrivateKey(); PrivateKey pk2 = PrivateKey::RandomPrivateKey();