diff --git a/browser.js b/browser.js index 9403a8c..1452843 100644 --- a/browser.js +++ b/browser.js @@ -21,6 +21,8 @@ function assert(condition, message) { } exports.getPublic = function(privateKey) { + // This function has sync API so we throw an error immediately. + // (`elliptic` doesn't do this). assert(privateKey.length === 32, "Bad private key"); // XXX(Kagami): `elliptic.utils.encode` returns array for every // encoding except `hex`. @@ -28,15 +30,24 @@ exports.getPublic = function(privateKey) { }; exports.sign = function(privateKey, msg) { - var key = ec.keyPair(privateKey); return new Promise(function(resolve) { + var key = ec.keyPair(privateKey); resolve(new Buffer(key.sign(msg).toDER())); }); }; exports.verify = function(key, msg, sig) { - key = ec.keyPair(key); return new Promise(function(resolve, reject) { + key = ec.keyPair(key); return key.verify(msg, sig) ? resolve() : reject(); }); }; + +exports.derive = function(privateKeyA, publicKeyB) { + return new Promise(function(resolve) { + var keyA = ec.keyPair(privateKeyA); + var keyB = ec.keyPair(publicKeyB); + var Px = keyA.derive(keyB.getPublic()); // BN instance + resolve(new Buffer(Px.toString(16), "hex")); + }); +}; diff --git a/test.js b/test.js index 524d8b0..892f4bb 100644 --- a/test.js +++ b/test.js @@ -2,11 +2,20 @@ var expect = require("chai").expect; var crypto = require("crypto"); var eccrypto = require("./"); +var msg = crypto.createHash("sha256").update("test").digest(); +var otherMsg = crypto.createHash("sha256").update("test2").digest(); + var privateKey = Buffer(32); privateKey.fill(1); var publicKey = eccrypto.getPublic(privateKey); -var msg = crypto.createHash("sha256").update("test").digest(); -var otherMsg = crypto.createHash("sha256").update("test2").digest(); + +var privateKeyA = Buffer(32); +privateKeyA.fill(2); +var publicKeyA = eccrypto.getPublic(privateKeyA); + +var privateKeyB = Buffer(32); +privateKeyB.fill(3); +var publicKeyB = eccrypto.getPublic(privateKeyB); describe("Key convertion", function() { it("should allow to convert private key to public", function() { @@ -22,12 +31,11 @@ describe("Key convertion", function() { describe("ECDSA", function() { it("should allow to sign and verify message", function() { - return eccrypto.sign(privateKey, msg) - .then(function(sig) { - expect(Buffer.isBuffer(sig)).to.be.true; - expect(sig.toString("hex")).to.equal("3044022078c15897a34de6566a0d396fdef660698c59fef56d34ee36bef14ad89ee0f6f8022016e02e8b7285d93feafafbe745702f142973a77d5c2fa6293596357e17b3b47c"); - return eccrypto.verify(publicKey, msg, sig); - }); + return eccrypto.sign(privateKey, msg).then(function(sig) { + expect(Buffer.isBuffer(sig)).to.be.true; + expect(sig.toString("hex")).to.equal("3044022078c15897a34de6566a0d396fdef660698c59fef56d34ee36bef14ad89ee0f6f8022016e02e8b7285d93feafafbe745702f142973a77d5c2fa6293596357e17b3b47c"); + return eccrypto.verify(publicKey, msg, sig); + }); }); it("should allow to verify using private key", function() { @@ -39,13 +47,12 @@ describe("ECDSA", function() { }); it("shouldn't verify incorrect signature", function(done) { - eccrypto.sign(privateKey, msg) - .then(function(sig) { - expect(Buffer.isBuffer(sig)).to.be.true; - return eccrypto.verify(publicKey, otherMsg, sig); - }).catch(function() { + eccrypto.sign(privateKey, msg).then(function(sig) { + expect(Buffer.isBuffer(sig)).to.be.true; + eccrypto.verify(publicKey, otherMsg, sig).catch(function() { done(); }); + }); }); it("should reject promise on invalid key when signing", function(done) { @@ -55,23 +62,38 @@ describe("ECDSA", function() { }); it("should reject promise on invalid key when verifying", function(done) { - eccrypto.sign(privateKey, msg) - .then(function(sig) { - expect(Buffer.isBuffer(sig)).to.be.true; - return eccrypto.verify(Buffer("test"), msg, sig); - }).catch(function() { + eccrypto.sign(privateKey, msg).then(function(sig) { + expect(Buffer.isBuffer(sig)).to.be.true; + eccrypto.verify(Buffer("test"), msg, sig).catch(function() { done(); }); + }); }); it("should reject promise on invalid sig when verifying", function(done) { - eccrypto.sign(privateKey, msg) - .then(function(sig) { - expect(Buffer.isBuffer(sig)).to.be.true; - sig[0] ^= 1; - return eccrypto.verify(publicKey, msg, sig); - }).catch(function() { + eccrypto.sign(privateKey, msg).then(function(sig) { + expect(Buffer.isBuffer(sig)).to.be.true; + sig[0] ^= 1; + eccrypto.verify(publicKey, msg, sig).catch(function() { done(); }); + }); }); }); + +if (typeof window !== "undefined") { +describe("ECDH", function() { + it("should derive shared secret from privkey A and pubkey B", function() { + return eccrypto.derive(privateKeyA, publicKeyB).then(function(Px) { + expect(Buffer.isBuffer(Px)).to.be.true; + expect(Px.length).to.equal(32); + expect(Px.toString("hex")).to.equal("aca78f27d5f23b2e7254a0bb8df128e7c0f922d47ccac72814501e07b7291886"); + return eccrypto.derive(privateKeyB, publicKeyA).then(function(Px2) { + expect(Buffer.isBuffer(Px2)).to.be.true; + expect(Px2.length).to.equal(32); + expect(Px.toString("hex")).to.equal(Px2.toString("hex")); + }); + }); + }); +}); +}