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:
parent
78a753a2d4
commit
d11361be9e
88
src/eckey.cc
88
src/eckey.cc
|
@ -10,6 +10,8 @@
|
||||||
#include <openssl/ecdsa.h>
|
#include <openssl/ecdsa.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "eckey.h"
|
#include "eckey.h"
|
||||||
|
|
||||||
|
@ -121,6 +123,7 @@ void Key::Init(Handle<Object> target)
|
||||||
// Static methods
|
// Static methods
|
||||||
NODE_SET_METHOD(s_ct->GetFunction(), "generateSync", GenerateSync);
|
NODE_SET_METHOD(s_ct->GetFunction(), "generateSync", GenerateSync);
|
||||||
NODE_SET_METHOD(s_ct->GetFunction(), "fromDER", FromDER);
|
NODE_SET_METHOD(s_ct->GetFunction(), "fromDER", FromDER);
|
||||||
|
NODE_SET_METHOD(s_ct->GetFunction(), "addUncompressed", AddUncompressed);
|
||||||
|
|
||||||
target->Set(String::NewSymbol("Key"),
|
target->Set(String::NewSymbol("Key"),
|
||||||
s_ct->GetFunction());
|
s_ct->GetFunction());
|
||||||
|
@ -402,6 +405,91 @@ Key::FromDER(const Arguments& args)
|
||||||
return scope.Close(result);
|
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>
|
Handle<Value>
|
||||||
Key::VerifySignature(const Arguments& args)
|
Key::VerifySignature(const Arguments& args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -86,6 +86,9 @@ public:
|
||||||
static Handle<Value>
|
static Handle<Value>
|
||||||
FromDER(const Arguments& args);
|
FromDER(const Arguments& args);
|
||||||
|
|
||||||
|
static Handle<Value>
|
||||||
|
AddUncompressed(const Arguments& args);
|
||||||
|
|
||||||
static Handle<Value>
|
static Handle<Value>
|
||||||
VerifySignature(const Arguments& args);
|
VerifySignature(const Arguments& args);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ var should = chai.should();
|
||||||
|
|
||||||
var Key = bitcore.Key;
|
var Key = bitcore.Key;
|
||||||
describe('Key', function() {
|
describe('Key', function() {
|
||||||
it('should initialze the main object', function() {
|
it('should initialize the main object', function() {
|
||||||
should.exist(Key);
|
should.exist(Key);
|
||||||
});
|
});
|
||||||
it('should be able to create instance', function() {
|
it('should be able to create instance', function() {
|
||||||
|
@ -114,4 +114,20 @@ describe('Key', function() {
|
||||||
ret.should.equal(false);
|
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…
Reference in New Issue