Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

please add cryptonight-superfast #14

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Algorithms
* cryptonight (v0, v1, v2, xtl, msr, rto, xao)
* cryptonight-light (v0, v1)
* cryptonight-heavy (v0, xhv, tube)
* cryptonight-superfast (v0)

Usage
-----
Expand All @@ -24,7 +25,7 @@ So far this native Node.js addon can do the following hashing algos
```javascript
var multiHashing = require('cryptonight-hashing');

var algorithms = ['cryptonight', 'cryptonight_light', 'cryptonight_heavy' ];
var algorithms = ['cryptonight', 'cryptonight_light', 'cryptonight_heavy', 'cryptonight_superfast' ];

var data = new Buffer("7000000001e980924e4e1109230383e66d62945ff8e749903bea4336755c00000000000051928aff1b4d72416173a8c3948159a09a73ac3bb556aa6bfbcad1a85da7f4c1d13350531e24031b939b9e2b", "hex");

Expand Down
90 changes: 90 additions & 0 deletions multihashing.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,31 @@ NAN_METHOD(cryptonight_heavy) {
info.GetReturnValue().Set(returnValue);
}

NAN_METHOD(cryptonight_superfast) {
if (info.Length() < 1) return THROW_ERROR_EXCEPTION("You must provide one argument.");

Local<Object> target = info[0]->ToObject();
if (!Buffer::HasInstance(target)) return THROW_ERROR_EXCEPTION("Argument 1 should be a buffer object.");

int variant = 0;

if (info.Length() >= 2) {
if (!info[1]->IsNumber()) return THROW_ERROR_EXCEPTION("Argument 2 should be a number");
variant = Nan::To<int>(info[1]).FromMaybe(0);
}

char output[32];
init_ctx();
switch (variant) {
case 0: cryptonight_single_hash<xmrig::CRYPTONIGHT_SUPERFAST, SOFT_AES, xmrig::VARIANT_0 >(reinterpret_cast<const uint8_t*>(Buffer::Data(target)), Buffer::Length(target), reinterpret_cast<uint8_t*>(output), &ctx);
break;
default: cryptonight_single_hash<xmrig::CRYPTONIGHT_SUPERFAST, SOFT_AES, xmrig::VARIANT_0 >(reinterpret_cast<const uint8_t*>(Buffer::Data(target)), Buffer::Length(target), reinterpret_cast<uint8_t*>(output), &ctx);
}

v8::Local<v8::Value> returnValue = Nan::CopyBuffer(output, 32).ToLocalChecked();
info.GetReturnValue().Set(returnValue);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class CCryptonightAsync : public Nan::AsyncWorker {
Expand Down Expand Up @@ -360,6 +385,69 @@ NAN_METHOD(cryptonight_heavy_async) {
Nan::AsyncQueueWorker(new CCryptonightHeavyAsync(callback, Buffer::Data(target), Buffer::Length(target), variant));
}

class CCryptonightSuperfastAsync : public Nan::AsyncWorker {

private:

struct cryptonight_ctx* m_ctx;
const char* const m_input;
const uint32_t m_input_len;
const int m_variant;
char m_output[32];

public:

CCryptonightSuperfastAsync(Nan::Callback* const callback, const char* const input, const uint32_t input_len, const int variant)
: Nan::AsyncWorker(callback), m_ctx(static_cast<cryptonight_ctx *>(_mm_malloc(sizeof(cryptonight_ctx), 16))),
m_input(input), m_input_len(input_len), m_variant(variant) {
m_ctx->memory = static_cast<uint8_t *>(_mm_malloc(xmrig::CRYPTONIGHT_SUPERFAST_MEMORY, 4096));
}

~CCryptonightSuperfastAsync() {
_mm_free(m_ctx->memory);
_mm_free(m_ctx);
}

void Execute () {
switch (m_variant) {
case 0: cryptonight_single_hash<xmrig::CRYPTONIGHT_SUPERFAST, SOFT_AES, xmrig::VARIANT_0 >(reinterpret_cast<const uint8_t*>(m_input), m_input_len, reinterpret_cast<uint8_t*>(m_output), &m_ctx);
break;
default: cryptonight_single_hash<xmrig::CRYPTONIGHT_SUPERFAST, SOFT_AES, xmrig::VARIANT_0 >(reinterpret_cast<const uint8_t*>(m_input), m_input_len, reinterpret_cast<uint8_t*>(m_output), &m_ctx);
}
}

void HandleOKCallback () {
Nan::HandleScope scope;

v8::Local<v8::Value> argv[] = {
Nan::Null(),
v8::Local<v8::Value>(Nan::CopyBuffer(m_output, 32).ToLocalChecked())
};
callback->Call(2, argv, async_resource);
}
};

NAN_METHOD(cryptonight_superfast_async) {
if (info.Length() < 2) return THROW_ERROR_EXCEPTION("You must provide at least two arguments.");

Local<Object> target = info[0]->ToObject();
if (!Buffer::HasInstance(target)) return THROW_ERROR_EXCEPTION("Argument should be a buffer object.");

int variant = 0;

int callback_arg_num;
if (info.Length() >= 3) {
if (!info[1]->IsNumber()) return THROW_ERROR_EXCEPTION("Argument 2 should be a number");
variant = Nan::To<int>(info[1]).FromMaybe(0);
callback_arg_num = 2;
} else {
callback_arg_num = 1;
}

Callback *callback = new Nan::Callback(info[callback_arg_num].As<v8::Function>());
Nan::AsyncQueueWorker(new CCryptonightSuperfastAsync(callback, Buffer::Data(target), Buffer::Length(target), variant));
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Expand All @@ -370,6 +458,8 @@ NAN_MODULE_INIT(init) {
Nan::Set(target, Nan::New("cryptonight_light_async").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(cryptonight_light_async)).ToLocalChecked());
Nan::Set(target, Nan::New("cryptonight_heavy").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(cryptonight_heavy)).ToLocalChecked());
Nan::Set(target, Nan::New("cryptonight_heavy_async").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(cryptonight_heavy_async)).ToLocalChecked());
Nan::Set(target, Nan::New("cryptonight_superfast").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(cryptonight_superfast)).ToLocalChecked());
Nan::Set(target, Nan::New("cryptonight_superfast_async").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(cryptonight_superfast_async)).ToLocalChecked());
}

NODE_MODULE(cryptonight, init)
1 change: 1 addition & 0 deletions tests/cryptonight_superfast.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
40865aa88741ec1dccbd2bc6ff36b94d547158db94698e3ca03de4819a659fef 0305a0dbd6bf05cf16e503f3a66f78007cbf34144332ecbfc22ed95c8700383b309ace1923a0964b00000008ba939a62724c0d7581fce5761e9d8a0e6a1c3f924fdd8493d1115649c05eb601
3 changes: 3 additions & 0 deletions tests/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ node test.js
node test_async.js
node test_async_light.js
node test_async_heavy.js
node test_async_superfast.js
node test_sync-1.js
node test_sync-2.js
node test_sync-xtl.js
Expand All @@ -20,6 +21,8 @@ node test_sync_light-1.js
node test_sync_heavy.js
node test_sync_heavy-xhv.js
node test_sync_heavy-tube.js
node test_sync_superfast.js
node test_perf.js
node test_perf_light.js
node test_perf_heavy.js
node test_perf_superfast.js
29 changes: 29 additions & 0 deletions tests/test_async_superfast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use strict";
let multiHashing = require('../build/Release/cryptonight-hashing');
let fs = require('fs');
let lineReader = require('readline');

let testsFailed = 0, testsPassed = 0, line_count = 0;
let lr = lineReader.createInterface({
input: fs.createReadStream('cryptonight_superfast.txt')
});
lr.on('line', function (line) {
let line_data = line.split(/ (.+)/);
line_count += 1;
multiHashing.cryptonight_superfast_async(Buffer.from(line_data[1], 'hex'), function(err, result){
result = result.toString('hex');
if (line_data[0] !== result){
console.error(line_data[1] + ": " + result);
testsFailed += 1;
} else {
testsPassed += 1;
}
if (line_count === (testsFailed + testsPassed)){
if (testsFailed > 0){
console.log(testsFailed + '/' + (testsPassed + testsFailed) + ' tests failed on: cryptonight_superfast_async');
} else {
console.log(testsPassed + ' tests passed on: cryptonight_superfast_async');
}
}
});
});
12 changes: 12 additions & 0 deletions tests/test_perf_superfast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use strict";
let multiHashing = require('../build/Release/cryptonight-hashing');

const ITER = 100;
let input = Buffer.from("test");

let start = Date.now();
for (let i = ITER; i; -- i) {
multiHashing.cryptonight_superfast(input);
}
let end = Date.now();
console.log("Perf: " + 1000 * ITER / (end - start) + " H/s");
26 changes: 26 additions & 0 deletions tests/test_sync_superfast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"use strict";
let multiHashing = require('../build/Release/cryptonight-hashing');
let fs = require('fs');
let lineReader = require('readline');

let testsFailed = 0, testsPassed = 0;
let lr = lineReader.createInterface({
input: fs.createReadStream('cryptonight_superfast.txt')
});
lr.on('line', function (line) {
let line_data = line.split(/ (.+)/);
let result = multiHashing.cryptonight_superfast(Buffer.from(line_data[1], 'hex')).toString('hex');
if (line_data[0] !== result){
console.error(line_data[1] + ": " + result);
testsFailed += 1;
} else {
testsPassed += 1;
}
});
lr.on('close', function(){
if (testsFailed > 0){
console.log(testsFailed + '/' + (testsPassed + testsFailed) + ' tests failed on: cryptonight_superfast');
} else {
console.log(testsPassed + ' tests passed on: cryptonight_superfast');
}
});
9 changes: 5 additions & 4 deletions xmrig/common/xmrig.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ namespace xmrig

enum Algo {
INVALID_ALGO = -1,
CRYPTONIGHT, /* CryptoNight (Monero) */
CRYPTONIGHT_LITE, /* CryptoNight-Lite (AEON) */
CRYPTONIGHT_HEAVY /* CryptoNight-Heavy (RYO) */
CRYPTONIGHT, /* CryptoNight (Monero) */
CRYPTONIGHT_LITE, /* CryptoNight-Lite (AEON) */
CRYPTONIGHT_HEAVY, /* CryptoNight-Heavy (RYO) */
CRYPTONIGHT_SUPERFAST /* CryptoNight-Superfast (XFH) */
};


Expand All @@ -59,7 +60,7 @@ enum AlgoVariant {

enum Variant {
VARIANT_AUTO = -1, // Autodetect
VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy
VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy or CryptoNight-Superfast
VARIANT_1 = 1, // CryptoNight variant 1 also known as Monero7 and CryptoNightV7
VARIANT_TUBE = 2, // Modified CryptoNight-Heavy (TUBE only)
VARIANT_XTL = 3, // Modified CryptoNight variant 1 (Stellite only)
Expand Down
18 changes: 9 additions & 9 deletions xmrig/crypto/CryptoNight_arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output)
xin6 = _mm_load_si128(input + 10);
xin7 = _mm_load_si128(input + 11);

if (ALGO == xmrig::CRYPTONIGHT_HEAVY) {
if (ALGO == xmrig::CRYPTONIGHT_HEAVY || ALGO == xmrig::CRYPTONIGHT_SUPERFAST) {
for (size_t i = 0; i < 16; i++) {
aes_round<SOFT_AES>(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
aes_round<SOFT_AES>(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
Expand Down Expand Up @@ -323,12 +323,12 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
aes_round<SOFT_AES>(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
aes_round<SOFT_AES>(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);

if (ALGO == xmrig::CRYPTONIGHT_HEAVY) {
if (ALGO == xmrig::CRYPTONIGHT_HEAVY || ALGO == xmrig::CRYPTONIGHT_SUPERFAST) {
mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7);
}
}

if (ALGO == xmrig::CRYPTONIGHT_HEAVY) {
if (ALGO == xmrig::CRYPTONIGHT_HEAVY || ALGO == xmrig::CRYPTONIGHT_SUPERFAST) {
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);
Expand Down Expand Up @@ -510,15 +510,15 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si
ah0 ^= ch;
idx0 = al0;

if (ALGO == xmrig::CRYPTONIGHT_HEAVY) {
if (ALGO == xmrig::CRYPTONIGHT_HEAVY || ALGO == xmrig::CRYPTONIGHT_SUPERFAST) {
const int64x2_t x = vld1q_s64(reinterpret_cast<const int64_t *>(&l0[idx0 & MASK]));
const int64_t n = vgetq_lane_s64(x, 0);
const int32_t d = vgetq_lane_s32(x, 2);
const int64_t q = n / (d | 0x5);

((int64_t*)&l0[idx0 & MASK])[0] = n ^ q;

if (VARIANT == xmrig::VARIANT_XHV) {
if (VARIANT == xmrig::VARIANT_XHV || ALGO == xmrig::CRYPTONIGHT_SUPERFAST) {
idx0 = (~d) ^ q;
}
else {
Expand Down Expand Up @@ -641,15 +641,15 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si
ah0 ^= ch;
idx0 = al0;

if (ALGO == xmrig::CRYPTONIGHT_HEAVY) {
if (ALGO == xmrig::CRYPTONIGHT_HEAVY || ALGO == xmrig::CRYPTONIGHT_SUPERFAST) {
const int64x2_t x = vld1q_s64(reinterpret_cast<const int64_t *>(&l0[idx0 & MASK]));
const int64_t n = vgetq_lane_s64(x, 0);
const int32_t d = vgetq_lane_s32(x, 2);
const int64_t q = n / (d | 0x5);

((int64_t*)&l0[idx0 & MASK])[0] = n ^ q;

if (VARIANT == xmrig::VARIANT_XHV) {
if (VARIANT == xmrig::VARIANT_XHV || ALGO == xmrig::CRYPTONIGHT_SUPERFAST) {
idx0 = (~d) ^ q;
}
else {
Expand Down Expand Up @@ -684,15 +684,15 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si
ah1 ^= ch;
idx1 = al1;

if (ALGO == xmrig::CRYPTONIGHT_HEAVY) {
if (ALGO == xmrig::CRYPTONIGHT_HEAVY || ALGO == xmrig::CRYPTONIGHT_SUPERFAST) {
const int64x2_t x = vld1q_s64(reinterpret_cast<const int64_t *>(&l1[idx1 & MASK]));
const int64_t n = vgetq_lane_s64(x, 0);
const int32_t d = vgetq_lane_s32(x, 2);
const int64_t q = n / (d | 0x5);

((int64_t*)&l1[idx1 & MASK])[0] = n ^ q;

if (VARIANT == xmrig::VARIANT_XHV) {
if (VARIANT == xmrig::VARIANT_XHV || ALGO == xmrig::CRYPTONIGHT_SUPERFAST) {
idx1 = (~d) ^ q;
}
else {
Expand Down
Loading