Browse Source

expose group operation

BIP32 needs to be able to add two points on the secp256k1 curve. This
functionality was not already being exposed from OpenSSL in bitcore. I have
added an "addUncompressed" function to the Key class which takes in two points
in uncompressed form, adds them, and returns the result. This is necessary for
BIP32.
patch-2
Ryan X. Charles 11 years ago
parent
commit
d11361be9e
  1. 88
      src/eckey.cc
  2. 3
      src/eckey.h
  3. 18
      test/test.Key.js

88
src/eckey.cc

@ -10,6 +10,8 @@
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <iostream>
#include "common.h"
#include "eckey.h"
@ -121,6 +123,7 @@ void Key::Init(Handle<Object> target)
// Static methods
NODE_SET_METHOD(s_ct->GetFunction(), "generateSync", GenerateSync);
NODE_SET_METHOD(s_ct->GetFunction(), "fromDER", FromDER);
NODE_SET_METHOD(s_ct->GetFunction(), "addUncompressed", AddUncompressed);
target->Set(String::NewSymbol("Key"),
s_ct->GetFunction());
@ -402,6 +405,91 @@ Key::FromDER(const Arguments& args)
return scope.Close(result);
}
Handle<Value>
Key::AddUncompressed(const Arguments& args)
{
HandleScope scope;
if (args.Length() != 2) {
return VException("Two arguments expected: point0, point1");
}
if (!Buffer::HasInstance(args[0])) {
return VException("Argument 'point0' must be of type Buffer");
}
if (Buffer::Length(args[0]) != 65) {
return VException("Argument 'point0' must have length 65");
}
if (!Buffer::HasInstance(args[1])) {
return VException("Argument 'point1' must be of type Buffer");
}
if (Buffer::Length(args[1]) != 65) {
return VException("Argument 'point1' must have length 65");
}
Handle<Object> point0_buf = args[0]->ToObject();
unsigned char *point0 = (unsigned char*) Buffer::Data(point0_buf);
Handle<Object> point1_buf = args[1]->ToObject();
unsigned char *point1 = (unsigned char*) Buffer::Data(point1_buf);
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
const EC_GROUP *group = EC_KEY_get0_group(eckey);
BN_CTX *ctx;
EC_POINT *p0, *p1, *r;
BIGNUM *p0x, *p0y, *p1x, *p1y, *rx, *ry;
Buffer *rbuf;
unsigned char *rcx, *rcy;
p0 = EC_POINT_new(group);
p1 = EC_POINT_new(group);
r = EC_POINT_new(group);
p0x = BN_bin2bn(&point0[1], 32, BN_new());
p0y = BN_bin2bn(&point0[33], 32, BN_new());
p1x = BN_bin2bn(&point1[1], 32, BN_new());
p1y = BN_bin2bn(&point1[33], 32, BN_new());
ctx = BN_CTX_new();
EC_POINT_set_affine_coordinates_GFp(group, p0, p0x, p0y, ctx);
EC_POINT_set_affine_coordinates_GFp(group, p1, p1x, p1y, ctx);
EC_POINT_add(group, r, p0, p1, ctx);
rx = BN_new();
ry = BN_new();
EC_POINT_get_affine_coordinates_GFp(group, r, rx, ry, ctx);
rbuf = Buffer::New(65);
rcx = (unsigned char *)malloc(32);
rcy = (unsigned char *)malloc(32);
BN_bn2bin(rx, rcx);
BN_bn2bin(ry, rcy);
memcpy(&(((unsigned char *)Buffer::Data(rbuf))[1]), rcx, 32);
memcpy(&(((unsigned char *)Buffer::Data(rbuf))[33]), rcy, 32);
((unsigned char *)Buffer::Data(rbuf))[0] = 0x04;
//free: eckey, p0, p1, r, p0x, p0y, p1x, p1y, ctx, rx, ry, /*rbuf,*/ rcx, rcy
free(rcy); //TODO: also clear
free(rcx); //TODO: also clear
BN_clear_free(ry);
BN_clear_free(rx);
//do not free rbuf - this is returned
BN_CTX_free(ctx);
BN_clear_free(p0x);
BN_clear_free(p0y);
BN_clear_free(p1x);
BN_clear_free(p1y);
EC_POINT_free(r);
EC_POINT_free(p1);
EC_POINT_free(p0);
EC_KEY_free(eckey);
return scope.Close(rbuf->handle_);
}
Handle<Value>
Key::VerifySignature(const Arguments& args)
{

3
src/eckey.h

@ -86,6 +86,9 @@ public:
static Handle<Value>
FromDER(const Arguments& args);
static Handle<Value>
AddUncompressed(const Arguments& args);
static Handle<Value>
VerifySignature(const Arguments& args);

18
test/test.Key.js

@ -9,7 +9,7 @@ var should = chai.should();
var Key = bitcore.Key;
describe('Key', function() {
it('should initialze the main object', function() {
it('should initialize the main object', function() {
should.exist(Key);
});
it('should be able to create instance', function() {
@ -114,4 +114,20 @@ describe('Key', function() {
ret.should.equal(false);
});
describe('#addUncompressed', function() {
it('should exist', function() {
should.exist(Key.addUncompressed);
});
it('should add two uncompressed public keys', function() {
var key1 = Key.generateSync();
key1.compressed = false;
var key2 = Key.generateSync();
key2.compressed = false;
var pubkey1 = key1.public;
var pubkey2 = key2.public;
var pubkey = Key.addUncompressed(pubkey1, pubkey2);
pubkey.length.should.equal(65);
});
});
});

Loading…
Cancel
Save