From d11361be9e2b0417f177ac52043f3036feba7ba0 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Sun, 23 Mar 2014 10:35:28 -0700 Subject: [PATCH] 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. --- src/eckey.cc | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ src/eckey.h | 3 ++ test/test.Key.js | 18 +++++++++- 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/eckey.cc b/src/eckey.cc index ed632605d..d8831b29f 100644 --- a/src/eckey.cc +++ b/src/eckey.cc @@ -10,6 +10,8 @@ #include #include +#include + #include "common.h" #include "eckey.h" @@ -121,6 +123,7 @@ void Key::Init(Handle 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 +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 point0_buf = args[0]->ToObject(); + unsigned char *point0 = (unsigned char*) Buffer::Data(point0_buf); + + Handle 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 Key::VerifySignature(const Arguments& args) { diff --git a/src/eckey.h b/src/eckey.h index 8322ff123..1c2b9222e 100644 --- a/src/eckey.h +++ b/src/eckey.h @@ -86,6 +86,9 @@ public: static Handle FromDER(const Arguments& args); + static Handle + AddUncompressed(const Arguments& args); + static Handle VerifySignature(const Arguments& args); diff --git a/test/test.Key.js b/test/test.Key.js index 4918e9013..23cbc9526 100644 --- a/test/test.Key.js +++ b/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); + }); + }); + });