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.
This commit is contained in:
Ryan X. Charles 2014-03-23 10:35:28 -07:00
parent 78a753a2d4
commit d11361be9e
3 changed files with 108 additions and 1 deletions

View File

@ -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)
{

View File

@ -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);

View File

@ -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);
});
});
});