diff --git a/src/bls/bls.h b/src/bls/bls.h index d16914c5683c7..5cdc50eb27fe8 100644 --- a/src/bls/bls.h +++ b/src/bls/bls.h @@ -57,7 +57,7 @@ class CBLSWrapper static constexpr size_t SerSize = _SerSize; explicit CBLSWrapper() = default; - explicit CBLSWrapper(const std::vector& vecBytes) : CBLSWrapper() + explicit CBLSWrapper(Span vecBytes) : CBLSWrapper() { SetByteVector(vecBytes); } @@ -99,18 +99,18 @@ class CBLSWrapper *(static_cast(this)) = C(); } - void SetByteVector(const std::vector& vecBytes, const bool specificLegacyScheme) + void SetByteVector(Span vecBytes, const bool specificLegacyScheme) { if (vecBytes.size() != SerSize) { Reset(); return; } - if (ranges::all_of(vecBytes, [](uint8_t c) { return c == 0; })) { + if (std::all_of(vecBytes.begin(), vecBytes.end(), [](uint8_t c) { return c == 0; })) { Reset(); } else { try { - impl = ImplType::FromBytes(bls::Bytes(vecBytes), specificLegacyScheme); + impl = ImplType::FromBytes(bls::Bytes(vecBytes.data(), SerSize), specificLegacyScheme); fValid = true; } catch (...) { Reset(); @@ -119,20 +119,20 @@ class CBLSWrapper cachedHash.SetNull(); } - void SetByteVector(const std::vector& vecBytes) + void SetByteVector(Span vecBytes) { SetByteVector(vecBytes, bls::bls_legacy_scheme.load()); } - std::vector ToByteVector(const bool specificLegacyScheme) const + std::array ToByteVector(const bool specificLegacyScheme) const { if (!fValid) { - return std::vector(SerSize, 0); + return {}; } - return impl.Serialize(specificLegacyScheme); + return impl.SerializeToArray(specificLegacyScheme); } - std::vector ToByteVector() const + std::array ToByteVector() const { return ToByteVector(bls::bls_legacy_scheme.load()); } @@ -185,7 +185,7 @@ class CBLSWrapper template inline void Unserialize(Stream& s, const bool specificLegacyScheme, bool checkMalleable = true) { - std::vector vecBytes(SerSize, 0); + std::array vecBytes{}; s.read(reinterpret_cast(vecBytes.data()), SerSize); SetByteVector(vecBytes, specificLegacyScheme); @@ -228,7 +228,7 @@ class CBLSWrapper inline std::string ToString(const bool specificLegacyScheme) const { - std::vector buf = ToByteVector(specificLegacyScheme); + auto buf = ToByteVector(specificLegacyScheme); return HexStr(buf); } @@ -255,6 +255,12 @@ struct CBLSIdImplicit : public uint256 { return {begin(), end()}; } + [[nodiscard]] std::array SerializeToArray(const bool fLegacy) const + { + std::array ret{}; + std::copy(begin(), end(), ret.begin()); + return ret; + } }; class CBLSId : public CBLSWrapper @@ -405,7 +411,7 @@ class CBLSLazyWrapper private: mutable std::mutex mutex; - mutable std::vector vecBytes; + mutable std::array vecBytes; mutable bool bufValid{false}; mutable bool bufLegacyScheme{true}; @@ -416,7 +422,7 @@ class CBLSLazyWrapper public: CBLSLazyWrapper() : - vecBytes(BLSObject::SerSize, 0), + vecBytes{}, bufLegacyScheme(bls::bls_legacy_scheme.load()) {} @@ -434,7 +440,7 @@ class CBLSLazyWrapper if (r.bufValid) { vecBytes = r.vecBytes; } else { - vecBytes.resize(BLSObject::SerSize); +// vecBytes.resize(BLSObject::SerSize); std::fill(vecBytes.begin(), vecBytes.end(), 0); } objInitialized = r.objInitialized; @@ -457,7 +463,7 @@ class CBLSLazyWrapper { std::unique_lock l(mutex); if (!objInitialized && !bufValid) { - vecBytes.resize(BLSObject::SerSize); +// vecBytes.resize(BLSObject::SerSize); std::fill(vecBytes.begin(), vecBytes.end(), 0); } else if (!bufValid || (bufLegacyScheme != specificLegacyScheme)) { vecBytes = obj.ToByteVector(specificLegacyScheme); @@ -542,7 +548,7 @@ class CBLSLazyWrapper { std::unique_lock l(mutex); if (!objInitialized && !bufValid) { - vecBytes.resize(BLSObject::SerSize); +// vecBytes.resize(BLSObject::SerSize); std::fill(vecBytes.begin(), vecBytes.end(), 0); hash.SetNull(); } else if (!bufValid) { diff --git a/src/bls/bls_ies.cpp b/src/bls/bls_ies.cpp index b57dfdb2edd64..4896e2b695835 100644 --- a/src/bls/bls_ies.cpp +++ b/src/bls/bls_ies.cpp @@ -49,8 +49,7 @@ bool CBLSIESEncryptedBlob::Encrypt(size_t idx, const CBLSPublicKey& peerPubKey, return false; } - std::vector symKey = pk.ToByteVector(); - symKey.resize(32); + auto symKey = pk.ToByteVector(); uint256 iv = GetIV(idx); return EncryptBlob(plainTextData, dataSize, data, symKey.data(), iv.begin()); @@ -63,8 +62,7 @@ bool CBLSIESEncryptedBlob::Decrypt(size_t idx, const CBLSSecretKey& secretKey, C return false; } - std::vector symKey = pk.ToByteVector(); - symKey.resize(32); + auto symKey = pk.ToByteVector(); uint256 iv = GetIV(idx); return DecryptBlob(data.data(), data.size(), decryptedDataRet, symKey.data(), iv.begin()); @@ -117,8 +115,7 @@ bool CBLSIESMultiRecipientBlobs::Encrypt(size_t idx, const CBLSPublicKey& recipi return false; } - std::vector symKey = pk.ToByteVector(); - symKey.resize(32); + auto symKey = pk.ToByteVector(); return EncryptBlob(blob.data(), blob.size(), blobs[idx], symKey.data(), ivVector[idx].begin()); } @@ -134,8 +131,7 @@ bool CBLSIESMultiRecipientBlobs::Decrypt(size_t idx, const CBLSSecretKey& sk, Bl return false; } - std::vector symKey = pk.ToByteVector(); - symKey.resize(32); + auto symKey = pk.ToByteVector(); uint256 iv = ivSeed; for (size_t i = 0; i < idx; i++) { diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index 61a5f65159078..44affae954c0b 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -22,6 +22,7 @@ #include #include +//#include constexpr static CAmount DEFAULT_MAX_RAW_TX_FEE{COIN / 10}; @@ -65,7 +66,8 @@ bool CCoinJoinQueue::Sign() bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const { bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip()); - if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) { + Span span(const_cast(vchSig.data()), vchSig.size()); + if (!CBLSSignature(span).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) { LogPrint(BCLog::COINJOIN, "CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed\n"); return false; } @@ -114,7 +116,8 @@ bool CCoinJoinBroadcastTx::Sign() bool CCoinJoinBroadcastTx::CheckSignature(const CBLSPublicKey& blsPubKey) const { bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip()); - if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) { + Span span(const_cast(vchSig.data()), vchSig.size()); + if (!CBLSSignature(span).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) { LogPrint(BCLog::COINJOIN, "CCoinJoinBroadcastTx::CheckSignature -- VerifyInsecure() failed\n"); return false; } diff --git a/src/coinjoin/coinjoin.h b/src/coinjoin/coinjoin.h index 22f541303ecf0..0aecd297724b3 100644 --- a/src/coinjoin/coinjoin.h +++ b/src/coinjoin/coinjoin.h @@ -18,6 +18,7 @@ #include #include +#include class CCoinJoin; class CConnman; @@ -200,7 +201,7 @@ class CCoinJoinQueue uint256 m_protxHash; int64_t nTime{0}; bool fReady{false}; //ready for submit - std::vector vchSig; + std::array vchSig; // memory only bool fTried{false}; @@ -272,7 +273,7 @@ class CCoinJoinBroadcastTx CTransactionRef tx; COutPoint masternodeOutpoint; uint256 m_protxHash; - std::vector vchSig; + std::array vchSig; int64_t sigTime{0}; CCoinJoinBroadcastTx() : diff --git a/src/dashbls/.gitignore b/src/dashbls/.gitignore index 38818e6ab83de..bec3896a5c071 100644 --- a/src/dashbls/.gitignore +++ b/src/dashbls/.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/src/dashbls/CMakeLists.txt b/src/dashbls/CMakeLists.txt index f730426e1f083..f413f97cc7a98 100644 --- a/src/dashbls/CMakeLists.txt +++ b/src/dashbls/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/src/dashbls/apple.rust.deps.sh b/src/dashbls/apple.rust.deps.sh new file mode 100755 index 0000000000000..7d3b8de22f4c6 --- /dev/null +++ b/src/dashbls/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/src/dashbls/apple.rust.sh b/src/dashbls/apple.rust.sh new file mode 100755 index 0000000000000..e105c3ce6ce13 --- /dev/null +++ b/src/dashbls/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/src/dashbls/apple.rust.single.sh b/src/dashbls/apple.rust.single.sh new file mode 100755 index 0000000000000..d99722bf02c76 --- /dev/null +++ b/src/dashbls/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/src/dashbls/emsdk_build.sh b/src/dashbls/emsdk_build.sh index 704f43cfbcc8d..17f5f307ba50c 100755 --- a/src/dashbls/emsdk_build.sh +++ b/src/dashbls/emsdk_build.sh @@ -7,4 +7,4 @@ mkdir -p js_build cd js_build emcmake cmake -G "Unix Makefiles" .. -emmake make +#emmake make diff --git a/src/dashbls/include/dashbls/elements.hpp b/src/dashbls/include/dashbls/elements.hpp index a147115907bf5..95937f62dbc6c 100644 --- a/src/dashbls/include/dashbls/elements.hpp +++ b/src/dashbls/include/dashbls/elements.hpp @@ -59,6 +59,8 @@ class G1Element { GTElement Pair(const G2Element &b) const; uint32_t GetFingerprint(bool fLegacy = false) const; std::vector Serialize(bool fLegacy = false) const; + std::array SerializeToArray(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 +103,8 @@ class G2Element { G2Element Negate() const; GTElement Pair(const G1Element &a) const; std::vector Serialize(bool fLegacy = false) const; + std::array SerializeToArray(bool fLegacy = false) const; + G2Element Copy(); friend bool operator==(G2Element const &a, G2Element const &b); friend bool operator!=(G2Element const &a, G2Element const &b); @@ -125,6 +129,7 @@ class GTElement { void Serialize(uint8_t *buffer) const; std::vector Serialize() const; + std::array SerializeToArray() const; friend bool operator==(GTElement const &a, GTElement const &b); friend bool operator!=(GTElement const &a, GTElement const &b); diff --git a/src/dashbls/include/dashbls/privatekey.hpp b/src/dashbls/include/dashbls/privatekey.hpp index beebbb05aba3d..d02a7d292c120 100644 --- a/src/dashbls/include/dashbls/privatekey.hpp +++ b/src/dashbls/include/dashbls/privatekey.hpp @@ -82,6 +82,7 @@ class PrivateKey { // Serialize the key into bytes void Serialize(uint8_t *buffer) const; std::vector Serialize(bool fLegacy = false) const; + std::array SerializeToArray(bool fLegacy = false) const; G2Element SignG2( const uint8_t *msg, diff --git a/src/dashbls/js-bindings/CMakeLists.txt b/src/dashbls/js-bindings/CMakeLists.txt index 55de66444a373..03da706af724b 100644 --- a/src/dashbls/js-bindings/CMakeLists.txt +++ b/src/dashbls/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/src/dashbls/js-bindings/blsjs.d.ts b/src/dashbls/js-bindings/blsjs.d.ts index 4cd30bc621114..95cb05962ad12 100644 --- a/src/dashbls/js-bindings/blsjs.d.ts +++ b/src/dashbls/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/src/dashbls/js-bindings/jsbindings.cpp b/src/dashbls/js-bindings/jsbindings.cpp index f390923eb808b..81daa4abc74e9 100644 --- a/src/dashbls/js-bindings/jsbindings.cpp +++ b/src/dashbls/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/src/dashbls/js-bindings/wrappers/SchemeMPLWrapper.h b/src/dashbls/js-bindings/wrappers/SchemeMPLWrapper.h index 972d7e3a761ae..e5a4ae5ef860b 100644 --- a/src/dashbls/js-bindings/wrappers/SchemeMPLWrapper.h +++ b/src/dashbls/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/src/dashbls/python-impl/op_swu_g2.py b/src/dashbls/python-impl/op_swu_g2.py index 2872611215125..afdb40cf714b4 100644 --- a/src/dashbls/python-impl/op_swu_g2.py +++ b/src/dashbls/python-impl/op_swu_g2.py @@ -21,6 +21,7 @@ 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/src/dashbls/rust-bindings/.gitignore b/src/dashbls/rust-bindings/.gitignore new file mode 100644 index 0000000000000..cb117fd6ee838 --- /dev/null +++ b/src/dashbls/rust-bindings/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target \ No newline at end of file diff --git a/src/dashbls/rust-bindings/bls-dash-sys/.rustfmt.toml b/src/dashbls/rust-bindings/bls-dash-sys/.rustfmt.toml new file mode 100644 index 0000000000000..f5fe8f31884fb --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/Cargo.toml b/src/dashbls/rust-bindings/bls-dash-sys/Cargo.toml new file mode 100644 index 0000000000000..c5a04be4deba3 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/bindings.rs b/src/dashbls/rust-bindings/bls-dash-sys/bindings.rs new file mode 100644 index 0000000000000..b90527e85fa2b --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/build.rs b/src/dashbls/rust-bindings/bls-dash-sys/build.rs new file mode 100644 index 0000000000000..47cd7ddb122b1 --- /dev/null +++ b/src/dashbls/rust-bindings/bls-dash-sys/build.rs @@ -0,0 +1,355 @@ +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 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 = 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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.cpp new file mode 100644 index 0000000000000..177c4d7371427 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/chaincode.h new file mode 100644 index 0000000000000..688cf3f51e65e --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.cpp new file mode 100644 index 0000000000000..541f5f992cf1d --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedprivatekey.h new file mode 100644 index 0000000000000..18ca3c28f301a --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.cpp new file mode 100644 index 0000000000000..703c32e0216fc --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/bip32/extendedpublickey.h new file mode 100644 index 0000000000000..51465cae039c9 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/blschia.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/blschia.cpp new file mode 100644 index 0000000000000..2b3c274dc44c3 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/blschia.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/blschia.h new file mode 100644 index 0000000000000..ebc3b518dcfa4 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.cpp new file mode 100644 index 0000000000000..5214bc4fc931e --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/elements.h new file mode 100644 index 0000000000000..fa1b5ae581172 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/error.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/error.h new file mode 100644 index 0000000000000..57525b77fa645 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.cpp new file mode 100644 index 0000000000000..4e1d0df346614 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/privatekey.h new file mode 100644 index 0000000000000..147e1a618f21e --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/schemes.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/schemes.cpp new file mode 100644 index 0000000000000..bc2e632c8027e --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/schemes.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/schemes.h new file mode 100644 index 0000000000000..41b39a61038de --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/threshold.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/threshold.cpp new file mode 100644 index 0000000000000..2bb668483df5a --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/threshold.h b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/threshold.h new file mode 100644 index 0000000000000..054ddffcd89ea --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/utils.cpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/utils.cpp new file mode 100644 index 0000000000000..85ad174c84d3e --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/utils.hpp b/src/dashbls/rust-bindings/bls-dash-sys/c-bindings/utils.hpp new file mode 100644 index 0000000000000..42e7898a3fc44 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/include.h b/src/dashbls/rust-bindings/bls-dash-sys/include.h new file mode 100644 index 0000000000000..4189a0748cac8 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/src/lib.rs b/src/dashbls/rust-bindings/bls-dash-sys/src/lib.rs new file mode 100644 index 0000000000000..a24bad5d77c7d --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-dash-sys/tests/sign_and_verify.rs b/src/dashbls/rust-bindings/bls-dash-sys/tests/sign_and_verify.rs new file mode 100644 index 0000000000000..6ceee4961c4b0 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/.rustfmt.toml b/src/dashbls/rust-bindings/bls-signatures/.rustfmt.toml new file mode 100644 index 0000000000000..f5fe8f31884fb --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/Cargo.toml b/src/dashbls/rust-bindings/bls-signatures/Cargo.toml new file mode 100644 index 0000000000000..8c6f1e3c1d9a2 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/bip32/chain_code.rs b/src/dashbls/rust-bindings/bls-signatures/src/bip32/chain_code.rs new file mode 100644 index 0000000000000..f5271cc45b648 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/bip32/mod.rs b/src/dashbls/rust-bindings/bls-signatures/src/bip32/mod.rs new file mode 100644 index 0000000000000..6b3a64326ecb6 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/bip32/private_key.rs b/src/dashbls/rust-bindings/bls-signatures/src/bip32/private_key.rs new file mode 100644 index 0000000000000..af4394f179799 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/bip32/public_key.rs b/src/dashbls/rust-bindings/bls-signatures/src/bip32/public_key.rs new file mode 100644 index 0000000000000..43fa484f0cc2d --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/elements.rs b/src/dashbls/rust-bindings/bls-signatures/src/elements.rs new file mode 100644 index 0000000000000..3388ce022a242 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/legacy/bip32/mod.rs b/src/dashbls/rust-bindings/bls-signatures/src/legacy/bip32/mod.rs new file mode 100644 index 0000000000000..5426eac84a797 --- /dev/null +++ b/src/dashbls/rust-bindings/bls-signatures/src/legacy/bip32/mod.rs @@ -0,0 +1,2 @@ +mod private_key; +mod public_key; diff --git a/src/dashbls/rust-bindings/bls-signatures/src/legacy/bip32/private_key.rs b/src/dashbls/rust-bindings/bls-signatures/src/legacy/bip32/private_key.rs new file mode 100644 index 0000000000000..c818c37214b55 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/legacy/bip32/public_key.rs b/src/dashbls/rust-bindings/bls-signatures/src/legacy/bip32/public_key.rs new file mode 100644 index 0000000000000..eb0bda8513583 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/legacy/elements.rs b/src/dashbls/rust-bindings/bls-signatures/src/legacy/elements.rs new file mode 100644 index 0000000000000..ca205a8073c5a --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/legacy/mod.rs b/src/dashbls/rust-bindings/bls-signatures/src/legacy/mod.rs new file mode 100644 index 0000000000000..d84ab9d0259b3 --- /dev/null +++ b/src/dashbls/rust-bindings/bls-signatures/src/legacy/mod.rs @@ -0,0 +1,2 @@ +mod bip32; +mod elements; diff --git a/src/dashbls/rust-bindings/bls-signatures/src/lib.rs b/src/dashbls/rust-bindings/bls-signatures/src/lib.rs new file mode 100644 index 0000000000000..e6d76b81495ab --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/private_key.rs b/src/dashbls/rust-bindings/bls-signatures/src/private_key.rs new file mode 100755 index 0000000000000..bc74d710f30ac --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/schemes.rs b/src/dashbls/rust-bindings/bls-signatures/src/schemes.rs new file mode 100644 index 0000000000000..3019bc0b4aa69 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/bls-signatures/src/utils.rs b/src/dashbls/rust-bindings/bls-signatures/src/utils.rs new file mode 100644 index 0000000000000..8461e25e93991 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/example/Cargo.toml b/src/dashbls/rust-bindings/example/Cargo.toml new file mode 100644 index 0000000000000..8cbc6b7d91968 --- /dev/null +++ b/src/dashbls/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/src/dashbls/rust-bindings/example/src/main.rs b/src/dashbls/rust-bindings/example/src/main.rs new file mode 100644 index 0000000000000..afc7c27cbb4ed --- /dev/null +++ b/src/dashbls/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/src/dashbls/setjmp_patch.diff b/src/dashbls/setjmp_patch.diff new file mode 100644 index 0000000000000..f4a5c80f1c2c7 --- /dev/null +++ b/src/dashbls/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/dashbls/src/CMakeLists.txt b/src/dashbls/src/CMakeLists.txt index a021e7894fdd8..c3c1abd7593d9 100644 --- a/src/dashbls/src/CMakeLists.txt +++ b/src/dashbls/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/dashbls/src/elements.cpp b/src/dashbls/src/elements.cpp index d53426da02604..af718227396f3 100644 --- a/src/dashbls/src/elements.cpp +++ b/src/dashbls/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) @@ -182,6 +190,29 @@ std::vector G1Element::Serialize(const bool fLegacy) const { return std::vector(buffer + 1, buffer + 1 + G1Element::SIZE); } +std::array G1Element::SerializeToArray(const bool fLegacy) const { + uint8_t buffer[G1Element::SIZE + 1]; + g1_write_bin(buffer, G1Element::SIZE + 1, p, 1); + + if (buffer[0] == 0x00) { // infinity + std::array result{}; + result[0] = 0xc0; + return result; + } + + if (buffer[0] == 0x03) { // sign bit set + buffer[1] |= fLegacy ? 0x80 : 0x20; + } + + if (!fLegacy) { + buffer[1] |= 0x80; // indicate compression + } + + std::array result{}; + std::copy_n(buffer + 1, G1Element::SIZE, result.begin()); + return result; +} + bool operator==(const G1Element & a, const G1Element &b) { return g1_cmp(a.p, b.p) == RLC_EQ; @@ -358,6 +389,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; @@ -405,6 +444,44 @@ std::vector G2Element::Serialize(const bool fLegacy) const { return result; } +std::array G2Element::SerializeToArray(const bool fLegacy) const { + uint8_t buffer[G2Element::SIZE + 1]; + g2_write_bin(buffer, G2Element::SIZE + 1, (g2_st*)q, 1); + + std::array result{}; + + if (buffer[0] == 0x00) { // infinity + result.fill(0); + result[0] = 0xc0; + return result; + } + + if (fLegacy) { + if (buffer[0] == 0x03) { // sign bit set + buffer[1] |= 0x80; + } + } else { + // remove leading 3 bits + buffer[1] &= 0x1f; + buffer[49] &= 0x1f; + if (buffer[0] == 0x03) { + buffer[49] |= 0xa0; // swapped later to 0 + } else { + buffer[49] |= 0x80; + } + } + + if (fLegacy) { + std::memcpy(result.data(), buffer + 1, G2Element::SIZE); + } else { + // Swap buffer, relic uses the opposite ordering for Fq2 elements + std::memcpy(result.data(), buffer + 1 + G2Element::SIZE / 2, G2Element::SIZE / 2); + std::memcpy(result.data() + G2Element::SIZE / 2, buffer + 1, G2Element::SIZE / 2); + } + + return result; +} + bool operator==(G2Element const& a, G2Element const& b) { return g2_cmp((g2_st*)a.q, (g2_st*)b.q) == RLC_EQ; @@ -534,4 +611,11 @@ std::vector GTElement::Serialize() const return data; } +std::array GTElement::SerializeToArray() const +{ + std::array data{}; + Serialize(data.data()); + return data; +} + } // end namespace bls diff --git a/src/dashbls/src/privatekey.cpp b/src/dashbls/src/privatekey.cpp index 865507dfc7d6d..d4dd32d116776 100644 --- a/src/dashbls/src/privatekey.cpp +++ b/src/dashbls/src/privatekey.cpp @@ -284,6 +284,13 @@ std::vector PrivateKey::Serialize(const bool fLegacy) const return data; } +std::array PrivateKey::SerializeToArray(bool fLegacy) const +{ + std::array data{}; + Serialize(data.data()); + return data; +} + G2Element PrivateKey::SignG2( const uint8_t *msg, size_t len, diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 5f429859865cc..7f493998685c9 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -606,7 +606,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde newList.SetHeight(nHeight); } - newList.SetBlockHash(block.GetHash()); + newList.SetBlockHash(pindex->GetBlockHash()); oldList = GetListForBlockInternal(pindex->pprev); diff = oldList.BuildDiff(newList); @@ -1442,7 +1442,8 @@ template static bool CheckHashSig(const ProTx& proTx, const PKHash& pkhash, TxValidationState& state) { std::string strError; - if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), proTx.vchSig, strError)) { + auto span_vchSig = Span(const_cast(proTx.vchSig.data()), proTx.vchSig.size()); + if (!CHashSigner::VerifyHash(::SerializeHash(proTx), ToKeyID(pkhash), span_vchSig, strError)) { return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig"); } return true; @@ -1452,7 +1453,8 @@ template static bool CheckStringSig(const ProTx& proTx, const PKHash& pkhash, TxValidationState& state) { std::string strError; - if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), proTx.vchSig, proTx.MakeSignString(), strError)) { + auto span_vchSig = Span(const_cast(proTx.vchSig.data()), proTx.vchSig.size()); + if (!CMessageSigner::VerifyMessage(ToKeyID(pkhash), span_vchSig, proTx.MakeSignString(), strError)) { return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig"); } return true; @@ -1581,7 +1583,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxVali } } else { // collateral is part of this ProRegTx, so we know the collateral is owned by the issuer - if (!ptx.vchSig.empty()) { + if (!std::all_of(ptx.vchSig.begin(), ptx.vchSig.end(), [](unsigned char c) { return c == 0; })) { return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-sig"); } } diff --git a/src/evo/providertx.h b/src/evo/providertx.h index 85f7f921d99df..7fb5db4100e10 100644 --- a/src/evo/providertx.h +++ b/src/evo/providertx.h @@ -48,7 +48,7 @@ class CProRegTx uint16_t nOperatorReward{0}; CScript scriptPayout; uint256 inputsHash; // replay protection - std::vector vchSig; + std::array vchSig{}; SERIALIZE_METHODS(CProRegTx, obj) { @@ -216,7 +216,7 @@ class CProUpRegTx CKeyID keyIDVoting; CScript scriptPayout; uint256 inputsHash; // replay protection - std::vector vchSig; + std::array vchSig; SERIALIZE_METHODS(CProUpRegTx, obj) { diff --git a/src/governance/object.cpp b/src/governance/object.cpp index 2ee21f823eb13..f346af2121616 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -317,7 +317,8 @@ bool CGovernanceObject::CheckSignature(const CBLSPublicKey& pubKey) const CBLSSignature sig; const auto pindex = llmq::utils::V19ActivationIndex(::ChainActive().Tip()); bool is_bls_legacy_scheme = pindex == nullptr || nTime < pindex->pprev->nTime; - sig.SetByteVector(vchSig, is_bls_legacy_scheme); + auto span = Span(const_cast(vchSig.data()), vchSig.size()); + sig.SetByteVector(span, is_bls_legacy_scheme); if (!sig.VerifyInsecure(pubKey, GetSignatureHash(), is_bls_legacy_scheme)) { LogPrintf("CGovernanceObject::CheckSignature -- VerifyInsecure() failed\n"); return false; diff --git a/src/governance/object.h b/src/governance/object.h index de96d9111631e..88c01338f9a51 100644 --- a/src/governance/object.h +++ b/src/governance/object.h @@ -127,7 +127,7 @@ class CGovernanceObject /// Masternode info for signed objects COutPoint masternodeOutpoint; - std::vector vchSig; + std::array vchSig; /// is valid by blockchain bool fCachedLocalValidity; diff --git a/src/governance/vote.cpp b/src/governance/vote.cpp index cea35b32d0a9a..eb77371aeaa43 100644 --- a/src/governance/vote.cpp +++ b/src/governance/vote.cpp @@ -172,9 +172,11 @@ bool CGovernanceVote::Sign(const CKey& key, const CKeyID& keyID) if (Params().NetworkIDString() == CBaseChainParams::TESTNET) { uint256 signatureHash = GetSignatureHash(); - if (!CHashSigner::SignHash(signatureHash, key, vchSig)) { + if (auto opt_sig = CHashSigner::SignHash(signatureHash, key); !opt_sig) { LogPrintf("CGovernanceVote::Sign -- SignHash() failed\n"); return false; + } else { + vchSig = {opt_sig->begin(), opt_sig->end()}; } if (!CHashSigner::VerifyHash(signatureHash, keyID, vchSig, strError)) { @@ -185,9 +187,11 @@ bool CGovernanceVote::Sign(const CKey& key, const CKeyID& keyID) std::string strMessage = masternodeOutpoint.ToStringShort() + "|" + nParentHash.ToString() + "|" + ::ToString(nVoteSignal) + "|" + ::ToString(nVoteOutcome) + "|" + ::ToString(nTime); - if (!CMessageSigner::SignMessage(strMessage, vchSig, key)) { + if (auto opt_sig = CMessageSigner::SignMessage(strMessage, key); !opt_sig) { LogPrintf("CGovernanceVote::Sign -- SignMessage() failed\n"); return false; + } else { + vchSig = {opt_sig->begin(), opt_sig->end()}; } if (!CMessageSigner::VerifyMessage(keyID, vchSig, strMessage, strError)) { @@ -203,9 +207,12 @@ bool CGovernanceVote::CheckSignature(const CKeyID& keyID) const { std::string strError; + // TODO remove when Verify* methods are spanified + auto span_vchSig = Span(const_cast(vchSig.data()), vchSig.size()); + // Harden Spork6 so that it is active on testnet and no other networks if (Params().NetworkIDString() == CBaseChainParams::TESTNET) { - if (!CHashSigner::VerifyHash(GetSignatureHash(), keyID, vchSig, strError)) { + if (!CHashSigner::VerifyHash(GetSignatureHash(), keyID, span_vchSig, strError)) { LogPrint(BCLog::GOBJECT, "CGovernanceVote::IsValid -- VerifyHash() failed, error: %s\n", strError); return false; } @@ -215,7 +222,7 @@ bool CGovernanceVote::CheckSignature(const CKeyID& keyID) const ::ToString(nVoteOutcome) + "|" + ::ToString(nTime); - if (!CMessageSigner::VerifyMessage(keyID, vchSig, strMessage, strError)) { + if (!CMessageSigner::VerifyMessage(keyID, span_vchSig, strMessage, strError)) { LogPrint(BCLog::GOBJECT, "CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s\n", strError); return false; } @@ -224,13 +231,15 @@ bool CGovernanceVote::CheckSignature(const CKeyID& keyID) const return true; } + bool CGovernanceVote::Sign(const CBLSSecretKey& key) { CBLSSignature sig = key.Sign(GetSignatureHash()); if (!sig.IsValid()) { return false; } - vchSig = sig.ToByteVector(); + auto bytes = sig.ToByteVector(); + vchSig = {bytes.begin(), bytes.end()}; return true; } @@ -239,7 +248,8 @@ bool CGovernanceVote::CheckSignature(const CBLSPublicKey& pubKey) const CBLSSignature sig; const auto pindex = llmq::utils::V19ActivationIndex(::ChainActive().Tip()); bool is_bls_legacy_scheme = pindex == nullptr || nTime < pindex->pprev->nTime; - sig.SetByteVector(vchSig, is_bls_legacy_scheme); + auto span = Span(const_cast(vchSig.data()), vchSig.size()); + sig.SetByteVector(span, is_bls_legacy_scheme); if (!sig.VerifyInsecure(pubKey, GetSignatureHash(), is_bls_legacy_scheme)) { LogPrintf("CGovernanceVote::CheckSignature -- VerifyInsecure() failed\n"); return false; diff --git a/src/governance/vote.h b/src/governance/vote.h index 0675b59c25acc..76e949a5e11f4 100644 --- a/src/governance/vote.h +++ b/src/governance/vote.h @@ -7,7 +7,6 @@ #include -class CGovernanceVote; class CBLSPublicKey; class CBLSSecretKey; class CConnman; @@ -67,6 +66,7 @@ class CGovernanceVote uint256 nParentHash; int nVoteOutcome; // see VOTE_OUTCOMES above int64_t nTime; + // TODO split out BLS and ECCDSA key classes and convert to std::array std::vector vchSig; /** Memory only. */ @@ -95,8 +95,7 @@ class CGovernanceVote UpdateHash(); } - void SetSignature(const std::vector& vchSigIn) { vchSig = vchSigIn; } - + void SetSignature(Span vchSigIn) { vchSig = {vchSigIn.begin(), vchSigIn.end()}; } bool Sign(const CKey& key, const CKeyID& keyID); bool CheckSignature(const CKeyID& keyID) const; bool Sign(const CBLSSecretKey& key); diff --git a/src/init.cpp b/src/init.cpp index f5760880642c7..4024c0483ed28 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1694,7 +1694,8 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc fMasternodeMode = false; std::string strMasterNodeBLSPrivKey = args.GetArg("-masternodeblsprivkey", ""); if (!strMasterNodeBLSPrivKey.empty()) { - CBLSSecretKey keyOperator(ParseHex(strMasterNodeBLSPrivKey)); + auto hex_vector = ParseHex(strMasterNodeBLSPrivKey); + CBLSSecretKey keyOperator(hex_vector); if (!keyOperator.IsValid()) { return InitError(_("Invalid masternodeblsprivkey. Please see documentation.")); } diff --git a/src/key.cpp b/src/key.cpp index 04959dc74a298..5b04219f7e9fd 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -243,10 +243,10 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const { return pubkey.Verify(hash, vchSig); } -bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) const { +std::optional> CKey::SignCompact(const uint256 &hash) const { if (!fValid) - return false; - vchSig.resize(CPubKey::COMPACT_SIGNATURE_SIZE); + return std::nullopt; + std::array vchSig{}; int rec = -1; secp256k1_ecdsa_recoverable_signature sig; int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, nullptr); @@ -255,7 +255,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) assert(ret); assert(rec != -1); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); - return true; + return {vchSig}; } bool CKey::Load(const CPrivKey &seckey, const CPubKey &vchPubKey, bool fSkipCheck=false) { diff --git a/src/key.h b/src/key.h index f1b3099b2fdd4..ddbd2e944a443 100644 --- a/src/key.h +++ b/src/key.h @@ -125,7 +125,7 @@ class CKey * 0x1D = second key with even y, 0x1E = second key with odd y, * add 0x04 for compressed keys. */ - bool SignCompact(const uint256& hash, std::vector& vchSig) const; + std::optional> SignCompact(const uint256& hash) const; //! Derive BIP32 child key. bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; diff --git a/src/llmq/dkgsession.cpp b/src/llmq/dkgsession.cpp index e9d95c5084959..f1d8d4fd337a0 100644 --- a/src/llmq/dkgsession.cpp +++ b/src/llmq/dkgsession.cpp @@ -990,11 +990,11 @@ void CDKGSession::SendCommitment(CDKGPendingMessages& pendingMessages) qc.quorumSig = skShare.Sign(commitmentHash); if (lieType == 3) { - std::vector buf = qc.sig.ToByteVector(); + auto buf = qc.sig.ToByteVector(); buf[5]++; qc.sig.SetByteVector(buf); } else if (lieType == 4) { - std::vector buf = qc.quorumSig.ToByteVector(); + auto buf = qc.quorumSig.ToByteVector(); buf[5]++; qc.quorumSig.SetByteVector(buf); } diff --git a/src/messagesigner.cpp b/src/messagesigner.cpp index 1cb8a99a276fd..1318bf253096b 100644 --- a/src/messagesigner.cpp +++ b/src/messagesigner.cpp @@ -20,21 +20,21 @@ bool CMessageSigner::GetKeysFromSecret(const std::string& strSecret, CKey& keyRe return true; } -bool CMessageSigner::SignMessage(const std::string& strMessage, std::vector& vchSigRet, const CKey& key) +std::optional> CMessageSigner::SignMessage(const std::string& strMessage, const CKey& key) { CHashWriter ss(SER_GETHASH, 0); ss << MESSAGE_MAGIC; ss << strMessage; - return CHashSigner::SignHash(ss.GetHash(), key, vchSigRet); + return CHashSigner::SignHash(ss.GetHash(), key); } -bool CMessageSigner::VerifyMessage(const CPubKey& pubkey, const std::vector& vchSig, const std::string& strMessage, std::string& strErrorRet) +bool CMessageSigner::VerifyMessage(const CPubKey& pubkey, Span vchSig, const std::string& strMessage, std::string& strErrorRet) { return VerifyMessage(pubkey.GetID(), vchSig, strMessage, strErrorRet); } -bool CMessageSigner::VerifyMessage(const CKeyID& keyID, const std::vector& vchSig, const std::string& strMessage, std::string& strErrorRet) +bool CMessageSigner::VerifyMessage(const CKeyID& keyID, Span vchSig, const std::string& strMessage, std::string& strErrorRet) { CHashWriter ss(SER_GETHASH, 0); ss << MESSAGE_MAGIC; @@ -43,17 +43,17 @@ bool CMessageSigner::VerifyMessage(const CKeyID& keyID, const std::vector& vchSigRet) +std::optional> CHashSigner::SignHash(const uint256& hash, const CKey& key) { - return key.SignCompact(hash, vchSigRet); + return key.SignCompact(hash); } -bool CHashSigner::VerifyHash(const uint256& hash, const CPubKey& pubkey, const std::vector& vchSig, std::string& strErrorRet) +bool CHashSigner::VerifyHash(const uint256& hash, const CPubKey& pubkey, Span vchSig, std::string& strErrorRet) { return VerifyHash(hash, pubkey.GetID(), vchSig, strErrorRet); } -bool CHashSigner::VerifyHash(const uint256& hash, const CKeyID& keyID, const std::vector& vchSig, std::string& strErrorRet) +bool CHashSigner::VerifyHash(const uint256& hash, const CKeyID& keyID, Span vchSig, std::string& strErrorRet) { CPubKey pubkeyFromSig; if(!pubkeyFromSig.RecoverCompact(hash, vchSig)) { diff --git a/src/messagesigner.h b/src/messagesigner.h index 6b063936c385e..6b8d42adea8b0 100644 --- a/src/messagesigner.h +++ b/src/messagesigner.h @@ -15,11 +15,11 @@ class CMessageSigner /// Set the private/public key values, returns true if successful static bool GetKeysFromSecret(const std::string& strSecret, CKey& keyRet, CPubKey& pubkeyRet); /// Sign the message, returns true if successful - static bool SignMessage(const std::string& strMessage, std::vector& vchSigRet, const CKey& key); + static std::optional> SignMessage(const std::string& strMessage, const CKey& key); /// Verify the message signature, returns true if successful - static bool VerifyMessage(const CPubKey& pubkey, const std::vector& vchSig, const std::string& strMessage, std::string& strErrorRet); + static bool VerifyMessage(const CPubKey& pubkey, Span vchSig, const std::string& strMessage, std::string& strErrorRet); /// Verify the message signature, returns true if successful - static bool VerifyMessage(const CKeyID& keyID, const std::vector& vchSig, const std::string& strMessage, std::string& strErrorRet); + static bool VerifyMessage(const CKeyID& keyID, Span vchSig, const std::string& strMessage, std::string& strErrorRet); }; /** Helper class for signing hashes and checking their signatures @@ -28,11 +28,11 @@ class CHashSigner { public: /// Sign the hash, returns true if successful - static bool SignHash(const uint256& hash, const CKey& key, std::vector& vchSigRet); + static std::optional> SignHash(const uint256& hash, const CKey& key); /// Verify the hash signature, returns true if successful - static bool VerifyHash(const uint256& hash, const CPubKey& pubkey, const std::vector& vchSig, std::string& strErrorRet); + static bool VerifyHash(const uint256& hash, const CPubKey& pubkey, Span vchSig, std::string& strErrorRet); /// Verify the hash signature, returns true if successful - static bool VerifyHash(const uint256& hash, const CKeyID& keyID, const std::vector& vchSig, std::string& strErrorRet); + static bool VerifyHash(const uint256& hash, const CKeyID& keyID, Span vchSig, std::string& strErrorRet); }; #endif // BITCOIN_MESSAGESIGNER_H diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 6c259680c2870..6163051169fb6 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -184,7 +184,7 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector& vchS return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey); } -bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector& vchSig) { +bool CPubKey::RecoverCompact(const uint256 &hash, Span vchSig) { if (vchSig.size() != COMPACT_SIGNATURE_SIZE) return false; int recid = (vchSig[0] - 27) & 3; diff --git a/src/pubkey.h b/src/pubkey.h index 9b633972677c0..ce3a66ae6c296 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -197,7 +197,7 @@ class CPubKey static bool CheckLowS(const std::vector& vchSig); //! Recover a public key from a compact signature. - bool RecoverCompact(const uint256& hash, const std::vector& vchSig); + bool RecoverCompact(const uint256& hash, Span vchSig); //! Turn this public key into an uncompressed public key. bool Decompress(); diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index 80a73ec8c6553..c910095dc1dab 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -289,11 +289,13 @@ template static void SignSpecialTxPayloadByHash(const CMutableTransaction& tx, SpecialTxPayload& payload, const CKey& key) { UpdateSpecialTxInputsHash(tx, payload); - payload.vchSig.clear(); + payload.vchSig.fill(0); uint256 hash = ::SerializeHash(payload); - if (!CHashSigner::SignHash(hash, key, payload.vchSig)) { + if (auto opt_sig = CHashSigner::SignHash(hash, key); !opt_sig) { throw JSONRPCError(RPC_INTERNAL_ERROR, "failed to sign special tx"); + } else { + payload.vchSig = *opt_sig; } } @@ -301,11 +303,13 @@ template static void SignSpecialTxPayloadByString(const CMutableTransaction& tx, SpecialTxPayload& payload, const CKey& key) { UpdateSpecialTxInputsHash(tx, payload); - payload.vchSig.clear(); + payload.vchSig.fill(0); std::string m = payload.MakeSignString(); - if (!CMessageSigner::SignMessage(m, payload.vchSig, key)) { + if (auto opt_sig = CMessageSigner::SignMessage(m, key); !opt_sig) { throw JSONRPCError(RPC_INTERNAL_ERROR, "failed to sign special tx"); + } else { + payload.vchSig = *opt_sig; } } @@ -703,11 +707,6 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request, ptx.keyIDVoting = keyIDVoting; ptx.scriptPayout = GetScriptForDestination(payoutDest); - if (!isFundRegister) { - // make sure fee calculation works - ptx.vchSig.resize(65); - } - CTxDestination fundDest = payoutDest; if (!request.params[paramIdx + 6].isNull()) { fundDest = DecodeDestination(request.params[paramIdx + 6].get_str()); @@ -753,7 +752,7 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request, if (isPrepareRegister) { // external signing with collateral key - ptx.vchSig.clear(); + ptx.vchSig.fill(0); SetTxPayload(tx, ptx); UniValue ret(UniValue::VOBJ); @@ -826,8 +825,9 @@ static UniValue protx_register_submit(const JSONRPCRequest& request) if (!ptx.vchSig.empty()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "payload signature not empty"); } - - ptx.vchSig = DecodeBase64(request.params[1].get_str().c_str()); + auto vec_sig = DecodeBase64(request.params[1].get_str().c_str()); + CHECK_NONFATAL(vec_sig.size() == CPubKey::COMPACT_SIGNATURE_SIZE); + std::copy(vec_sig.begin(), vec_sig.end(), ptx.vchSig.begin()); SetTxPayload(tx, ptx); return SignAndSendSpecialTx(request, tx); @@ -1076,9 +1076,6 @@ static UniValue protx_update_registrar_wrapper(const JSONRPCRequest& request, co tx.nVersion = 3; tx.nType = TRANSACTION_PROVIDER_UPDATE_REGISTRAR; - // make sure we get anough fees added - ptx.vchSig.resize(65); - CTxDestination feeSourceDest = payoutDest; if (!request.params[4].isNull()) { feeSourceDest = DecodeDestination(request.params[4].get_str()); diff --git a/src/serialize.h b/src/serialize.h index 367cbc302fb7a..1dc2973942510 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -811,6 +812,34 @@ struct VectorFormatter }; }; +template +struct ArrayFormatter +{ + template + void Ser(Stream& s, const std::array& arr) + { + Formatter formatter; + WriteCompactSize(s, N); + for (const T& elem : arr) { + formatter.Ser(s, elem); + } + } + + template + void Unser(Stream& s, std::array& arr) + { + Formatter formatter; + size_t size = ReadCompactSize(s); + if (size < N) { + throw std::runtime_error(strprintf("ERROR Mismatch in array size when unserializing. %d, %d", size, N)); + } + for (size_t i = 0; i < N; ++i) { + formatter.Unser(s, arr[i]); + } + }; +}; + + /** * Forward declarations */ @@ -844,6 +873,19 @@ template void Unserialize_impl(Stream& template void Unserialize_impl(Stream& is, std::vector& v, const V&); template inline void Unserialize(Stream& is, std::vector& v); +/** + * std::array + * arrays of unsigned char are a special case and are intended to be serialized as a single opaque blob. + */ +template void Serialize_impl(Stream& os, const std::array& v, const unsigned char&); +template void Serialize_impl(Stream& os, const std::array& v, const bool&); +template void Serialize_impl(Stream& os, const std::array& v, const V&); +template inline void Serialize(Stream& os, const std::array& v); +template void Unserialize_impl(Stream& is, std::array& v, const unsigned char&); +template void Unserialize_impl(Stream& is, std::array& v, const V&); +template inline void Unserialize(Stream& is, std::array& v); + + /** * pair */ @@ -1115,6 +1157,71 @@ inline void Unserialize(Stream& is, std::vector& v) } +/** + * std::array + */ +template +void Serialize_impl(Stream& os, const std::array& arr, const unsigned char&) +{ + WriteCompactSize(os, N); + if (!arr.empty()) + os.write((char*)arr.data(), N * sizeof(T)); +} + +template +void Serialize_impl(Stream& os, const std::array& arr, const bool&) +{ + // A special case for std::array, as dereferencing + // std::array::const_iterator does not result in a const bool& + // due to std::array's special casing for bool arguments. + WriteCompactSize(os, N); + for (bool elem : arr) { + ::Serialize(os, elem); + } +} + +template +void Serialize_impl(Stream& os, const std::array& arr, const V&) +{ + Serialize(os, Using>(arr)); +} + +template +inline void Serialize(Stream& os, const std::array& arr) +{ + Serialize_impl(os, arr, T()); +} + + +template +void Unserialize_impl(Stream& is, std::array& arr, const unsigned char&) +{ + // Limit size per read so bogus size value won't cause out of memory + unsigned int nSize = ReadCompactSize(is); + if (nSize > N) { + throw std::runtime_error(strprintf("ERROR2 Mismatch in array size when unserializing. %d, %d", nSize, N)); + } + unsigned int i = 0; + while (i < nSize) + { + unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); + is.read((char*)&arr[i], blk * sizeof(T)); + i += blk; + } +} + +template +void Unserialize_impl(Stream& is, std::array& arr, const V&) +{ + Unserialize(is, Using>>(arr)); +} + +template +inline void Unserialize(Stream& is, std::array& arr) +{ + Unserialize_impl(is, arr, T()); +} + /** * pair diff --git a/src/spork.cpp b/src/spork.cpp index 7dc55bd297870..8095ff76309ed 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -360,10 +360,10 @@ bool CSporkMessage::Sign(const CKey& key) if (std::string strError; Params().NetworkIDString() == CBaseChainParams::TESTNET) { uint256 hash = GetSignatureHash(); - if (!CHashSigner::SignHash(hash, key, vchSig)) { + if (auto opt_sig = CHashSigner::SignHash(hash, key); !opt_sig) { LogPrintf("CSporkMessage::Sign -- SignHash() failed\n"); return false; - } + } else vchSig = *opt_sig; if (!CHashSigner::VerifyHash(hash, pubKeyId, vchSig, strError)) { LogPrintf("CSporkMessage::Sign -- VerifyHash() failed, error: %s\n", strError); @@ -372,10 +372,10 @@ bool CSporkMessage::Sign(const CKey& key) } else { std::string strMessage = ToString(nSporkID) + ToString(nValue) + ToString(nTimeSigned); - if (!CMessageSigner::SignMessage(strMessage, vchSig, key)) { + if (auto opt_sig = CMessageSigner::SignMessage(strMessage, key); !opt_sig) { LogPrintf("CSporkMessage::Sign -- SignMessage() failed\n"); return false; - } + } else vchSig = *opt_sig; if (!CMessageSigner::VerifyMessage(pubKeyId, vchSig, strMessage, strError)) { LogPrintf("CSporkMessage::Sign -- VerifyMessage() failed, error: %s\n", strError); @@ -388,18 +388,19 @@ bool CSporkMessage::Sign(const CKey& key) bool CSporkMessage::CheckSignature(const CKeyID& pubKeyId) const { + auto span_sig = Span(const_cast(vchSig.data()), vchSig.size()); // Harden Spork6 so that it is active on testnet and no other networks if (std::string strError; Params().NetworkIDString() == CBaseChainParams::TESTNET) { uint256 hash = GetSignatureHash(); - if (!CHashSigner::VerifyHash(hash, pubKeyId, vchSig, strError)) { + if (!CHashSigner::VerifyHash(hash, pubKeyId, span_sig, strError)) { LogPrint(BCLog::SPORK, "CSporkMessage::CheckSignature -- VerifyHash() failed, error: %s\n", strError); return false; } } else { std::string strMessage = ToString(nSporkID) + ToString(nValue) + ToString(nTimeSigned); - if (!CMessageSigner::VerifyMessage(pubKeyId, vchSig, strMessage, strError)) { + if (!CMessageSigner::VerifyMessage(pubKeyId, span_sig, strMessage, strError)) { LogPrint(BCLog::SPORK, "CSporkMessage::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); return false; } @@ -411,9 +412,10 @@ bool CSporkMessage::CheckSignature(const CKeyID& pubKeyId) const std::optional CSporkMessage::GetSignerKeyID() const { CPubKey pubkeyFromSig; + auto span = Span(const_cast(vchSig.data()), vchSig.size()); // Harden Spork6 so that it is active on testnet and no other networks if (Params().NetworkIDString() == CBaseChainParams::TESTNET) { - if (!pubkeyFromSig.RecoverCompact(GetSignatureHash(), vchSig)) { + if (!pubkeyFromSig.RecoverCompact(GetSignatureHash(), span)) { return std::nullopt; } } else { @@ -421,7 +423,7 @@ std::optional CSporkMessage::GetSignerKeyID() const CHashWriter ss(SER_GETHASH, 0); ss << MESSAGE_MAGIC; ss << strMessage; - if (!pubkeyFromSig.RecoverCompact(ss.GetHash(), vchSig)) { + if (!pubkeyFromSig.RecoverCompact(ss.GetHash(), span)) { return std::nullopt; } } diff --git a/src/spork.h b/src/spork.h index 75df308056678..5889028bb909f 100644 --- a/src/spork.h +++ b/src/spork.h @@ -97,7 +97,7 @@ extern std::unique_ptr sporkManager; class CSporkMessage { private: - std::vector vchSig; + std::array vchSig; public: SporkId nSporkID{0}; diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index b48aed3f02889..e030a3d7c4245 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -153,7 +153,9 @@ static CMutableTransaction CreateProUpRegTx(const CTxMemPool& mempool, SimpleUTX tx.nType = TRANSACTION_PROVIDER_UPDATE_REGISTRAR; FundTransaction(tx, utxos, GetScriptForDestination(PKHash(coinbaseKey.GetPubKey())), 1 * COIN, coinbaseKey); proTx.inputsHash = CalcTxInputsHash(CTransaction(tx)); - CHashSigner::SignHash(::SerializeHash(proTx), mnKey, proTx.vchSig); + auto opt_sig = CHashSigner::SignHash(::SerializeHash(proTx), mnKey); + assert(opt_sig.has_value()); + proTx.vchSig = *opt_sig; SetTxPayload(tx, proTx); SignTransaction(mempool, tx, coinbaseKey); @@ -628,7 +630,9 @@ void FuncTestMempoolReorg(TestChainSetup& setup) tx_reg.nType = TRANSACTION_PROVIDER_REGISTER; FundTransaction(tx_reg, utxos, scriptPayout, dmn_types::Regular.collat_amount, setup.coinbaseKey); payload.inputsHash = CalcTxInputsHash(CTransaction(tx_reg)); - CMessageSigner::SignMessage(payload.MakeSignString(), payload.vchSig, collateralKey); + auto opt_sig = CMessageSigner::SignMessage(payload.MakeSignString(), collateralKey); + assert(opt_sig.has_value()); + payload.vchSig = *opt_sig; SetTxPayload(tx_reg, payload); SignTransaction(*(setup.m_node.mempool), tx_reg, setup.coinbaseKey); @@ -697,7 +701,9 @@ void FuncTestMempoolDualProregtx(TestChainSetup& setup) tx_reg2.nType = TRANSACTION_PROVIDER_REGISTER; FundTransaction(tx_reg2, utxos, scriptPayout, dmn_types::Regular.collat_amount, setup.coinbaseKey); payload.inputsHash = CalcTxInputsHash(CTransaction(tx_reg2)); - CMessageSigner::SignMessage(payload.MakeSignString(), payload.vchSig, collateralKey); + auto opt_sig = CMessageSigner::SignMessage(payload.MakeSignString(), collateralKey); + assert(opt_sig.has_value()); + payload.vchSig = *opt_sig; SetTxPayload(tx_reg2, payload); SignTransaction(*(setup.m_node.mempool), tx_reg2, setup.coinbaseKey); @@ -759,7 +765,10 @@ void FuncVerifyDB(TestChainSetup& setup) tx_reg.nType = TRANSACTION_PROVIDER_REGISTER; FundTransaction(tx_reg, utxos, scriptPayout, dmn_types::Regular.collat_amount, setup.coinbaseKey); payload.inputsHash = CalcTxInputsHash(CTransaction(tx_reg)); - CMessageSigner::SignMessage(payload.MakeSignString(), payload.vchSig, collateralKey); + auto opt_sig = CMessageSigner::SignMessage(payload.MakeSignString(), collateralKey); + assert(opt_sig.has_value()); + payload.vchSig = *opt_sig; + SetTxPayload(tx_reg, payload); SignTransaction(*(setup.m_node.mempool), tx_reg, setup.coinbaseKey); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 913cbfcdc1543..ca135570b47b9 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -110,19 +110,22 @@ BOOST_AUTO_TEST_CASE(key_test1) // compact signatures (with key recovery) - std::vector csign1, csign2, csign1C, csign2C; + auto opt_sign1 = key1.SignCompact (hashMsg); + auto opt_sign2 = key2.SignCompact (hashMsg); + auto opt_sign1c = key1C.SignCompact(hashMsg); + auto opt_sign2c = key2C.SignCompact(hashMsg); - BOOST_CHECK(key1.SignCompact (hashMsg, csign1)); - BOOST_CHECK(key2.SignCompact (hashMsg, csign2)); - BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C)); - BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C)); + BOOST_CHECK(opt_sign1); + BOOST_CHECK(opt_sign2); + BOOST_CHECK(opt_sign1c); + BOOST_CHECK(opt_sign2c); CPubKey rkey1, rkey2, rkey1C, rkey2C; - BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1)); - BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2)); - BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C)); - BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C)); + BOOST_CHECK(rkey1.RecoverCompact (hashMsg, *opt_sign1)); + BOOST_CHECK(rkey2.RecoverCompact (hashMsg, *opt_sign2)); + BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, *opt_sign1c)); + BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, *opt_sign2c)); BOOST_CHECK(rkey1 == pubkey1); BOOST_CHECK(rkey2 == pubkey2); @@ -143,12 +146,21 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(key2C.Sign(hashMsg, detsigc)); BOOST_CHECK(detsig == detsigc); BOOST_CHECK(detsig == ParseHex("3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); - BOOST_CHECK(key1.SignCompact(hashMsg, detsig)); - BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc)); + auto opt_detsig = key1.SignCompact(hashMsg); + auto opt_detsigc = key1C.SignCompact(hashMsg); + + BOOST_CHECK(opt_detsig); + BOOST_CHECK(opt_detsigc); + detsig = std::vector{opt_detsig->begin(), opt_detsig->end()}; + detsigc = std::vector{opt_detsigc->begin(), opt_detsigc->end()}; BOOST_CHECK(detsig == ParseHex("1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); BOOST_CHECK(detsigc == ParseHex("205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); - BOOST_CHECK(key2.SignCompact(hashMsg, detsig)); - BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc)); + opt_detsig = key2.SignCompact(hashMsg); + opt_detsigc = key2C.SignCompact(hashMsg); + BOOST_CHECK(opt_detsig.has_value()); + BOOST_CHECK(opt_detsigc.has_value()); + detsig = std::vector{opt_detsig->begin(), opt_detsig->end()}; + detsigc = std::vector{opt_detsigc->begin(), opt_detsigc->end()}; BOOST_CHECK(detsig == ParseHex("1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); } diff --git a/src/util/message.cpp b/src/util/message.cpp index ac2a1f8306eaf..ceddf7d771a2f 100644 --- a/src/util/message.cpp +++ b/src/util/message.cpp @@ -58,15 +58,12 @@ bool MessageSign( const std::string& message, std::string& signature) { - std::vector signature_bytes; - - if (!privkey.SignCompact(MessageHash(message), signature_bytes)) { + if (auto opt_sig_bytes = privkey.SignCompact(MessageHash(message)); !opt_sig_bytes.has_value()) { return false; + } else { + signature = EncodeBase64(*opt_sig_bytes); + return true; } - - signature = EncodeBase64(signature_bytes); - - return true; } uint256 MessageHash(const std::string& message)