From e103615f4964570cc1d9d89655cb55ec01101578 Mon Sep 17 00:00:00 2001 From: Kagami Hiiragi Date: Wed, 24 Dec 2014 02:14:28 +0300 Subject: [PATCH] Implement sign/verify for node implementation --- index.js | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++- package.json | 1 + test.js | 58 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 122 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 6aab852..a07ca4e 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,69 @@ +/** + * Node.js eccrypto implementation. + * @module eccrypto + */ + +"use strict"; + +require("es6-promise").polyfill(); var secp256k1 = require("secp256k1"); -exports.getPublic = secp256k1.createPublicKey.bind(null); +/** + * Compute the public key for a given private key. + * @param {Buffer} publicKey A 32-byte private key + * @return {Buffer} A 65-byte public key + */ +exports.getPublic = function(privateKey) { + return secp256k1.createPublicKey(privateKey); +}; + +/** + * Create an ECDSA signature. + * @param {Buffer} privateKey A 32-byte private key + * @param {Buffer} msg The message being signed + * @return {Promise.} A promise that resolves with the + * signature or rejects with error code: + * + * - 0: invalid nonce + * - -1: invalid private key or message + */ +// FIXME(Kagami): What to do in case of invalid nonce? +exports.sign = function(privateKey, msg) { + return new Promise(function(resolve, reject) { + try { + secp256k1.sign(privateKey, msg, function(code, sig) { + if (code === 1) { + resolve(sig); + } else { + reject(code); + } + }); + } catch(e) { + reject(-1); + } + }); +}; + +/** + * Verify an ECDSA signature. + * @param {Buffer} publicKey The public key + * @param {Buffer} msg The message being verified + * @param {Buffer} sig The signature + * @return {Promise.} A promise that resolves on correct + * signature and rejects on bad signature with error code: + * + * - 0: incorrect signature + * - -1: invalid public key + * - -2: invalid signature + */ +exports.verify = function(publicKey, msg, sig) { + return new Promise(function(resolve, reject) { + secp256k1.verify(publicKey, msg, sig, function(code) { + if (code === 1) { + resolve(); + } else { + reject(code); + } + }); + }); +}; diff --git a/package.json b/package.json index c989ad1..e33dd9e 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "mocha": "*" }, "dependencies": { + "es6-promise": "^2.0.1", "secp256k1": "~0.0.13" } } diff --git a/test.js b/test.js index 327f999..6864784 100644 --- a/test.js +++ b/test.js @@ -1,10 +1,60 @@ var expect = require("chai").expect; var eccrypto = require("./"); +var privateKey = Buffer(32); +privateKey.fill(1); +var publicKey = eccrypto.getPublic(privateKey); +var msg = Buffer("test"); + describe("Key", function() { - it("should allow to convert private key to public", function() { - var privateKey = Buffer(32); - privateKey.fill(1); - expect(eccrypto.getPublic(privateKey).toString("hex")).to.equal("041b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f70beaf8f588b541507fed6a642c5ab42dfdf8120a7f639de5122d47a69a8e8d1"); + it("should allow to convert private key to public", function() { + expect(publicKey.toString("hex")).to.equal("041b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f70beaf8f588b541507fed6a642c5ab42dfdf8120a7f639de5122d47a69a8e8d1"); + }); +}); + +describe("ECDSA", function() { + it("should allow to sign and verify message", function() { + return eccrypto.sign(privateKey, msg) + .then(function(sig) { + return eccrypto.verify(publicKey, msg, sig); + }); + }); + + it("shouldn't verify incorrect signature", function(done) { + eccrypto.sign(privateKey, msg) + .then(function(sig) { + return eccrypto.verify(publicKey, Buffer("other msg"), sig); + }).catch(function(code) { + expect(code).to.equal(0); + done(); + }); + }); + + it("should reject promise on invalid key when signing", function(done) { + eccrypto.sign(Buffer("test"), msg).catch(function(code) { + expect(code).to.equal(-1); + done(); + }); + }); + + it("should reject promise on invalid key when verifying", function(done) { + eccrypto.sign(privateKey, msg) + .then(function(sig) { + return eccrypto.verify(Buffer("test"), msg, sig); + }).catch(function(code) { + expect(code).to.equal(-1); + done(); + }); + }); + + it("should reject promise on invalid sig when verifying", function(done) { + eccrypto.sign(privateKey, msg) + .then(function(sig) { + sig[0] ^= 1; + return eccrypto.verify(publicKey, msg, sig); + }).catch(function(code) { + expect(code).to.equal(-2); + done(); + }); }); });