From f01ebd97d2081e29bc2d264d09fbbd7ec3fcc829 Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Wed, 1 Oct 2014 21:08:06 -0400 Subject: [PATCH] Buffers, identities, and randomNumbers. --- examples/identity.js | 5 ++ lib/constants.js | 18 ++-- lib/identity.js | 53 +++++------ test/identity.js | 204 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 242 insertions(+), 38 deletions(-) create mode 100644 examples/identity.js create mode 100644 test/identity.js diff --git a/examples/identity.js b/examples/identity.js new file mode 100644 index 0000000..1bbc260 --- /dev/null +++ b/examples/identity.js @@ -0,0 +1,5 @@ +var Identity = require('../lib/identity'); + +var identity = new Identity( 0x02 ); + +console.log( identity.toString() ); diff --git a/lib/constants.js b/lib/constants.js index c64494d..43bf75b 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,15 +1,17 @@ exports.mainnet = { - pubkeyhash: 0x00, - privkey: 0x80, - scripthash: 0x05, - bip32pubkey: 0x0488b21e, + pubkeyhash: 0x00, + identpersist: 0x01, + identephem: 0x02, + privkey: 0x80, + scripthash: 0x05, + bip32pubkey: 0x0488b21e, bip32privkey: 0x0488ade4, }; exports.testnet = { - pubkeyhash: 0x6f, - privkey: 0xef, - scripthash: 0xc4, - bip32pubkey: 0x043587cf, + pubkeyhash: 0x6f, + privkey: 0xef, + scripthash: 0xc4, + bip32pubkey: 0x043587cf, bip32privkey: 0x04358394, }; diff --git a/lib/identity.js b/lib/identity.js index bd85ccd..789cb54 100644 --- a/lib/identity.js +++ b/lib/identity.js @@ -1,12 +1,14 @@ var base58check = require('./base58check'); -var constants = require('./constants'); -var Hash = require('./hash'); -var Pubkey = require('./pubkey'); -var Script = require('./script'); +var constants = require('./constants'); +var Hash = require('./hash'); +var Pubkey = require('./pubkey'); +var Script = require('./script'); +var Random = require('./random'); function Identity(buf) { - if (!(this instanceof Identity)) - return new Identity(buf); + // TODO: instantiate identities without providing any configuration + if (!(this instanceof Identity)) return new Identity(buf); + if (Buffer.isBuffer(buf)) { this.fromBuffer(buf); } else if (typeof buf === 'string') { @@ -19,9 +21,9 @@ function Identity(buf) { }; Identity.prototype.set = function(obj) { - this.hashbuf = obj.hashbuf || this.hashbuf || null; - this.networkstr = obj.networkstr || this.networkstr || 'mainnet'; - this.typestr = obj.typestr || this.typestr || 'pubkeyhash'; + this.hashbuf = obj.hashbuf || this.hashbuf || null; + this.networkstr = obj.networkstr || this.networkstr || 'mainnet'; + this.typestr = obj.typestr || this.typestr || 'identephem'; return this; }; @@ -29,18 +31,13 @@ Identity.prototype.fromBuffer = function(buf) { if (buf.length !== 1 + 20) throw new Error('Identity buffers must be exactly 21 bytes'); var version = buf[0]; - if (version === constants['mainnet']['pubkeyhash']) { + + if (version === constants['mainnet']['identephem']) { this.networkstr = 'mainnet'; - this.typestr = 'pubkeyhash'; - } else if (version === constants['mainnet']['scripthash']) { + this.typestr = 'identephem'; + } else if (version === constants['mainnet']['identpersist']) { this.networkstr = 'mainnet'; - this.typestr = 'scripthash'; - } else if (version === constants['testnet']['pubkeyhash']) { - this.networkstr = 'testnet'; - this.typestr = 'pubkeyhash'; - } else if (version === constants['testnet']['scripthash']) { - this.networkstr = 'testnet'; - this.typestr = 'scripthash'; + this.typestr = 'identpersist'; } else { this.networkstr = 'unknown'; this.typestr = 'unknown'; @@ -56,21 +53,14 @@ Identity.prototype.fromHashbuf = function(hashbuf, networkstr, typestr) { throw new Error('hashbuf must be exactly 20 bytes'); this.hashbuf = hashbuf; this.networkstr = networkstr || 'mainnet'; - this.typestr = typestr || 'pubkeyhash'; + this.typestr = typestr || 'identephem'; return this; }; Identity.prototype.fromPubkey = function(pubkey, networkstr) { this.hashbuf = Hash.sha256ripemd160(pubkey.toBuffer()); this.networkstr = networkstr || 'mainnet'; - this.typestr = 'pubkeyhash'; - return this; -}; - -Identity.prototype.fromScript = function(script, networkstr) { - this.hashbuf = Hash.sha256ripemd160(script.toBuffer()); - this.networkstr = networkstr || 'mainnet'; - this.typestr = 'scripthash'; + this.typestr = 'identephem'; return this; }; @@ -98,6 +88,9 @@ Identity.prototype.isValid = function() { }; Identity.prototype.toBuffer = function() { + + console.log(this.networkstr); process.exit(); + version = new Buffer([constants[this.networkstr][this.typestr]]); var buf = Buffer.concat([version, this.hashbuf]); return buf; @@ -112,8 +105,8 @@ Identity.prototype.validate = function() { throw new Error('hash must be a buffer of 20 bytes'); if (this.networkstr !== 'mainnet' && this.networkstr !== 'testnet') throw new Error('networkstr must be "mainnet" or "testnet"'); - if (this.typestr !== 'pubkeyhash' && this.typestr !== 'scripthash') - throw new Error('typestr must be "pubkeyhash" or "scripthash"'); + if (this.typestr !== 'identephem' && this.typestr !== 'scripthash') + throw new Error('typestr must be "identephem" or "scripthash"'); return this; }; diff --git a/test/identity.js b/test/identity.js new file mode 100644 index 0000000..a37be64 --- /dev/null +++ b/test/identity.js @@ -0,0 +1,204 @@ +var should = require('chai').should(); +var constants = require('../lib/constants'); +var Pubkey = require('../lib/pubkey'); +var Identity = require('../lib/identity'); +var Script = require('../lib/script'); + +describe('Identity', function() { + + var pubkeyhash = new Buffer('3c3fa3d4adcaf8f52d5b1843975e122548269937', 'hex'); + var buf = Buffer.concat([new Buffer([0]), pubkeyhash]); + var str = '16VZnHwRhwrExfeHFHGjwrgEMq8VcYPs9r'; + + it('should create a new identity object', function() { + var identity = new Identity(); + should.exist(identity); + identity = Identity(buf); + should.exist(identity); + identity = Identity(str); + should.exist(identity); + }); + + describe('@isValid', function() { + + it('should validate this valid identity string', function() { + Identity.isValid(str).should.equal(true); + }); + + it('should invalidate this valid identity string', function() { + Identity.isValid(str.substr(1)).should.equal(false); + }); + + }); + + describe('#fromBuffer', function() { + + it('should make an identity from a buffer', function() { + Identity().fromBuffer(buf).toString().should.equal(str); + }); + + }); + + describe('#fromHashbuf', function() { + + it('should make an identity from a hashbuf', function() { + Identity().fromHashbuf(pubkeyhash).toString().should.equal(str); + var a = Identity().fromHashbuf(pubkeyhash, 'testnet', 'scripthash'); + a.networkstr.should.equal('testnet'); + a.typestr.should.equal('scripthash'); + }); + + it('should throw an error for invalid length hashbuf', function() { + (function() { + Identity().fromHashbuf(buf); + }).should.throw('hashbuf must be exactly 20 bytes'); + }); + + }); + + describe('#fromPubkey', function() { + + it('should make this identity from a compressed pubkey', function() { + var pubkey = new Pubkey(); + pubkey.fromDER(new Buffer('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004', 'hex')); + var identity = new Identity(); + identity.fromPubkey(pubkey); + identity.toString().should.equal('19gH5uhqY6DKrtkU66PsZPUZdzTd11Y7ke'); + }); + + it('should make this identity from an uncompressed pubkey', function() { + var pubkey = new Pubkey(); + pubkey.fromDER(new Buffer('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004', 'hex')); + var identity = new Identity(); + pubkey.compressed = false; + identity.fromPubkey(pubkey, 'mainnet'); + identity.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX'); + }); + + }); + + describe('#fromScript', function() { + + it('should make this identity from a script', function() { + var script = Script().fromString("OP_CHECKMULTISIG"); + var identity = Identity().fromScript(script); + identity.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); + }); + + it('should make this identity from other script', function() { + var script = Script().fromString("OP_CHECKSIG OP_HASH160"); + var identity = Identity().fromScript(script); + identity.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7'); + }); + + }); + + describe('#fromString', function() { + + it('should derive from this known identity string mainnet', function() { + var identity = new Identity(); + identity.fromString(str); + identity.toBuffer().slice(1).toString('hex').should.equal(pubkeyhash.toString('hex')); + }); + + it('should derive from this known identity string testnet', function() { + var identity = new Identity(); + identity.fromString(str); + identity.networkstr = 'testnet'; + identity.fromString(identity.toString()); + identity.toString().should.equal('mm1X5M2QWyHVjn7txrF7mmtZDpjCXzoa98'); + }); + + it('should derive from this known identity string mainnet scripthash', function() { + var identity = new Identity(); + identity.fromString(str); + identity.networkstr = 'mainnet'; + identity.typestr = 'scripthash'; + identity.fromString(identity.toString()); + identity.toString().should.equal('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo'); + }); + + it('should derive from this known identity string testnet scripthash', function() { + var identity = new Identity(); + identity.fromString(str); + identity.networkstr = 'testnet'; + identity.typestr = 'scripthash'; + identity.fromString(identity.toString()); + identity.toString().should.equal('2MxjnmaMtsJfyFcyG3WZCzS2RihdNuWqeX4'); + }); + + }); + + describe('#isValid', function() { + + it('should describe this valid identity as valid', function() { + var identity = new Identity(); + identity.fromString('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo'); + identity.isValid().should.equal(true); + }); + + it('should describe this identity with unknown network as invalid', function() { + var identity = new Identity(); + identity.fromString('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo'); + identity.networkstr = 'unknown'; + identity.isValid().should.equal(false); + }); + + it('should describe this identity with unknown type as invalid', function() { + var identity = new Identity(); + identity.fromString('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo'); + identity.typestr = 'unknown'; + identity.isValid().should.equal(false); + }); + + }); + + describe('#toBuffer', function() { + + it('should output this known hash', function() { + var identity = new Identity(); + identity.fromString(str); + identity.toBuffer().slice(1).toString('hex').should.equal(pubkeyhash.toString('hex')); + }); + + }); + + describe('#toString', function() { + + it('should output the same thing that was input', function() { + var identity = new Identity(); + identity.fromString(str); + identity.toString().should.equal(str); + }); + + }); + + describe('#validate', function() { + + it('should not throw an error on this valid identity', function() { + var identity = new Identity(); + identity.fromString(str); + should.exist(identity.validate()); + }); + + it('should throw an error on this invalid network', function() { + var identity = new Identity(); + identity.fromString(str); + identity.networkstr = 'unknown'; + (function() { + identity.validate(); + }).should.throw('networkstr must be "mainnet" or "testnet"'); + }); + + it('should throw an error on this invalid type', function() { + var identity = new Identity(); + identity.fromString(str); + identity.typestr = 'unknown'; + (function() { + identity.validate(); + }).should.throw('typestr must be "pubkeyhash" or "scripthash"'); + }); + + }); + +});