@credithub/jurischain-node 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.gyp +14 -0
- package/index.d.ts +10 -0
- package/index.js +4 -0
- package/jurischain.h +254 -0
- package/main.cpp +141 -0
- package/package.json +52 -0
package/binding.gyp
ADDED
package/index.d.ts
ADDED
package/index.js
ADDED
package/jurischain.h
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#ifndef H_JURISCHAIN
|
|
2
|
+
#define H_JURISCHAIN
|
|
3
|
+
|
|
4
|
+
#define JURISCHAIN_VERSION "1.1.3"
|
|
5
|
+
|
|
6
|
+
#include <stdlib.h>
|
|
7
|
+
#include <stdint.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
|
|
10
|
+
#ifndef KECCAKF_ROUNDS
|
|
11
|
+
#define KECCAKF_ROUNDS 24
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
#ifndef ROTL64
|
|
15
|
+
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
#ifndef HASH_LEN
|
|
19
|
+
#define HASH_LEN 32
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Header-only library: every function has internal linkage (static inline)
|
|
24
|
+
* so the header can be #included in multiple translation units without
|
|
25
|
+
* causing duplicate-symbol errors at link time.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/* state context */
|
|
29
|
+
typedef struct {
|
|
30
|
+
union { /* state */
|
|
31
|
+
uint8_t b[200]; /* 8-bit bytes */
|
|
32
|
+
uint64_t q[25]; /* 64-bit words */
|
|
33
|
+
} st;
|
|
34
|
+
int pt, rsiz, mdlen; /* these don't overflow */
|
|
35
|
+
} sha3_ctx_t;
|
|
36
|
+
|
|
37
|
+
typedef struct {
|
|
38
|
+
uint8_t payload[HASH_LEN + 1];
|
|
39
|
+
uint8_t seed[HASH_LEN];
|
|
40
|
+
} jurischain_ctx_t;
|
|
41
|
+
|
|
42
|
+
/* Compression function */
|
|
43
|
+
static inline void sha3_keccakf(uint64_t st[25]) {
|
|
44
|
+
/* constants */
|
|
45
|
+
const uint64_t keccakf_rndc[24] = {
|
|
46
|
+
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
|
|
47
|
+
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
|
|
48
|
+
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
|
|
49
|
+
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
|
|
50
|
+
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
|
|
51
|
+
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
|
|
52
|
+
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
|
|
53
|
+
0x8000000000008080, 0x0000000080000001, 0x8000000080008008};
|
|
54
|
+
const int keccakf_rotc[24] = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
|
55
|
+
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44};
|
|
56
|
+
const int keccakf_piln[24] = {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
|
57
|
+
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1};
|
|
58
|
+
|
|
59
|
+
/* variables */
|
|
60
|
+
int i = 0, j = 0, r = 0;
|
|
61
|
+
uint64_t t = 0, bc[5] = {
|
|
62
|
+
0,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
|
|
66
|
+
uint8_t *v;
|
|
67
|
+
|
|
68
|
+
/* endianess conversion. this is redundant on little-endian targets */
|
|
69
|
+
for (i = 0; i < 25; i++) {
|
|
70
|
+
v = (uint8_t *)&st[i];
|
|
71
|
+
st[i] = ((uint64_t)v[0]) | (((uint64_t)v[1]) << 8) |
|
|
72
|
+
(((uint64_t)v[2]) << 16) | (((uint64_t)v[3]) << 24) |
|
|
73
|
+
(((uint64_t)v[4]) << 32) | (((uint64_t)v[5]) << 40) |
|
|
74
|
+
(((uint64_t)v[6]) << 48) | (((uint64_t)v[7]) << 56);
|
|
75
|
+
}
|
|
76
|
+
#endif
|
|
77
|
+
|
|
78
|
+
/* actual iteration */
|
|
79
|
+
for (r = 0; r < KECCAKF_ROUNDS; r++) {
|
|
80
|
+
/* Theta */
|
|
81
|
+
for (i = 0; i < 5; i++)
|
|
82
|
+
bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];
|
|
83
|
+
|
|
84
|
+
for (i = 0; i < 5; i++) {
|
|
85
|
+
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
|
|
86
|
+
for (j = 0; j < 25; j += 5) st[j + i] ^= t;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Rho Pi */
|
|
90
|
+
t = st[1];
|
|
91
|
+
for (i = 0; i < 24; i++) {
|
|
92
|
+
j = keccakf_piln[i];
|
|
93
|
+
bc[0] = st[j];
|
|
94
|
+
st[j] = ROTL64(t, keccakf_rotc[i]);
|
|
95
|
+
t = bc[0];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Chi */
|
|
99
|
+
for (j = 0; j < 25; j += 5) {
|
|
100
|
+
for (i = 0; i < 5; i++) bc[i] = st[j + i];
|
|
101
|
+
for (i = 0; i < 5; i++) st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Iota */
|
|
105
|
+
st[0] ^= keccakf_rndc[r];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
|
|
109
|
+
#error WebAssembly should be little endian
|
|
110
|
+
/* endianess conversion. this is redundant on little-endian targets */
|
|
111
|
+
for (i = 0; i < 25; i++) {
|
|
112
|
+
v = (uint8_t *)&st[i];
|
|
113
|
+
t = st[i];
|
|
114
|
+
v[0] = t & 0xFF;
|
|
115
|
+
v[1] = (t >> 8) & 0xFF;
|
|
116
|
+
v[2] = (t >> 16) & 0xFF;
|
|
117
|
+
v[3] = (t >> 24) & 0xFF;
|
|
118
|
+
v[4] = (t >> 32) & 0xFF;
|
|
119
|
+
v[5] = (t >> 40) & 0xFF;
|
|
120
|
+
v[6] = (t >> 48) & 0xFF;
|
|
121
|
+
v[7] = (t >> 56) & 0xFF;
|
|
122
|
+
}
|
|
123
|
+
#endif
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Initialize the context for SHA3 (mdlen = hash output in bytes) */
|
|
127
|
+
static inline int sha3_init(sha3_ctx_t *c, int mdlen) {
|
|
128
|
+
int i = 0;
|
|
129
|
+
|
|
130
|
+
for (i = 0; i < 25; i++) c->st.q[i] = 0;
|
|
131
|
+
c->mdlen = mdlen;
|
|
132
|
+
c->rsiz = 200 - 2 * mdlen;
|
|
133
|
+
c->pt = 0;
|
|
134
|
+
|
|
135
|
+
return 1;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* update state with more data */
|
|
139
|
+
static inline int sha3_update(sha3_ctx_t *c, const void *data, size_t len) {
|
|
140
|
+
size_t i = 0;
|
|
141
|
+
int j = 0;
|
|
142
|
+
|
|
143
|
+
j = c->pt;
|
|
144
|
+
for (i = 0; i < len; i++) {
|
|
145
|
+
c->st.b[j++] ^= ((const uint8_t *)data)[i];
|
|
146
|
+
if (j >= c->rsiz) {
|
|
147
|
+
sha3_keccakf(c->st.q);
|
|
148
|
+
j = 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
c->pt = j;
|
|
152
|
+
|
|
153
|
+
return 1;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* finalize and output a hash (digest goes to md) */
|
|
157
|
+
static inline int sha3_final(void *md, sha3_ctx_t *c) {
|
|
158
|
+
int i = 0;
|
|
159
|
+
|
|
160
|
+
c->st.b[c->pt] ^= 0x06;
|
|
161
|
+
c->st.b[c->rsiz - 1] ^= 0x80;
|
|
162
|
+
sha3_keccakf(c->st.q);
|
|
163
|
+
|
|
164
|
+
for (i = 0; i < c->mdlen; i++) {
|
|
165
|
+
((uint8_t *)md)[i] = c->st.b[i];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return 1;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* compute a SHA-3 hash (md) of given byte length from "in" */
|
|
172
|
+
static inline void *sha3(const void *in, size_t inlen, void *md, int mdlen) {
|
|
173
|
+
sha3_ctx_t sha3;
|
|
174
|
+
|
|
175
|
+
memset(&sha3, 0, sizeof(sha3));
|
|
176
|
+
|
|
177
|
+
sha3_init(&sha3, mdlen);
|
|
178
|
+
sha3_update(&sha3, in, inlen);
|
|
179
|
+
sha3_final(md, &sha3);
|
|
180
|
+
|
|
181
|
+
return md;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static inline void jurischain_gen(jurischain_ctx_t *challenge, uint8_t d, const void *seed, size_t inlen) {
|
|
185
|
+
uint8_t rand_hash[HASH_LEN] = { 0, };
|
|
186
|
+
if (!challenge || !seed || inlen == 0) return;
|
|
187
|
+
memset(challenge, 0, sizeof(jurischain_ctx_t));
|
|
188
|
+
sha3(seed, inlen, rand_hash, HASH_LEN);
|
|
189
|
+
memcpy(challenge->seed, rand_hash, sizeof(rand_hash));
|
|
190
|
+
memcpy(challenge->payload, rand_hash, sizeof(rand_hash));
|
|
191
|
+
challenge->payload[HASH_LEN] = d;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
static inline jurischain_ctx_t *jurischain_init(void) {
|
|
195
|
+
jurischain_ctx_t *ptr = (jurischain_ctx_t *)malloc(sizeof(jurischain_ctx_t));
|
|
196
|
+
if (ptr) memset(ptr, 0, sizeof(jurischain_ctx_t));
|
|
197
|
+
return ptr;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
static inline void jurischain_destroy(jurischain_ctx_t **ptr) {
|
|
201
|
+
if (!ptr || !*ptr) return;
|
|
202
|
+
memset(*ptr, 0, sizeof(jurischain_ctx_t));
|
|
203
|
+
free(*ptr);
|
|
204
|
+
*ptr = NULL;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
static inline int jurischain_verify(jurischain_ctx_t *challenge) {
|
|
208
|
+
uint8_t hash_concat[HASH_LEN * 2] = { 0, },
|
|
209
|
+
response[HASH_LEN] = { 0, };
|
|
210
|
+
uint64_t res64[HASH_LEN / 8] = { 0, };
|
|
211
|
+
uint64_t mask = 0, valid = 1, i = 0;
|
|
212
|
+
uint8_t d = 0;
|
|
213
|
+
|
|
214
|
+
if (!challenge) return 0;
|
|
215
|
+
|
|
216
|
+
memcpy(hash_concat, challenge->seed, HASH_LEN);
|
|
217
|
+
memcpy(&hash_concat[HASH_LEN], challenge->payload, HASH_LEN);
|
|
218
|
+
|
|
219
|
+
d = challenge->payload[HASH_LEN];
|
|
220
|
+
|
|
221
|
+
sha3(hash_concat, HASH_LEN * 2, response, HASH_LEN);
|
|
222
|
+
|
|
223
|
+
/*
|
|
224
|
+
* Interpret the digest as little-endian 64-bit words. memcpy avoids the
|
|
225
|
+
* strict-aliasing and unaligned-access undefined behaviour that a raw
|
|
226
|
+
* (uint64_t *) cast over a byte buffer would introduce. WebAssembly and
|
|
227
|
+
* all supported native targets are little-endian.
|
|
228
|
+
*/
|
|
229
|
+
memcpy(res64, response, HASH_LEN);
|
|
230
|
+
|
|
231
|
+
/* check that the first `d` bits are zero */
|
|
232
|
+
for (i = 0; i < (d / 64u); i++)
|
|
233
|
+
if (res64[i] != 0) valid = 0;
|
|
234
|
+
|
|
235
|
+
if ((d % 64u) != 0) {
|
|
236
|
+
/* guard: shifting a 64-bit value by 64 is undefined behaviour, so this
|
|
237
|
+
* mask is only ever computed when (d % 64) is in the range 1..63 */
|
|
238
|
+
mask = (uint64_t)0xFFFFFFFFFFFFFFFFULL >> (64u - (d % 64u));
|
|
239
|
+
if ((res64[d / 64u] & mask) != 0) valid = 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return (int)valid;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
static inline int jurischain_try(jurischain_ctx_t *challenge) {
|
|
246
|
+
uint8_t rand_hash[HASH_LEN] = { 0, };
|
|
247
|
+
if (!challenge) return 0;
|
|
248
|
+
sha3(challenge->seed, HASH_LEN, rand_hash, HASH_LEN);
|
|
249
|
+
memcpy(challenge->seed, rand_hash, HASH_LEN);
|
|
250
|
+
|
|
251
|
+
return jurischain_verify(challenge);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
#endif
|
package/main.cpp
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#include <cstdint>
|
|
2
|
+
#include <cstdio>
|
|
3
|
+
#include <cstring>
|
|
4
|
+
#include <nan.h>
|
|
5
|
+
|
|
6
|
+
#include "jurischain.h"
|
|
7
|
+
|
|
8
|
+
class Jurischain : public Nan::ObjectWrap {
|
|
9
|
+
public:
|
|
10
|
+
static NAN_MODULE_INIT(Init) {
|
|
11
|
+
v8::Local<v8::FunctionTemplate> ctor =
|
|
12
|
+
Nan::New<v8::FunctionTemplate>(Jurischain::New);
|
|
13
|
+
static Nan::Persistent<v8::Function> constructor;
|
|
14
|
+
|
|
15
|
+
ctor->SetClassName(Nan::New("Jurischain").ToLocalChecked());
|
|
16
|
+
ctor->InstanceTemplate()->SetInternalFieldCount(1);
|
|
17
|
+
|
|
18
|
+
Nan::SetPrototypeMethod(ctor, "challengeResponse", Define);
|
|
19
|
+
Nan::SetPrototypeMethod(ctor, "readChallenge", Retrieve);
|
|
20
|
+
Nan::SetPrototypeMethod(ctor, "solveStep", Solve);
|
|
21
|
+
Nan::SetPrototypeMethod(ctor, "verify", Verify);
|
|
22
|
+
|
|
23
|
+
constructor.Reset(Nan::GetFunction(ctor).ToLocalChecked());
|
|
24
|
+
Nan::Set(target, Nan::New("Jurischain").ToLocalChecked(),
|
|
25
|
+
Nan::GetFunction(ctor).ToLocalChecked());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private:
|
|
29
|
+
jurischain_ctx_t context;
|
|
30
|
+
|
|
31
|
+
explicit Jurischain(uint8_t d, const void *seed, size_t inlen) {
|
|
32
|
+
std::memset(&context, 0, sizeof(context));
|
|
33
|
+
jurischain_gen(&context, d, seed, inlen);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
~Jurischain() {
|
|
37
|
+
std::memset(&context, 0, sizeof(context));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static NAN_METHOD(New) {
|
|
41
|
+
if (!info.IsConstructCall()) {
|
|
42
|
+
return Nan::ThrowError("Jurischain must be called with the new keyword");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (info.Length() < 2) {
|
|
46
|
+
return Nan::ThrowTypeError("expected 2 arguments: difficulty (number) and seed (string)");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!info[0]->IsNumber()) {
|
|
50
|
+
return Nan::ThrowTypeError("difficulty must be a number");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
double rawDifficulty = Nan::To<double>(info[0]).FromMaybe(0.0);
|
|
54
|
+
|
|
55
|
+
if (rawDifficulty != static_cast<int>(rawDifficulty)) {
|
|
56
|
+
return Nan::ThrowTypeError("difficulty must be an integer");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (rawDifficulty < 1 || rawDifficulty > 255) {
|
|
60
|
+
return Nan::ThrowRangeError("difficulty must be between 1 and 255");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!info[1]->IsString()) {
|
|
64
|
+
return Nan::ThrowTypeError("seed must be a string");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Nan::Utf8String seed(info[1]);
|
|
68
|
+
|
|
69
|
+
if (seed.length() <= 0 || *seed == nullptr) {
|
|
70
|
+
return Nan::ThrowTypeError("seed must be a non-empty string");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
uint8_t difficulty = static_cast<uint8_t>(rawDifficulty);
|
|
74
|
+
Jurischain *obj = new Jurischain(difficulty,
|
|
75
|
+
static_cast<const void *>(*seed), seed.length());
|
|
76
|
+
obj->Wrap(info.This());
|
|
77
|
+
info.GetReturnValue().Set(info.This());
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static NAN_METHOD(Verify) {
|
|
81
|
+
Jurischain *obj = Nan::ObjectWrap::Unwrap<Jurischain>(info.This());
|
|
82
|
+
info.GetReturnValue().Set(
|
|
83
|
+
Nan::New<v8::Boolean>(jurischain_verify(&obj->context) != 0));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static NAN_METHOD(Solve) {
|
|
87
|
+
Jurischain *obj = Nan::ObjectWrap::Unwrap<Jurischain>(info.This());
|
|
88
|
+
info.GetReturnValue().Set(
|
|
89
|
+
Nan::New<v8::Boolean>(jurischain_try(&obj->context) != 0));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static NAN_METHOD(Define) {
|
|
93
|
+
if (info.Length() < 1) {
|
|
94
|
+
return Nan::ThrowTypeError("expected 1 argument: hex response string");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!info[0]->IsString()) {
|
|
98
|
+
return Nan::ThrowTypeError("response must be a string");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Nan::Utf8String response(info[0]);
|
|
102
|
+
const int expectedLen = HASH_LEN * 2;
|
|
103
|
+
|
|
104
|
+
if (response.length() != expectedLen) {
|
|
105
|
+
return Nan::ThrowRangeError(
|
|
106
|
+
"response must be exactly 64 hex characters");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const char *hex = *response;
|
|
110
|
+
if (hex == nullptr) {
|
|
111
|
+
return Nan::ThrowTypeError("response string is invalid");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
Jurischain *obj = Nan::ObjectWrap::Unwrap<Jurischain>(info.This());
|
|
115
|
+
|
|
116
|
+
for (size_t i = 0; i < HASH_LEN; i++) {
|
|
117
|
+
if (std::sscanf(hex + (i * 2), "%02hhX", &obj->context.seed[i]) != 1) {
|
|
118
|
+
std::memset(obj->context.seed, 0, HASH_LEN);
|
|
119
|
+
char errmsg[64];
|
|
120
|
+
std::snprintf(errmsg, sizeof(errmsg),
|
|
121
|
+
"response contains invalid hex at position %zu", i * 2);
|
|
122
|
+
return Nan::ThrowError(errmsg);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
info.GetReturnValue().Set(Nan::New<v8::Boolean>(true));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static NAN_METHOD(Retrieve) {
|
|
130
|
+
Jurischain *obj = Nan::ObjectWrap::Unwrap<Jurischain>(info.This());
|
|
131
|
+
|
|
132
|
+
char str[(HASH_LEN * 2) + 1] = { 0 };
|
|
133
|
+
for (int i = 0; i < HASH_LEN; i++) {
|
|
134
|
+
std::snprintf(str + (i * 2), 3, "%02hhX", obj->context.seed[i]);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
info.GetReturnValue().Set(Nan::New(str).ToLocalChecked());
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
NODE_MODULE(Jurischain, Jurischain::Init);
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@credithub/jurischain-node",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Native Node.js binding for JurisChain Proof-of-Work CAPTCHA. Challenges terminals instead of humans to mitigate DDoS attacks.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"require": "./index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"index.js",
|
|
15
|
+
"index.d.ts",
|
|
16
|
+
"main.cpp",
|
|
17
|
+
"jurischain.h",
|
|
18
|
+
"binding.gyp"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"prepack": "node -e \"require('fs').copyFileSync('../../include/jurischain.h','jurischain.h')\"",
|
|
22
|
+
"install": "node-gyp rebuild",
|
|
23
|
+
"rebuild": "node-gyp rebuild",
|
|
24
|
+
"test": "node -e \"const { Jurischain } = require('.'); const j = new Jurischain(1, 'test'); console.log('OK:', j.readChallenge());\""
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/credithub/jurischain.git"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"captcha",
|
|
32
|
+
"proof-of-work",
|
|
33
|
+
"sha3",
|
|
34
|
+
"blockchain"
|
|
35
|
+
],
|
|
36
|
+
"author": "CreditHub <tech@credithub.com.br>",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/credithub/jurischain/issues"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=14.0.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"bindings": "^1.5.0",
|
|
46
|
+
"nan": "^2.19.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"node-gyp": "^10.0.0"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/credithub/jurischain#readme"
|
|
52
|
+
}
|