From 304210c1321aee4a14989466b3a8752691819008 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Sat, 9 Aug 2014 19:42:25 -0700 Subject: [PATCH] add tests for all ecdsa functions --- lib/ecdsa.js | 47 ++++++++++++++++++------ test/test.ecdsa.js | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 10 deletions(-) diff --git a/lib/ecdsa.js b/lib/ecdsa.js index 4892a22..1130f99 100644 --- a/lib/ecdsa.js +++ b/lib/ecdsa.js @@ -1,6 +1,7 @@ var bn = require('./bn'); var point = require('./point'); var Signature = require('./signature'); +var Key = require('./key'); var Privkey = require('./privkey'); var Pubkey = require('./pubkey'); var Random = require('./random'); @@ -12,6 +13,29 @@ var ECDSA = function(hash, key, sig, k) { this.k = k; }; +ECDSA.prototype.fromString = function(str) { + var obj = JSON.parse(str); + if (obj.hash) + this.hash = new Buffer(obj.hash, 'hex'); + if (obj.key) + this.key = (new Key()).fromString(obj.key); + if (obj.sig) + this.sig = (new Signature()).fromString(obj.sig); + if (obj.k) + this.k = bn(obj.k, 10); + return this; +}; + +ECDSA.prototype.randomK = function() { + var N = point.getN(); + var k; + do { + k = bn.fromBuffer(Random.getRandomBuffer(32)); + } while (!(k.lt(N) && k.gt(0))); + this.k = k; + return this; +}; + ECDSA.prototype.sigError = function() { if (!Buffer.isBuffer(this.hash) || this.hash.length !== 32) return 'Invalid hash'; @@ -44,16 +68,6 @@ ECDSA.prototype.sigError = function() { return false; }; -ECDSA.prototype.randomK = function() { - var N = point.getN(); - var k; - do { - k = bn.fromBuffer(Random.getRandomBuffer(32)); - } while (!(k.lt(N) && k.gt(0))); - this.k = k; - return this; -}; - ECDSA.prototype.sign = function() { var hash = this.hash; var privkey = this.key.privkey; @@ -82,6 +96,19 @@ ECDSA.prototype.signRandomK = function() { return this.sign(); }; +ECDSA.prototype.toString = function() { + var obj = {}; + if (this.hash) + obj.hash = this.hash.toString('hex'); + if (this.key) + obj.key = this.key.toString(); + if (this.sig) + obj.sig = this.sig.toString(); + if (this.k) + obj.k = this.k.toString(); + return JSON.stringify(obj); +}; + ECDSA.prototype.verify = function() { if (!this.sigError()) return true; diff --git a/test/test.ecdsa.js b/test/test.ecdsa.js index 674b744..1632f9c 100644 --- a/test/test.ecdsa.js +++ b/test/test.ecdsa.js @@ -3,6 +3,7 @@ var Hash = require('../lib/hash'); var Key = require('../lib/key'); var Privkey = require('../lib/privkey'); var Pubkey = require('../lib/pubkey'); +var Signature = require('../lib/signature'); var bn = require('../lib/bn'); var point = require('../lib/point'); var should = require('chai').should(); @@ -20,6 +21,80 @@ describe("ecdsa", function() { ecdsa.key.pubkey = new Pubkey(point(bn.fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex')), bn.fromBuffer(new Buffer('4836ab292c105a711ed10fcfd30999c31ff7c02456147747e03e739ad527c380', 'hex')))); + describe('#fromString', function() { + + it('should to a round trip with to string', function() { + var str = ecdsa.toString(); + var ecdsa2 = new ECDSA(); + ecdsa2.fromString(str); + should.exist(ecdsa.hash); + should.exist(ecdsa.key); + }); + + }); + + describe('#randomK', function() { + + it('should generate a new random k when called twice in a row', function() { + ecdsa.randomK(); + var k1 = ecdsa.k; + ecdsa.randomK(); + var k2 = ecdsa.k; + (k1.cmp(k2) === 0).should.equal(false); + }); + + it('should generate a random k that is (almost always) greater than this relatively small number', function() { + ecdsa.randomK(); + var k1 = ecdsa.k; + var k2 = bn(Math.pow(2, 32)).mul(bn(Math.pow(2, 32))).mul(bn(Math.pow(2, 32))); + k2.gt(k1).should.equal(false); + }); + + }); + + describe('#sigError', function() { + + it('should return an error if the hash is invalid', function() { + var ecdsa = new ECDSA(); + ecdsa.sigError().should.equal('Invalid hash'); + }); + + it('should return an error if the pubkey is invalid', function() { + var ecdsa = new ECDSA(); + ecdsa.hash = Hash.sha256(new Buffer('test')); + ecdsa.sigError().should.equal("Invalid pubkey: TypeError: Cannot read property 'pubkey' of undefined"); + }); + + it('should return an error if r, s are invalid', function() { + var ecdsa = new ECDSA(); + ecdsa.hash = Hash.sha256(new Buffer('test')); + ecdsa.pubkey = new Pubkey(); + ecdsa.pubkey.fromDER(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex')); + ecdsa.sig = new Signature(); + ecdsa.sig.r = bn(0); + ecdsa.sig.s = bn(0); + ecdsa.sigError().should.equal("Invalid pubkey: TypeError: Cannot read property 'pubkey' of undefined"); + }); + + it('should return an error if the signature is incorrect', function() { + ecdsa.sig = new Signature(); + ecdsa.sig.fromString('3046022100e9915e6236695f093a4128ac2a956c40ed971531de2f4f41ba05fac7e2bd019c02210094e6a4a769cc7f2a8ab3db696c7cd8d56bcdbfff860a8c81de4bc6a798b90827'); + ecdsa.sig.r = ecdsa.sig.r.add(bn(1)); + ecdsa.sigError().should.equal("Invalid signature"); + }); + + }); + + describe('#sign', function() { + + it('should create a valid signature', function() { + ecdsa.randomK(); + ecdsa.sign(); + ecdsa.verify().should.equal(true); + }); + + }); + describe('#signRandomK', function() { it('should produce a signature', function() { @@ -29,9 +104,24 @@ describe("ecdsa", function() { }); + describe('#toString', function() { + + it('should convert this to a string', function() { + var str = ecdsa.toString(); + (typeof str === 'string').should.equal(true); + }); + + }); + describe('#verify', function() { it('should verify a signature that was just signed', function() { + ecdsa.sig = new Signature(); + ecdsa.sig.fromString('3046022100e9915e6236695f093a4128ac2a956c40ed971531de2f4f41ba05fac7e2bd019c02210094e6a4a769cc7f2a8ab3db696c7cd8d56bcdbfff860a8c81de4bc6a798b90827'); + ecdsa.verify().should.equal(true); + }); + + it('should verify this known good signature', function() { ecdsa.signRandomK(); ecdsa.verify().should.equal(true); });