From 62cd9fffa39bc296268b6134cd903d2705023835 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 15 Nov 2020 01:31:20 +0300 Subject: [PATCH] Automate AES-NI and AVX detection on runtime, make it default on x86-based systems (#1578) Rework CPU extensions detection code and build with AES-NI and AVX support by default --- .github/workflows/build-osx.yml | 20 +++ .github/workflows/build-qt.yml | 20 --- .github/workflows/build.yml | 18 ++- .gitignore | 3 +- Makefile | 7 +- Makefile.homebrew | 7 +- Makefile.linux | 21 +-- Makefile.mingw | 17 +- Makefile.osx | 8 +- build/CMakeLists.txt | 16 +- build/build_mingw.cmd | 29 ++-- .../installer.iss => build/win_installer.iss | 13 +- contrib/i2pd.conf | 9 ++ daemon/Daemon.cpp | 5 +- debian/compat | 2 +- .../{02-fix-1210.patch => 01-fix-1210.patch} | 0 debian/patches/01-tune-build-opts.patch | 15 -- debian/patches/series | 3 +- libi2pd/CPU.cpp | 33 ++-- libi2pd/CPU.h | 2 +- libi2pd/Config.cpp | 18 ++- libi2pd/Crypto.cpp | 145 +++++++++--------- libi2pd/Crypto.h | 13 +- libi2pd/Identity.cpp | 2 +- libi2pd/api.cpp | 5 +- qt/i2pd_qt/i2pd_qt.pro | 16 +- 26 files changed, 209 insertions(+), 238 deletions(-) create mode 100644 .github/workflows/build-osx.yml delete mode 100644 .github/workflows/build-qt.yml rename Win32/installer.iss => build/win_installer.iss (75%) rename debian/patches/{02-fix-1210.patch => 01-fix-1210.patch} (100%) delete mode 100644 debian/patches/01-tune-build-opts.patch diff --git a/.github/workflows/build-osx.yml b/.github/workflows/build-osx.yml new file mode 100644 index 00000000..50672d26 --- /dev/null +++ b/.github/workflows/build-osx.yml @@ -0,0 +1,20 @@ +name: Build on OSX + +on: [push, pull_request] + +jobs: + build: + name: With USE_UPNP=${{ matrix.with_upnp }} + runs-on: macOS-latest + strategy: + fail-fast: true + matrix: + with_upnp: ['yes', 'no'] + steps: + - uses: actions/checkout@v2 + - name: install packages + run: | + brew update + brew install boost miniupnpc openssl@1.1 + - name: build application + run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3 diff --git a/.github/workflows/build-qt.yml b/.github/workflows/build-qt.yml deleted file mode 100644 index d4fde2b9..00000000 --- a/.github/workflows/build-qt.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Build on Ubuntu - -on: [push, pull_request] - -jobs: - build: - name: With QT GUI - runs-on: ubuntu-16.04 - steps: - - uses: actions/checkout@v2 - - name: install packages - run: | - sudo add-apt-repository ppa:mhier/libboost-latest - sudo apt-get update - sudo apt-get install build-essential qt5-default libqt5gui5 libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev - - name: build application - run: | - cd qt/i2pd_qt - qmake - make -j3 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5e5152e0..bb995219 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,4 +18,20 @@ jobs: sudo apt-get update sudo apt-get install build-essential libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev - name: build application - run: make USE_AVX=no USE_AESNI=no USE_UPNP=${{ matrix.with_upnp }} -j3 + run: make USE_UPNP=${{ matrix.with_upnp }} -j3 + + build_qt: + name: With QT GUI + runs-on: ubuntu-16.04 + steps: + - uses: actions/checkout@v2 + - name: install packages + run: | + sudo add-apt-repository ppa:mhier/libboost-latest + sudo apt-get update + sudo apt-get install build-essential qt5-default libqt5gui5 libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev + - name: build application + run: | + cd qt/i2pd_qt + qmake + make -j3 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3319fa10..2506fd93 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,12 @@ router.info router.keys i2p -libi2pd.so netDb /i2pd /libi2pd.a /libi2pdclient.a +/libi2pd.so +/libi2pdclient.so *.exe diff --git a/Makefile b/Makefile index 35d76b82..c359d7c7 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,6 @@ DAEMON_SRC_DIR := daemon include filelist.mk USE_AESNI := yes -USE_AVX := yes USE_STATIC := no USE_MESHNET := no USE_UPNP := no @@ -77,7 +76,7 @@ deps: mk_obj_dir @sed -i -e '/\.o:/ s/^/obj\//' $(DEPS) obj/%.o: %.cpp - $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $< + $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -c -o $@ $< # '-' is 'ignore if missing' on first run -include $(DEPS) @@ -88,11 +87,11 @@ $(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) ifneq ($(USE_STATIC),yes) - $(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^ + $(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) endif $(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) - $(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^ + $(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) $(SHLIB) $(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) $(AR) -r $@ $^ diff --git a/Makefile.homebrew b/Makefile.homebrew index 64301c02..c1992296 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -35,10 +35,7 @@ endif # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic ifeq ($(USE_AESNI),yes) - CXXFLAGS += -maes -endif -ifeq ($(USE_AVX),1) - CXXFLAGS += -mavx + CXXFLAGS += -D__AES__ -maes endif install: all @@ -51,4 +48,4 @@ install: all @ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/ @ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf @ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt - @ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf \ No newline at end of file + @ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf diff --git a/Makefile.linux b/Makefile.linux index 3ef4793c..6a7590c1 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -1,5 +1,5 @@ # set defaults instead redefine -CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation -Wno-psabi +CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-psabi LDFLAGS ?= ${LD_DEBUG} ## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time @@ -49,7 +49,7 @@ endif # UPNP Support (miniupnpc 1.5 and higher) ifeq ($(USE_UPNP),yes) - CXXFLAGS += -DUSE_UPNP + NEEDED_CXXFLAGS += -DUSE_UPNP ifeq ($(USE_STATIC),yes) LDLIBS += $(LIBDIR)/libminiupnpc.a else @@ -58,20 +58,7 @@ endif endif ifeq ($(USE_AESNI),yes) -#check if AES-NI is supported by CPU -ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) - machine := $(shell uname -m) - ifeq ($(machine), aarch64) - CXXFLAGS += -DARM64AES - else - CPU_FLAGS += -maes - endif -endif -endif - -ifeq ($(USE_AVX),yes) -#check if AVX supported by CPU -ifneq ($(shell $(GREP) -c avx /proc/cpuinfo),0) - CPU_FLAGS += -mavx +ifeq (, $(findstring arm, $(SYS))$(findstring aarch64, $(SYS))) # no arm and aarch64 in dumpmachine + NEEDED_CXXFLAGS += -D__AES__ -maes endif endif diff --git a/Makefile.mingw b/Makefile.mingw index 2782b715..764606b6 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,7 +1,7 @@ USE_WIN32_APP=yes CXX = g++ WINDRES = windres -CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN +CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN -fPIC -msse INCFLAGS = -Idaemon -I. LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ @@ -42,25 +42,18 @@ LDLIBS += \ -lpthread ifeq ($(USE_WIN32_APP), yes) - CXXFLAGS += -DWIN32_APP + NEEDED_CXXFLAGS += -DWIN32_APP LDFLAGS += -mwindows DAEMON_RC += Win32/Resource.rc DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) endif ifeq ($(USE_WINXP_FLAGS), yes) - CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 + NEEDED_CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 endif -# don't change following line to ifeq ($(USE_AESNI),yes) !!! -ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes -else - CPU_FLAGS += -msse -endif - -ifeq ($(USE_AVX),1) - CPU_FLAGS += -mavx +ifeq ($(USE_AESNI),yes) + NEEDED_CXXFLAGS += -D__AES__ -maes endif ifeq ($(USE_ASLR),yes) diff --git a/Makefile.osx b/Makefile.osx index c6af4fc2..2e52585e 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -22,12 +22,8 @@ ifeq ($(USE_UPNP),yes) endif endif -ifeq ($(USE_AESNI),1) - CXXFLAGS += -maes +ifeq ($(USE_AESNI),yes) + CXXFLAGS += -D__AES__ -maes else CXXFLAGS += -msse endif - -ifeq ($(USE_AVX),1) - CXXFLAGS += -mavx -endif diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 827e20d3..6f9fbae6 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -11,9 +11,8 @@ if(WIN32 OR MSVC OR MSYS OR MINGW) message(SEND_ERROR "cmake build for windows is not supported. Please use MSYS2 with makefiles in project root.") endif() -# configurale options -option(WITH_AESNI "Use AES-NI instructions set" OFF) -option(WITH_AVX "Use AVX instructions" OFF) +# configurable options +option(WITH_AESNI "Use AES-NI instructions set" ON) option(WITH_HARDENING "Use hardening compiler flags" OFF) option(WITH_LIBRARY "Build library" ON) option(WITH_BINARY "Build binary" ON) @@ -189,13 +188,11 @@ if(UNIX) endif() endif() -if(WITH_AESNI) +# Note: AES-NI and AVX is available on x86-based CPU's. +# Here also ARM64 implementation, but currently we don't support it. +if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386")) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes") - add_definitions(-DAESNI) -endif() - -if(WITH_AVX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx") + add_definitions(-D__AES__) endif() if(WITH_ADDRSANITIZER) @@ -309,7 +306,6 @@ message(STATUS "Architecture : ${ARCHITECTURE}") message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}") message(STATUS "Options:") message(STATUS " AESNI : ${WITH_AESNI}") -message(STATUS " AVX : ${WITH_AVX}") message(STATUS " HARDENING : ${WITH_HARDENING}") message(STATUS " LIBRARY : ${WITH_LIBRARY}") message(STATUS " BINARY : ${WITH_BINARY}") diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index ec861bb2..37a1d454 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -30,10 +30,10 @@ REM we must work in root of repo cd .. REM deleting old log files -del /S build_*.log >> nul +del /S build_*.log >> nul 2>&1 echo Receiving latest commit and cleaning up... -%xSH% "git pull && make clean" > build/build_git.log 2>&1 +%xSH% "git checkout contrib/* && git pull && make clean" > build/build.log 2>&1 echo. REM set to variable current commit hash @@ -43,16 +43,17 @@ FOR /F "usebackq" %%a IN (`%xSH% 'git describe --tags'`) DO ( %xSH% "echo To use configs and certificates, move all files and certificates folder from contrib directory here. > README.txt" >> nul +REM converting configuration files to DOS format (usable in default notepad) +%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/*" > build/build.log 2>&1 + REM starting building set MSYSTEM=MINGW32 set bitness=32 call :BUILDING -echo. set MSYSTEM=MINGW64 set bitness=64 call :BUILDING -echo. REM building for WinXP set "WD=C:\msys64-xp\usr\bin\" @@ -62,7 +63,10 @@ set "xSH=%WD%bash -lc" call :BUILDING_XP echo. -del README.txt >> nul +REM compile installer +C:\PROGRA~2\INNOSE~1\ISCC.exe build\win_installer.iss + +del README.txt i2pd_x32.exe i2pd_x64.exe i2pd_xp.exe >> nul echo Build complete... pause @@ -70,20 +74,13 @@ exit /b 0 :BUILDING %xSH% "make clean" >> nul -echo Building i2pd %tag% for win%bitness%: -echo Build AVX+AESNI... -%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_avx_aesni_%tag%.log 2>&1 -echo Build AVX... -%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip %FILELIST% && make clean" > build/build_win%bitness%_avx_%tag%.log 2>&1 -echo Build AESNI... -%xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_aesni_%tag%.log 2>&1 -echo Build without extensions... -%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1 +echo Building i2pd %tag% for win%bitness% +%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && cp i2pd.exe i2pd_x%bitness%.exe && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1 goto EOF :BUILDING_XP %xSH% "make clean" >> nul -echo Building i2pd %tag% for winxp... -%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads% && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build/build_winxp_%tag%.log 2>&1 +echo Building i2pd %tag% for winxp +%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads% && cp i2pd.exe i2pd_xp.exe && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build/build_winxp_%tag%.log 2>&1 :EOF \ No newline at end of file diff --git a/Win32/installer.iss b/build/win_installer.iss similarity index 75% rename from Win32/installer.iss rename to build/win_installer.iss index cc40c409..007cd643 100644 --- a/Win32/installer.iss +++ b/build/win_installer.iss @@ -1,6 +1,7 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.34.0" #define I2Pd_Publisher "PurpleI2P" +; Get application version from compiled binary +#define I2Pd_ver GetFileVersionString(AddBackslash(SourcePath) + "..\i2pd_x64.exe") [Setup] AppName={#I2Pd_AppName} @@ -10,9 +11,9 @@ DefaultDirName={pf}\I2Pd DefaultGroupName=I2Pd UninstallDisplayIcon={app}\I2Pd.exe OutputDir=. -LicenseFile=../LICENSE +LicenseFile=..\LICENSE OutputBaseFilename=setup_{#I2Pd_AppName}_v{#I2Pd_ver} -SetupIconFile=mask.ico +SetupIconFile=..\Win32\mask.ico InternalCompressLevel=ultra64 Compression=lzma/ultra64 SolidCompression=true @@ -23,10 +24,12 @@ AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2} AppPublisherURL=http://i2pd.website/ AppSupportURL=https://github.com/PurpleI2P/i2pd/issues AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases +CloseApplications=yes [Files] -Source: ..\i2pd_x86.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: not IsWin64 -Source: ..\i2pd_x64.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64 +Source: ..\i2pd_x32.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: not IsWin64; MinVersion: 6.0 +Source: ..\i2pd_x64.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64; MinVersion: 6.0 +Source: ..\i2pd_xp.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64; OnlyBelowVersion: 6.0 Source: ..\README.md; DestDir: {app}; DestName: Readme.txt; Flags: onlyifdoesntexist Source: ..\contrib\i2pd.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist Source: ..\contrib\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 2174abe8..5ef39bc9 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -229,3 +229,12 @@ verify = true [persist] ## Save peer profiles on disk (default: true) # profiles = true + +[cpuext] +## Use CPU AES-NI instructions set when work with cryptography when available (default: true) +# aesni = true +## Use CPU AVX instructions set when work with cryptography when available (default: true) +# avx = true +## Force usage of CPU instructions set, even if they not found +## DO NOT TOUCH that option if you really don't know what are you doing! +# force = false \ No newline at end of file diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 0317704a..839495a5 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -128,7 +128,10 @@ namespace i2p LogPrint(eLogDebug, "FS: data directory: ", datadir); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); - i2p::crypto::InitCrypto (precomputation); + bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); + bool avx; i2p::config::GetOption("cpuext.avx", avx); + bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt); + i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt); int netID; i2p::config::GetOption("netid", netID); i2p::context.SetNetID (netID); diff --git a/debian/compat b/debian/compat index f11c82a4..9a037142 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -9 \ No newline at end of file +10 \ No newline at end of file diff --git a/debian/patches/02-fix-1210.patch b/debian/patches/01-fix-1210.patch similarity index 100% rename from debian/patches/02-fix-1210.patch rename to debian/patches/01-fix-1210.patch diff --git a/debian/patches/01-tune-build-opts.patch b/debian/patches/01-tune-build-opts.patch deleted file mode 100644 index e06a8621..00000000 --- a/debian/patches/01-tune-build-opts.patch +++ /dev/null @@ -1,15 +0,0 @@ -Index: i2pd/Makefile -=================================================================== ---- i2pd.orig/Makefile -+++ i2pd/Makefile -@@ -13,8 +13,8 @@ DAEMON_SRC_DIR := daemon - - include filelist.mk - --USE_AESNI := yes --USE_AVX := yes -+USE_AESNI := no -+USE_AVX := no - USE_STATIC := no - USE_MESHNET := no - USE_UPNP := no diff --git a/debian/patches/series b/debian/patches/series index 002802b5..07f821c8 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1 @@ -01-tune-build-opts.patch -02-fix-1210.patch +01-fix-1210.patch diff --git a/libi2pd/CPU.cpp b/libi2pd/CPU.cpp index e7eff473..0bd830e3 100644 --- a/libi2pd/CPU.cpp +++ b/libi2pd/CPU.cpp @@ -27,37 +27,24 @@ namespace cpu bool aesni = false; bool avx = false; - void Detect() + void Detect(bool AesSwitch, bool AvxSwitch, bool force) { -#if defined(__AES__) || defined(__AVX__) - #if defined(__x86_64__) || defined(__i386__) int info[4]; __cpuid(0, info[0], info[1], info[2], info[3]); if (info[0] >= 0x00000001) { __cpuid(0x00000001, info[0], info[1], info[2], info[3]); -#ifdef __AES__ - aesni = info[2] & bit_AES; // AESNI -#endif // __AES__ -#ifdef __AVX__ - avx = info[2] & bit_AVX; // AVX -#endif // __AVX__ + if ((info[2] & bit_AES && AesSwitch) || (AesSwitch && force)) { + aesni = true; + } + if ((info[2] & bit_AVX && AvxSwitch) || (AvxSwitch && force)) { + avx = true; + } } -#endif // defined(__x86_64__) || defined(__i386__) +#endif // defined(__x86_64__) || defined(__i386__) -#ifdef __AES__ - if(aesni) - { - LogPrint(eLogInfo, "AESNI enabled"); - } -#endif // __AES__ -#ifdef __AVX__ - if(avx) - { - LogPrint(eLogInfo, "AVX enabled"); - } -#endif // __AVX__ -#endif // defined(__AES__) || defined(__AVX__) + LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled")); + LogPrint(eLogInfo, "AVX ", (avx ? "enabled" : "disabled")); } } } diff --git a/libi2pd/CPU.h b/libi2pd/CPU.h index 9677b293..f021bccb 100644 --- a/libi2pd/CPU.h +++ b/libi2pd/CPU.h @@ -16,7 +16,7 @@ namespace cpu extern bool aesni; extern bool avx; - void Detect(); + void Detect(bool AesSwitch, bool AvxSwitch, bool force); } } diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index fc479532..d99fdde1 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -47,11 +47,11 @@ namespace config { ("ifname", value()->default_value(""), "Network interface to bind to") ("ifname4", value()->default_value(""), "Network interface to bind to for ipv4") ("ifname6", value()->default_value(""), "Network interface to bind to for ipv6") - ("nat", value()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") + ("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") - ("ipv4", value()->default_value(true), "Enable communication through ipv4 (default: enabled)") + ("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)") ("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)") - ("reservedrange", value()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)") + ("reservedrange", bool_switch()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)") ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") ("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)") ("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)") @@ -59,8 +59,8 @@ namespace config { ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") - ("ntcp", value()->default_value(false), "Ignored. Always false") - ("ssu", value()->default_value(true), "Enable SSU transport (default: enabled)") + ("ntcp", bool_switch()->default_value(false), "Ignored. Always false") + ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") ("ntcpproxy", value()->default_value(""), "Ignored") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") @@ -266,6 +266,13 @@ namespace config { ("persist.addressbook", value()->default_value(true), "Persist full addresses (default: true)") ; + options_description cpuext("CPU encryption extensions options"); + cpuext.add_options() + ("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used") + ("cpuext.avx", bool_switch()->default_value(true), "Use auto detection for AVX CPU extensions. If false, AVX will be not used") + ("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines") + ; + m_OptionsDesc .add(general) .add(limits) @@ -286,6 +293,7 @@ namespace config { .add(ntcp2) .add(nettime) .add(persist) + .add(cpuext) ; } diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index ea2cd675..523828ce 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -119,7 +119,7 @@ namespace crypto ~CryptoConstants () { - BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae); + BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae); } }; @@ -522,7 +522,7 @@ namespace crypto bn2buf (y, encrypted + len, len); RAND_bytes (encrypted + 2*len, 256 - 2*len); } - // ecryption key and iv + // encryption key and iv EC_POINT_mul (curve, p, nullptr, key, k, ctx); EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr); uint8_t keyBuf[64], iv[64], shared[32]; @@ -638,7 +638,7 @@ namespace crypto { uint64_t buf[256]; uint64_t hash[12]; // 96 bytes -#ifdef __AVX__ +#if defined(__x86_64__) || defined(__i386__) if(i2p::cpu::avx) { __asm__ @@ -657,7 +657,7 @@ namespace crypto : : [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads), [buf]"r"(buf), [hash]"r"(hash) - : "memory", "%xmm0" // TODO: change to %ymm0 later + : "memory", "%xmm0" // TODO: change to %ymm0 later ); } else @@ -688,7 +688,7 @@ namespace crypto // concatenate with msg memcpy (buf + 8, msg, len); // calculate first hash - MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes + MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes // calculate digest MD5((uint8_t *)hash, 96, digest); @@ -696,35 +696,28 @@ namespace crypto // AES #ifdef __AES__ - #ifdef ARM64AES - void init_aesenc(void){ - // TODO: Implementation - } - - #endif - #define KeyExpansion256(round0,round1) \ - "pshufd $0xff, %%xmm2, %%xmm2 \n" \ - "movaps %%xmm1, %%xmm4 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pshufd $0xff, %%xmm2, %%xmm2 \n" \ + "movaps %%xmm1, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm1 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm1 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm1 \n" \ "pxor %%xmm2, %%xmm1 \n" \ - "movaps %%xmm1, "#round0"(%[sched]) \n" \ + "movaps %%xmm1, "#round0"(%[sched]) \n" \ "aeskeygenassist $0, %%xmm1, %%xmm4 \n" \ - "pshufd $0xaa, %%xmm4, %%xmm2 \n" \ - "movaps %%xmm3, %%xmm4 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pshufd $0xaa, %%xmm4, %%xmm2 \n" \ + "movaps %%xmm3, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm3 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm3 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm3 \n" \ "pxor %%xmm2, %%xmm3 \n" \ - "movaps %%xmm3, "#round1"(%[sched]) \n" + "movaps %%xmm3, "#round1"(%[sched]) \n" #endif #ifdef __AES__ @@ -750,16 +743,16 @@ namespace crypto KeyExpansion256(192,208) "aeskeygenassist $64, %%xmm3, %%xmm2 \n" // key expansion final - "pshufd $0xff, %%xmm2, %%xmm2 \n" - "movaps %%xmm1, %%xmm4 \n" - "pslldq $4, %%xmm4 \n" + "pshufd $0xff, %%xmm2, %%xmm2 \n" + "movaps %%xmm1, %%xmm4 \n" + "pslldq $4, %%xmm4 \n" "pxor %%xmm4, %%xmm1 \n" - "pslldq $4, %%xmm4 \n" + "pslldq $4, %%xmm4 \n" "pxor %%xmm4, %%xmm1 \n" - "pslldq $4, %%xmm4 \n" + "pslldq $4, %%xmm4 \n" "pxor %%xmm4, %%xmm1 \n" "pxor %%xmm2, %%xmm1 \n" - "movups %%xmm1, 224(%[sched]) \n" + "movups %%xmm1, 224(%[sched]) \n" : // output : [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input : "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged @@ -794,9 +787,9 @@ namespace crypto { __asm__ ( - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" EncryptAES256(sched) - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" ); } @@ -833,9 +826,9 @@ namespace crypto { __asm__ ( - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" DecryptAES256(sched) - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" ); } @@ -848,7 +841,7 @@ namespace crypto #ifdef __AES__ #define CallAESIMC(offset) \ - "movaps "#offset"(%[shed]), %%xmm0 \n" \ + "movaps "#offset"(%[shed]), %%xmm0 \n" \ "aesimc %%xmm0, %%xmm0 \n" \ "movaps %%xmm0, "#offset"(%[shed]) \n" #endif @@ -873,7 +866,7 @@ namespace crypto if(i2p::cpu::aesni) { ExpandKey (key); // expand encryption key first - // then invert it using aesimc + // then invert it using aesimc __asm__ ( CallAESIMC(16) @@ -906,18 +899,18 @@ namespace crypto { __asm__ ( - "movups (%[iv]), %%xmm1 \n" + "movups (%[iv]), %%xmm1 \n" "1: \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n" EncryptAES256(sched) - "movaps %%xmm0, %%xmm1 \n" - "movups %%xmm0, (%[out]) \n" + "movaps %%xmm0, %%xmm1 \n" + "movups %%xmm0, (%[out]) \n" "add $16, %[in] \n" "add $16, %[out] \n" "dec %[num] \n" "jnz 1b \n" - "movups %%xmm1, (%[iv]) \n" + "movups %%xmm1, (%[iv]) \n" : : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) @@ -951,12 +944,12 @@ namespace crypto { __asm__ ( - "movups (%[iv]), %%xmm1 \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[iv]), %%xmm1 \n" + "movups (%[in]), %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n" EncryptAES256(sched) - "movups %%xmm0, (%[out]) \n" - "movups %%xmm0, (%[iv]) \n" + "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[iv]) \n" : : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out) @@ -975,19 +968,19 @@ namespace crypto { __asm__ ( - "movups (%[iv]), %%xmm1 \n" + "movups (%[iv]), %%xmm1 \n" "1: \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" "movaps %%xmm0, %%xmm2 \n" DecryptAES256(sched) "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" "movaps %%xmm2, %%xmm1 \n" "add $16, %[in] \n" "add $16, %[out] \n" "dec %[num] \n" "jnz 1b \n" - "movups %%xmm1, (%[iv]) \n" + "movups %%xmm1, (%[iv]) \n" : : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) @@ -1021,12 +1014,12 @@ namespace crypto { __asm__ ( - "movups (%[iv]), %%xmm1 \n" - "movups (%[in]), %%xmm0 \n" - "movups %%xmm0, (%[iv]) \n" + "movups (%[iv]), %%xmm1 \n" + "movups (%[in]), %%xmm0 \n" + "movups %%xmm0, (%[iv]) \n" DecryptAES256(sched) "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" : : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out) @@ -1046,7 +1039,7 @@ namespace crypto __asm__ ( // encrypt IV - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" EncryptAES256(sched_iv) "movaps %%xmm0, %%xmm1 \n" // double IV encryption @@ -1056,11 +1049,11 @@ namespace crypto "1: \n" "add $16, %[in] \n" "add $16, %[out] \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n" EncryptAES256(sched_l) - "movaps %%xmm0, %%xmm1 \n" - "movups %%xmm0, (%[out]) \n" + "movaps %%xmm0, %%xmm1 \n" + "movups %%xmm0, (%[out]) \n" "dec %[num] \n" "jnz 1b \n" : @@ -1097,11 +1090,11 @@ namespace crypto "1: \n" "add $16, %[in] \n" "add $16, %[out] \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" "movaps %%xmm0, %%xmm2 \n" DecryptAES256(sched_l) "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" "movaps %%xmm2, %%xmm1 \n" "dec %[num] \n" "jnz 1b \n" @@ -1324,23 +1317,23 @@ namespace crypto } void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len) - { - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, m_H, 32); - SHA256_Update (&ctx, buf, len); - SHA256_Final (m_H, &ctx); - } - - void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret) - { - HKDF (m_CK, sharedSecret, 32, "", m_CK); + { + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, buf, len); + SHA256_Final (m_H, &ctx); + } + + void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret) + { + HKDF (m_CK, sharedSecret, 32, "", m_CK); // new ck is m_CK[0:31], key is m_CK[32:63] - } - + } + // init and terminate -/* std::vector > m_OpenSSLMutexes; +/* std::vector > m_OpenSSLMutexes; static void OpensslLockingCallback(int mode, int type, const char * file, int line) { if (type > 0 && (size_t)type < m_OpenSSLMutexes.size ()) @@ -1351,10 +1344,10 @@ namespace crypto m_OpenSSLMutexes[type]->unlock (); } }*/ - - void InitCrypto (bool precomputation) + + void InitCrypto (bool precomputation, bool aesni, bool avx, bool force) { - i2p::cpu::Detect (); + i2p::cpu::Detect (aesni, avx, force); #if LEGACY_OPENSSL SSL_library_init (); #endif diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 205be44d..da7a4bf4 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -169,9 +169,6 @@ namespace crypto #ifdef __AES__ - #ifdef ARM64AES - void init_aesenc(void) __attribute__((constructor)); - #endif class ECBCryptoAESNI { public: @@ -316,13 +313,13 @@ namespace crypto struct NoiseSymmetricState { uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/; - + void MixHash (const uint8_t * buf, size_t len); - void MixKey (const uint8_t * sharedSecret); - }; - + void MixKey (const uint8_t * sharedSecret); + }; + // init and terminate - void InitCrypto (bool precomputation); + void InitCrypto (bool precomputation, bool aesni, bool avx, bool force); void TerminateCrypto (); } } diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 7784cc90..88523492 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -828,7 +828,7 @@ namespace data XORMetric operator^(const IdentHash& key1, const IdentHash& key2) { XORMetric m; -#ifdef __AVX__ +#if defined(__x86_64__) || defined(__i386__) if(i2p::cpu::avx) { __asm__ diff --git a/libi2pd/api.cpp b/libi2pd/api.cpp index 569fbd8c..faeee84d 100644 --- a/libi2pd/api.cpp +++ b/libi2pd/api.cpp @@ -37,7 +37,10 @@ namespace api i2p::fs::Init(); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); - i2p::crypto::InitCrypto (precomputation); + bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); + bool avx; i2p::config::GetOption("cpuext.avx", avx); + bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt); + i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt); int netID; i2p::config::GetOption("netid", netID); i2p::context.SetNetID (netID); diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index dba69143..eed4cd7b 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -4,14 +4,16 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = i2pd_qt TEMPLATE = app -QMAKE_CXXFLAGS *= -Wno-unused-parameter -Wno-maybe-uninitialized +QMAKE_CXXFLAGS *= -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-deprecated-copy CONFIG += strict_c++ c++11 CONFIG(debug, debug|release) { message(Debug build) DEFINES += DEBUG_WITH_DEFAULT_LOGGING + I2PDMAKE += DEBUG=yes } else { message(Release build) + I2PDMAKE += DEBUG=no } SOURCES += DaemonQT.cpp mainwindow.cpp \ @@ -73,19 +75,19 @@ FORMS += mainwindow.ui \ LIBS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a -lz -libi2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_AVX=no USE_AESNI=no USE_UPNP=yes DEBUG=no api +libi2pd.commands = @echo Building i2pd libraries libi2pd.target = $$PWD/../../libi2pd.a -libi2pd.depends = FORCE +libi2pd.depends = i2pd FORCE -libi2pdclient.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_AVX=no USE_AESNI=no USE_UPNP=yes DEBUG=no api_client -libi2pdclient.target = $$PWD/../../libi2pdclient.a -libi2pdclient.depends = FORCE +i2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes $$I2PDMAKE api_client +i2pd.target += $$PWD/../../libi2pdclient.a +i2pd.depends = FORCE cleani2pd.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) clean cleani2pd.depends = clean PRE_TARGETDEPS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a -QMAKE_EXTRA_TARGETS += cleani2pd libi2pd libi2pdclient +QMAKE_EXTRA_TARGETS += cleani2pd i2pd libi2pd CLEAN_DEPS += cleani2pd