Skip to content

Commit 11f2d42

Browse files
committed
Added support for cryptonight light and the variant.
1 parent d5f8a1d commit 11f2d42

5 files changed

Lines changed: 77 additions & 16 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,5 @@ Credits
7979
* [bcrypt](http://en.wikipedia.org/wiki/Bcrypt) - Niels Provos and David Mazières
8080
* [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)
8181
* [PhearZero](https://github.com/PhearZero) Michael J Feher
82+
* [codebling](https://github.com/codebling) CodeBling
83+
* [Monero](https://github.com/monero-project/monero) The Monero Project

cryptonight.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121

2222
#define MEMORY (1 << 21) /* 2 MiB */
2323
#define ITER (1 << 20)
24+
#define MASK 0x1FFFF
25+
26+
#define LITE_MEMORY (1 << 20) /* 2 MiB */
27+
#define LITE_ITER (1 << 19)
28+
#define LITE_MASK 0xFFFF
29+
2430
#define AES_BLOCK_SIZE 16
2531
#define AES_KEY_SIZE 32 /*16*/
2632
#define INIT_SIZE_BLK 8
@@ -84,8 +90,8 @@ static void (* const extra_hashes[4])(const void *, size_t, char *) = {
8490
extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey);
8591
extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey);
8692

87-
static inline size_t e2i(const uint8_t* a) {
88-
return (*((uint64_t*) a) / AES_BLOCK_SIZE) & (MEMORY / AES_BLOCK_SIZE - 1);
93+
static inline size_t e2i(const uint8_t* a, size_t mask) {
94+
return (*((uint64_t*) a) / AES_BLOCK_SIZE) & mask;
8995
}
9096

9197
static void mul(const uint8_t* a, const uint8_t* b, uint8_t* res) {
@@ -151,18 +157,21 @@ struct cryptonight_ctx {
151157
oaes_ctx* aes_ctx;
152158
};
153159

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

162171
VARIANT1_INIT();
163172

164173
oaes_key_import_data(ctx->aes_ctx, ctx->aes_key, AES_KEY_SIZE);
165-
for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) {
174+
for (i = 0; i < memory / INIT_SIZE_BYTE; i++) {
166175
for (j = 0; j < INIT_SIZE_BLK; j++) {
167176
aesb_pseudo_round(&ctx->text[AES_BLOCK_SIZE * j],
168177
&ctx->text[AES_BLOCK_SIZE * j],
@@ -176,27 +185,27 @@ void cryptonight_hash(const char* input, char* output, uint32_t len, int variant
176185
ctx->b[i] = ctx->state.k[16 + i] ^ ctx->state.k[48 + i];
177186
}
178187

179-
for (i = 0; i < ITER / 2; i++) {
188+
for (i = 0; i < iterations / 2; i++) {
180189
/* Dependency chain: address -> read value ------+
181190
* written value <-+ hard function (AES or MUL) <+
182191
* next address <-+
183192
*/
184193
/* Iteration 1 */
185-
j = e2i(ctx->a);
194+
j = e2i(ctx->a, mask);
186195
aesb_single_round(&ctx->long_state[j * AES_BLOCK_SIZE], ctx->c, ctx->a);
187196
xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j * AES_BLOCK_SIZE]);
188197
VARIANT1_1((uint8_t*)&ctx->long_state[j * AES_BLOCK_SIZE]);
189198
/* Iteration 2 */
190199
mul_sum_xor_dst(ctx->c, ctx->a,
191-
&ctx->long_state[e2i(ctx->c) * AES_BLOCK_SIZE]);
200+
&ctx->long_state[e2i(ctx->c, mask) * AES_BLOCK_SIZE]);
192201
copy_block(ctx->b, ctx->c);
193202
VARIANT1_2((uint8_t*)
194-
&ctx->long_state[e2i(ctx->c) * AES_BLOCK_SIZE]);
203+
&ctx->long_state[e2i(ctx->c, mask) * AES_BLOCK_SIZE]);
195204
}
196205

197206
memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE);
198207
oaes_key_import_data(ctx->aes_ctx, &ctx->state.hs.b[32], AES_KEY_SIZE);
199-
for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) {
208+
for (i = 0; i < memory / INIT_SIZE_BYTE; i++) {
200209
for (j = 0; j < INIT_SIZE_BLK; j++) {
201210
xor_blocks(&ctx->text[j * AES_BLOCK_SIZE],
202211
&ctx->long_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]);

cryptonight.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ extern "C" {
77

88
#include <stdint.h>
99

10-
void cryptonight_hash(const char* input, char* output, uint32_t len, int variant);
10+
void cryptonight_hash(const char* input, char* output, uint32_t len, int variant, int lite);
1111
void cryptonight_fast_hash(const char* input, char* output, uint32_t len);
1212

1313
#ifdef __cplusplus

multihashing.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,47 @@ NAN_METHOD(cryptonight) {
403403
else {
404404
if (cn_variant > 0 && input_len < 43)
405405
return except("Argument must be 43 bytes for monero variant 1+");
406-
cryptonight_hash(input, output, input_len, cn_variant);
406+
cryptonight_hash(input, output, input_len, cn_variant, 0);
407+
}
408+
409+
info.GetReturnValue().Set(dest.ToLocalChecked());
410+
}
411+
412+
NAN_METHOD(cryptonightlite) {
413+
bool fast = false;
414+
uint32_t cn_variant = 0;
415+
416+
if (info.Length() < 1)
417+
return except("You must provide one argument.");
418+
419+
if (info.Length() >= 2) {
420+
if (info.Length() >= 2) {
421+
if(info[1]->IsBoolean())
422+
fast = info[1]->ToBoolean()->BooleanValue();
423+
else if(info[1]->IsUint32())
424+
cn_variant = info[1]->ToUint32()->Uint32Value();
425+
else
426+
return except("Argument 2 should be a boolean or uint32_t");
427+
}
428+
}
429+
430+
Local<Object> target = info[0]->ToObject();
431+
432+
if(!node::Buffer::HasInstance(target))
433+
return except("Argument should be a buffer object.");
434+
435+
char * input = node::Buffer::Data(target);
436+
Nan::MaybeLocal<v8::Object> dest = Nan::NewBuffer(32);
437+
char* output = node::Buffer::Data(dest.ToLocalChecked());
438+
439+
uint32_t input_len = node::Buffer::Length(target);
440+
441+
if(fast)
442+
cryptonight_fast_hash(input, output, input_len);
443+
else {
444+
if (cn_variant > 0 && input_len < 43)
445+
return except("Argument must be 43 bytes for aeon variant 1+");
446+
cryptonight_hash(input, output, input_len, cn_variant, 1);
407447
}
408448

409449
info.GetReturnValue().Set(dest.ToLocalChecked());
@@ -575,6 +615,8 @@ NAN_MODULE_INIT(Init) {
575615
GetFunction(New<FunctionTemplate>(shavite3)).ToLocalChecked());
576616
Nan::Set(target, New<String>("cryptonight").ToLocalChecked(),
577617
GetFunction(New<FunctionTemplate>(cryptonight)).ToLocalChecked());
618+
Nan::Set(target, New<String>("cryptonight-lite").ToLocalChecked(),
619+
GetFunction(New<FunctionTemplate>(cryptonightlite)).ToLocalChecked());
578620
Nan::Set(target, New<String>("x13").ToLocalChecked(),
579621
GetFunction(New<FunctionTemplate>(x13)).ToLocalChecked());
580622
Nan::Set(target, New<String>("boolberry").ToLocalChecked(),

tests/cryptonight-tests.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@ const multiHashing = require('../build/Release/multihashing');
22
const assert = require('assert');
33

44
var cn_data = new Buffer("6465206f6d6e69627573206475626974616e64756d", "hex");
5-
var cnv1_data = new Buffer("0100fb8e8ac805899323371bb790db19218afd8db8e3755d8b90f39b3d5506a9abce4fa912244500000000ee8146d49fa93ee724deb57d12cbc6c6f3b924d946127c7a97418f9348828f0f02", "hex");
5+
var xmrig_data = new Buffer("0100fb8e8ac805899323371bb790db19218afd8db8e3755d8b90f39b3d5506a9abce4fa912244500000000ee8146d49fa93ee724deb57d12cbc6c6f3b924d946127c7a97418f9348828f0f02", "hex");
66
var cn_hash = new Buffer("2f8e3df40bd11f9ac90c743ca8e32bb391da4fb98612aa3b6cdc639ee00b31f5", "hex");
7-
var cnv1_hash = new Buffer("c9fae8425d8688dc236bcdbc42fdb42d376c6ec190501aa84b04a4b4cf1ee122", "hex");
7+
var xmrig_cnvariant1_hash = new Buffer("c9fae8425d8688dc236bcdbc42fdb42d376c6ec190501aa84b04a4b4cf1ee122", "hex");
8+
var xmrig_cnlite_hash = new Buffer("28a22bad3f93d1408fca472eb5ad1cbe75f21d053c8ce5b3af105a57713e21dd", "hex");
9+
var xmrig_cnlitevariant1_hash = new Buffer("87c4e570653eb4c2b42b7a0d546559452dfab573b82ec52f152b7ff98e79446f", "hex");
810

911
hashedData = multiHashing['cryptonight'](cn_data);
10-
hashedData_v1 = multiHashing['cryptonight'](cnv1_data, 1);
12+
cn_variant1Data = multiHashing['cryptonight'](xmrig_data, 1);
13+
cnlite_data = multiHashing['cryptonight-lite'](xmrig_data, 0);
14+
cnlite_variant1Data = multiHashing['cryptonight-lite'](xmrig_data, 1);
1115

1216
console.log(hashedData);
13-
console.log(hashedData_v1);
17+
console.log(cn_variant1Data);
18+
console.log(cnlite_data);
19+
console.log(cnlite_variant1Data);
1420

1521
assert.deepEqual(hashedData, cn_hash);
16-
assert.deepEqual(hashedData_v1, cnv1_hash);
22+
assert.deepEqual(cn_variant1Data, xmrig_cnvariant1_hash);
23+
assert.deepEqual(cnlite_data, xmrig_cnlite_hash);
24+
assert.deepEqual(cnlite_variant1Data, xmrig_cnlitevariant1_hash);

0 commit comments

Comments
 (0)