diff --git a/lib/Point.js b/lib/Point.js index 64d4dd7f8..92311921c 100644 --- a/lib/Point.js +++ b/lib/Point.js @@ -19,6 +19,12 @@ Point.add = function(p1, p2) { return Point.fromUncompressedPubKey(pubKey); }; +Point.multiply = function(p1, x) { + var u1 = p1.toUncompressedPubKey(); + var pubKey = CPPKey.multiply(u1, x); + return Point.fromUncompressedPubKey(pubKey); +}; + //convert the public key of a Key into a Point Point.fromUncompressedPubKey = function(pubkey) { var point = new Point(); diff --git a/src/eckey.cc b/src/eckey.cc index 8f279a61b..d864fd629 100644 --- a/src/eckey.cc +++ b/src/eckey.cc @@ -124,6 +124,7 @@ void Key::Init(Handle target) NODE_SET_METHOD(s_ct->GetFunction(), "generateSync", GenerateSync); NODE_SET_METHOD(s_ct->GetFunction(), "fromDER", FromDER); NODE_SET_METHOD(s_ct->GetFunction(), "addUncompressed", AddUncompressed); + NODE_SET_METHOD(s_ct->GetFunction(), "multiply", Multiply); target->Set(String::NewSymbol("Key"), s_ct->GetFunction()); @@ -486,6 +487,87 @@ Key::AddUncompressed(const Arguments& args) return scope.Close(rbuf->handle_); } +Handle +Key::Multiply(const Arguments& args) +{ + HandleScope scope; + + if (args.Length() != 2) { + return VException("Two arguments expected: point0, x"); + } + 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 'x' must be of type Buffer"); + } + if (Buffer::Length(args[1]) != 32) { + return VException("Argument 'x' must have length 32"); + } + + Handle point0_buf = args[0]->ToObject(); + unsigned char *point0 = (unsigned char*) Buffer::Data(point0_buf); + + Handle x_buf = args[1]->ToObject(); + unsigned char *xval = (unsigned char*) Buffer::Data(x_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; + EC_POINT *p0, *r; + //BIGNUM *p0x, *p0y, *p1x, *p1y, *rx, *ry; + BIGNUM *p0x, *p0y, *x, *rx, *ry; + Buffer *rbuf; + + 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()); + x = BN_bin2bn(&xval[0], 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); + + //int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, size_t num, const EC_POINT *p[], const BIGNUM *m[], BN_CTX *ctx); + //int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx); + EC_POINT_mul(group, r, NULL, p0, x, ctx); + + rx = BN_new(); + ry = BN_new(); + EC_POINT_get_affine_coordinates_GFp(group, r, rx, ry, ctx); + + rbuf = Buffer::New(65); + EC_POINT_point2oct(group, r, POINT_CONVERSION_UNCOMPRESSED, (unsigned char *)Buffer::Data(rbuf), 65, ctx); + + //free: eckey, p0, p1, r, p0x, p0y, p1x, p1y, ctx, rx, ry, /*rbuf,*/ rcx, rcy + 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(x); + //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 1c2b9222e..250765421 100644 --- a/src/eckey.h +++ b/src/eckey.h @@ -89,6 +89,9 @@ public: static Handle AddUncompressed(const Arguments& args); + static Handle + Multiply(const Arguments& args); + static Handle VerifySignature(const Arguments& args);