Skip to content

Commit

Permalink
update decrepit and abandoned equihash code to work with the latest g…
Browse files Browse the repository at this point in the history
…cc and node-gyp
  • Loading branch information
lilyannehall committed Nov 18, 2024
0 parents commit b195908
Show file tree
Hide file tree
Showing 19 changed files with 3,896 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build
node_modules
proof.log
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# equihash *modernized node.js native addon*

This package is a modern refactor of khovratovich/equihash, which has not seen updates since 2016. It borrows from digitalbazaar/equihash's native node.js addon, which has not been updated since 2017. This package reworks them to compile with the latest versions of node-gyp and g++.

## usage

```sh
npm install @tacticalchihuahua/equihash
```

```js
import { solve, verify } from '@tacticalchihuahua/equihash';
import { randomBytes } from 'crypto';

const N = 90;
const K = 5;

// example
async function demo() {
const seed = randomBytes(32);
const solution = await solve(seed, N, K);
const valid = await verify(solution.proof, solution.nonce, N, K);

console.log(solution); // {proof,nonce,n,k}
console.log(valid); // true/false
}
```

## recommended parameters ( N, K )

### For cryptocurrencies

* (100/110/120, 4)
* (108/114/120/126, 5)

### For client puzzles

* (60/70/80/90,4)
* (90/96/102,5)

## links

* [Original C++ implementation of equihash proof-of-work by khovratovich](https://github.com/khovratovich/equihash)
* [Original Native Node.js module by digitalbazaar](https://github.com/digitalbazaar/equihash)

## license

<p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><a property="dct:title" rel="cc:attributionURL" href="https://github.com/lilyannehall/equihash">@tacticalchihuahua/equihash</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://github.com/lilyannehall">Lily Anne Hall</a> is marked with <a href="https://creativecommons.org/publicdomain/zero/1.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC0 1.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/zero.svg?ref=chooser-v1" alt=""></a></p>
158 changes: 158 additions & 0 deletions addon.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#include <nan.h>

#include "pow.h" // NOLINT(build/include)

using Nan::AsyncQueueWorker;
using Nan::AsyncWorker;
using Nan::Callback;
using Nan::GetFunction;
using Nan::HandleScope;
using Nan::New;
using Nan::Null;
using Nan::Set;
using Nan::To;
using v8::Context;
using v8::Function;
using v8::FunctionTemplate;
using v8::Handle;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;

Nan::TryCatch try_catch;

class EquihashSolutionWorker : public AsyncWorker {
public:
EquihashSolutionWorker(const unsigned n, const unsigned k, _POW::Seed seed,
Callback* callback)
: AsyncWorker(callback), n(n), k(k), seed(seed) {}
~EquihashSolutionWorker() {}

// Executed inside the worker-thread.
// It is not safe to access V8, or V8 data structures
// here, so everything we need for input and output
// should go on `this`.
void Execute() {
_POW::Equihash equihash(n, k, seed);
_POW::Proof p = equihash.FindProof();
solution = p.inputs;
nonce = p.nonce;
// printhex("solution", &solution[0], solution.size());
}

// Executed when the async work is complete
// this function will be run inside the main event loop
// so it is safe to use V8 again
void HandleOKCallback() {
HandleScope scope;
Local<Object> proofValue =
Nan::CopyBuffer((const char*)&solution[0], solution.size() * 4)
.ToLocalChecked();

Local<Value> argv[] = {Null(), proofValue, New(nonce), New(n), New(k)};

callback->Call(5, argv);
}

private:
unsigned n;
unsigned k;
_POW::Nonce nonce;
_POW::Seed seed;
std::vector<_POW::Input> solution;
};

NAN_METHOD(Solve) {
// ensure first argument is an object
if (!info[0]->IsObject()) {
Nan::ThrowTypeError("'options' must be an object");
return;
}
// ensure second argument is a callback
if (!info[1]->IsFunction()) {
Nan::ThrowTypeError("'callback' must be a function");
return;
}

Handle<Object> object = Handle<Object>::Cast(info[0]);
Callback* callback = new Callback(info[1].As<Function>());

v8::Local<v8::String> k_str = Nan::New<v8::String>("k").ToLocalChecked();
v8::MaybeLocal<v8::Value> kValue = Nan::Get(object, k_str).ToLocalChecked();
v8::Local<v8::String> n_str = Nan::New<v8::String>("n").ToLocalChecked();
v8::MaybeLocal<v8::Value> nValue = Nan::Get(object, n_str);
v8::Local<v8::String> nonce_str =
Nan::New<v8::String>("nonce").ToLocalChecked();
v8::MaybeLocal<v8::Value> nonceValue = Nan::Get(object, nonce_str);
v8::Local<v8::String> seed_str =
Nan::New<v8::String>("seed").ToLocalChecked();
v8::MaybeLocal<v8::Value> seedValue = Nan::Get(object, seed_str);

const unsigned n = To<uint32_t>(nValue.ToLocalChecked()).FromJust();
const unsigned k = To<uint32_t>(kValue.ToLocalChecked()).FromJust();
size_t bufferLength = node::Buffer::Length(seedValue.ToLocalChecked()) / 4;
unsigned* seedBuffer =
(unsigned*)node::Buffer::Data(seedValue.ToLocalChecked());

_POW::Seed seed(seedBuffer, bufferLength);

AsyncQueueWorker(new EquihashSolutionWorker(n, k, seed, callback));
}

NAN_METHOD(Verify) {
// ensure first argument is an object
if (!info[0]->IsObject()) {
Nan::ThrowTypeError("'options' must be an object");
return;
}

Handle<Object> object = Handle<Object>::Cast(info[0]);

v8::Local<v8::String> k_str = Nan::New<v8::String>("k").ToLocalChecked();
Nan::MaybeLocal<v8::Value> kValue = Nan::Get(object, k_str);
v8::Local<v8::String> n_str = Nan::New<v8::String>("n").ToLocalChecked();
Nan::MaybeLocal<v8::Value> nValue = Nan::Get(object, n_str);
v8::Local<v8::String> nonce_str =
Nan::New<v8::String>("nonce").ToLocalChecked();
Nan::MaybeLocal<v8::Value> nonceValue = Nan::Get(object, nonce_str);
v8::Local<v8::String> seed_str =
Nan::New<v8::String>("seed").ToLocalChecked();
Nan::MaybeLocal<v8::Value> seedValue = Nan::Get(object, seed_str);
v8::Local<v8::String> value_str =
Nan::New<v8::String>("value").ToLocalChecked();
Nan::MaybeLocal<v8::Value> inputValue = Nan::Get(object, value_str);

const unsigned n = To<uint32_t>(nValue.ToLocalChecked()).FromJust();
const unsigned k = To<uint32_t>(kValue.ToLocalChecked()).FromJust();
const unsigned nonce = To<uint32_t>(nonceValue.ToLocalChecked()).FromJust();
size_t seedBufferLength =
node::Buffer::Length(seedValue.ToLocalChecked()) / 4;
unsigned* seedBuffer =
(unsigned*)node::Buffer::Data(seedValue.ToLocalChecked());
size_t inputBufferLength =
node::Buffer::Length(inputValue.ToLocalChecked()) / 4;
unsigned* inputBuffer =
(unsigned*)node::Buffer::Data(inputValue.ToLocalChecked());

// initialize the proof object
_POW::Seed seed(seedBuffer, seedBufferLength);
std::vector<_POW::Input> inputs;
inputs.resize(inputBufferLength, 0);
std::copy(inputBuffer, inputBuffer + inputBufferLength, inputs.begin());
_POW::Proof p(n, k, seed, nonce, inputs);

// check the proof
info.GetReturnValue().Set(p.Test());
}

NAN_MODULE_INIT(InitAll) {
Set(target, New<String>("solve").ToLocalChecked(),
GetFunction(New<FunctionTemplate>(Solve)).ToLocalChecked());
Set(target, New<String>("verify").ToLocalChecked(),
GetFunction(New<FunctionTemplate>(Verify)).ToLocalChecked());
}

NODE_MODULE(addon, InitAll)
9 changes: 9 additions & 0 deletions addon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef EQUIHASH_ADDON_H_
#define EQUIHASH_ADDON_H_

#include <nan.h>

NAN_METHOD(Solve);
NAN_METHOD(Verify);

#endif // EQUIHASH_KHOVRATOVICH_ADDON_H_
15 changes: 15 additions & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"targets": [
{
"target_name": "equihash",
"sources": [
"addon.cc",
"pow.cc",
"blake/blake2b.cpp"
],
"include_dirs": [
"<!(node -e \"require('nan')\")"
]
}
]
}
72 changes: 72 additions & 0 deletions blake/blake2-config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
BLAKE2 reference source code package - optimized C implementations
Written in 2012 by Samuel Neves <[email protected]>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#pragma once
#ifndef __BLAKE2_CONFIG_H__
#define __BLAKE2_CONFIG_H__

// These don't work everywhere
#if defined(__SSE2__)
#define HAVE_SSE2
#endif

#if defined(__SSSE3__)
#define HAVE_SSSE3
#endif

#if defined(__SSE4_1__)
#define HAVE_SSE41
#endif

#if defined(__AVX__)
#define HAVE_AVX
#endif

#if defined(__XOP__)
#define HAVE_XOP
#endif


#ifdef HAVE_AVX2
#ifndef HAVE_AVX
#define HAVE_AVX
#endif
#endif

#ifdef HAVE_XOP
#ifndef HAVE_AVX
#define HAVE_AVX
#endif
#endif

#ifdef HAVE_AVX
#ifndef HAVE_SSE41
#define HAVE_SSE41
#endif
#endif

#ifdef HAVE_SSE41
#ifndef HAVE_SSSE3
#define HAVE_SSSE3
#endif
#endif

#ifdef HAVE_SSSE3
#define HAVE_SSE2
#endif

#if !defined(HAVE_SSE2)
#error "This code requires at least SSE2."
#endif

#endif

Loading

0 comments on commit b195908

Please sign in to comment.