diff --git a/.gitignore b/.gitignore
index ca5bcc52fe..34695ef324 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+/test/CMakeFiles
+/test/*/CMakeFiles
/build
/CMakeLists.txt.user
/.idea
@@ -7,3 +9,4 @@
CMakeCache.txt
cmake_install.cmake
Makefile
+cmake-build-release/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b8a80312c2..a5856edad3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 1.4.0
+- Fixed CPU affinity on Windows for NUMA and CPUs with lot of cores
+- Implemented per thread configurable Multihash mode (double, triple, quadruple, quintuple)
+- Rebased from XMRig 2.4.4
# v1.3.2
- Added start xmrigDaemonr without config file and only CCServer/auth token as params needed #14
- Dashboard now uses servertime for calculation to avoid clock drifts and false offline detection
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fa6dcfbbff..3def07437c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,8 +1,9 @@
cmake_minimum_required(VERSION 2.8)
project(xmrig)
-#set(CMAKE_BUILD_TYPE Debug)
-set(CMAKE_BUILD_TYPE Release)
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+ set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
+endif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
option(WITH_LIBCPUID "Use Libcpuid" ON)
option(WITH_AEON "CryptoNight-Lite support" ON)
@@ -13,57 +14,6 @@ option(WITH_CC_SERVER "CC Server" ON)
include (CheckIncludeFile)
include (cmake/cpu.cmake)
-
-set(HEADERS
- src/3rdparty/align.h
- src/api/Api.h
- src/api/ApiState.h
- src/api/NetworkState.h
- src/App.h
- src/interfaces/IClientListener.h
- src/interfaces/IJobResultListener.h
- src/interfaces/ILogBackend.h
- src/interfaces/IStrategy.h
- src/interfaces/IStrategyListener.h
- src/interfaces/IWorker.h
- src/net/Client.h
- src/net/Job.h
- src/net/JobId.h
- src/net/JobResult.h
- src/net/Network.h
- src/net/strategies/DonateStrategy.h
- src/net/strategies/FailoverStrategy.h
- src/net/strategies/SinglePoolStrategy.h
- src/net/SubmitResult.h
- src/version.h
- src/workers/DoubleWorker.h
- src/workers/Handle.h
- src/workers/Hashrate.h
- src/workers/SingleWorker.h
- src/workers/Worker.h
- src/workers/Workers.h
- )
-
-set(HEADERS_CRYPTO
- src/crypto/c_blake256.h
- src/crypto/c_groestl.h
- src/crypto/c_jh.h
- src/crypto/c_keccak.h
- src/crypto/c_skein.h
- src/crypto/CryptoNight.h
- src/crypto/CryptoNight_test.h
- src/crypto/groestl_tables.h
- src/crypto/hash.h
- src/crypto/skein_port.h
- src/crypto/soft_aes.h
- )
-
-if (XMRIG_ARM)
- set(HEADERS_CRYPTO "${HEADERS_CRYPTO}" src/crypto/CryptoNight_arm.h)
-else()
- set(HEADERS_CRYPTO "${HEADERS_CRYPTO}" src/crypto/CryptoNight_x86.h)
-endif()
-
set(SOURCES
src/api/Api.cpp
src/api/ApiState.cpp
@@ -77,10 +27,9 @@ set(SOURCES
src/net/strategies/SinglePoolStrategy.cpp
src/net/SubmitResult.cpp
src/Summary.cpp
- src/workers/DoubleWorker.cpp
+ src/workers/MultiWorker.cpp
src/workers/Handle.cpp
src/workers/Hashrate.cpp
- src/workers/SingleWorker.cpp
src/workers/Worker.cpp
src/workers/Workers.cpp
src/xmrig.cpp
@@ -95,20 +44,6 @@ set(SOURCES_CRYPTO
src/crypto/CryptoNight.cpp
)
-set(HEADERS_COMMON
- src/interfaces/IConsoleListener.h
- src/Console.h
- src/Mem.h
- src/Cpu.h
- src/net/Url.h
- src/Options.h
- src/log/ConsoleLog.h
- src/log/FileLog.h
- src/log/Log.h
- src/Platform.h
- src/Summary.h
-)
-
set(SOURCES_COMMON
src/Console.cpp
src/Mem.cpp
@@ -219,11 +154,6 @@ if (WITH_CC_SERVER)
message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC=OFF` to build without CC Server support")
endif()
- set(HEADERS_CC_SERVER
- src/cc/CCServer.h
- src/cc/Service.h
- src/cc/Httpd.h)
-
set(SOURCES_CC_SERVER
src/cc/CCServer.cpp
src/cc/Service.cpp
@@ -234,18 +164,11 @@ if (WITH_CC_SERVER)
endif()
if (WITH_CC_CLIENT)
- set(HEADERS_CC_CLIENT
- src/cc/CCClient.h)
-
set(SOURCES_CC_CLIENT
src/cc/CCClient.cpp)
endif()
if (WITH_CC_SERVER OR WITH_CC_CLIENT)
- set(HEADERS_CC_COMMON
- src/cc/ControlCommand.h
- src/cc/ClientStatus.h)
-
set(SOURCES_CC_COMMON
src/cc/ControlCommand.cpp
src/cc/ClientStatus.cpp)
@@ -257,13 +180,31 @@ include_directories(src)
include_directories(src/3rdparty)
include_directories(${UV_INCLUDE_DIR})
-add_executable(xmrigMiner ${HEADERS} ${SOURCES} ${HEADERS_COMMON} ${SOURCES_COMMON} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES} ${SOURCES_CC_COMMON} ${HEADERS_CC_COMMON} ${SOURCES_CC_CLIENT} ${HEADERS_CC_CLIENT})
-target_link_libraries(xmrigMiner ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB})
+add_library(xmrig_common STATIC ${SOURCES_COMMON})
+add_library(xmrig_os_dependencies STATIC ${SOURCES_OS} ${SOURCES_SYSLOG})
+add_library(xmrig_cpuid STATIC ${SOURCES_CPUID})
+
+if (WITH_CC_SERVER OR WITH_CC_CLIENT)
+ add_library(xmrig_cc_common STATIC ${SOURCES_CC_COMMON})
+endif (WITH_CC_SERVER OR WITH_CC_CLIENT)
+
+add_executable(xmrigMiner ${SOURCES} ${SOURCES_CRYPTO} ${HTTPD_SOURCES} ${SOURCES_CC_CLIENT} res/app.rc)
+
+target_link_libraries(xmrigMiner xmrig_common xmrig_cpuid xmrig_os_dependencies
+ ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB})
+
+if (WITH_CC_CLIENT)
+ target_link_libraries(xmrigMiner xmrig_cc_common)
+endif (WITH_CC_CLIENT)
add_executable(xmrigDaemon src/cc/XMRigd.cpp res/app.rc)
if (WITH_CC_SERVER AND MHD_FOUND)
- add_executable(xmrigCCServer ${HEADERS_COMMON} ${SOURCES_COMMON} ${SOURCES_OS} ${SOURCES_CPUID} ${SOURCES_SYSLOG} ${SOURCES_CC_COMMON} ${HEADERS_CC_COMMON} ${SOURCES_CC_SERVER} ${HEADERS_CC_SERVER})
- target_link_libraries(xmrigCCServer ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB})
+ add_executable(xmrigCCServer ${SOURCES_CC_SERVER} res/app.rc)
+ target_link_libraries(xmrigCCServer
+ xmrig_common xmrig_cpuid xmrig_os_dependencies xmrig_cc_common
+ ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB})
set_target_properties(xmrigCCServer PROPERTIES COMPILE_FLAGS "-DXMRIG_CC_SERVER ${SHARED_FLAGS}")
endif()
+
+add_subdirectory(test EXCLUDE_FROM_ALL)
\ No newline at end of file
diff --git a/README.md b/README.md
index c4d6872dfc..e5b8bef327 100644
--- a/README.md
+++ b/README.md
@@ -106,12 +106,13 @@ xmrigDaemon -o pool.minemonero.pro:5555 -u YOUR_WALLET -p x -k --cc-url=IP_OF_CC
-O, --userpass=U:P username:password pair for mining server
-u, --user=USERNAME username for mining server
-p, --pass=PASSWORD password for mining server
- -t, --threads=N number of miner threads
- -v, --av=N algorithm variation, 0 auto select
+ -t, --threads=N number of miner threads (0 enables automatic selection of optimal number of threads, default: 0)
+ -m, --multihash-factor=N number of hash blocks per thread to process at a time (0 enables automatic selection of optimal number of hash blocks, default: 0)
+ -A, --aesni=N selection of AES-NI mode (0 auto, 1 on, 2 off, default: 0)
-k, --keepalive send keepalived for prevent timeout (need pool support)
-r, --retries=N number of times to retry before switch to backup server (default: 5)
-R, --retry-pause=N time to pause between retries (default: 5)
- --doublehash-thread-mask for av=2/4 only, limits doublehash to given threads (mask), (default: all threads)
+ --multihash-thread-mask for multihash-factor > 1 only, limits multihash to given threads (mask), (default: all threads)
--cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1
--cpu-priority set process priority (0 idle, 2 normal to 5 highest)
--no-huge-pages disable huge pages support
@@ -135,33 +136,51 @@ xmrigDaemon -o pool.minemonero.pro:5555 -u YOUR_WALLET -p x -k --cc-url=IP_OF_CC
-l, --log-file=FILE log all output to a file
-h, --help display this help and exit
-V, --version output version information and exit
+ -v, --av=N DEPRECATED - algorithm variation, 0 auto select
+ --doublehash-thread-mask DEPRECATED - same as multihash-thread-mask
```
Also you can use configuration via config file, default **[config.json](https://github.com/Bendr0id/xmrigCC/wiki/Config-XMRigDaemon)**. You can load multiple config files and combine it with command line options.
-## Algorithm variations
-* `--av=1` For CPUs with hardware AES.
-* `--av=2` Lower power mode (double hash) of `1`.
-* `--av=3` Software AES implementation.
-* `--av=4` Lower power mode (double hash) of `3`.
+## Multihash (multihash-factor)
+With this option it is possible to increase the number of hashblocks calculated by a single thread in each round.
+Selecting multihash-factors greater than 1 increases the L3 cache demands relative to the multihash-factor.
+E.g. at multihash-factor 2, each Cryptonight thread requires 4MB and each Cryptonight-lite thread requires 2 MB of L3 cache.
+With multihash-factor 3, they need 6MB or 3MB respectively.
-## Doublehash thread Mask (only for low power mode (av=2 and av=4))
-With this option you can limit doublehash to the given threads (mask). This can significantly improve your hashrate by using unused l3 cache. The default is to run av2/av4 mode on all threads.
+Setting multihash-factor to 0 will allow automatic detection of the optimal value.
+Xmrig will then try to utilize as much of the L3 cache as possible for the selected number of threads.
+If the threads parameter has been set to auto, Xmrig will detect the optimal number of threads first.
+After that it finds the greatest possible multihash-factor.
+
+### Multihash for low power operation
+Depending the CPU and its L3 caches, it can make sense to replace multiple single hash threads with single multi-hash counterparts.
+This change might come at the price of a minor drop in effective hash-rate, yet it will also reduce heat production and power consumption of the used CPU.
+
+### Multihash for optimal CPU exploitation
+In certain environments (e.g. vServer) the system running xmrig can have access to relatively large amounts of L3 cache, but may has access to only a few CPU cores.
+In such cases, running xmrig with higher multihash-factors can lead to improvements.
+
+
+## Multihash thread Mask (only for multihash-factor > 1)
+With this option you can limit multihash to the given threads (mask).
+This can significantly improve your hashrate by using unused l3 cache.
+The default is to run the configured multihash-factor on all threads.
```
{
...
-"av":2,
-"doublehash-thread-mask":"0x5", // in binary -> 0101
+"multihash-factor":2,
+"multihash-thread-mask":"0x5", // in binary -> 0101
"threads": 4,
...
}
```
-This will limit doublehash mode (av=2,av=4) to thread 0 and thread 2, thread 1 and thread 3 will run in single hashmode (av=1,av=3).
+This will limit multihash mode (multihash-factor = 2) to thread 0 and thread 2, thread 1 and thread 3 will run in single hashmode.
## Common Issues
@@ -193,13 +212,18 @@ This will limit doublehash mode (av=2,av=4) to thread 0 and thread 2, thread 1 a
### CPU mining performance
-Please note performance is highly dependent on system load. The numbers above are obtained on an idle system. Tasks heavily using a processor cache, such as video playback, can greatly degrade hashrate. Optimal number of threads depends on the size of the L3 cache of a processor, 1 thread requires 2 MB (Cryptonight) or 1MB (Cryptonigh-Lite) of cache.
+Please note performance is highly dependent on system load.
+The numbers above are obtained on an idle system.
+Tasks heavily using a processor cache, such as video playback, can greatly degrade hashrate.
+Optimal number of threads depends on the size of the L3 cache of a processor, 1 thread requires 2 MB (Cryptonight) or 1MB (Cryptonigh-Lite) of cache.
### Maximum performance checklist
* Idle operating system.
* Do not exceed optimal thread count.
* Use modern CPUs with AES-NI instruction set.
* Try setup optimal cpu affinity.
+* Try decreasing number of threads while increasing multihash-factor.
+ Allocate unused cores and L3 cache with the help of multihash-thread-mask.
* Enable fast memory (Large/Huge pages).
## Donations
diff --git a/config_cc.json b/config_cc.json
deleted file mode 100644
index 734b863324..0000000000
--- a/config_cc.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "background": false,
- "colors": true,
- "log-file": null,
- "syslog": false,
- "cc-server": {
- "port": 3344, // port the CC Server will listens on
- "access-token": "mySecret", // access token for CC Clients
- "user": "admin", // admin user for access CC Dashboard
- "pass": "pass" // admin pass for access CC Dashboard
- }
-}
diff --git a/index.html b/index.html
index f54bfb6590..e763cfb6b8 100644
--- a/index.html
+++ b/index.html
@@ -386,7 +386,7 @@
var clientId = $('#minerEditor').find('.form-group')["0"].dataset.value;
var clientConfig = $('#config').val();
- setClientConfig(clientId, clientConfig, false);
+ setClientConfig(clientId, clientConfig);
});
$('#multiMinerEditorReplace').click(function(event) {
@@ -406,7 +406,7 @@
jsonClientConfig = JSON.stringify(jsonClientConfig,undefined, 2);
jsonClientConfig = jsonClientConfig.replace(new RegExp(search.trim(), 'g'), replacement.trim()).trim();
- setClientConfig(clientId, jsonClientConfig, true);
+ setClientConfig(clientId, jsonClientConfig);
},
error: function (data) {
setError('Unable to fetch ' + clientId + '_config.json - Please make sure that you pulled the config before!');
@@ -471,7 +471,7 @@
tooltip += (row.client_status.hugepages_enabled ? "enabled" : "disabled");
tooltip += '\n';
tooltip += "Used Threads: " + row.client_status.current_threads;
- tooltip += (row.client_status.double_hash_mode ? " [double hash mode]" :"");
+ tooltip += (row.client_status.hash_factor > 1 ? " [" + row.client_status.hash_factor + "x multi hash mode]" :"");
tooltip += '\n';
tooltip += "Client IP: " + row.client_status.external_ip;
tooltip += '\n';
@@ -531,25 +531,17 @@
}, 10000);
}
- function setClientConfig(clientId, clientConfig, isMultiConfigEdit) {
+ function setClientConfig(clientId, clientConfig) {
$.ajax({
url: "/admin/setClientConfig?clientId=" + clientId,
type: 'POST',
dataType: "text",
data: clientConfig,
success: function(data){
- if (isMultiConfigEdit) {
- setSuccess('Successfully updated configs for the selected miners - You need push the config to the miners to apply the config.');
- } else {
- setSuccess('Successfully updated config for: ' + clientId + ' - You need push the config to the miner to apply the config.');
- }
+ setSuccess('Successfully updated config for: ' + clientId + ' - You need push the config to the miner to apply the config.');
},
error: function (data) {
- if (isMultiConfigEdit) {
- setError('Failed to update configs for the selected miners \nError:' + JSON.stringify(data,undefined, 2));
- } else {
- setError('Failed to update config for: ' + clientId + ' \nError: ' + JSON.stringify(data,undefined, 2));
- }
+ setError('Failed to update config for: ' + clientId + ' \nError: ' + JSON.stringify(data,undefined, 2));
}
});
}
diff --git a/src/App.cpp b/src/App.cpp
index af80fc7dbf..4f4fb205c4 100644
--- a/src/App.cpp
+++ b/src/App.cpp
@@ -67,6 +67,7 @@ App::App(int argc, char **argv) :
m_self = this;
Cpu::init();
+
m_options = Options::parse(argc, argv);
if (!m_options) {
return;
@@ -137,12 +138,13 @@ int App::start()
background();
- if (!CryptoNight::init(m_options->algo(), m_options->algoVariant())) {
+ if (!CryptoNight::init(m_options->algo(), m_options->aesni())) {
LOG_ERR("\"%s\" hash self-test failed.", m_options->algoName());
return EINVAL;
}
Mem::allocate(m_options);
+
Summary::print();
# ifndef XMRIG_NO_API
diff --git a/src/Cpu.cpp b/src/Cpu.cpp
index ff6f49e950..5f440bef4c 100644
--- a/src/Cpu.cpp
+++ b/src/Cpu.cpp
@@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466
* Copyright 2016 Jay D Dee
* Copyright 2016-2017 XMRig
+ * Copyright 2018 Sebastian Stolzenberg
*
*
* This program is free software: you can redistribute it and/or modify
@@ -22,60 +23,116 @@
*/
+#include
+#include
+#include
+#include
+
#include
-#include
-#include
+#include
#include "Cpu.h"
+#include "CpuImpl.h"
+CpuImpl& CpuImpl::instance()
+{
+ static CpuImpl cpu;
+ return cpu;
+}
-bool Cpu::m_l2_exclusive = false;
-char Cpu::m_brand[64] = { 0 };
-int Cpu::m_flags = 0;
-int Cpu::m_l2_cache = 0;
-int Cpu::m_l3_cache = 0;
-int Cpu::m_sockets = 1;
-int Cpu::m_totalCores = 0;
-int Cpu::m_totalThreads = 0;
-
+CpuImpl::CpuImpl()
+ : m_l2_exclusive(false)
+ , m_brand{ 0 }
+ , m_flags(0)
+ , m_l2_cache(0)
+ , m_l3_cache(0)
+ , m_sockets(1)
+ , m_totalCores(0)
+ , m_totalThreads(0)
+{
+}
-int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
+void CpuImpl::optimizeParameters(size_t& threadsCount, size_t& hashFactor,
+ Options::Algo algo, size_t maxCpuUsage, bool safeMode)
{
- if (m_totalThreads == 1) {
- return 1;
- }
+ // limits hashfactor to maximum possible value defined by compiler flag
+ hashFactor = std::min(hashFactor, static_cast(MAX_NUM_HASH_BLOCKS));
- int cache = 0;
- if (m_l3_cache) {
- cache = m_l2_exclusive ? (m_l2_cache + m_l3_cache) : m_l3_cache;
+ if (!safeMode && threadsCount > 0 && hashFactor > 0)
+ {
+ // all parameters have been set manually and safe mode is off ... no optimization necessary
+ return;
}
- else {
- cache = m_l2_cache;
- }
-
- int count = 0;
- const int size = (algo ? 1024 : 2048) * (doubleHash ? 2 : 1);
- if (cache) {
- count = cache / size;
- }
- else {
- count = m_totalThreads / 2;
+ size_t cache = availableCache();
+ size_t algoBlockSize;
+ switch (algo) {
+ case Options::ALGO_CRYPTONIGHT_LITE:
+ algoBlockSize = 1024;
+ break;
+ case Options::ALGO_CRYPTONIGHT:
+ default:
+ algoBlockSize = 2048;
+ break;
}
- if (count > m_totalThreads) {
- count = m_totalThreads;
+ size_t maximumReasonableFactor = std::max(cache / algoBlockSize, static_cast(1ul));
+ size_t maximumReasonableThreadCount = std::min(maximumReasonableFactor, m_totalThreads);
+ size_t maximumReasonableHashFactor = std::min(maximumReasonableFactor, static_cast(MAX_NUM_HASH_BLOCKS));
+
+ if (safeMode) {
+ if (threadsCount > maximumReasonableThreadCount) {
+ threadsCount = maximumReasonableThreadCount;
+ }
+ if (hashFactor > maximumReasonableFactor / threadsCount) {
+ hashFactor = std::min(maximumReasonableFactor / threadsCount, maximumReasonableHashFactor);
+ hashFactor = std::max(hashFactor, static_cast(1));
+ }
}
- if (((float) count / m_totalThreads * 100) > maxCpuUsage) {
- count = (int) ceil((float) m_totalThreads * (maxCpuUsage / 100.0));
+ if (threadsCount == 0) {
+ if (hashFactor == 0) {
+ threadsCount = maximumReasonableThreadCount;
+ }
+ else {
+ threadsCount = std::min(maximumReasonableThreadCount,
+ maximumReasonableFactor / hashFactor);
+ }
+ if (maxCpuUsage < 100)
+ {
+ threadsCount = std::min(threadsCount, m_totalThreads * maxCpuUsage / 100);
+ }
+ threadsCount = std::max(threadsCount, static_cast(1));
}
+ if (hashFactor == 0) {
+ hashFactor = std::min(maximumReasonableHashFactor, maximumReasonableFactor / threadsCount);
+ hashFactor = std::max(hashFactor, static_cast(1));
+ }
+}
- return count < 1 ? 1 : count;
+bool CpuImpl::hasAES()
+{
+ return (m_flags & Cpu::AES) != 0;
+}
+
+bool CpuImpl::isX64()
+{
+ return (m_flags & Cpu::X86_64) != 0;
}
+size_t CpuImpl::availableCache()
+{
+ size_t cache = 0;
+ if (m_l3_cache) {
+ cache = m_l2_exclusive ? (m_l2_cache + m_l3_cache) : m_l3_cache;
+ }
+ else {
+ cache = m_l2_cache;
+ }
+ return cache;
+}
-void Cpu::initCommon()
+void CpuImpl::initCommon()
{
struct cpu_raw_data_t raw = { 0 };
struct cpu_id_t data = { 0 };
@@ -105,14 +162,75 @@ void Cpu::initCommon()
}
# if defined(__x86_64__) || defined(_M_AMD64)
- m_flags |= X86_64;
+ m_flags |= Cpu::X86_64;
# endif
if (data.flags[CPU_FEATURE_AES]) {
- m_flags |= AES;
+ m_flags |= Cpu::AES;
}
if (data.flags[CPU_FEATURE_BMI2]) {
- m_flags |= BMI2;
+ m_flags |= Cpu::BMI2;
}
}
+
+void Cpu::init()
+{
+ CpuImpl::instance().init();
+}
+
+void Cpu::optimizeParameters(size_t& threadsCount, size_t& hashFactor, Options::Algo algo,
+ size_t maxCpuUsage, bool safeMode)
+{
+ CpuImpl::instance().optimizeParameters(threadsCount, hashFactor, algo, maxCpuUsage, safeMode);
+}
+
+void Cpu::setAffinity(int id, uint64_t mask)
+{
+ CpuImpl::instance().setAffinity(id, mask);
+}
+
+bool Cpu::hasAES()
+{
+ return CpuImpl::instance().hasAES();
+}
+
+bool Cpu::isX64()
+{
+ return CpuImpl::instance().isX64();
+}
+
+const char* Cpu::brand()
+{
+ return CpuImpl::instance().brand();
+}
+
+size_t Cpu::cores()
+{
+ return CpuImpl::instance().cores();
+}
+
+size_t Cpu::l2()
+{
+ return CpuImpl::instance().l2();
+}
+
+size_t Cpu::l3()
+{
+ return CpuImpl::instance().l3();
+}
+
+size_t Cpu::sockets()
+{
+ return CpuImpl::instance().sockets();
+}
+
+size_t Cpu::threads()
+{
+ return CpuImpl::instance().threads();
+}
+
+size_t Cpu::availableCache()
+{
+ return CpuImpl::instance().availableCache();
+}
diff --git a/src/Cpu.h b/src/Cpu.h
index 9444274d2f..90bf3e1811 100644
--- a/src/Cpu.h
+++ b/src/Cpu.h
@@ -24,9 +24,9 @@
#ifndef __CPU_H__
#define __CPU_H__
+#include
-#include
-
+#include "Options.h"
class Cpu
{
@@ -37,30 +37,22 @@ class Cpu
BMI2 = 4
};
- static int optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage);
static void init();
- static void setAffinity(int id, uint64_t mask);
- static inline bool hasAES() { return (m_flags & AES) != 0; }
- static inline bool isX64() { return (m_flags & X86_64) != 0; }
- static inline const char *brand() { return m_brand; }
- static inline int cores() { return m_totalCores; }
- static inline int l2() { return m_l2_cache; }
- static inline int l3() { return m_l3_cache; }
- static inline int sockets() { return m_sockets; }
- static inline int threads() { return m_totalThreads; }
+ static void optimizeParameters(size_t& threadsCount, size_t& hashFactor, Options::Algo algo,
+ size_t maxCpuUsage, bool safeMode);
-private:
- static void initCommon();
+ static void setAffinity(int id, uint64_t mask);
- static bool m_l2_exclusive;
- static char m_brand[64];
- static int m_flags;
- static int m_l2_cache;
- static int m_l3_cache;
- static int m_sockets;
- static int m_totalCores;
- static int m_totalThreads;
+ static bool hasAES();
+ static bool isX64();
+ static const char *brand();
+ static size_t l2();
+ static size_t l3();
+ static size_t cores();
+ static size_t sockets();
+ static size_t threads();
+ static size_t availableCache();
};
diff --git a/src/workers/DoubleWorker.h b/src/CpuImpl.h
similarity index 50%
rename from src/workers/DoubleWorker.h
rename to src/CpuImpl.h
index 711f4bd1c0..96d3ad4e26 100644
--- a/src/workers/DoubleWorker.h
+++ b/src/CpuImpl.h
@@ -5,7 +5,7 @@
* Copyright 2014-2016 Wolf9466
* Copyright 2016 Jay D Dee
* Copyright 2016-2017 XMRig
- *
+ * Copyright 2018 Sebastian Stolzenberg
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,38 +21,47 @@
* along with this program. If not, see .
*/
-#ifndef __DOUBLEWORKER_H__
-#define __DOUBLEWORKER_H__
-
-
-#include "align.h"
-#include "net/Job.h"
-#include "net/JobResult.h"
-#include "workers/Worker.h"
+#ifndef __CPU_IMPL_H__
+#define __CPU_IMPL_H__
-class Handle;
+#include
+#include
+#include "Options.h"
-class DoubleWorker : public Worker
+class CpuImpl
{
public:
- DoubleWorker(Handle *handle);
- ~DoubleWorker();
+ static CpuImpl& instance();
+ CpuImpl();
+ void init();
- void start() override;
+ void optimizeParameters(size_t& threadsCount, size_t& hashFactor, Options::Algo algo,
+ size_t maxCpuUsage, bool safeMode);
+ void setAffinity(int id, uint64_t mask);
-private:
- bool resume(const Job &job);
- void consumeJob();
- void save(const Job &job);
+ bool hasAES();
+ bool isX64();
+ const char *brand() { return m_brand; }
+ size_t l2() { return m_l2_cache; }
+ size_t l3() { return m_l3_cache; }
+ size_t cores() { return m_totalCores; }
+ size_t sockets() { return m_sockets; }
+ size_t threads() { return m_totalThreads; }
+ size_t availableCache();
- class State;
+private:
+ void initCommon();
- uint8_t m_hash[64];
- State *m_state;
- State *m_pausedState;
+ bool m_l2_exclusive;
+ char m_brand[64];
+ int m_flags;
+ size_t m_l2_cache;
+ size_t m_l3_cache;
+ size_t m_sockets;
+ size_t m_totalCores;
+ size_t m_totalThreads;
};
-
-#endif /* __SINGLEWORKER_H__ */
+#endif /* __CPU_IMPL_H__ */
diff --git a/src/Cpu_arm.cpp b/src/Cpu_arm.cpp
index c2047ffbb6..8b91f331a8 100644
--- a/src/Cpu_arm.cpp
+++ b/src/Cpu_arm.cpp
@@ -27,23 +27,18 @@
#include "Cpu.h"
-
-char Cpu::m_brand[64] = { 0 };
-int Cpu::m_flags = 0;
-int Cpu::m_l2_cache = 0;
-int Cpu::m_l3_cache = 0;
-int Cpu::m_sockets = 1;
-int Cpu::m_totalCores = 0;
-int Cpu::m_totalThreads = 0;
-
-
-int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
+void CpuImpl::init()
{
- return m_totalThreads;
+ m_brand = {0};
+ m_flags = 0;
+ m_l2_cache = 0;
+ m_l3_cache = 0;
+ m_sockets = 1;
+ m_totalCores = 0;
+ m_totalThreads = 0;
}
-
-void Cpu::initCommon()
+void CpuImpl::initCommon()
{
memcpy(m_brand, "Unknown", 7);
diff --git a/src/Cpu_mac.cpp b/src/Cpu_mac.cpp
index 357e15efe3..94c97032d4 100644
--- a/src/Cpu_mac.cpp
+++ b/src/Cpu_mac.cpp
@@ -30,7 +30,7 @@
#include "Cpu.h"
-void Cpu::init()
+void CpuImpl::init()
{
# ifdef XMRIG_NO_LIBCPUID
m_totalThreads = sysconf(_SC_NPROCESSORS_CONF);
@@ -40,6 +40,6 @@ void Cpu::init()
}
-void Cpu::setAffinity(int id, uint64_t mask)
+void CpuImpl::setAffinity(int id, uint64_t mask)
{
}
diff --git a/src/Cpu_stub.cpp b/src/Cpu_stub.cpp
index 0b9196eea2..ad3aa1ef4b 100644
--- a/src/Cpu_stub.cpp
+++ b/src/Cpu_stub.cpp
@@ -108,13 +108,6 @@ int Cpu::m_totalCores = 0;
int Cpu::m_totalThreads = 0;
-int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
-{
- int count = m_totalThreads / 2;
- return count < 1 ? 1 : count;
-}
-
-
void Cpu::initCommon()
{
cpu_brand_string(m_brand);
diff --git a/src/Cpu_unix.cpp b/src/Cpu_unix.cpp
index 9a13e7a523..8ae7f567f5 100644
--- a/src/Cpu_unix.cpp
+++ b/src/Cpu_unix.cpp
@@ -36,7 +36,7 @@
#include
-#include "Cpu.h"
+#include "CpuImpl.h"
#ifdef __FreeBSD__
@@ -44,7 +44,7 @@ typedef cpuset_t cpu_set_t;
#endif
-void Cpu::init()
+void CpuImpl::init()
{
# ifdef XMRIG_NO_LIBCPUID
m_totalThreads = sysconf(_SC_NPROCESSORS_CONF);
@@ -54,12 +54,12 @@ void Cpu::init()
}
-void Cpu::setAffinity(int id, uint64_t mask)
+void CpuImpl::setAffinity(int id, uint64_t mask)
{
cpu_set_t set;
CPU_ZERO(&set);
- for (int i = 0; i < m_totalThreads; i++) {
+ for (int i = 0; i < threads(); i++) {
if (mask & (1UL << i)) {
CPU_SET(i, &set);
}
diff --git a/src/Cpu_win.cpp b/src/Cpu_win.cpp
index 13113a1787..d967421c8c 100644
--- a/src/Cpu_win.cpp
+++ b/src/Cpu_win.cpp
@@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466
* Copyright 2016 Jay D Dee
* Copyright 2016-2017 XMRig
+ * Copyright 2018 BenDroid
*
*
* This program is free software: you can redistribute it and/or modify
@@ -25,10 +26,10 @@
#include
-#include "Cpu.h"
+#include "CpuImpl.h"
+#include "Mem.h"
-
-void Cpu::init()
+void CpuImpl::init()
{
# ifdef XMRIG_NO_LIBCPUID
SYSTEM_INFO sysinfo;
@@ -41,12 +42,24 @@ void Cpu::init()
}
-void Cpu::setAffinity(int id, uint64_t mask)
+void CpuImpl::setAffinity(int id, uint64_t mask)
{
if (id == -1) {
SetProcessAffinityMask(GetCurrentProcess(), mask);
- }
- else {
- SetThreadAffinityMask(GetCurrentThread(), mask);
+ } else {
+ Mem::ThreadBitSet threadAffinityMask = Mem::ThreadBitSet(mask);
+
+ int threadCount = 0;
+
+ for (int i = 0; i < m_totalThreads; i++) {
+ if (threadAffinityMask.test(i)) {
+ if (threadCount == id) {
+ SetThreadAffinityMask(GetCurrentThread(), 1ULL << i);
+ break;
+ }
+
+ threadCount++;
+ }
+ }
}
}
diff --git a/src/Mem.cpp b/src/Mem.cpp
index 05a2f31b7d..5d9261d050 100644
--- a/src/Mem.cpp
+++ b/src/Mem.cpp
@@ -27,16 +27,15 @@
#include "crypto/CryptoNight.h"
#include "Mem.h"
-#include "Options.h"
-bool Mem::m_doubleHash = false;
int Mem::m_algo = 0;
int Mem::m_flags = 0;
-int Mem::m_threads = 0;
+size_t Mem::m_hashFactor = 1;
+size_t Mem::m_threads = 0;
size_t Mem::m_memorySize = 0;
uint8_t *Mem::m_memory = nullptr;
-int64_t Mem::m_doubleHashThreadMask = -1L;
+Mem::ThreadBitSet Mem::m_multiHashThreadMask = Mem::ThreadBitSet(-1L);
cryptonight_ctx *Mem::create(int threadId)
{
@@ -45,7 +44,7 @@ cryptonight_ctx *Mem::create(int threadId)
size_t offset = 0;
for (int i=0; i < threadId; i++) {
offset += sizeof(cryptonight_ctx);
- offset += isDoubleHash(i) ? scratchPadSize*2 : scratchPadSize;
+ offset += scratchPadSize * getThreadHashFactor(i);
}
auto* ctx = reinterpret_cast(&m_memory[offset]);
diff --git a/src/Mem.h b/src/Mem.h
index 1325907fb5..ffbc7d019d 100644
--- a/src/Mem.h
+++ b/src/Mem.h
@@ -5,6 +5,8 @@
* Copyright 2014-2016 Wolf9466
* Copyright 2016 Jay D Dee
* Copyright 2016-2017 XMRig
+ * Copyright 2018 Sebastian Stolzenberg
+ * Copyright 2018 BenDroid
*
*
* This program is free software: you can redistribute it and/or modify
@@ -25,8 +27,9 @@
#define __MEM_H__
-#include
-#include
+#include
+#include
+#include
#include "align.h"
#include "Options.h"
@@ -37,6 +40,7 @@ struct cryptonight_ctx;
class Mem
{
public:
+ typedef std::bitset<64> ThreadBitSet;
enum Flags {
HugepagesAvailable = 1,
HugepagesEnabled = 2,
@@ -47,18 +51,23 @@ class Mem
static cryptonight_ctx *create(int threadId);
static void release();
- static inline bool isDoubleHash(int threadId) { return m_doubleHash && (m_doubleHashThreadMask == -1L || ((m_doubleHashThreadMask >> threadId) & 1)); }
+ static inline size_t hashFactor() { return m_hashFactor; }
+ static inline size_t getThreadHashFactor(int threadId)
+ {
+ return (m_multiHashThreadMask.all() ||
+ m_multiHashThreadMask.test(threadId)) ? m_hashFactor : 1;
+ }
static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; }
static inline bool isHugepagesEnabled() { return (m_flags & HugepagesEnabled) != 0; }
static inline int flags() { return m_flags; }
- static inline int threads() { return m_threads; }
+ static inline size_t threads() { return m_threads; }
private:
- static bool m_doubleHash;
+ static size_t m_hashFactor;
+ static size_t m_threads;
static int m_algo;
static int m_flags;
- static int m_threads;
- static int64_t m_doubleHashThreadMask;
+ static ThreadBitSet m_multiHashThreadMask;
static size_t m_memorySize;
VAR_ALIGN(16, static uint8_t *m_memory);
};
diff --git a/src/Mem_unix.cpp b/src/Mem_unix.cpp
index 97555cdb54..820dde81d3 100644
--- a/src/Mem_unix.cpp
+++ b/src/Mem_unix.cpp
@@ -22,7 +22,7 @@
*/
-#include
+#include
#include
@@ -36,26 +36,20 @@
#include "crypto/CryptoNight.h"
#include "log/Log.h"
#include "Mem.h"
-#include "Options.h"
bool Mem::allocate(const Options* options)
{
m_algo = options->algo();
m_threads = options->threads();
- m_doubleHash = options->doubleHash();
- m_doubleHashThreadMask = options->doubleHashThreadMask();
+ m_hashFactor = options->hashFactor();
+ m_multiHashThreadMask = Mem::ThreadBitSet(options->multiHashThreadMask());
m_memorySize = 0;
size_t scratchPadSize = m_algo == Options::ALGO_CRYPTONIGHT ? MEMORY : MEMORY_LITE;
for (int i=0; i < m_threads; i++) {
m_memorySize += sizeof(cryptonight_ctx);
-
- if (isDoubleHash(i)) {
- m_memorySize += scratchPadSize*2;
- } else {
- m_memorySize += scratchPadSize;
- }
+ m_memorySize += scratchPadSize * getThreadHashFactor(i);
}
if (!options->hugePages()) {
@@ -70,7 +64,7 @@ bool Mem::allocate(const Options* options)
# elif defined(__FreeBSD__)
m_memory = static_cast(mmap(0, m_memorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER | MAP_PREFAULT_READ, -1, 0));
# else
- m_memory = static_cast(mmap(0, m_memorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0));
+ m_memory = static_cast(mmap(nullptr, m_memorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0));
# endif
if (m_memory == MAP_FAILED) {
m_memory = static_cast(_mm_malloc(m_memorySize, 16));
diff --git a/src/Mem_win.cpp b/src/Mem_win.cpp
index 2229c2ac37..dff6f3be9b 100644
--- a/src/Mem_win.cpp
+++ b/src/Mem_win.cpp
@@ -148,19 +148,14 @@ bool Mem::allocate(const Options* options)
{
m_algo = options->algo();
m_threads = options->threads();
- m_doubleHash = options->doubleHash();
- m_doubleHashThreadMask = options->doubleHashThreadMask();
+ m_hashFactor = options->hashFactor();
+ m_multiHashThreadMask = Mem::ThreadBitSet(options->multiHashThreadMask());
m_memorySize = 0;
size_t scratchPadSize = m_algo == Options::ALGO_CRYPTONIGHT ? MEMORY : MEMORY_LITE;
for (int i=0; i < m_threads; i++) {
m_memorySize += sizeof(cryptonight_ctx);
-
- if (isDoubleHash(i)) {
- m_memorySize += scratchPadSize*2;
- } else {
- m_memorySize += scratchPadSize;
- }
+ m_memorySize += scratchPadSize * getThreadHashFactor(i);
}
m_memorySize = m_memorySize - (m_memorySize % MEMORY) + MEMORY;
diff --git a/src/Options.cpp b/src/Options.cpp
index 8001032061..8e2d98e30b 100644
--- a/src/Options.cpp
+++ b/src/Options.cpp
@@ -23,10 +23,9 @@
*/
-#include
+#include
#include
-
#ifdef _MSC_VER
# include "getopt/getopt.h"
#else
@@ -75,7 +74,7 @@ Options:\n"
-k, --keepalive send keepalived for prevent timeout (need pool support)\n\
-r, --retries=N number of times to retry before switch to backup server (default: 5)\n\
-R, --retry-pause=N time to pause between retries (default: 5)\n\
- --doublehash-thread-mask for av=2/4 only, limits doublehash to given threads (mask), (default: all threads)\n\
+ --multihash-thread-mask for av=2/4 only, limits multihash to given threads (mask), (default: all threads)\n\
--cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\
--cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\
--no-huge-pages disable huge pages support\n\
@@ -127,6 +126,8 @@ static char const short_options[] = "a:c:khBp:Px:r:R:s:t:T:o:u:O:v:Vl:S";
static struct option const options[] = {
{ "algo", 1, nullptr, 'a' },
{ "av", 1, nullptr, 'v' },
+ { "aesni", 1, nullptr, 'A' },
+ { "multihash-factor", 1, nullptr, 'm' },
{ "background", 0, nullptr, 'B' },
{ "config", 1, nullptr, 'c' },
{ "cpu-affinity", 1, nullptr, 1020 },
@@ -165,13 +166,16 @@ static struct option const options[] = {
{ "cc-custom-dashboard", 1, nullptr, 4010 },
{ "daemonized", 0, nullptr, 4011 },
{ "doublehash-thread-mask", 1, nullptr, 4013 },
- { 0, 0, 0, 0 }
+ { "multihash-thread-mask", 1, nullptr, 4013 },
+ { nullptr, 0, nullptr, 0 }
};
static struct option const config_options[] = {
{ "algo", 1, nullptr, 'a' },
{ "av", 1, nullptr, 'v' },
+ { "aesni", 1, nullptr, 'A' },
+ { "multihash-factor", 1, nullptr, 'm' },
{ "background", 0, nullptr, 'B' },
{ "colors", 0, nullptr, 2000 },
{ "cpu-affinity", 1, nullptr, 1020 },
@@ -188,7 +192,8 @@ static struct option const config_options[] = {
{ "threads", 1, nullptr, 't' },
{ "user-agent", 1, nullptr, 1008 },
{ "doublehash-thread-mask", 1, nullptr, 4013 },
- { 0, 0, 0, 0 }
+ { "multihash-thread-mask", 1, nullptr, 4013 },
+ { nullptr, 0, nullptr, 0 }
};
@@ -199,7 +204,7 @@ static struct option const pool_options[] = {
{ "userpass", 1, nullptr, 'O' },
{ "keepalive", 0, nullptr ,'k' },
{ "nicehash", 0, nullptr, 1006 },
- { 0, 0, 0, 0 }
+ { nullptr, 0, nullptr, 0 }
};
@@ -207,7 +212,7 @@ static struct option const api_options[] = {
{ "port", 1, nullptr, 4000 },
{ "access-token", 1, nullptr, 4001 },
{ "worker-id", 1, nullptr, 4002 },
- { 0, 0, 0, 0 }
+ { nullptr, 0, nullptr, 0 }
};
@@ -216,7 +221,7 @@ static struct option const cc_client_options[] = {
{ "access-token", 1, nullptr, 4004 },
{ "worker-id", 1, nullptr, 4005 },
{ "update-interval-s", 1, nullptr, 4012 },
- { 0, 0, 0, 0 }
+ { nullptr, 0, nullptr, 0 }
};
static struct option const cc_server_options[] = {
@@ -226,7 +231,7 @@ static struct option const cc_server_options[] = {
{ "pass", 1, nullptr, 4008 },
{ "client-config-folder", 1, nullptr, 4009 },
{ "custom-dashboard", 1, nullptr, 4010 },
- { 0, 0, 0, 0 }
+ { nullptr, 0, nullptr, 0 }
};
static const char *algo_names[] = {
@@ -239,7 +244,7 @@ static const char *algo_names[] = {
Options *Options::parse(int argc, char **argv)
{
- Options *options = new Options(argc, argv);
+ auto options = new Options(argc, argv);
if (options->isReady()) {
m_self = options;
return m_self;
@@ -259,7 +264,6 @@ const char *Options::algoName() const
Options::Options(int argc, char **argv) :
m_background(false),
m_colors(true),
- m_doubleHash(false),
m_hugePages(true),
m_ready(false),
m_safe(false),
@@ -277,8 +281,10 @@ Options::Options(int argc, char **argv) :
m_ccAdminPass(nullptr),
m_ccClientConfigFolder(nullptr),
m_ccCustomDashboard(nullptr),
- m_algo(0),
- m_algoVariant(0),
+ m_algo(ALGO_CRYPTONIGHT),
+ m_algoVariant(AV0_AUTO),
+ m_aesni(AESNI_AUTO),
+ m_hashFactor(0),
m_apiPort(0),
m_donateLevel(kDonateLevel),
m_maxCpuUsage(75),
@@ -290,14 +296,14 @@ Options::Options(int argc, char **argv) :
m_ccUpdateInterval(10),
m_ccPort(0),
m_affinity(-1L),
- m_doubleHashThreadMask(-1L)
+ m_multiHashThreadMask(-1L)
{
m_pools.push_back(new Url());
int key;
- while (1) {
- key = getopt_long(argc, argv, short_options, options, NULL);
+ while (true) {
+ key = getopt_long(argc, argv, short_options, options, nullptr);
if (key < 0) {
break;
}
@@ -337,22 +343,9 @@ Options::Options(int argc, char **argv) :
fprintf(stderr, "Neither pool nor CCServer URL supplied. Exiting.\n");
return;
}
-
- m_algoVariant = getAlgoVariant();
- if (m_algoVariant == AV2_AESNI_DOUBLE || m_algoVariant == AV4_SOFT_AES_DOUBLE) {
- m_doubleHash = true;
- }
#endif
- if (!m_threads) {
- m_threads = Cpu::optimalThreadsCount(m_algo, m_doubleHash, m_maxCpuUsage);
- }
- else if (m_safe) {
- const int count = Cpu::optimalThreadsCount(m_algo, m_doubleHash, m_maxCpuUsage);
- if (m_threads > count) {
- m_threads = count;
- }
- }
+ optimizeAlgorithmConfiguration();
for (Url *url : m_pools) {
url->applyExceptions();
@@ -407,7 +400,7 @@ bool Options::parseArg(int key, const char *arg)
case 'o': /* --url */
if (m_pools.size() > 1 || m_pools[0]->isValid()) {
- Url *url = new Url(arg);
+ auto url = new Url(arg);
if (url->isValid()) {
m_pools.push_back(url);
}
@@ -494,6 +487,8 @@ bool Options::parseArg(int key, const char *arg)
case 'r': /* --retries */
case 'R': /* --retry-pause */
case 'v': /* --av */
+ case 'A': /* --aesni */
+ case 'm': /* --multihash-factor */
case 1003: /* --donate-level */
case 1004: /* --max-cpu-usage */
case 1007: /* --print-time */
@@ -541,7 +536,7 @@ bool Options::parseArg(int key, const char *arg)
return parseArg(key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10));
}
- case 4013: { /* --doublehash-thread-mask */
+ case 4013: { /* --multihash-thread-mask */
const char *p = strstr(arg, "0x");
return parseArg(key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10));
}
@@ -596,7 +591,23 @@ bool Options::parseArg(int key, uint64_t arg)
return false;
}
- m_algoVariant = (int) arg;
+ m_algoVariant = static_cast(arg);
+ break;
+
+ case 'A': /* --aesni */
+ if (arg < AESNI_AUTO || arg > AESNI_OFF) {
+ showUsage(1);
+ return false;
+ }
+ m_aesni = static_cast(arg);
+ break;
+
+ case 'm': /* --multihash-factor */
+ if (arg > MAX_NUM_HASH_BLOCKS) {
+ showUsage(1);
+ return false;
+ }
+ m_hashFactor = arg;
break;
case 1003: /* --donate-level */
@@ -658,9 +669,9 @@ bool Options::parseArg(int key, uint64_t arg)
m_ccUpdateInterval = (int) arg;
break;
- case 4013: /* --doublehash-thread-mask */
+ case 4013: /* --multihash-thread-mask */
if (arg) {
- m_doubleHashThreadMask = arg;
+ m_multiHashThreadMask = arg;
}
break;
default:
@@ -737,8 +748,8 @@ void Options::parseConfig(const char *fileName)
return;
}
- for (size_t i = 0; i < ARRAY_SIZE(config_options); i++) {
- parseJSON(&config_options[i], doc);
+ for (auto option : config_options) {
+ parseJSON(&option, doc);
}
const rapidjson::Value &pools = doc["pools"];
@@ -748,30 +759,30 @@ void Options::parseConfig(const char *fileName)
continue;
}
- for (size_t i = 0; i < ARRAY_SIZE(pool_options); i++) {
- parseJSON(&pool_options[i], value);
+ for (auto option : pool_options) {
+ parseJSON(&option, value);
}
}
}
const rapidjson::Value &api = doc["api"];
if (api.IsObject()) {
- for (size_t i = 0; i < ARRAY_SIZE(api_options); i++) {
- parseJSON(&api_options[i], api);
+ for (auto api_option : api_options) {
+ parseJSON(&api_option, api);
}
}
const rapidjson::Value &ccClient = doc["cc-client"];
if (ccClient.IsObject()) {
- for (size_t i = 0; i < ARRAY_SIZE(cc_client_options); i++) {
- parseJSON(&cc_client_options[i], ccClient);
+ for (auto cc_client_option : cc_client_options) {
+ parseJSON(&cc_client_option, ccClient);
}
}
const rapidjson::Value &ccServer = doc["cc-server"];
if (ccServer.IsObject()) {
- for (size_t i = 0; i < ARRAY_SIZE(cc_server_options); i++) {
- parseJSON(&cc_server_options[i], ccServer);
+ for (auto cc_server_option : cc_server_options) {
+ parseJSON(&cc_server_option, ccServer);
}
}
}
@@ -848,7 +859,7 @@ bool Options::setAlgo(const char *algo)
{
for (size_t i = 0; i < ARRAY_SIZE(algo_names); i++) {
if (algo_names[i] && !strcmp(algo, algo_names[i])) {
- m_algo = (int) i;
+ m_algo = static_cast(i);
break;
}
@@ -868,41 +879,50 @@ bool Options::setAlgo(const char *algo)
return true;
}
-
-int Options::getAlgoVariant() const
+void Options::optimizeAlgorithmConfiguration()
{
-# ifndef XMRIG_NO_AEON
- if (m_algo == ALGO_CRYPTONIGHT_LITE) {
- return getAlgoVariantLite();
- }
-# endif
-
- if (m_algoVariant <= AV0_AUTO || m_algoVariant >= AV_MAX) {
- return Cpu::hasAES() ? AV1_AESNI : AV3_SOFT_AES;
- }
-
- if (m_safe && !Cpu::hasAES() && m_algoVariant <= AV2_AESNI_DOUBLE) {
- return m_algoVariant + 2;
- }
-
- return m_algoVariant;
-}
-
-
-#ifndef XMRIG_NO_AEON
-int Options::getAlgoVariantLite() const
-{
- if (m_algoVariant <= AV0_AUTO || m_algoVariant >= AV_MAX) {
- return Cpu::hasAES() ? AV2_AESNI_DOUBLE : AV4_SOFT_AES_DOUBLE;
+ // backwards compatibility for configs still setting algo variant (av)
+ // av overrides mutli-hash and aesni when they are either not set or when they are set to auto
+ if (m_algoVariant != AV0_AUTO) {
+ size_t hashFactor = m_hashFactor;
+ AesNi aesni = m_aesni;
+ switch (m_algoVariant) {
+ case AV1_AESNI:
+ hashFactor = 1;
+ aesni = AESNI_ON;
+ break;
+ case AV2_AESNI_DOUBLE:
+ hashFactor = 2;
+ aesni = AESNI_ON;
+ break;
+ case AV3_SOFT_AES:
+ hashFactor = 1;
+ aesni = AESNI_OFF;
+ break;
+ case AV4_SOFT_AES_DOUBLE:
+ hashFactor = 2;
+ aesni = AESNI_OFF;
+ break;
+ case AV0_AUTO:
+ default:
+ // no change
+ break;
+ }
+ if (m_hashFactor == 0) {
+ m_hashFactor = hashFactor;
+ }
+ if (m_aesni == AESNI_AUTO) {
+ m_aesni = aesni;
+ }
}
- if (m_safe && !Cpu::hasAES() && m_algoVariant <= AV2_AESNI_DOUBLE) {
- return m_algoVariant + 2;
+ AesNi aesniFromCpu = Cpu::hasAES() ? AESNI_ON : AESNI_OFF;
+ if (m_aesni == AESNI_AUTO || m_safe) {
+ m_aesni = aesniFromCpu;
}
- return m_algoVariant;
+ Cpu::optimizeParameters(m_threads, m_hashFactor, m_algo, m_maxCpuUsage, m_safe);
}
-#endif
bool Options::parseCCUrl(const char* url)
{
diff --git a/src/Options.h b/src/Options.h
index 5402af3298..24bae1afe8 100644
--- a/src/Options.h
+++ b/src/Options.h
@@ -25,14 +25,15 @@
#ifndef __OPTIONS_H__
#define __OPTIONS_H__
+#ifndef MAX_NUM_HASH_BLOCKS
+#define MAX_NUM_HASH_BLOCKS 5
+#endif
-#include
+#include
#include
-
#include "rapidjson/fwd.h"
-
class Url;
struct option;
@@ -54,12 +55,17 @@ class Options
AV_MAX
};
+ enum AesNi {
+ AESNI_AUTO,
+ AESNI_ON,
+ AESNI_OFF
+ };
+
static inline Options* i() { return m_self; }
static Options *parse(int argc, char **argv);
inline bool background() const { return m_background; }
inline bool colors() const { return m_colors; }
- inline bool doubleHash() const { return m_doubleHash; }
inline bool hugePages() const { return m_hugePages; }
inline bool syslog() const { return m_syslog; }
inline bool daemonized() const { return m_daemonized; }
@@ -76,19 +82,20 @@ class Options
inline const char *ccClientConfigFolder() const { return m_ccClientConfigFolder; }
inline const char *ccCustomDashboard() const { return m_ccCustomDashboard == nullptr ? "index.html" : m_ccCustomDashboard; }
inline const std::vector &pools() const { return m_pools; }
- inline int algo() const { return m_algo; }
- inline int algoVariant() const { return m_algoVariant; }
+ inline Algo algo() const { return m_algo; }
+ inline bool aesni() const { return m_aesni == AESNI_ON; }
+ inline size_t hashFactor() const { return m_hashFactor; }
inline int apiPort() const { return m_apiPort; }
inline int donateLevel() const { return m_donateLevel; }
inline int printTime() const { return m_printTime; }
inline int priority() const { return m_priority; }
inline int retries() const { return m_retries; }
inline int retryPause() const { return m_retryPause; }
- inline int threads() const { return m_threads; }
+ inline size_t threads() const { return m_threads; }
inline int ccUpdateInterval() const { return m_ccUpdateInterval; }
inline int ccPort() const { return m_ccPort; }
inline int64_t affinity() const { return m_affinity; }
- inline int64_t doubleHashThreadMask() const { return m_doubleHashThreadMask; }
+ inline int64_t multiHashThreadMask() const { return m_multiHashThreadMask; }
inline void setColors(bool colors) { m_colors = colors; }
inline static void release() { delete m_self; }
@@ -118,15 +125,10 @@ class Options
bool setAlgo(const char *algo);
- int getAlgoVariant() const;
-# ifndef XMRIG_NO_AEON
- int getAlgoVariantLite() const;
-# endif
-
+ void optimizeAlgorithmConfiguration();
bool m_background;
bool m_colors;
- bool m_doubleHash;
bool m_hugePages;
bool m_ready;
bool m_safe;
@@ -144,20 +146,22 @@ class Options
char *m_ccAdminPass;
char *m_ccClientConfigFolder;
char *m_ccCustomDashboard;
- int m_algo;
- int m_algoVariant;
+ Algo m_algo;
+ AlgoVariant m_algoVariant;
+ AesNi m_aesni;
+ size_t m_hashFactor;
int m_apiPort;
int m_donateLevel;
- int m_maxCpuUsage;
+ size_t m_maxCpuUsage;
int m_printTime;
int m_priority;
int m_retries;
int m_retryPause;
- int m_threads;
+ size_t m_threads;
int m_ccUpdateInterval;
int m_ccPort;
int64_t m_affinity;
- int64_t m_doubleHashThreadMask;
+ int64_t m_multiHashThreadMask;
std::vector m_pools;
};
diff --git a/src/Summary.cpp b/src/Summary.cpp
index 5caa4197dd..f729c556ef 100644
--- a/src/Summary.cpp
+++ b/src/Summary.cpp
@@ -92,29 +92,29 @@ static void print_cpu()
static void print_threads()
{
char dhtMaskBuf[256];
- if (Options::i()->doubleHash() && Options::i()->doubleHashThreadMask() != -1L) {
+ if (Options::i()->hashFactor() > 1 && Options::i()->multiHashThreadMask() != -1L) {
std::string singleThreads;
- std::string doubleThreads;
+ std::string multiThreads;
+
+ auto addThread = [](std::string& threads, int id) {
+ if (!threads.empty()) {
+ threads.append(", ");
+ }
+ threads.append(std::to_string(id));
+ };
for (int i=0; i < Options::i()->threads(); i++) {
- if (Mem::isDoubleHash(i)) {
- if (!doubleThreads.empty()) {
- doubleThreads.append(", ");
- }
-
- doubleThreads.append(std::to_string(i));
- } else {
- if (!singleThreads.empty()) {
- singleThreads.append(" ");
- }
-
- singleThreads.append(std::to_string(i));
+ if (Mem::getThreadHashFactor(i) > 1) {
+ addThread(multiThreads, i);
+ }
+ else {
+ addThread(singleThreads, i);
}
}
- snprintf(dhtMaskBuf, 256, ", doubleHashThreadMask=0x%" PRIX64 " [single threads: %s; double threads: %s]",
- Options::i()->doubleHashThreadMask(), singleThreads.c_str(), doubleThreads.c_str());
+ snprintf(dhtMaskBuf, 256, ", multiHashThreadMask=0x%" PRIX64 " [single threads: %s; multihash threads: %s]",
+ Options::i()->multiHashThreadMask(), singleThreads.c_str(), multiThreads.c_str());
}
else {
dhtMaskBuf[0] = '\0';
@@ -128,10 +128,13 @@ static void print_threads()
affBuf[0] = '\0';
}
- Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mTHREADS: \x1B[01;36m%d\x1B[01;37m, %s, av=%d, %sdonate=%d%%\x1B[01;37m%s%s" : " * THREADS: %d, %s, av=%d, %sdonate=%d%%%s%s",
+ Log::i()->text(Options::i()->colors() ?
+ "\x1B[01;32m * \x1B[01;37mTHREADS: \x1B[01;36m%d\x1B[01;37m, %s, aes=%d, hf=%zu, %sdonate=%d%%\x1B[01;37m%s%s" :
+ " * THREADS: %d, %s, aes=%d, hf=%zu, %sdonate=%d%%\x1B[01;37m%s%s",
Options::i()->threads(),
Options::i()->algoName(),
- Options::i()->algoVariant(),
+ Options::i()->aesni(),
+ Options::i()->hashFactor(),
Options::i()->colors() && Options::i()->donateLevel() == 0 ? "\x1B[01;31m" : "",
Options::i()->donateLevel(),
affBuf,
diff --git a/src/cc/CCClient.cpp b/src/cc/CCClient.cpp
index 1f604d0928..43dee8325c 100644
--- a/src/cc/CCClient.cpp
+++ b/src/cc/CCClient.cpp
@@ -79,7 +79,7 @@ CCClient::CCClient(Options* options, uv_async_t* async)
m_clientStatus.setHugepagesEnabled(Mem::isHugepagesEnabled());
m_clientStatus.setHugepages(Mem::isHugepagesAvailable());
- m_clientStatus.setDoubleHashMode(m_options->doubleHash());
+ m_clientStatus.setHashFactor(Mem::hashFactor());
m_clientStatus.setVersion(Version::string());
m_clientStatus.setCpuBrand(Cpu::brand());
diff --git a/src/cc/ClientStatus.cpp b/src/cc/ClientStatus.cpp
index d529c22c28..a51ba902d6 100644
--- a/src/cc/ClientStatus.cpp
+++ b/src/cc/ClientStatus.cpp
@@ -35,9 +35,9 @@ ClientStatus::ClientStatus()
: m_currentStatus(Status::PAUSED),
m_hasHugepages(false),
m_isHugepagesEnabled(false),
- m_isDoubleHashMode(false),
m_isCpuX64(false),
m_hasCpuAES(false),
+ m_hashFactor(1),
m_hashrateShort(0),
m_hashrateMedium(0),
m_hashrateLong(0),
@@ -147,14 +147,14 @@ void ClientStatus::setHugepagesEnabled(bool hugepagesEnabled)
m_isHugepagesEnabled = hugepagesEnabled;
}
-bool ClientStatus::isDoubleHashMode() const
+int ClientStatus::getHashFactor() const
{
- return m_isDoubleHashMode;
+ return m_hashFactor;
}
-void ClientStatus::setDoubleHashMode(bool isDoubleHashMode)
+void ClientStatus::setHashFactor(int hashFactor)
{
- m_isDoubleHashMode = isDoubleHashMode;
+ m_hashFactor = hashFactor;
}
bool ClientStatus::isCpuX64() const
@@ -365,8 +365,8 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
m_isHugepagesEnabled = clientStatus["hugepages_enabled"].GetBool();
}
- if (clientStatus.HasMember("double_hash_mode")) {
- m_isDoubleHashMode = clientStatus["double_hash_mode"].GetBool();
+ if (clientStatus.HasMember("hash_factor")) {
+ m_hashFactor = clientStatus["hash_factor"].GetInt();
}
if (clientStatus.HasMember("cpu_is_x64")) {
@@ -459,7 +459,7 @@ rapidjson::Value ClientStatus::toJson(rapidjson::MemoryPoolAllocator (aesni=1, multihash-factor=1),
+ // 2 -> (aesni=1, multihash-factor=2),
+ // 3 -> (aesni=2, multihash-factor=1),
+ // 4 -> (aesni=2, multihash-factor=2))
+ "aesni": 0, // selection of AES-NI mode (0 auto, 1 on, 2 off)
+ "threads": 0, // number of miner threads (not set or 0 enables automatic selection of optimal thread count)
+ "multihash-factor": 0, // number of hash blocks to process at a time (not set or 0 enables automatic selection of optimal number of hash blocks)
+ "multihash-thread-mask" : null, // for multihash-factors>0 only, limits multihash to given threads (mask), mask "0x3" means run multihash on thread 0 and 1 only (default: all threads)
"background": false, // true to run the miner in the background (Windows only, for *nix plase use screen/tmux or systemd service instead)
"colors": true, // false to disable colored output
"cpu-affinity": null, // set process affinity to CPU core(s), mask "0x3" for cores 0 and 1
@@ -14,7 +21,6 @@
"retry-pause": 5, // time to pause between retries
"safe": false, // true to safe adjust threads and av settings for current CPU
"syslog": false, // use system log for output messages
- "threads": null, // number of miner threads
"pools": [
{
"url": "", // URL of mining server
diff --git a/src/crypto/CryptoNight.cpp b/src/crypto/CryptoNight.cpp
index 506068d3b7..3783b8d9b2 100644
--- a/src/crypto/CryptoNight.cpp
+++ b/src/crypto/CryptoNight.cpp
@@ -5,6 +5,8 @@
* Copyright 2014-2016 Wolf9466
* Copyright 2016 Jay D Dee
* Copyright 2016-2017 XMRig
+ * Copyright 2018 Sebastian Stolzenberg
+ * Copyright 2018 BenDroid
*
*
* This program is free software: you can redistribute it and/or modify
@@ -21,7 +23,6 @@
* along with this program. If not, see .
*/
-
#include "crypto/CryptoNight.h"
#if defined(XMRIG_ARM)
@@ -31,129 +32,105 @@
#endif
#include "crypto/CryptoNight_test.h"
-#include "net/Job.h"
-#include "net/JobResult.h"
-#include "Options.h"
-
-
-void (*cryptonight_hash_ctx_s)(const void *input, size_t size, void *output, cryptonight_ctx *ctx) = nullptr;
-void (*cryptonight_hash_ctx_d)(const void *input, size_t size, void *output, cryptonight_ctx *ctx) = nullptr;
-
-
-static void cryptonight_av1_aesni(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) {
-# if !defined(XMRIG_ARMv7)
- cryptonight_hash<0x80000, MEMORY, 0x1FFFF0, false>(input, size, output, ctx);
-# endif
-}
-
-static void cryptonight_av2_aesni_double(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+template
+static void cryptonight_aesni(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
# if !defined(XMRIG_ARMv7)
- cryptonight_double_hash<0x80000, MEMORY, 0x1FFFF0, false>(input, size, output, ctx);
+ CryptoNightMultiHash<0x80000, MEMORY, 0x1FFFF0, false, NUM_HASH_BLOCKS>::hash(input, size, output, ctx);
# endif
}
-
-static void cryptonight_av3_softaes(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
- cryptonight_hash<0x80000, MEMORY, 0x1FFFF0, true>(input, size, output, ctx);
+template
+static void cryptonight_softaes(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+ CryptoNightMultiHash<0x80000, MEMORY, 0x1FFFF0, true, NUM_HASH_BLOCKS>::hash(input, size, output, ctx);
}
-
-static void cryptonight_av4_softaes_double(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
- cryptonight_double_hash<0x80000, MEMORY, 0x1FFFF0, true>(input, size, output, ctx);
-}
-
-
-static void cryptonight_lite_av1_aesni(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+template
+static void cryptonight_lite_aesni(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
# if !defined(XMRIG_ARMv7)
- cryptonight_hash<0x40000, MEMORY_LITE, 0xFFFF0, false>(input, size, output, ctx);
-#endif
-}
-
-
-static void cryptonight_lite_av2_aesni_double(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
-# if !defined(XMRIG_ARMv7)
- cryptonight_double_hash<0x40000, MEMORY_LITE, 0xFFFF0, false>(input, size, output, ctx);
+ CryptoNightMultiHash<0x40000, MEMORY_LITE, 0xFFFF0, false, NUM_HASH_BLOCKS>::hash(input, size, output, ctx);
# endif
}
-
-static void cryptonight_lite_av3_softaes(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
- cryptonight_hash<0x40000, MEMORY_LITE, 0xFFFF0, true>(input, size, output, ctx);
+template
+static void cryptonight_lite_softaes(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+ CryptoNightMultiHash<0x40000, MEMORY_LITE, 0xFFFF0, true, NUM_HASH_BLOCKS>::hash(input, size, output, ctx);
}
+void (*cryptonight_hash_ctx[MAX_NUM_HASH_BLOCKS])(const void *input, size_t size, void *output, cryptonight_ctx *ctx);
-static void cryptonight_lite_av4_softaes_double(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
- cryptonight_double_hash<0x40000, MEMORY_LITE, 0xFFFF0, true>(input, size, output, ctx);
+template
+void setCryptoNightHashMethods(Options::Algo algo, bool aesni)
+{
+
+ switch (algo) {
+ case Options::ALGO_CRYPTONIGHT:
+ if (aesni) {
+ cryptonight_hash_ctx[HASH_FACTOR - 1] = cryptonight_aesni;
+ } else {
+ cryptonight_hash_ctx[HASH_FACTOR - 1] = cryptonight_softaes;
+ }
+ break;
+
+ case Options::ALGO_CRYPTONIGHT_LITE:
+ if (aesni) {
+ cryptonight_hash_ctx[HASH_FACTOR - 1] = cryptonight_lite_aesni;
+ } else {
+ cryptonight_hash_ctx[HASH_FACTOR - 1] = cryptonight_lite_softaes;
+ }
+ break;
+ }
+ // next iteration
+ setCryptoNightHashMethods(algo, aesni);
}
-void (*cryptonight_variations[8])(const void *input, size_t size, void *output, cryptonight_ctx *ctx) = {
- cryptonight_av1_aesni,
- cryptonight_av2_aesni_double,
- cryptonight_av3_softaes,
- cryptonight_av4_softaes_double,
- cryptonight_lite_av1_aesni,
- cryptonight_lite_av2_aesni_double,
- cryptonight_lite_av3_softaes,
- cryptonight_lite_av4_softaes_double
+template <>
+void setCryptoNightHashMethods<0>(Options::Algo algo, bool aesni)
+{
+ // template recursion abort
};
-
-void CryptoNight::hash(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx* ctx)
+bool CryptoNight::init(int algo, bool aesni)
{
- cryptonight_hash_ctx_s(input, size, output, ctx);
+ setCryptoNightHashMethods(static_cast(algo), aesni);
+ return selfTest(algo);
}
-void CryptoNight::hashDouble(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx* ctx)
+void CryptoNight::hash(size_t factor, const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx* ctx)
{
- cryptonight_hash_ctx_d(input, size, output, ctx);
+ cryptonight_hash_ctx[factor-1](input, size, output, ctx);
}
-bool CryptoNight::init(int algo, int variant)
+bool CryptoNight::selfTest(int algo)
{
- if (variant < 1 || variant > 4)
- {
+ if (cryptonight_hash_ctx[0] == nullptr || cryptonight_hash_ctx[2] == nullptr ||
+ cryptonight_hash_ctx[2] == nullptr || cryptonight_hash_ctx[3] == nullptr ||
+ cryptonight_hash_ctx[4] == nullptr) {
return false;
}
- int index = 0;
-
- if (algo == Options::ALGO_CRYPTONIGHT_LITE) {
- index += 4;
- }
-
- if (variant == 3 || variant == 4)
- {
- index += 2;
- }
-
- cryptonight_hash_ctx_s = cryptonight_variations[index];
- cryptonight_hash_ctx_d = cryptonight_variations[index+1];
-
- return selfTest(algo);
-}
+ char output[160];
-bool CryptoNight::selfTest(int algo)
-{
- if (cryptonight_hash_ctx_s == nullptr || cryptonight_hash_ctx_d == nullptr) {
- return false;
- }
+ auto ctx = (struct cryptonight_ctx*) _mm_malloc(sizeof(struct cryptonight_ctx), 16);
+ ctx->memory = (uint8_t *) _mm_malloc(MEMORY * 6, 16);
- char output[64];
+ cryptonight_hash_ctx[0](test_input, 76, output, ctx);
+ bool resultSingle = memcmp(output, algo == Options::ALGO_CRYPTONIGHT_LITE ? test_output1 : test_output0, 32) == 0;
- struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) _mm_malloc(sizeof(struct cryptonight_ctx), 16);
- ctx->memory = (uint8_t *) _mm_malloc(MEMORY * 2, 16);
+ cryptonight_hash_ctx[1](test_input, 76, output, ctx);
+ bool resultDouble = memcmp(output, algo == Options::ALGO_CRYPTONIGHT_LITE ? test_output1 : test_output0, 64) == 0;
- cryptonight_hash_ctx_s(test_input, 76, output, ctx);
+ cryptonight_hash_ctx[2](test_input, 76, output, ctx);
+ bool resultTriple = memcmp(output, algo == Options::ALGO_CRYPTONIGHT_LITE ? test_output1 : test_output0, 96) == 0;
- bool resultSingle = memcmp(output, algo == Options::ALGO_CRYPTONIGHT_LITE ? test_output1 : test_output0, 32) == 0;
+ cryptonight_hash_ctx[3](test_input, 76, output, ctx);
+ bool resultQuadruple = memcmp(output, algo == Options::ALGO_CRYPTONIGHT_LITE ? test_output1 : test_output0, 128) == 0;
- cryptonight_hash_ctx_d(test_input, 76, output, ctx);
+ cryptonight_hash_ctx[4](test_input, 76, output, ctx);
+ bool resultQuintuple = memcmp(output, algo == Options::ALGO_CRYPTONIGHT_LITE ? test_output1 : test_output0, 160) == 0;
_mm_free(ctx->memory);
_mm_free(ctx);
- bool resultDouble = memcmp(output, algo == Options::ALGO_CRYPTONIGHT_LITE ? test_output1 : test_output0, 64) == 0;
-
- return resultSingle && resultDouble;
-}
+ return resultSingle && resultDouble && resultTriple && resultQuadruple && resultQuintuple;
+}
\ No newline at end of file
diff --git a/src/crypto/CryptoNight.h b/src/crypto/CryptoNight.h
index f562b21c96..faef076ca2 100644
--- a/src/crypto/CryptoNight.h
+++ b/src/crypto/CryptoNight.h
@@ -25,20 +25,17 @@
#define __CRYPTONIGHT_H__
-#include
-#include
-
+#include
+#include
#include "align.h"
-
+#include "Options.h"
#define MEMORY 2097152 /* 2 MiB */
#define MEMORY_LITE 1048576 /* 1 MiB */
-
struct cryptonight_ctx {
- VAR_ALIGN(16, uint8_t state0[200]);
- VAR_ALIGN(16, uint8_t state1[200]);
+ VAR_ALIGN(16, uint8_t state[MAX_NUM_HASH_BLOCKS][208]); // 208 instead of 200 to maintain aligned to 16 byte boundaries
VAR_ALIGN(16, uint8_t* memory);
};
@@ -46,16 +43,16 @@ struct cryptonight_ctx {
class Job;
class JobResult;
-
class CryptoNight
{
public:
- static void hash(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx* ctx);
- static bool init(int algo, int variant);
- static void hashDouble(const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx* ctx);
+ static bool init(int algo, bool aesni);
+
+ static void hash(size_t factor, const uint8_t* input, size_t size, uint8_t* output, cryptonight_ctx* ctx);
private:
static bool selfTest(int algo);
};
+
#endif /* __CRYPTONIGHT_H__ */
diff --git a/src/crypto/CryptoNight_arm.h b/src/crypto/CryptoNight_arm.h
index 15be6c3dc7..77cfd7c37f 100644
--- a/src/crypto/CryptoNight_arm.h
+++ b/src/crypto/CryptoNight_arm.h
@@ -6,6 +6,8 @@
* Copyright 2016 Jay D Dee
* Copyright 2016 Imran Yusuff
* Copyright 2016-2017 XMRig
+ * Copyright 2018 Sebastian Stolzenberg
+ * Copyright 2018 BenDroid
*
*
* This program is free software: you can redistribute it and/or modify
@@ -47,27 +49,32 @@ extern "C"
}
-static inline void do_blake_hash(const void* input, size_t len, char* output) {
+static inline void do_blake_hash(const void* input, size_t len, char* output)
+{
blake256_hash(reinterpret_cast(output), static_cast(input), len);
}
-static inline void do_groestl_hash(const void* input, size_t len, char* output) {
+static inline void do_groestl_hash(const void* input, size_t len, char* output)
+{
groestl(static_cast(input), len * 8, reinterpret_cast(output));
}
-static inline void do_jh_hash(const void* input, size_t len, char* output) {
+static inline void do_jh_hash(const void* input, size_t len, char* output)
+{
jh_hash(32 * 8, static_cast(input), 8 * len, reinterpret_cast(output));
}
-static inline void do_skein_hash(const void* input, size_t len, char* output) {
+static inline void do_skein_hash(const void* input, size_t len, char* output)
+{
xmr_skein(static_cast(input), reinterpret_cast(output));
}
-void (* const extra_hashes[4])(const void *, size_t, char *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash};
+void
+(* const extra_hashes[4])(const void*, size_t, char*) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash};
static inline __attribute__((always_inline)) __m128i _mm_set_epi64x(const uint64_t a, const uint64_t b)
@@ -94,7 +101,9 @@ static inline uint64_t __umul128(uint64_t a, uint64_t b, uint64_t* hi)
return (uint64_t) r;
}
#else
-static inline uint64_t __umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) {
+
+static inline uint64_t __umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi)
+{
// multiplier = ab = a * 2^32 + b
// multiplicand = cd = c * 2^32 + d
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
@@ -118,6 +127,7 @@ static inline uint64_t __umul128(uint64_t multiplier, uint64_t multiplicand, uin
return product_lo;
}
+
#endif
@@ -154,18 +164,20 @@ template
static inline void soft_aes_genkey_sub(__m128i* xout0, __m128i* xout2)
{
__m128i xout1 = soft_aeskeygenassist(*xout2);
- xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
+ xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
*xout0 = sl_xor(*xout0);
*xout0 = _mm_xor_si128(*xout0, xout1);
- xout1 = soft_aeskeygenassist<0x00>(*xout0);
- xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
+ xout1 = soft_aeskeygenassist<0x00>(*xout0);
+ xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
*xout2 = sl_xor(*xout2);
*xout2 = _mm_xor_si128(*xout2, xout1);
}
template
-static inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3, __m128i* k4, __m128i* k5, __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
+static inline void
+aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3, __m128i* k4, __m128i* k5,
+ __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
{
__m128i xout0 = _mm_load_si128(memory);
__m128i xout2 = _mm_load_si128(memory + 1);
@@ -191,7 +203,9 @@ static inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, _
template
-static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
+static inline void
+aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6,
+ __m128i* x7)
{
if (SOFT_AES) {
*x0 = soft_aesenc(*x0, key);
@@ -205,21 +219,21 @@ static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2,
}
# ifndef XMRIG_ARMv7
else {
- *x0 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x0), key));
- *x1 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x1), key));
- *x2 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x2), key));
- *x3 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x3), key));
- *x4 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x4), key));
- *x5 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x5), key));
- *x6 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x6), key));
- *x7 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x7), key));
+ *x0 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t*) x0), key));
+ *x1 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t*) x1), key));
+ *x2 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t*) x2), key));
+ *x3 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t*) x3), key));
+ *x4 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t*) x4), key));
+ *x5 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t*) x5), key));
+ *x6 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t*) x6), key));
+ *x7 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t*) x7), key));
}
# endif
}
template
-static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output)
+static inline void cn_explode_scratchpad(const __m128i* input, __m128i* output)
{
__m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7;
__m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
@@ -259,8 +273,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output)
xin5 ^= k9;
xin6 ^= k9;
xin7 ^= k9;
- }
- else {
+ } else {
aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
}
@@ -277,7 +290,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output)
template
-static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
+static inline void cn_implode_scratchpad(const __m128i* input, __m128i* output)
{
__m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7;
__m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
@@ -293,8 +306,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
xout6 = _mm_load_si128(output + 10);
xout7 = _mm_load_si128(output + 11);
- for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8)
- {
+ for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) {
xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0);
xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1);
xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2);
@@ -327,8 +339,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
xout5 ^= k9;
xout6 ^= k9;
xout7 ^= k9;
- }
- else {
+ } else {
aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
}
}
@@ -343,149 +354,723 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
_mm_store_si128(output + 11, xout7);
}
+// n-Loop version. Seems to be little bit slower then the hardcoded one.
+template
+class CryptoNightMultiHash
+{
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ const uint8_t* l[NUM_HASH_BLOCKS];
+ uint64_t* h[NUM_HASH_BLOCKS];
+ uint64_t al[NUM_HASH_BLOCKS];
+ uint64_t ah[NUM_HASH_BLOCKS];
+ __m128i bx[NUM_HASH_BLOCKS];
+ uint64_t idx[NUM_HASH_BLOCKS];
+
+ for (size_t hashBlock = 0; hashBlock < NUM_HASH_BLOCKS; ++hashBlock) {
+ keccak(static_cast(input) + hashBlock * size, (int) size,
+ ctx->state[hashBlock], 200);
+ }
+
+ for (size_t hashBlock = 0; hashBlock < NUM_HASH_BLOCKS; ++hashBlock) {
+ l[hashBlock] = ctx->memory + hashBlock * MEM;
+ h[hashBlock] = reinterpret_cast(ctx->state[hashBlock]);
+
+ cn_explode_scratchpad((__m128i*) h[hashBlock], (__m128i*) l[hashBlock]);
+
+ al[hashBlock] = h[hashBlock][0] ^ h[hashBlock][4];
+ ah[hashBlock] = h[hashBlock][1] ^ h[hashBlock][5];
+ bx[hashBlock] =
+ _mm_set_epi64x(h[hashBlock][3] ^ h[hashBlock][7], h[hashBlock][2] ^ h[hashBlock][6]);
+ idx[hashBlock] = h[hashBlock][0] ^ h[hashBlock][4];
+ }
+
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ for (size_t hashBlock = 0; hashBlock < NUM_HASH_BLOCKS; ++hashBlock) {
+ __m128i cx;
+ cx = _mm_load_si128((__m128i*) &l[hashBlock][idx[hashBlock] & MASK]);
+
+ if (SOFT_AES) {
+ cx = soft_aesenc(cx, _mm_set_epi64x(ah[hashBlock], al[hashBlock]));
+ } else {
+ cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah[hashBlock], al[hashBlock]));
+ }
+
+ _mm_store_si128((__m128i*) &l[hashBlock][idx[hashBlock] & MASK],
+ _mm_xor_si128(bx[hashBlock], cx));
+ idx[hashBlock] = EXTRACT64(cx);
+ bx[hashBlock] = cx;
+
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l[hashBlock][idx[hashBlock] & MASK])[0];
+ ch = ((uint64_t*) &l[hashBlock][idx[hashBlock] & MASK])[1];
+ lo = __umul128(idx[hashBlock], cl, &hi);
+
+ al[hashBlock] += hi;
+ ah[hashBlock] += lo;
+
+ ((uint64_t*) &l[hashBlock][idx[hashBlock] & MASK])[0] = al[hashBlock];
+ ((uint64_t*) &l[hashBlock][idx[hashBlock] & MASK])[1] = ah[hashBlock];
+
+ ah[hashBlock] ^= ch;
+ al[hashBlock] ^= cl;
+ idx[hashBlock] = al[hashBlock];
+ }
+ }
+
+ for (size_t hashBlock = 0; hashBlock < NUM_HASH_BLOCKS; ++hashBlock) {
+ cn_implode_scratchpad((__m128i*) l[hashBlock], (__m128i*) h[hashBlock]);
+ keccakf(h[hashBlock], 24);
+ extra_hashes[ctx->state[hashBlock][0] & 3](ctx->state[hashBlock], 200,
+ static_cast(output) + hashBlock * 32);
+ }
+ }
+};
template
-inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, cryptonight_ctx *__restrict__ ctx)
+class CryptoNightMultiHash
{
- keccak(static_cast(input), (int) size, ctx->state0, 200);
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ const uint8_t* l;
+ uint64_t* h;
+ uint64_t al;
+ uint64_t ah;
+ __m128i bx;
+ uint64_t idx;
- cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory);
+ keccak(static_cast(input), (int) size, ctx->state[0], 200);
- const uint8_t* l0 = ctx->memory;
- uint64_t* h0 = reinterpret_cast(ctx->state0);
+ l = ctx->memory;
+ h = reinterpret_cast(ctx->state[0]);
- uint64_t al0 = h0[0] ^ h0[4];
- uint64_t ah0 = h0[1] ^ h0[5];
- __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+ cn_explode_scratchpad((__m128i*) h, (__m128i*) l);
- uint64_t idx0 = h0[0] ^ h0[4];
+ al = h[0] ^ h[4];
+ ah = h[1] ^ h[5];
+ bx = _mm_set_epi64x(h[3] ^ h[7], h[2] ^ h[6]);
+ idx = h[0] ^ h[4];
- for (size_t i = 0; i < ITERATIONS; i++) {
- __m128i cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]);
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ __m128i cx = _mm_load_si128((__m128i*) &l[idx & MASK]);
- if (SOFT_AES) {
- cx = soft_aesenc(cx, _mm_set_epi64x(ah0, al0));
- }
- else {
-# ifndef XMRIG_ARMv7
- cx = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah0, al0);
+ if (SOFT_AES) {
+ cx = soft_aesenc(cx, _mm_set_epi64x(ah, al));
+ } else {
+# ifndef XMRIG_ARMv7
+ cx = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah, al);
# endif
- }
+ }
+
+ _mm_store_si128((__m128i*) &l[idx & MASK], _mm_xor_si128(bx, cx));
+ idx = EXTRACT64(cx);
+ bx = cx;
- _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx));
- idx0 = EXTRACT64(cx);
- bx0 = cx;
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l[idx & MASK])[0];
+ ch = ((uint64_t*) &l[idx & MASK])[1];
+ lo = __umul128(idx, cl, &hi);
- uint64_t hi, lo, cl, ch;
- cl = ((uint64_t*) &l0[idx0 & MASK])[0];
- ch = ((uint64_t*) &l0[idx0 & MASK])[1];
- lo = __umul128(idx0, cl, &hi);
+ al += hi;
+ ah += lo;
- al0 += hi;
- ah0 += lo;
+ ((uint64_t*) &l[idx & MASK])[0] = al;
+ ((uint64_t*) &l[idx & MASK])[1] = ah;
- ((uint64_t*)&l0[idx0 & MASK])[0] = al0;
- ((uint64_t*)&l0[idx0 & MASK])[1] = ah0;
+ ah ^= ch;
+ al ^= cl;
+ idx = al;
+ }
- ah0 ^= ch;
- al0 ^= cl;
- idx0 = al0;
+ cn_implode_scratchpad((__m128i*) l, (__m128i*) h);
+ keccakf(h, 24);
+ extra_hashes[ctx->state[0][0] & 3](ctx->state[0], 200, static_cast(output));
}
+};
+
+template
+class CryptoNightMultiHash
+{
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ keccak((const uint8_t*) input, (int) size, ctx->state[0], 200);
+ keccak((const uint8_t*) input + size, (int) size, ctx->state[1], 200);
+
+ const uint8_t* l0 = ctx->memory;
+ const uint8_t* l1 = ctx->memory + MEM;
+ uint64_t* h0 = reinterpret_cast(ctx->state[0]);
+ uint64_t* h1 = reinterpret_cast(ctx->state[1]);
+
+ cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
+ cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
+
+ uint64_t al0 = h0[0] ^h0[4];
+ uint64_t al1 = h1[0] ^h1[4];
+ uint64_t ah0 = h0[1] ^h0[5];
+ uint64_t ah1 = h1[1] ^h1[5];
+
+ __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+ __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
+
+ uint64_t idx0 = h0[0] ^h0[4];
+ uint64_t idx1 = h1[0] ^h1[4];
+
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ __m128i cx0 = _mm_load_si128((__m128i*) &l0[idx0 & MASK]);
+ __m128i cx1 = _mm_load_si128((__m128i*) &l1[idx1 & MASK]);
+
+ if (SOFT_AES) {
+ cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
+ cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
+ } else {
+# ifndef XMRIG_ARMv7
+ cx0 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx0, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah0, al0);
+ cx1 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx1, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah1, al1);
+# endif
+ }
- cn_implode_scratchpad((__m128i*) ctx->memory, (__m128i*) ctx->state0);
+ _mm_store_si128((__m128i*) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
+ _mm_store_si128((__m128i*) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));
- keccakf(h0, 24);
- extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, static_cast(output));
-}
+ idx0 = EXTRACT64(cx0);
+ idx1 = EXTRACT64(cx1);
+
+ bx0 = cx0;
+ bx1 = cx1;
+
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l0[idx0 & MASK])[0];
+ ch = ((uint64_t*) &l0[idx0 & MASK])[1];
+ lo = __umul128(idx0, cl, &hi);
+
+ al0 += hi;
+ ah0 += lo;
+ ((uint64_t*) &l0[idx0 & MASK])[0] = al0;
+ ((uint64_t*) &l0[idx0 & MASK])[1] = ah0;
+
+ ah0 ^= ch;
+ al0 ^= cl;
+ idx0 = al0;
+
+ cl = ((uint64_t*) &l1[idx1 & MASK])[0];
+ ch = ((uint64_t*) &l1[idx1 & MASK])[1];
+ lo = __umul128(idx1, cl, &hi);
+
+ al1 += hi;
+ ah1 += lo;
+
+ ((uint64_t*) &l1[idx1 & MASK])[0] = al1;
+ ((uint64_t*) &l1[idx1 & MASK])[1] = ah1;
+
+ ah1 ^= ch;
+ al1 ^= cl;
+ idx1 = al1;
+ }
+
+ cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
+ cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
+
+ keccakf(h0, 24);
+ keccakf(h1, 24);
+
+ extra_hashes[ctx->state[0][0] & 3](ctx->state[0], 200, static_cast(output));
+ extra_hashes[ctx->state[1][0] & 3](ctx->state[1], 200, static_cast(output) + 32);
+ }
+};
template
-inline void cryptonight_double_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, struct cryptonight_ctx *__restrict__ ctx)
+class CryptoNightMultiHash
{
- keccak((const uint8_t *) input, (int) size, ctx->state0, 200);
- keccak((const uint8_t *) input + size, (int) size, ctx->state1, 200);
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ keccak((const uint8_t*) input, (int) size, ctx->state[0], 200);
+ keccak((const uint8_t*) input + size, (int) size, ctx->state[1], 200);
+ keccak((const uint8_t*) input + 2 * size, (int) size, ctx->state[2], 200);
+
+ const uint8_t* l0 = ctx->memory;
+ const uint8_t* l1 = ctx->memory + MEM;
+ const uint8_t* l2 = ctx->memory + 2 * MEM;
+ uint64_t* h0 = reinterpret_cast(ctx->state[0]);
+ uint64_t* h1 = reinterpret_cast(ctx->state[1]);
+ uint64_t* h2 = reinterpret_cast(ctx->state[2]);
+
+ cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
+ cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
+ cn_explode_scratchpad((__m128i*) h2, (__m128i*) l2);
+
+ uint64_t al0 = h0[0] ^h0[4];
+ uint64_t al1 = h1[0] ^h1[4];
+ uint64_t al2 = h2[0] ^h2[4];
+ uint64_t ah0 = h0[1] ^h0[5];
+ uint64_t ah1 = h1[1] ^h1[5];
+ uint64_t ah2 = h2[1] ^h2[5];
+
+ __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+ __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
+ __m128i bx2 = _mm_set_epi64x(h2[3] ^ h2[7], h2[2] ^ h2[6]);
+
+ uint64_t idx0 = h0[0] ^h0[4];
+ uint64_t idx1 = h1[0] ^h1[4];
+ uint64_t idx2 = h2[0] ^h2[4];
+
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ __m128i cx0 = _mm_load_si128((__m128i*) &l0[idx0 & MASK]);
+ __m128i cx1 = _mm_load_si128((__m128i*) &l1[idx1 & MASK]);
+ __m128i cx2 = _mm_load_si128((__m128i*) &l2[idx2 & MASK]);
+
+ if (SOFT_AES) {
+ cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
+ cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
+ cx2 = soft_aesenc(cx2, _mm_set_epi64x(ah2, al2));
+ } else {
+# ifndef XMRIG_ARMv7
+ cx0 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx0, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah0, al0);
+ cx1 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx1, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah1, al1);
+ cx2 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx2, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah2, al2);
+# endif
+ }
- const uint8_t* l0 = ctx->memory;
- const uint8_t* l1 = ctx->memory + MEM;
- uint64_t* h0 = reinterpret_cast(ctx->state0);
- uint64_t* h1 = reinterpret_cast(ctx->state1);
+ _mm_store_si128((__m128i*) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
+ _mm_store_si128((__m128i*) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));
+ _mm_store_si128((__m128i*) &l2[idx2 & MASK], _mm_xor_si128(bx2, cx2));
- cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
- cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
+ idx0 = EXTRACT64(cx0);
+ idx1 = EXTRACT64(cx1);
+ idx2 = EXTRACT64(cx2);
- uint64_t al0 = h0[0] ^ h0[4];
- uint64_t al1 = h1[0] ^ h1[4];
- uint64_t ah0 = h0[1] ^ h0[5];
- uint64_t ah1 = h1[1] ^ h1[5];
+ bx0 = cx0;
+ bx1 = cx1;
+ bx2 = cx2;
- __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
- __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
- uint64_t idx0 = h0[0] ^ h0[4];
- uint64_t idx1 = h1[0] ^ h1[4];
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l0[idx0 & MASK])[0];
+ ch = ((uint64_t*) &l0[idx0 & MASK])[1];
+ lo = __umul128(idx0, cl, &hi);
- for (size_t i = 0; i < ITERATIONS; i++) {
- __m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]);
- __m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]);
+ al0 += hi;
+ ah0 += lo;
- if (SOFT_AES) {
- cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
- cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
+ ((uint64_t*) &l0[idx0 & MASK])[0] = al0;
+ ((uint64_t*) &l0[idx0 & MASK])[1] = ah0;
+
+ ah0 ^= ch;
+ al0 ^= cl;
+ idx0 = al0;
+
+
+ cl = ((uint64_t*) &l1[idx1 & MASK])[0];
+ ch = ((uint64_t*) &l1[idx1 & MASK])[1];
+ lo = __umul128(idx1, cl, &hi);
+
+ al1 += hi;
+ ah1 += lo;
+
+ ((uint64_t*) &l1[idx1 & MASK])[0] = al1;
+ ((uint64_t*) &l1[idx1 & MASK])[1] = ah1;
+
+ ah1 ^= ch;
+ al1 ^= cl;
+ idx1 = al1;
+
+
+ cl = ((uint64_t*) &l2[idx2 & MASK])[0];
+ ch = ((uint64_t*) &l2[idx2 & MASK])[1];
+ lo = __umul128(idx2, cl, &hi);
+
+ al2 += hi;
+ ah2 += lo;
+
+ ((uint64_t*) &l2[idx2 & MASK])[0] = al2;
+ ((uint64_t*) &l2[idx2 & MASK])[1] = ah2;
+
+ ah2 ^= ch;
+ al2 ^= cl;
+ idx2 = al2;
}
- else {
-# ifndef XMRIG_ARMv7
- cx0 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx0, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah0, al0);
- cx1 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx1, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah1, al1);
+
+ cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
+ cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
+ cn_implode_scratchpad((__m128i*) l2, (__m128i*) h2);
+
+ keccakf(h0, 24);
+ keccakf(h1, 24);
+ keccakf(h2, 24);
+
+ extra_hashes[ctx->state[0][0] & 3](ctx->state[0], 200, static_cast(output));
+ extra_hashes[ctx->state[1][0] & 3](ctx->state[1], 200, static_cast(output) + 32);
+ extra_hashes[ctx->state[2][0] & 3](ctx->state[2], 200, static_cast(output) + 64);
+ }
+};
+
+template
+class CryptoNightMultiHash
+{
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ keccak((const uint8_t*) input, (int) size, ctx->state[0], 200);
+ keccak((const uint8_t*) input + size, (int) size, ctx->state[1], 200);
+ keccak((const uint8_t*) input + 2 * size, (int) size, ctx->state[2], 200);
+ keccak((const uint8_t*) input + 3 * size, (int) size, ctx->state[3], 200);
+
+ const uint8_t* l0 = ctx->memory;
+ const uint8_t* l1 = ctx->memory + MEM;
+ const uint8_t* l2 = ctx->memory + 2 * MEM;
+ const uint8_t* l3 = ctx->memory + 3 * MEM;
+ uint64_t* h0 = reinterpret_cast(ctx->state[0]);
+ uint64_t* h1 = reinterpret_cast(ctx->state[1]);
+ uint64_t* h2 = reinterpret_cast(ctx->state[2]);
+ uint64_t* h3 = reinterpret_cast(ctx->state[3]);
+
+ cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
+ cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
+ cn_explode_scratchpad((__m128i*) h2, (__m128i*) l2);
+ cn_explode_scratchpad((__m128i*) h3, (__m128i*) l3);
+
+ uint64_t al0 = h0[0] ^h0[4];
+ uint64_t al1 = h1[0] ^h1[4];
+ uint64_t al2 = h2[0] ^h2[4];
+ uint64_t al3 = h3[0] ^h3[4];
+ uint64_t ah0 = h0[1] ^h0[5];
+ uint64_t ah1 = h1[1] ^h1[5];
+ uint64_t ah2 = h2[1] ^h2[5];
+ uint64_t ah3 = h3[1] ^h3[5];
+
+ __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+ __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
+ __m128i bx2 = _mm_set_epi64x(h2[3] ^ h2[7], h2[2] ^ h2[6]);
+ __m128i bx3 = _mm_set_epi64x(h3[3] ^ h3[7], h3[2] ^ h3[6]);
+
+ uint64_t idx0 = h0[0] ^h0[4];
+ uint64_t idx1 = h1[0] ^h1[4];
+ uint64_t idx2 = h2[0] ^h2[4];
+ uint64_t idx3 = h3[0] ^h3[4];
+
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ __m128i cx0 = _mm_load_si128((__m128i*) &l0[idx0 & MASK]);
+ __m128i cx1 = _mm_load_si128((__m128i*) &l1[idx1 & MASK]);
+ __m128i cx2 = _mm_load_si128((__m128i*) &l2[idx2 & MASK]);
+ __m128i cx3 = _mm_load_si128((__m128i*) &l3[idx3 & MASK]);
+
+ if (SOFT_AES) {
+ cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
+ cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
+ cx2 = soft_aesenc(cx2, _mm_set_epi64x(ah2, al2));
+ cx3 = soft_aesenc(cx3, _mm_set_epi64x(ah3, al3));
+ } else {
+# ifndef XMRIG_ARMv7
+ cx0 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx0, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah0, al0);
+ cx1 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx1, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah1, al1);
+ cx2 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx2, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah2, al2);
+ cx3 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx3, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah3, al3);
# endif
- }
+ }
+
+ _mm_store_si128((__m128i*) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
+ _mm_store_si128((__m128i*) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));
+ _mm_store_si128((__m128i*) &l2[idx2 & MASK], _mm_xor_si128(bx2, cx2));
+ _mm_store_si128((__m128i*) &l3[idx3 & MASK], _mm_xor_si128(bx3, cx3));
+
+ idx0 = EXTRACT64(cx0);
+ idx1 = EXTRACT64(cx1);
+ idx2 = EXTRACT64(cx2);
+ idx3 = EXTRACT64(cx3);
+
+ bx0 = cx0;
+ bx1 = cx1;
+ bx2 = cx2;
+ bx3 = cx3;
+
- _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
- _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l0[idx0 & MASK])[0];
+ ch = ((uint64_t*) &l0[idx0 & MASK])[1];
+ lo = __umul128(idx0, cl, &hi);
- idx0 = EXTRACT64(cx0);
- idx1 = EXTRACT64(cx1);
+ al0 += hi;
+ ah0 += lo;
- bx0 = cx0;
- bx1 = cx1;
+ ((uint64_t*) &l0[idx0 & MASK])[0] = al0;
+ ((uint64_t*) &l0[idx0 & MASK])[1] = ah0;
- uint64_t hi, lo, cl, ch;
- cl = ((uint64_t*) &l0[idx0 & MASK])[0];
- ch = ((uint64_t*) &l0[idx0 & MASK])[1];
- lo = __umul128(idx0, cl, &hi);
+ ah0 ^= ch;
+ al0 ^= cl;
+ idx0 = al0;
- al0 += hi;
- ah0 += lo;
- ((uint64_t*) &l0[idx0 & MASK])[0] = al0;
- ((uint64_t*) &l0[idx0 & MASK])[1] = ah0;
+ cl = ((uint64_t*) &l1[idx1 & MASK])[0];
+ ch = ((uint64_t*) &l1[idx1 & MASK])[1];
+ lo = __umul128(idx1, cl, &hi);
- ah0 ^= ch;
- al0 ^= cl;
- idx0 = al0;
+ al1 += hi;
+ ah1 += lo;
- cl = ((uint64_t*) &l1[idx1 & MASK])[0];
- ch = ((uint64_t*) &l1[idx1 & MASK])[1];
- lo = __umul128(idx1, cl, &hi);
+ ((uint64_t*) &l1[idx1 & MASK])[0] = al1;
+ ((uint64_t*) &l1[idx1 & MASK])[1] = ah1;
- al1 += hi;
- ah1 += lo;
+ ah1 ^= ch;
+ al1 ^= cl;
+ idx1 = al1;
- ((uint64_t*) &l1[idx1 & MASK])[0] = al1;
- ((uint64_t*) &l1[idx1 & MASK])[1] = ah1;
- ah1 ^= ch;
- al1 ^= cl;
- idx1 = al1;
+ cl = ((uint64_t*) &l2[idx2 & MASK])[0];
+ ch = ((uint64_t*) &l2[idx2 & MASK])[1];
+ lo = __umul128(idx2, cl, &hi);
+
+ al2 += hi;
+ ah2 += lo;
+
+ ((uint64_t*) &l2[idx2 & MASK])[0] = al2;
+ ((uint64_t*) &l2[idx2 & MASK])[1] = ah2;
+
+ ah2 ^= ch;
+ al2 ^= cl;
+ idx2 = al2;
+
+
+ cl = ((uint64_t*) &l3[idx3 & MASK])[0];
+ ch = ((uint64_t*) &l3[idx3 & MASK])[1];
+ lo = __umul128(idx3, cl, &hi);
+
+ al3 += hi;
+ ah3 += lo;
+
+ ((uint64_t*) &l3[idx3 & MASK])[0] = al3;
+ ((uint64_t*) &l3[idx3 & MASK])[1] = ah3;
+
+ ah3 ^= ch;
+ al3 ^= cl;
+ idx3 = al3;
+ }
+
+ cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
+ cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
+ cn_implode_scratchpad((__m128i*) l2, (__m128i*) h2);
+ cn_implode_scratchpad((__m128i*) l3, (__m128i*) h3);
+
+ keccakf(h0, 24);
+ keccakf(h1, 24);
+ keccakf(h2, 24);
+ keccakf(h3, 24);
+
+ extra_hashes[ctx->state[0][0] & 3](ctx->state[0], 200, static_cast(output));
+ extra_hashes[ctx->state[1][0] & 3](ctx->state[1], 200, static_cast(output) + 32);
+ extra_hashes[ctx->state[2][0] & 3](ctx->state[2], 200, static_cast(output) + 64);
+ extra_hashes[ctx->state[3][0] & 3](ctx->state[3], 200, static_cast(output) + 96);
}
+};
- cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
- cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
+template
+class CryptoNightMultiHash
+{
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ keccak((const uint8_t*) input, (int) size, ctx->state[0], 200);
+ keccak((const uint8_t*) input + size, (int) size, ctx->state[1], 200);
+ keccak((const uint8_t*) input + 2 * size, (int) size, ctx->state[2], 200);
+ keccak((const uint8_t*) input + 3 * size, (int) size, ctx->state[3], 200);
+ keccak((const uint8_t*) input + 4 * size, (int) size, ctx->state[4], 200);
+
+ const uint8_t* l0 = ctx->memory;
+ const uint8_t* l1 = ctx->memory + MEM;
+ const uint8_t* l2 = ctx->memory + 2 * MEM;
+ const uint8_t* l3 = ctx->memory + 3 * MEM;
+ const uint8_t* l4 = ctx->memory + 4 * MEM;
+ uint64_t* h0 = reinterpret_cast(ctx->state[0]);
+ uint64_t* h1 = reinterpret_cast(ctx->state[1]);
+ uint64_t* h2 = reinterpret_cast(ctx->state[2]);
+ uint64_t* h3 = reinterpret_cast(ctx->state[3]);
+ uint64_t* h4 = reinterpret_cast(ctx->state[4]);
+
+ cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
+ cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
+ cn_explode_scratchpad((__m128i*) h2, (__m128i*) l2);
+ cn_explode_scratchpad((__m128i*) h3, (__m128i*) l3);
+ cn_explode_scratchpad((__m128i*) h4, (__m128i*) l4);
+
+ uint64_t al0 = h0[0] ^h0[4];
+ uint64_t al1 = h1[0] ^h1[4];
+ uint64_t al2 = h2[0] ^h2[4];
+ uint64_t al3 = h3[0] ^h3[4];
+ uint64_t al4 = h4[0] ^h4[4];
+ uint64_t ah0 = h0[1] ^h0[5];
+ uint64_t ah1 = h1[1] ^h1[5];
+ uint64_t ah2 = h2[1] ^h2[5];
+ uint64_t ah3 = h3[1] ^h3[5];
+ uint64_t ah4 = h4[1] ^h4[5];
+
+ __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+ __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
+ __m128i bx2 = _mm_set_epi64x(h2[3] ^ h2[7], h2[2] ^ h2[6]);
+ __m128i bx3 = _mm_set_epi64x(h3[3] ^ h3[7], h3[2] ^ h3[6]);
+ __m128i bx4 = _mm_set_epi64x(h4[3] ^ h4[7], h4[2] ^ h4[6]);
+
+ uint64_t idx0 = h0[0] ^h0[4];
+ uint64_t idx1 = h1[0] ^h1[4];
+ uint64_t idx2 = h2[0] ^h2[4];
+ uint64_t idx3 = h3[0] ^h3[4];
+ uint64_t idx4 = h4[0] ^h4[4];
+
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ __m128i cx0 = _mm_load_si128((__m128i*) &l0[idx0 & MASK]);
+ __m128i cx1 = _mm_load_si128((__m128i*) &l1[idx1 & MASK]);
+ __m128i cx2 = _mm_load_si128((__m128i*) &l2[idx2 & MASK]);
+ __m128i cx3 = _mm_load_si128((__m128i*) &l3[idx3 & MASK]);
+ __m128i cx4 = _mm_load_si128((__m128i*) &l4[idx4 & MASK]);
+
+ if (SOFT_AES) {
+ cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
+ cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
+ cx2 = soft_aesenc(cx2, _mm_set_epi64x(ah2, al2));
+ cx3 = soft_aesenc(cx3, _mm_set_epi64x(ah3, al3));
+ cx4 = soft_aesenc(cx4, _mm_set_epi64x(ah4, al4));
+ } else {
+# ifndef XMRIG_ARMv7
+ cx0 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx0, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah0, al0);
+ cx1 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx1, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah1, al1);
+ cx2 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx2, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah2, al2);
+ cx3 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx3, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah3, al3);
+ cx4 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx4, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah4, al4);
+# endif;
+ }
+
+ _mm_store_si128((__m128i*) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
+ _mm_store_si128((__m128i*) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));
+ _mm_store_si128((__m128i*) &l2[idx2 & MASK], _mm_xor_si128(bx2, cx2));
+ _mm_store_si128((__m128i*) &l3[idx3 & MASK], _mm_xor_si128(bx3, cx3));
+ _mm_store_si128((__m128i*) &l4[idx4 & MASK], _mm_xor_si128(bx4, cx4));
+
+ idx0 = EXTRACT64(cx0);
+ idx1 = EXTRACT64(cx1);
+ idx2 = EXTRACT64(cx2);
+ idx3 = EXTRACT64(cx3);
+ idx4 = EXTRACT64(cx4);
+
+ bx0 = cx0;
+ bx1 = cx1;
+ bx2 = cx2;
+ bx3 = cx3;
+ bx4 = cx4;
+
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l0[idx0 & MASK])[0];
+ ch = ((uint64_t*) &l0[idx0 & MASK])[1];
+ lo = __umul128(idx0, cl, &hi);
+
+ al0 += hi;
+ ah0 += lo;
+
+ ((uint64_t*) &l0[idx0 & MASK])[0] = al0;
+ ((uint64_t*) &l0[idx0 & MASK])[1] = ah0;
+
+ ah0 ^= ch;
+ al0 ^= cl;
+ idx0 = al0;
+
+
+ cl = ((uint64_t*) &l1[idx1 & MASK])[0];
+ ch = ((uint64_t*) &l1[idx1 & MASK])[1];
+ lo = __umul128(idx1, cl, &hi);
+
+ al1 += hi;
+ ah1 += lo;
+
+ ((uint64_t*) &l1[idx1 & MASK])[0] = al1;
+ ((uint64_t*) &l1[idx1 & MASK])[1] = ah1;
+
+ ah1 ^= ch;
+ al1 ^= cl;
+ idx1 = al1;
+
+
+ cl = ((uint64_t*) &l2[idx2 & MASK])[0];
+ ch = ((uint64_t*) &l2[idx2 & MASK])[1];
+ lo = __umul128(idx2, cl, &hi);
+
+ al2 += hi;
+ ah2 += lo;
+
+ ((uint64_t*) &l2[idx2 & MASK])[0] = al2;
+ ((uint64_t*) &l2[idx2 & MASK])[1] = ah2;
+
+ ah2 ^= ch;
+ al2 ^= cl;
+ idx2 = al2;
+
+
+ cl = ((uint64_t*) &l3[idx3 & MASK])[0];
+ ch = ((uint64_t*) &l3[idx3 & MASK])[1];
+ lo = __umul128(idx3, cl, &hi);
+
+ al3 += hi;
+ ah3 += lo;
- keccakf(h0, 24);
- keccakf(h1, 24);
+ ((uint64_t*) &l3[idx3 & MASK])[0] = al3;
+ ((uint64_t*) &l3[idx3 & MASK])[1] = ah3;
- extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, static_cast(output));
- extra_hashes[ctx->state1[0] & 3](ctx->state1, 200, static_cast(output) + 32);
-}
+ ah3 ^= ch;
+ al3 ^= cl;
+ idx3 = al3;
+
+
+ cl = ((uint64_t*) &l4[idx4 & MASK])[0];
+ ch = ((uint64_t*) &l4[idx4 & MASK])[1];
+ lo = __umul128(idx4, cl, &hi);
+
+ al4 += hi;
+ ah4 += lo;
+
+ ((uint64_t*) &l4[idx4 & MASK])[0] = al4;
+ ((uint64_t*) &l4[idx4 & MASK])[1] = ah4;
+
+ ah4 ^= ch;
+ al4 ^= cl;
+ idx4 = al4;
+ }
+
+ cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
+ cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
+ cn_implode_scratchpad((__m128i*) l2, (__m128i*) h2);
+ cn_implode_scratchpad((__m128i*) l3, (__m128i*) h3);
+ cn_implode_scratchpad((__m128i*) l4, (__m128i*) h4);
+
+ keccakf(h0, 24);
+ keccakf(h1, 24);
+ keccakf(h2, 24);
+ keccakf(h3, 24);
+ keccakf(h4, 24);
+
+ extra_hashes[ctx->state[0][0] & 3](ctx->state[0], 200, static_cast(output));
+ extra_hashes[ctx->state[1][0] & 3](ctx->state[1], 200, static_cast(output) + 32);
+ extra_hashes[ctx->state[2][0] & 3](ctx->state[2], 200, static_cast(output) + 64);
+ extra_hashes[ctx->state[3][0] & 3](ctx->state[3], 200, static_cast(output) + 96);
+ extra_hashes[ctx->state[4][0] & 3](ctx->state[4], 200, static_cast(output) + 128);
+ }
+};
#endif /* __CRYPTONIGHT_ARM_H__ */
diff --git a/src/crypto/CryptoNight_test.h b/src/crypto/CryptoNight_test.h
index 3da686a0db..ed2b3feb71 100644
--- a/src/crypto/CryptoNight_test.h
+++ b/src/crypto/CryptoNight_test.h
@@ -25,7 +25,7 @@
#define __CRYPTONIGHT_TEST_H__
-const static uint8_t test_input[152] = {
+const static uint8_t test_input[456] = {
0x01, 0x00, 0xFB, 0x8E, 0x8A, 0xC8, 0x05, 0x89, 0x93, 0x23, 0x37, 0x1B, 0xB7, 0x90, 0xDB, 0x19,
0x21, 0x8A, 0xFD, 0x8D, 0xB8, 0xE3, 0x75, 0x5D, 0x8B, 0x90, 0xF3, 0x9B, 0x3D, 0x55, 0x06, 0xA9,
0xAB, 0xCE, 0x4F, 0xA9, 0x12, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x81, 0x46, 0xD4, 0x9F,
@@ -35,23 +35,59 @@ const static uint8_t test_input[152] = {
0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B,
0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62,
0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92,
+ 0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01,
+ 0x01, 0x00, 0xFB, 0x8E, 0x8A, 0xC8, 0x05, 0x89, 0x93, 0x23, 0x37, 0x1B, 0xB7, 0x90, 0xDB, 0x19,
+ 0x21, 0x8A, 0xFD, 0x8D, 0xB8, 0xE3, 0x75, 0x5D, 0x8B, 0x90, 0xF3, 0x9B, 0x3D, 0x55, 0x06, 0xA9,
+ 0xAB, 0xCE, 0x4F, 0xA9, 0x12, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x81, 0x46, 0xD4, 0x9F,
+ 0xA9, 0x3E, 0xE7, 0x24, 0xDE, 0xB5, 0x7D, 0x12, 0xCB, 0xC6, 0xC6, 0xF3, 0xB9, 0x24, 0xD9, 0x46,
+ 0x12, 0x7C, 0x7A, 0x97, 0x41, 0x8F, 0x93, 0x48, 0x82, 0x8F, 0x0F, 0x02,
+ 0x03, 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00,
+ 0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B,
+ 0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62,
+ 0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92,
+ 0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01,
+ 0x01, 0x00, 0xFB, 0x8E, 0x8A, 0xC8, 0x05, 0x89, 0x93, 0x23, 0x37, 0x1B, 0xB7, 0x90, 0xDB, 0x19,
+ 0x21, 0x8A, 0xFD, 0x8D, 0xB8, 0xE3, 0x75, 0x5D, 0x8B, 0x90, 0xF3, 0x9B, 0x3D, 0x55, 0x06, 0xA9,
+ 0xAB, 0xCE, 0x4F, 0xA9, 0x12, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x81, 0x46, 0xD4, 0x9F,
+ 0xA9, 0x3E, 0xE7, 0x24, 0xDE, 0xB5, 0x7D, 0x12, 0xCB, 0xC6, 0xC6, 0xF3, 0xB9, 0x24, 0xD9, 0x46,
+ 0x12, 0x7C, 0x7A, 0x97, 0x41, 0x8F, 0x93, 0x48, 0x82, 0x8F, 0x0F, 0x02,
+ 0x03, 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00,
+ 0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B,
+ 0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62,
+ 0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92,
0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01
};
-const static uint8_t test_output0[64] = {
+const static uint8_t test_output0[192] = {
0x1B, 0x60, 0x6A, 0x3F, 0x4A, 0x07, 0xD6, 0x48, 0x9A, 0x1B, 0xCD, 0x07, 0x69, 0x7B, 0xD1, 0x66,
0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F,
0x1A, 0x3F, 0xFB, 0xEE, 0x90, 0x9B, 0x42, 0x0D, 0x91, 0xF7, 0xBE, 0x6E, 0x5F, 0xB5, 0x6D, 0xB7,
+ 0x1B, 0x31, 0x10, 0xD8, 0x86, 0x01, 0x1E, 0x87, 0x7E, 0xE5, 0x78, 0x6A, 0xFD, 0x08, 0x01, 0x00,
+ 0x1B, 0x60, 0x6A, 0x3F, 0x4A, 0x07, 0xD6, 0x48, 0x9A, 0x1B, 0xCD, 0x07, 0x69, 0x7B, 0xD1, 0x66,
+ 0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F,
+ 0x1A, 0x3F, 0xFB, 0xEE, 0x90, 0x9B, 0x42, 0x0D, 0x91, 0xF7, 0xBE, 0x6E, 0x5F, 0xB5, 0x6D, 0xB7,
+ 0x1B, 0x31, 0x10, 0xD8, 0x86, 0x01, 0x1E, 0x87, 0x7E, 0xE5, 0x78, 0x6A, 0xFD, 0x08, 0x01, 0x00,
+ 0x1B, 0x60, 0x6A, 0x3F, 0x4A, 0x07, 0xD6, 0x48, 0x9A, 0x1B, 0xCD, 0x07, 0x69, 0x7B, 0xD1, 0x66,
+ 0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F,
+ 0x1A, 0x3F, 0xFB, 0xEE, 0x90, 0x9B, 0x42, 0x0D, 0x91, 0xF7, 0xBE, 0x6E, 0x5F, 0xB5, 0x6D, 0xB7,
0x1B, 0x31, 0x10, 0xD8, 0x86, 0x01, 0x1E, 0x87, 0x7E, 0xE5, 0x78, 0x6A, 0xFD, 0x08, 0x01, 0x00
};
-const static uint8_t test_output1[64] = {
+const static uint8_t test_output1[192] = {
0x28, 0xA2, 0x2B, 0xAD, 0x3F, 0x93, 0xD1, 0x40, 0x8F, 0xCA, 0x47, 0x2E, 0xB5, 0xAD, 0x1C, 0xBE,
0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD,
0x36, 0x95, 0xB4, 0xB5, 0x3B, 0xB0, 0x03, 0x58, 0xB0, 0xAD, 0x38, 0xDC, 0x16, 0x0F, 0xEB, 0x9E,
0x00, 0x4E, 0xEC, 0xE0, 0x9B, 0x83, 0xA7, 0x2E, 0xF6, 0xBA, 0x98, 0x64, 0xD3, 0x51, 0x0C, 0x88,
+ 0x28, 0xA2, 0x2B, 0xAD, 0x3F, 0x93, 0xD1, 0x40, 0x8F, 0xCA, 0x47, 0x2E, 0xB5, 0xAD, 0x1C, 0xBE,
+ 0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD,
+ 0x36, 0x95, 0xB4, 0xB5, 0x3B, 0xB0, 0x03, 0x58, 0xB0, 0xAD, 0x38, 0xDC, 0x16, 0x0F, 0xEB, 0x9E,
+ 0x00, 0x4E, 0xEC, 0xE0, 0x9B, 0x83, 0xA7, 0x2E, 0xF6, 0xBA, 0x98, 0x64, 0xD3, 0x51, 0x0C, 0x88,
+ 0x28, 0xA2, 0x2B, 0xAD, 0x3F, 0x93, 0xD1, 0x40, 0x8F, 0xCA, 0x47, 0x2E, 0xB5, 0xAD, 0x1C, 0xBE,
+ 0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD,
+ 0x36, 0x95, 0xB4, 0xB5, 0x3B, 0xB0, 0x03, 0x58, 0xB0, 0xAD, 0x38, 0xDC, 0x16, 0x0F, 0xEB, 0x9E,
+ 0x00, 0x4E, 0xEC, 0xE0, 0x9B, 0x83, 0xA7, 0x2E, 0xF6, 0xBA, 0x98, 0x64, 0xD3, 0x51, 0x0C, 0x88
};
diff --git a/src/crypto/CryptoNight_x86.h b/src/crypto/CryptoNight_x86.h
index 362a1a9f44..f1a0fbe7d9 100644
--- a/src/crypto/CryptoNight_x86.h
+++ b/src/crypto/CryptoNight_x86.h
@@ -5,6 +5,8 @@
* Copyright 2014-2016 Wolf9466
* Copyright 2016 Jay D Dee
* Copyright 2016-2017 XMRig
+ * Copyright 2018 Sebastian Stolzenberg
+ * Copyright 2018 BenDroid
*
*
* This program is free software: you can redistribute it and/or modify
@@ -47,42 +49,47 @@ extern "C"
}
-static inline void do_blake_hash(const void* input, size_t len, char* output) {
+static inline void do_blake_hash(const void* input, size_t len, char* output)
+{
blake256_hash(reinterpret_cast(output), static_cast(input), len);
}
-static inline void do_groestl_hash(const void* input, size_t len, char* output) {
+static inline void do_groestl_hash(const void* input, size_t len, char* output)
+{
groestl(static_cast(input), len * 8, reinterpret_cast(output));
}
-static inline void do_jh_hash(const void* input, size_t len, char* output) {
+static inline void do_jh_hash(const void* input, size_t len, char* output)
+{
jh_hash(32 * 8, static_cast(input), 8 * len, reinterpret_cast(output));
}
-static inline void do_skein_hash(const void* input, size_t len, char* output) {
+static inline void do_skein_hash(const void* input, size_t len, char* output)
+{
xmr_skein(static_cast(input), reinterpret_cast(output));
}
-void (* const extra_hashes[4])(const void *, size_t, char *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash};
-
+void (* const extra_hashes[4])(const void*, size_t, char*) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash};
#if defined(__x86_64__) || defined(_M_AMD64)
# define EXTRACT64(X) _mm_cvtsi128_si64(X)
# ifdef __GNUC__
+
static inline uint64_t __umul128(uint64_t a, uint64_t b, uint64_t* hi)
{
unsigned __int128 r = (unsigned __int128) a * (unsigned __int128) b;
*hi = r >> 64;
return (uint64_t) r;
}
+
# else
- #define __umul128 _umul128
+#define __umul128 _umul128
# endif
#elif defined(__i386__) || defined(_M_IX86)
# define HI32(X) \
@@ -139,11 +146,11 @@ template
static inline void aes_genkey_sub(__m128i* xout0, __m128i* xout2)
{
__m128i xout1 = _mm_aeskeygenassist_si128(*xout2, rcon);
- xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
+ xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
*xout0 = sl_xor(*xout0);
*xout0 = _mm_xor_si128(*xout0, xout1);
- xout1 = _mm_aeskeygenassist_si128(*xout0, 0x00);
- xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
+ xout1 = _mm_aeskeygenassist_si128(*xout0, 0x00);
+ xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
*xout2 = sl_xor(*xout2);
*xout2 = _mm_xor_si128(*xout2, xout1);
}
@@ -153,18 +160,20 @@ template
static inline void soft_aes_genkey_sub(__m128i* xout0, __m128i* xout2)
{
__m128i xout1 = soft_aeskeygenassist(*xout2);
- xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
+ xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
*xout0 = sl_xor(*xout0);
*xout0 = _mm_xor_si128(*xout0, xout1);
- xout1 = soft_aeskeygenassist<0x00>(*xout0);
- xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
+ xout1 = soft_aeskeygenassist<0x00>(*xout0);
+ xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
*xout2 = sl_xor(*xout2);
*xout2 = _mm_xor_si128(*xout2, xout1);
}
template
-static inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3, __m128i* k4, __m128i* k5, __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
+static inline void
+aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3, __m128i* k4, __m128i* k5,
+ __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
{
__m128i xout0 = _mm_load_si128(memory);
__m128i xout2 = _mm_load_si128(memory + 1);
@@ -190,7 +199,9 @@ static inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, _
template
-static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
+static inline void
+aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6,
+ __m128i* x7)
{
if (SOFT_AES) {
*x0 = soft_aesenc(*x0, key);
@@ -201,8 +212,7 @@ static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2,
*x5 = soft_aesenc(*x5, key);
*x6 = soft_aesenc(*x6, key);
*x7 = soft_aesenc(*x7, key);
- }
- else {
+ } else {
*x0 = _mm_aesenc_si128(*x0, key);
*x1 = _mm_aesenc_si128(*x1, key);
*x2 = _mm_aesenc_si128(*x2, key);
@@ -216,7 +226,7 @@ static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2,
template
-static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output)
+static inline void cn_explode_scratchpad(const __m128i* input, __m128i* output)
{
__m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7;
__m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
@@ -257,7 +267,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output)
template
-static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
+static inline void cn_implode_scratchpad(const __m128i* input, __m128i* output)
{
__m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7;
__m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
@@ -273,8 +283,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
xout6 = _mm_load_si128(output + 10);
xout7 = _mm_load_si128(output + 11);
- for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8)
- {
+ for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) {
xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0);
xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1);
xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2);
@@ -306,146 +315,713 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
_mm_store_si128(output + 11, xout7);
}
+// n-Loop version. Seems to be little bit slower then the hardcoded one.
+template
+class CryptoNightMultiHash
+{
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ const uint8_t* l[NUM_HASH_BLOCKS];
+ uint64_t* h[NUM_HASH_BLOCKS];
+ uint64_t al[NUM_HASH_BLOCKS];
+ uint64_t ah[NUM_HASH_BLOCKS];
+ __m128i bx[NUM_HASH_BLOCKS];
+ uint64_t idx[NUM_HASH_BLOCKS];
+
+ for (size_t hashBlock = 0; hashBlock < NUM_HASH_BLOCKS; ++hashBlock) {
+ keccak(static_cast(input) + hashBlock * size, (int) size,
+ ctx->state[hashBlock], 200);
+ }
+
+ for (size_t hashBlock = 0; hashBlock < NUM_HASH_BLOCKS; ++hashBlock) {
+ l[hashBlock] = ctx->memory + hashBlock * MEM;
+ h[hashBlock] = reinterpret_cast(ctx->state[hashBlock]);
+
+ cn_explode_scratchpad((__m128i*) h[hashBlock], (__m128i*) l[hashBlock]);
+
+ al[hashBlock] = h[hashBlock][0] ^ h[hashBlock][4];
+ ah[hashBlock] = h[hashBlock][1] ^ h[hashBlock][5];
+ bx[hashBlock] =
+ _mm_set_epi64x(h[hashBlock][3] ^ h[hashBlock][7], h[hashBlock][2] ^ h[hashBlock][6]);
+ idx[hashBlock] = h[hashBlock][0] ^ h[hashBlock][4];
+ }
+
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ for (size_t hashBlock = 0; hashBlock < NUM_HASH_BLOCKS; ++hashBlock) {
+ __m128i cx;
+ cx = _mm_load_si128((__m128i*) &l[hashBlock][idx[hashBlock] & MASK]);
+
+ if (SOFT_AES) {
+ cx = soft_aesenc(cx, _mm_set_epi64x(ah[hashBlock], al[hashBlock]));
+ } else {
+ cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah[hashBlock], al[hashBlock]));
+ }
+
+ _mm_store_si128((__m128i*) &l[hashBlock][idx[hashBlock] & MASK],
+ _mm_xor_si128(bx[hashBlock], cx));
+ idx[hashBlock] = EXTRACT64(cx);
+ bx[hashBlock] = cx;
+
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l[hashBlock][idx[hashBlock] & MASK])[0];
+ ch = ((uint64_t*) &l[hashBlock][idx[hashBlock] & MASK])[1];
+ lo = __umul128(idx[hashBlock], cl, &hi);
+
+ al[hashBlock] += hi;
+ ah[hashBlock] += lo;
+
+ ((uint64_t*) &l[hashBlock][idx[hashBlock] & MASK])[0] = al[hashBlock];
+ ((uint64_t*) &l[hashBlock][idx[hashBlock] & MASK])[1] = ah[hashBlock];
+
+ ah[hashBlock] ^= ch;
+ al[hashBlock] ^= cl;
+ idx[hashBlock] = al[hashBlock];
+ }
+ }
+
+ for (size_t hashBlock = 0; hashBlock < NUM_HASH_BLOCKS; ++hashBlock) {
+ cn_implode_scratchpad((__m128i*) l[hashBlock], (__m128i*) h[hashBlock]);
+ keccakf(h[hashBlock], 24);
+ extra_hashes[ctx->state[hashBlock][0] & 3](ctx->state[hashBlock], 200,
+ static_cast(output) + hashBlock * 32);
+ }
+ }
+};
template
-inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, cryptonight_ctx *__restrict__ ctx)
+class CryptoNightMultiHash
{
- keccak(static_cast(input), (int) size, ctx->state0, 200);
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ const uint8_t* l;
+ uint64_t* h;
+ uint64_t al;
+ uint64_t ah;
+ __m128i bx;
+ uint64_t idx;
- cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory);
+ keccak(static_cast(input), (int) size, ctx->state[0], 200);
- const uint8_t* l0 = ctx->memory;
- uint64_t* h0 = reinterpret_cast(ctx->state0);
+ l = ctx->memory;
+ h = reinterpret_cast(ctx->state[0]);
- uint64_t al0 = h0[0] ^ h0[4];
- uint64_t ah0 = h0[1] ^ h0[5];
- __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+ cn_explode_scratchpad((__m128i*) h, (__m128i*) l);
- uint64_t idx0 = h0[0] ^ h0[4];
+ al = h[0] ^ h[4];
+ ah = h[1] ^ h[5];
+ bx = _mm_set_epi64x(h[3] ^ h[7], h[2] ^ h[6]);
+ idx = h[0] ^ h[4];
- for (size_t i = 0; i < ITERATIONS; i++) {
- __m128i cx;
- cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]);
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ __m128i cx = _mm_load_si128((__m128i*) &l[idx & MASK]);
- if (SOFT_AES) {
- cx = soft_aesenc(cx, _mm_set_epi64x(ah0, al0));
- }
- else {
- cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0));
- }
+ if (SOFT_AES) {
+ cx = soft_aesenc(cx, _mm_set_epi64x(ah, al));
+ } else {
+ cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah, al));
+ }
+
+ _mm_store_si128((__m128i*) &l[idx & MASK], _mm_xor_si128(bx, cx));
+ idx = EXTRACT64(cx);
+ bx = cx;
- _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx));
- idx0 = EXTRACT64(cx);
- bx0 = cx;
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l[idx & MASK])[0];
+ ch = ((uint64_t*) &l[idx & MASK])[1];
+ lo = __umul128(idx, cl, &hi);
- uint64_t hi, lo, cl, ch;
- cl = ((uint64_t*) &l0[idx0 & MASK])[0];
- ch = ((uint64_t*) &l0[idx0 & MASK])[1];
- lo = __umul128(idx0, cl, &hi);
+ al += hi;
+ ah += lo;
- al0 += hi;
- ah0 += lo;
+ ((uint64_t*) &l[idx & MASK])[0] = al;
+ ((uint64_t*) &l[idx & MASK])[1] = ah;
- ((uint64_t*)&l0[idx0 & MASK])[0] = al0;
- ((uint64_t*)&l0[idx0 & MASK])[1] = ah0;
+ ah ^= ch;
+ al ^= cl;
+ idx = al;
+ }
- ah0 ^= ch;
- al0 ^= cl;
- idx0 = al0;
+ cn_implode_scratchpad((__m128i*) l, (__m128i*) h);
+ keccakf(h, 24);
+ extra_hashes[ctx->state[0][0] & 3](ctx->state[0], 200, static_cast(output));
}
+};
+
+template
+class CryptoNightMultiHash
+{
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ keccak((const uint8_t*) input, (int) size, ctx->state[0], 200);
+ keccak((const uint8_t*) input + size, (int) size, ctx->state[1], 200);
- cn_implode_scratchpad((__m128i*) ctx->memory, (__m128i*) ctx->state0);
+ const uint8_t* l0 = ctx->memory;
+ const uint8_t* l1 = ctx->memory + MEM;
+ uint64_t* h0 = reinterpret_cast(ctx->state[0]);
+ uint64_t* h1 = reinterpret_cast(ctx->state[1]);
- keccakf(h0, 24);
- extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, static_cast(output));
-}
+ cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
+ cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
+
+ uint64_t al0 = h0[0] ^h0[4];
+ uint64_t al1 = h1[0] ^h1[4];
+ uint64_t ah0 = h0[1] ^h0[5];
+ uint64_t ah1 = h1[1] ^h1[5];
+
+ __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+ __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
+
+ uint64_t idx0 = h0[0] ^h0[4];
+ uint64_t idx1 = h1[0] ^h1[4];
+
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ __m128i cx0 = _mm_load_si128((__m128i*) &l0[idx0 & MASK]);
+ __m128i cx1 = _mm_load_si128((__m128i*) &l1[idx1 & MASK]);
+
+ if (SOFT_AES) {
+ cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
+ cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
+ } else {
+ cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0));
+ cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1));
+ }
+
+ _mm_store_si128((__m128i*) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
+ _mm_store_si128((__m128i*) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));
+
+ idx0 = EXTRACT64(cx0);
+ idx1 = EXTRACT64(cx1);
+
+ bx0 = cx0;
+ bx1 = cx1;
+
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l0[idx0 & MASK])[0];
+ ch = ((uint64_t*) &l0[idx0 & MASK])[1];
+ lo = __umul128(idx0, cl, &hi);
+
+ al0 += hi;
+ ah0 += lo;
+
+ ((uint64_t*) &l0[idx0 & MASK])[0] = al0;
+ ((uint64_t*) &l0[idx0 & MASK])[1] = ah0;
+
+ ah0 ^= ch;
+ al0 ^= cl;
+ idx0 = al0;
+
+ cl = ((uint64_t*) &l1[idx1 & MASK])[0];
+ ch = ((uint64_t*) &l1[idx1 & MASK])[1];
+ lo = __umul128(idx1, cl, &hi);
+
+ al1 += hi;
+ ah1 += lo;
+ ((uint64_t*) &l1[idx1 & MASK])[0] = al1;
+ ((uint64_t*) &l1[idx1 & MASK])[1] = ah1;
+
+ ah1 ^= ch;
+ al1 ^= cl;
+ idx1 = al1;
+ }
+
+ cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
+ cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
+
+ keccakf(h0, 24);
+ keccakf(h1, 24);
+
+ extra_hashes[ctx->state[0][0] & 3](ctx->state[0], 200, static_cast(output));
+ extra_hashes[ctx->state[1][0] & 3](ctx->state[1], 200, static_cast(output) + 32);
+ }
+};
template
-inline void cryptonight_double_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, struct cryptonight_ctx *__restrict__ ctx)
+class CryptoNightMultiHash
{
- keccak((const uint8_t *) input, (int) size, ctx->state0, 200);
- keccak((const uint8_t *) input + size, (int) size, ctx->state1, 200);
+public:
+ inline static void hash(const void* __restrict__ input,
+ size_t size,
+ void* __restrict__ output,
+ cryptonight_ctx* __restrict__ ctx)
+ {
+ keccak((const uint8_t*) input, (int) size, ctx->state[0], 200);
+ keccak((const uint8_t*) input + size, (int) size, ctx->state[1], 200);
+ keccak((const uint8_t*) input + 2 * size, (int) size, ctx->state[2], 200);
- const uint8_t* l0 = ctx->memory;
- const uint8_t* l1 = ctx->memory + MEM;
- uint64_t* h0 = reinterpret_cast(ctx->state0);
- uint64_t* h1 = reinterpret_cast(ctx->state1);
+ const uint8_t* l0 = ctx->memory;
+ const uint8_t* l1 = ctx->memory + MEM;
+ const uint8_t* l2 = ctx->memory + 2 * MEM;
+ uint64_t* h0 = reinterpret_cast(ctx->state[0]);
+ uint64_t* h1 = reinterpret_cast(ctx->state[1]);
+ uint64_t* h2 = reinterpret_cast(ctx->state[2]);
- cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
- cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
+ cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
+ cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
+ cn_explode_scratchpad((__m128i*) h2, (__m128i*) l2);
- uint64_t al0 = h0[0] ^ h0[4];
- uint64_t al1 = h1[0] ^ h1[4];
- uint64_t ah0 = h0[1] ^ h0[5];
- uint64_t ah1 = h1[1] ^ h1[5];
+ uint64_t al0 = h0[0] ^h0[4];
+ uint64_t al1 = h1[0] ^h1[4];
+ uint64_t al2 = h2[0] ^h2[4];
+ uint64_t ah0 = h0[1] ^h0[5];
+ uint64_t ah1 = h1[1] ^h1[5];
+ uint64_t ah2 = h2[1] ^h2[5];
- __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
- __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
+ __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+ __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
+ __m128i bx2 = _mm_set_epi64x(h2[3] ^ h2[7], h2[2] ^ h2[6]);
- uint64_t idx0 = h0[0] ^ h0[4];
- uint64_t idx1 = h1[0] ^ h1[4];
+ uint64_t idx0 = h0[0] ^h0[4];
+ uint64_t idx1 = h1[0] ^h1[4];
+ uint64_t idx2 = h2[0] ^h2[4];
- for (size_t i = 0; i < ITERATIONS; i++) {
- __m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]);
- __m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]);
+ for (size_t i = 0; i < ITERATIONS; i++) {
+ __m128i cx0 = _mm_load_si128((__m128i*) &l0[idx0 & MASK]);
+ __m128i cx1 = _mm_load_si128((__m128i*) &l1[idx1 & MASK]);
+ __m128i cx2 = _mm_load_si128((__m128i*) &l2[idx2 & MASK]);
- if (SOFT_AES) {
- cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
- cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
- }
- else {
- cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0));
- cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1));
+ if (SOFT_AES) {
+ cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
+ cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
+ cx2 = soft_aesenc(cx2, _mm_set_epi64x(ah2, al2));
+ } else {
+ cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0));
+ cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1));
+ cx2 = _mm_aesenc_si128(cx2, _mm_set_epi64x(ah2, al2));
+ }
+
+ _mm_store_si128((__m128i*) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
+ _mm_store_si128((__m128i*) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));
+ _mm_store_si128((__m128i*) &l2[idx2 & MASK], _mm_xor_si128(bx2, cx2));
+
+ idx0 = EXTRACT64(cx0);
+ idx1 = EXTRACT64(cx1);
+ idx2 = EXTRACT64(cx2);
+
+ bx0 = cx0;
+ bx1 = cx1;
+ bx2 = cx2;
+
+
+ uint64_t hi, lo, cl, ch;
+ cl = ((uint64_t*) &l0[idx0 & MASK])[0];
+ ch = ((uint64_t*) &l0[idx0 & MASK])[1];
+ lo = __umul128(idx0, cl, &hi);
+
+ al0 += hi;
+ ah0 += lo;
+
+ ((uint64_t*) &l0[idx0 & MASK])[0] = al0;
+ ((uint64_t*) &l0[idx0 & MASK])[1] = ah0;
+
+ ah0 ^= ch;
+ al0 ^= cl;
+ idx0 = al0;
+
+
+ cl = ((uint64_t*) &l1[idx1 & MASK])[0];
+ ch = ((uint64_t*) &l1[idx1 & MASK])[1];
+ lo = __umul128(idx1, cl, &hi);
+
+ al1 += hi;
+ ah1 += lo;
+
+ ((uint64_t*) &l1[idx1 & MASK])[0] = al1;
+ ((uint64_t*) &l1[idx1 & MASK])[1] = ah1;
+
+ ah1 ^= ch;
+ al1 ^= cl;
+ idx1 = al1;
+
+
+ cl = ((uint64_t*) &l2[idx2 & MASK])[0];
+ ch = ((uint64_t*) &l2[idx2 & MASK])[1];
+ lo = __umul128(idx2, cl, &hi);
+
+ al2 += hi;
+ ah2 += lo;
+
+ ((uint64_t*) &l2[idx2 & MASK])[0] = al2;
+ ((uint64_t*) &l2[idx2 & MASK])[1] = ah2;
+
+ ah2 ^= ch;
+ al2 ^= cl;
+ idx2 = al2;
}
- _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
- _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));
+ cn_implode_scratchpad