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

changes by sumlnoether #2

Open
wants to merge 7 commits into
base: windows-compatibility
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
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ Algorithms
Usage
-----

Install
Install on Ubuntu 16.04

```bash
npm install multi-hashing
sudo apt-get nodejs nodejs-dev node-gyp npm
sudo ln -s /usr/bin/nodejs /usr/bin/node
npm install git+https://github.com/sumlnoether/node-multi-hashing-node8.git
```

So far this native Node.js addon can do the following hashing algos
Expand Down Expand Up @@ -79,3 +81,5 @@ Credits
* [bcrypt](http://en.wikipedia.org/wiki/Bcrypt) - Niels Provos and David Mazières
* [X11](http://www.darkcoin.io/), [Hefty1](http://heavycoin.github.io/about.html), [Quark](http://www.qrk.cc/) creators (they just mixed together a bunch of the above algos)
* [PhearZero](https://github.com/PhearZero) Michael J Feher
* [codebling](https://github.com/codebling) CodeBling
* [Monero](https://github.com/monero-project/monero) The Monero Project
57 changes: 49 additions & 8 deletions cryptonight.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// Portions Copyright (c) 2018 The Monero developers

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "crypto/oaes_lib.h"
#include "crypto/c_keccak.h"
#include "crypto/c_groestl.h"
Expand All @@ -17,11 +21,40 @@

#define MEMORY (1 << 21) /* 2 MiB */
#define ITER (1 << 20)
#define MASK 0x1FFFF

#define LITE_MEMORY (1 << 20) /* 2 MiB */
#define LITE_ITER (1 << 19)
#define LITE_MASK 0xFFFF

#define AES_BLOCK_SIZE 16
#define AES_KEY_SIZE 32 /*16*/
#define INIT_SIZE_BLK 8
#define INIT_SIZE_BYTE (INIT_SIZE_BLK * AES_BLOCK_SIZE)

#define VARIANT1_1(p) \
do if (variant > 0) \
{ \
const uint8_t tmp = ((const uint8_t*)(p))[11]; \
static const uint32_t table = 0x75310; \
const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \
((uint8_t*)(p))[11] = tmp ^ ((table >> index) & 0x30); \
} while(0)

#define VARIANT1_2(p) \
do if (variant > 0) \
{ \
((uint64_t*)p)[1] ^= tweak1_2; \
} while(0)

#define VARIANT1_INIT() \
if (variant > 0 && len < 43) \
{ \
fprintf(stderr, "Cryptonight variants need at least 43 bytes of data"); \
_exit(1); \
} \
const uint64_t tweak1_2 = variant > 0 ? *(const uint64_t*)(((const uint8_t*)input)+35) ^ ctx->state.hs.w[24] : 0

#pragma pack(push, 1)
union cn_slow_hash_state {
union hash_state hs;
Expand Down Expand Up @@ -57,8 +90,8 @@ static void (* const extra_hashes[4])(const void *, size_t, char *) = {
extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey);
extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey);

static inline size_t e2i(const uint8_t* a) {
return (*((uint64_t*) a) / AES_BLOCK_SIZE) & (MEMORY / AES_BLOCK_SIZE - 1);
static inline size_t e2i(const uint8_t* a, size_t mask) {
return (*((uint64_t*) a) / AES_BLOCK_SIZE) & mask;
}

static void mul(const uint8_t* a, const uint8_t* b, uint8_t* res) {
Expand Down Expand Up @@ -124,16 +157,21 @@ struct cryptonight_ctx {
oaes_ctx* aes_ctx;
};

void cryptonight_hash(const char* input, char* output, uint32_t len) {
void cryptonight_hash(const char* input, char* output, uint32_t len, int variant, int lite) {
struct cryptonight_ctx *ctx = alloca(sizeof(struct cryptonight_ctx));
hash_process(&ctx->state.hs, (const uint8_t*) input, len);
memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE);
memcpy(ctx->aes_key, ctx->state.hs.b, AES_KEY_SIZE);
ctx->aes_ctx = (oaes_ctx*) oaes_alloc();
size_t i, j;
size_t memory = lite ? LITE_MEMORY : MEMORY;
size_t iterations = lite ? LITE_ITER : ITER;
size_t mask = lite ? LITE_MASK : MASK;

VARIANT1_INIT();

oaes_key_import_data(ctx->aes_ctx, ctx->aes_key, AES_KEY_SIZE);
for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) {
for (i = 0; i < memory / INIT_SIZE_BYTE; i++) {
for (j = 0; j < INIT_SIZE_BLK; j++) {
aesb_pseudo_round(&ctx->text[AES_BLOCK_SIZE * j],
&ctx->text[AES_BLOCK_SIZE * j],
Expand All @@ -147,24 +185,27 @@ void cryptonight_hash(const char* input, char* output, uint32_t len) {
ctx->b[i] = ctx->state.k[16 + i] ^ ctx->state.k[48 + i];
}

for (i = 0; i < ITER / 2; i++) {
for (i = 0; i < iterations / 2; i++) {
/* Dependency chain: address -> read value ------+
* written value <-+ hard function (AES or MUL) <+
* next address <-+
*/
/* Iteration 1 */
j = e2i(ctx->a);
j = e2i(ctx->a, mask);
aesb_single_round(&ctx->long_state[j * AES_BLOCK_SIZE], ctx->c, ctx->a);
xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j * AES_BLOCK_SIZE]);
VARIANT1_1((uint8_t*)&ctx->long_state[j * AES_BLOCK_SIZE]);
/* Iteration 2 */
mul_sum_xor_dst(ctx->c, ctx->a,
&ctx->long_state[e2i(ctx->c) * AES_BLOCK_SIZE]);
&ctx->long_state[e2i(ctx->c, mask) * AES_BLOCK_SIZE]);
copy_block(ctx->b, ctx->c);
VARIANT1_2((uint8_t*)
&ctx->long_state[e2i(ctx->c, mask) * AES_BLOCK_SIZE]);
}

memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE);
oaes_key_import_data(ctx->aes_ctx, &ctx->state.hs.b[32], AES_KEY_SIZE);
for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) {
for (i = 0; i < memory / INIT_SIZE_BYTE; i++) {
for (j = 0; j < INIT_SIZE_BLK; j++) {
xor_blocks(&ctx->text[j * AES_BLOCK_SIZE],
&ctx->long_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]);
Expand Down
2 changes: 1 addition & 1 deletion cryptonight.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extern "C" {

#include <stdint.h>

void cryptonight_hash(const char* input, char* output, uint32_t len);
void cryptonight_hash(const char* input, char* output, uint32_t len, int variant, int lite);
void cryptonight_fast_hash(const char* input, char* output, uint32_t len);

#ifdef __cplusplus
Expand Down
93 changes: 72 additions & 21 deletions multihashing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extern "C" {
#include "cryptonight.h"
#include "x13.h"
#include "nist5.h"
#include "sha1.h",
#include "sha1.h"
#include "x15.h"
#include "fresh.h"
}
Expand Down Expand Up @@ -49,7 +49,7 @@ NAN_METHOD(quark) {
char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

quark_hash(input, output, input_len);
Expand Down Expand Up @@ -86,18 +86,18 @@ NAN_METHOD(scrypt) {

if(!node::Buffer::HasInstance(target))
return except("Argument should be a buffer object.");

Local<Number> numn = info[1]->ToNumber();
unsigned int nValue = numn->Value();
Local<Number> numr = info[2]->ToNumber();
unsigned int rValue = numr->Value();

char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

scrypt_N_R_1_256(input, output, nValue, rValue, input_len);

info.GetReturnValue().Set(dest.ToLocalChecked());
Expand Down Expand Up @@ -216,7 +216,7 @@ NAN_METHOD(skein) {
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

skein_hash(input, output, input_len);

info.GetReturnValue().Set(dest.ToLocalChecked());
Expand All @@ -235,7 +235,7 @@ NAN_METHOD(groestl) {
char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

groestl_hash(input, output, input_len);
Expand All @@ -256,7 +256,7 @@ NAN_METHOD(groestlmyriad) {
char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

groestlmyriad_hash(input, output, input_len);
Expand All @@ -277,7 +277,7 @@ NAN_METHOD(blake) {
char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

blake_hash(input, output, input_len);
Expand All @@ -298,7 +298,7 @@ NAN_METHOD(fugue) {
char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

fugue_hash(input, output, input_len);
Expand All @@ -319,7 +319,7 @@ NAN_METHOD(qubit) {
char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

qubit_hash(input, output, input_len);
Expand All @@ -340,7 +340,7 @@ NAN_METHOD(hefty1) {
char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

hefty1_hash(input, output, input_len);
Expand All @@ -361,7 +361,7 @@ NAN_METHOD(shavite3) {
char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

shavite3_hash(input, output, input_len);
Expand All @@ -371,14 +371,60 @@ NAN_METHOD(shavite3) {

NAN_METHOD(cryptonight) {
bool fast = false;
uint32_t cn_variant = 0;

if (info.Length() < 1)
return except("You must provide one argument.");

if (info.Length() >= 2) {
if (info.Length() >= 2) {
if(info[1]->IsBoolean())
fast = info[1]->ToBoolean()->BooleanValue();
else if(info[1]->IsUint32())
cn_variant = info[1]->ToUint32()->Uint32Value();
else
return except("Argument 2 should be a boolean or uint32_t");
}
}

Local<Object> target = info[0]->ToObject();

if(!node::Buffer::HasInstance(target))
return except("Argument should be a buffer object.");

char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

if(fast)
cryptonight_fast_hash(input, output, input_len);
else {
if (cn_variant > 0 && input_len < 43)
return except("Argument must be 43 bytes for monero variant 1+");
cryptonight_hash(input, output, input_len, cn_variant, 0);
}

info.GetReturnValue().Set(dest.ToLocalChecked());
}

NAN_METHOD(cryptonightlite) {
bool fast = false;
uint32_t cn_variant = 0;

if (info.Length() < 1)
return except("You must provide one argument.");

if (info.Length() >= 2) {
if(!info[1]->IsBoolean())
return except("Argument 2 should be a boolean");
fast = info[1]->ToBoolean()->BooleanValue();
if (info.Length() >= 2) {
if(info[1]->IsBoolean())
fast = info[1]->ToBoolean()->BooleanValue();
else if(info[1]->IsUint32())
cn_variant = info[1]->ToUint32()->Uint32Value();
else
return except("Argument 2 should be a boolean or uint32_t");
}
}

Local<Object> target = info[0]->ToObject();
Expand All @@ -389,13 +435,16 @@ NAN_METHOD(cryptonight) {
char * input = node::Buffer::Data(target);
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
char* output = node::Buffer::Data(dest.ToLocalChecked());

uint32_t input_len = node::Buffer::Length(target);

if(fast)
cryptonight_fast_hash(input, output, input_len);
else
cryptonight_hash(input, output, input_len);
else {
if (cn_variant > 0 && input_len < 43)
return except("Argument must be 43 bytes for aeon variant 1+");
cryptonight_hash(input, output, input_len, cn_variant, 1);
}

info.GetReturnValue().Set(dest.ToLocalChecked());
}
Expand Down Expand Up @@ -566,6 +615,8 @@ NAN_MODULE_INIT(Init) {
GetFunction(New<FunctionTemplate>(shavite3)).ToLocalChecked());
Nan::Set(target, New<String>("cryptonight").ToLocalChecked(),
GetFunction(New<FunctionTemplate>(cryptonight)).ToLocalChecked());
Nan::Set(target, New<String>("cryptonight-lite").ToLocalChecked(),
GetFunction(New<FunctionTemplate>(cryptonightlite)).ToLocalChecked());
Nan::Set(target, New<String>("x13").ToLocalChecked(),
GetFunction(New<FunctionTemplate>(x13)).ToLocalChecked());
Nan::Set(target, New<String>("boolberry").ToLocalChecked(),
Expand All @@ -581,4 +632,4 @@ NAN_MODULE_INIT(Init) {
}

NODE_MODULE(multihashing, Init)
}
}
24 changes: 24 additions & 0 deletions tests/cryptonight-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const multiHashing = require('../build/Release/multihashing');
const assert = require('assert');

var cn_data = new Buffer("6465206f6d6e69627573206475626974616e64756d", "hex");
var xmrig_data = new Buffer("0100fb8e8ac805899323371bb790db19218afd8db8e3755d8b90f39b3d5506a9abce4fa912244500000000ee8146d49fa93ee724deb57d12cbc6c6f3b924d946127c7a97418f9348828f0f02", "hex");
var cn_hash = new Buffer("2f8e3df40bd11f9ac90c743ca8e32bb391da4fb98612aa3b6cdc639ee00b31f5", "hex");
var xmrig_cnvariant1_hash = new Buffer("c9fae8425d8688dc236bcdbc42fdb42d376c6ec190501aa84b04a4b4cf1ee122", "hex");
var xmrig_cnlite_hash = new Buffer("28a22bad3f93d1408fca472eb5ad1cbe75f21d053c8ce5b3af105a57713e21dd", "hex");
var xmrig_cnlitevariant1_hash = new Buffer("87c4e570653eb4c2b42b7a0d546559452dfab573b82ec52f152b7ff98e79446f", "hex");

hashedData = multiHashing['cryptonight'](cn_data);
cn_variant1Data = multiHashing['cryptonight'](xmrig_data, 1);
cnlite_data = multiHashing['cryptonight-lite'](xmrig_data, 0);
cnlite_variant1Data = multiHashing['cryptonight-lite'](xmrig_data, 1);

console.log(hashedData);
console.log(cn_variant1Data);
console.log(cnlite_data);
console.log(cnlite_variant1Data);

assert.deepEqual(hashedData, cn_hash);
assert.deepEqual(cn_variant1Data, xmrig_cnvariant1_hash);
assert.deepEqual(cnlite_data, xmrig_cnlite_hash);
assert.deepEqual(cnlite_variant1Data, xmrig_cnlitevariant1_hash);
Loading