Skip to content

Commit 979d870

Browse files
authored
Update secp256k1 (support custom function for ECDH) (#137)
* Update secp256k1 to e34ceb3 * Move system include to end of list (#135) * Fix linting issues * Add preprocessor coditions for depricated V8 methods
1 parent 25a4b6c commit 979d870

9 files changed

Lines changed: 45 additions & 131 deletions

File tree

benchmarks/ecdsa.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use strict'
2-
var assert = require('assert')
2+
var assert = require('assert').strict
33
var BigInteger = require('bigi')
44
var ecdsa = require('ecdsa')
55
var ecurve = require('ecurve')

binding.gyp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,21 @@
2424
"./src/secp256k1-src/contrib/lax_der_privatekey_parsing.c"
2525
],
2626
"include_dirs": [
27-
"/usr/local/include",
2827
"./src/secp256k1-src",
2928
"./src/secp256k1-src/contrib",
3029
"./src/secp256k1-src/include",
3130
"./src/secp256k1-src/src",
32-
"<!(node -e \"require('nan')\")"
31+
"<!(node -e \"require('nan')\")",
32+
"/usr/local/include"
3333
],
3434
"defines": [
35+
"ENABLE_MODULE_ECDH=1",
3536
"ENABLE_MODULE_RECOVERY=1"
3637
],
3738
"cflags": [
3839
"-Wall",
3940
"-Wno-maybe-uninitialized",
41+
"-Wno-nonnull-compare",
4042
"-Wno-uninitialized",
4143
"-Wno-unused-function",
4244
"-Wextra"

lib/elliptic/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ exports.sign = function (message, privateKey, noncefn, data) {
214214
}
215215

216216
exports.verify = function (message, signature, publicKey) {
217-
var sigObj = {r: signature.slice(0, 32), s: signature.slice(32, 64)}
217+
var sigObj = { r: signature.slice(0, 32), s: signature.slice(32, 64) }
218218

219219
var sigr = new BN(sigObj.r)
220220
var sigs = new BN(sigObj.s)
@@ -224,11 +224,11 @@ exports.verify = function (message, signature, publicKey) {
224224
var pair = loadPublicKey(publicKey)
225225
if (pair === null) throw new Error(messages.EC_PUBLIC_KEY_PARSE_FAIL)
226226

227-
return ec.verify(message, sigObj, {x: pair.pub.x, y: pair.pub.y})
227+
return ec.verify(message, sigObj, { x: pair.pub.x, y: pair.pub.y })
228228
}
229229

230230
exports.recover = function (message, signature, recovery, compressed) {
231-
var sigObj = {r: signature.slice(0, 32), s: signature.slice(32, 64)}
231+
var sigObj = { r: signature.slice(0, 32), s: signature.slice(32, 64) }
232232

233233
var sigr = new BN(sigObj.r)
234234
var sigs = new BN(sigObj.s)

src/ecdh.cc

Lines changed: 11 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,13 @@
11
#include <node.h>
22
#include <nan.h>
33
#include <secp256k1.h>
4-
#include <util.h>
5-
#include <field_impl.h>
6-
#include <scalar_impl.h>
7-
#include <group_impl.h>
8-
#include <ecmult_const_impl.h>
9-
#include <ecmult_gen_impl.h>
4+
#include <secp256k1_ecdh.h>
105

116
#include "messages.h"
127
#include "util.h"
138

149
extern secp256k1_context* secp256k1ctx;
1510

16-
// from bitcoin/secp256k1
17-
#define ARG_CHECK(cond) do { \
18-
if (EXPECT(!(cond), 0)) { \
19-
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
20-
return 0; \
21-
} \
22-
} while(0)
23-
24-
static void default_illegal_callback_fn(const char* str, void* data) {
25-
(void)data;
26-
fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str);
27-
abort();
28-
}
29-
30-
static const secp256k1_callback default_illegal_callback = {
31-
default_illegal_callback_fn,
32-
NULL
33-
};
34-
35-
static void default_error_callback_fn(const char* str, void* data) {
36-
(void)data;
37-
fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str);
38-
abort();
39-
}
40-
41-
static const secp256k1_callback default_error_callback = {
42-
default_error_callback_fn,
43-
NULL
44-
};
45-
46-
struct secp256k1_context_struct {
47-
secp256k1_ecmult_context ecmult_ctx;
48-
secp256k1_ecmult_gen_context ecmult_gen_ctx;
49-
secp256k1_callback illegal_callback;
50-
secp256k1_callback error_callback;
51-
};
52-
53-
int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
54-
if (sizeof(secp256k1_ge_storage) == 64) {
55-
/* When the secp256k1_ge_storage type is exactly 64 byte, use its
56-
* representation inside secp256k1_pubkey, as conversion is very fast.
57-
* Note that secp256k1_pubkey_save must use the same representation. */
58-
secp256k1_ge_storage s;
59-
memcpy(&s, &pubkey->data[0], 64);
60-
secp256k1_ge_from_storage(ge, &s);
61-
} else {
62-
/* Otherwise, fall back to 32-byte big endian for X and Y. */
63-
secp256k1_fe x, y;
64-
secp256k1_fe_set_b32(&x, pubkey->data);
65-
secp256k1_fe_set_b32(&y, pubkey->data + 32);
66-
secp256k1_ge_set_xy(ge, &x, &y);
67-
}
68-
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
69-
return 1;
70-
}
71-
72-
void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
73-
if (sizeof(secp256k1_ge_storage) == 64) {
74-
secp256k1_ge_storage s;
75-
secp256k1_ge_to_storage(&s, ge);
76-
memcpy(&pubkey->data[0], &s, 64);
77-
} else {
78-
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
79-
secp256k1_fe_normalize_var(&ge->x);
80-
secp256k1_fe_normalize_var(&ge->y);
81-
secp256k1_fe_get_b32(pubkey->data, &ge->x);
82-
secp256k1_fe_get_b32(pubkey->data + 32, &ge->y);
83-
}
84-
}
85-
86-
// bindings
8711
NAN_METHOD(ecdh) {
8812
Nan::HandleScope scope;
8913

@@ -103,40 +27,20 @@ NAN_METHOD(ecdh) {
10327
return Nan::ThrowError(EC_PUBLIC_KEY_PARSE_FAIL);
10428
}
10529

106-
secp256k1_scalar s;
107-
int overflow = 0;
108-
secp256k1_scalar_set_b32(&s, private_key, &overflow);
109-
if (overflow || secp256k1_scalar_is_zero(&s)) {
110-
secp256k1_scalar_clear(&s);
30+
unsigned char output[32];
31+
if (secp256k1_ecdh(secp256k1ctx, &output[0], &public_key, private_key, secp256k1_ecdh_hash_function_sha256, NULL) == 0) {
11132
return Nan::ThrowError(ECDH_FAIL);
11233
}
11334

114-
secp256k1_ge pt;
115-
secp256k1_gej res;
116-
unsigned char y[1];
117-
unsigned char x[32];
118-
secp256k1_sha256_t sha;
119-
unsigned char output[32];
120-
121-
secp256k1_pubkey_load(secp256k1ctx, &pt, &public_key);
122-
secp256k1_ecmult_const(&res, &pt, &s);
123-
secp256k1_scalar_clear(&s);
124-
125-
secp256k1_ge_set_gej(&pt, &res);
126-
secp256k1_fe_normalize(&pt.y);
127-
secp256k1_fe_normalize(&pt.x);
128-
129-
y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);
130-
secp256k1_fe_get_b32(&x[0], &pt.x);
131-
132-
secp256k1_sha256_initialize(&sha);
133-
secp256k1_sha256_write(&sha, y, sizeof(y));
134-
secp256k1_sha256_write(&sha, x, sizeof(x));
135-
secp256k1_sha256_finalize(&sha, &output[0]);
136-
13735
info.GetReturnValue().Set(COPY_BUFFER(&output[0], 32));
13836
}
13937

38+
int ecdh_hash_function_unsafe(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
39+
memcpy(output, x, 32);
40+
memcpy(output + 32, y, 32);
41+
return 1;
42+
}
43+
14044
NAN_METHOD(ecdhUnsafe) {
14145
Nan::HandleScope scope;
14246

@@ -159,26 +63,12 @@ NAN_METHOD(ecdhUnsafe) {
15963
unsigned int flags = SECP256K1_EC_COMPRESSED;
16064
UPDATE_COMPRESSED_VALUE(flags, info[2], SECP256K1_EC_COMPRESSED, SECP256K1_EC_UNCOMPRESSED);
16165

162-
secp256k1_scalar s;
163-
int overflow = 0;
164-
secp256k1_scalar_set_b32(&s, private_key, &overflow);
165-
if (overflow || secp256k1_scalar_is_zero(&s)) {
166-
secp256k1_scalar_clear(&s);
66+
if (secp256k1_ecdh(secp256k1ctx, &public_key.data[0], &public_key, private_key, ecdh_hash_function_unsafe, NULL) == 0) {
16767
return Nan::ThrowError(ECDH_FAIL);
16868
}
16969

170-
secp256k1_ge pt;
171-
secp256k1_gej res;
17270
unsigned char output[65];
173-
size_t output_length = 65;
174-
175-
secp256k1_pubkey_load(secp256k1ctx, &pt, &public_key);
176-
secp256k1_ecmult_const(&res, &pt, &s);
177-
secp256k1_scalar_clear(&s);
178-
179-
secp256k1_ge_set_gej(&pt, &res);
180-
secp256k1_pubkey_save(&public_key, &pt);
181-
71+
size_t output_length = flags == SECP256K1_EC_COMPRESSED ? 33 : 65;
18272
secp256k1_ec_pubkey_serialize(secp256k1ctx, &output[0], &output_length, &public_key, flags);
18373
info.GetReturnValue().Set(COPY_BUFFER(&output[0], output_length));
18474
}

src/ecdsa.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,11 @@ NAN_METHOD(recover) {
130130
v8::Local<v8::Object> recid_object = info[2].As<v8::Object>();
131131
CHECK_TYPE_NUMBER(recid_object, RECOVERY_ID_TYPE_INVALID);
132132
CHECK_NUMBER_IN_INTERVAL(recid_object, -1, 4, RECOVERY_ID_VALUE_INVALID);
133+
#if (NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION)
134+
int recid = (int) recid_object->IntegerValue(info.GetIsolate()->GetCurrentContext()).ToChecked();
135+
#else
133136
int recid = (int) recid_object->IntegerValue();
137+
#endif
134138

135139
unsigned int flags = SECP256K1_EC_COMPRESSED;
136140
UPDATE_COMPRESSED_VALUE(flags, info[3], SECP256K1_EC_COMPRESSED, SECP256K1_EC_UNCOMPRESSED);

src/secp256k1-src

Submodule secp256k1-src updated 69 files

src/util.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,21 @@
88

99
#define COPY_BUFFER(data, datalen) Nan::CopyBuffer((const char*) data, (uint32_t) datalen).ToLocalChecked()
1010

11+
#if (NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION)
12+
#define UPDATE_COMPRESSED_VALUE(compressed, value, v_true, v_false) { \
13+
if (!value->IsUndefined()) { \
14+
CHECK_TYPE_BOOLEAN(value, COMPRESSED_TYPE_INVALID); \
15+
compressed = value->BooleanValue(info.GetIsolate()->GetCurrentContext()).ToChecked() ? v_true : v_false; \
16+
} \
17+
}
18+
#else
1119
#define UPDATE_COMPRESSED_VALUE(compressed, value, v_true, v_false) { \
1220
if (!value->IsUndefined()) { \
1321
CHECK_TYPE_BOOLEAN(value, COMPRESSED_TYPE_INVALID); \
1422
compressed = value->BooleanValue() ? v_true : v_false; \
1523
} \
1624
}
25+
#endif
1726

1827
// TypeError
1928
#define CHECK_TYPE_ARRAY(value, message) { \
@@ -78,10 +87,19 @@
7887
} \
7988
}
8089

90+
#if (NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION)
91+
#define CHECK_NUMBER_IN_INTERVAL(number, x, y, message) { \
92+
if (number->IntegerValue(info.GetIsolate()->GetCurrentContext()).ToChecked() <= x || number->IntegerValue(info.GetIsolate()->GetCurrentContext()).ToChecked() >= y) { \
93+
return Nan::ThrowRangeError(message); \
94+
} \
95+
}
96+
#else
8197
#define CHECK_NUMBER_IN_INTERVAL(number, x, y, message) { \
8298
if (number->IntegerValue() <= x || number->IntegerValue() >= y) { \
8399
return Nan::ThrowRangeError(message); \
84100
} \
85101
}
102+
#endif
103+
86104

87105
#endif

utils/getEndo.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ function getEndoBasis (lambda) {
9292
b2 = b2.neg()
9393
}
9494

95-
return [{a: a1, b: b1}, {a: a2, b: b2}]
95+
return [{ a: a1, b: b1 }, { a: a2, b: b2 }]
9696
}
9797

9898
// Compute beta and lambda, that lambda * P = (beta * Px; Py)

utils/redSqrt.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ for (var i = PWR.length - 1, start = PWR.bitLength() % 26; i >= 0; --i, start =
1818
if (operations.length > 0 && operations[operations.length - 1].op === 'sqr') {
1919
operations[operations.length - 1].v += 1
2020
} else {
21-
operations.push({op: 'sqr', v: 1})
21+
operations.push({ op: 'sqr', v: 1 })
2222
}
2323

2424
if (bit === 0 && current === 0) {
@@ -33,7 +33,7 @@ for (var i = PWR.length - 1, start = PWR.bitLength() % 26; i >= 0; --i, start =
3333
continue
3434
}
3535

36-
operations.push({op: 'mul', v: current})
36+
operations.push({ op: 'mul', v: current })
3737
reqValues[current] = true
3838
currentLen = 0
3939
current = 0

0 commit comments

Comments
 (0)