├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── lib └── eckey.js ├── package.json └── test ├── eckey.test.js └── mocha.opts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | coverage/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | test/ 3 | .DS_Store 4 | component.json 5 | bower.json 6 | .travis.yml 7 | coverage/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | dist: xenial 3 | language: node_js 4 | node_js: 5 | - "10" 6 | - "12" 7 | - "14" 8 | addons: 9 | apt: 10 | sources: 11 | - ubuntu-toolchain-r-test 12 | packages: 13 | - clang-3.5 14 | - g++-4.8 15 | services: 16 | - xvfb 17 | env: 18 | global: 19 | - DISPLAY=:99.0 20 | - RANDOM_TESTS_REPEAT=100 21 | jobs: 22 | - CXX=g++-4.8 TEST_SUITE=unit 23 | jobs: 24 | fast_finish: true 25 | include: 26 | - os: linux 27 | node_js: "14" 28 | env: CXX=g++-4.8 TEST_SUITE=lint 29 | - os: linux 30 | node_js: "14" 31 | env: CXX=clang++ TEST_SUITE=unit 32 | script: npm run $TEST_SUITE 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 1.0.0 / 2016-03-26 2 | ------------------ 3 | - upgraded to `secp256k1`. [#15][#15] 4 | 5 | 0.8.0 / 2014-09-29 6 | ------------------ 7 | - updated `"ecurve": "^0.8.0"` to `"ecurve": "^1.0.0"` 8 | 9 | 0.7.0 / 2014-06-11 10 | ------------------ 11 | * updated `"ecurve": "^0.6.0"` to `"ecurve": "^0.8.0"` 12 | * removed `terst` for `assert` 13 | 14 | 0.6.0 / 2014-06-03 15 | ------------------ 16 | * added field `pubKeyHash` and alias `publicHash` 17 | * removed semicolons (CryptoCoinJS should no longer use them) 18 | 19 | 0.5.0 / 2014-06-03 20 | ------------------ 21 | * add TravisCI 22 | * add Coveralls 23 | * upgraded `secure-random@~0.2.1` to `secure-random@^1.0.0` dev dep 24 | * removed `ecurve-names` dep, functionality is now present in `ecurve` 25 | * upgraded from `ecurve@~0.3.x` to `ecurve@^0.6.0` 26 | * removed static field `compressByDefault` 27 | * field `compressed` is now set to `true` by default 28 | * upgraded `terst` dev dep to `0.2.0` 29 | * upgraded `bigi@~0.2.0` to `bigi@^1.1.0` 30 | * add testling 31 | 32 | 0.4.2 / 2014-04-17 33 | ------------------ 34 | * bugfix: fixed `compressed` when `new` isn't used with the constructor. #12 35 | 36 | 0.4.1 / 2014-04-14 37 | ------------------ 38 | * bugfix: fixed input when `new` isn't used with the constructor. #11, #9 39 | 40 | 0.4.0 / 2014-03-09 41 | ------------------ 42 | * Dropped sha256 and ripemd160 deps. Upgraded to crypto-hashing library. 43 | * removed function wrapper 44 | * Changed the way the constuctor works. Only supports input types of `Array`, `Buffer`, or `Uint8Array`. Does NOT randomly generate a private key anymore. 45 | * added `publicKey` property 46 | * ~~added `pubKeyHash`/`publicHash` property~~ 47 | * added `publicPoint`, removed `getPubPoint()` 48 | * removed `getPub()`, use `publicKey` instead 49 | * removed `getPubKeyHash()`, use `publicHash` or `pubKeyHash` instead 50 | * removed `sign()` and `verify()`, methods can be accessed from [ecdsa](https://github.com/cryptocoinjs/ecdsa) 51 | * added `privateExportKey` 52 | * removed `getExportedPrivateKey`, note that `getExportedPrivateKey` was essentially just a way to get WIF 53 | * removed `decodeString()`, use package [coinstring][coinstring] in its place 54 | * removed `getBitcoinAddress()`, use package [coinstring][coinstring] in its place 55 | * removed `setCompressed`, use `compressed` property instead 56 | * removed deps: `ecdsa`, `convert-hex`, `btc-address`, `bs58` 57 | * updated deps: `ecurve` and `ecurve-names` 58 | * removed `pubKeyHash` property, removes dependency upon `crypto-hashing` 59 | * removed dep `crypto-hashing` 60 | 61 | 0.3.0 / 2014-02-03 62 | ------------------ 63 | * Removed bower and component support. Closes #8 64 | * Upgraded version number so that `cryptocoin` could install. Changes in `0.2.1` could qualify for a `0.3.0`. 65 | 66 | 0.2.1 / 2014-01-23 67 | ------------------ 68 | * Update dependency package names/versions 69 | 70 | 0.2.0 / 2013-12-07 71 | ------------------ 72 | * added `recoverPubKey()` from package `ecdsa` 73 | * updated to `ecdsa` `0.2.0` 74 | * [remiq](https://github.com/remiq) fixed `getExportedPrivateKey()`, see: https://github.com/cryptocoinjs/eckey/pull/2 75 | * updated name of deps: `bigi` and `bs58` 76 | 77 | 0.1.1 / 2013-12-05 78 | ------------------ 79 | * typo in `toString()` method. Closes #1 80 | 81 | 0.1.0 / 2013-11-20 82 | ------------------ 83 | * changed package name 84 | * removed AMD support 85 | 86 | 0.0.1 / 2013-11-12 87 | ------------------ 88 | * initial release 89 | 90 | [coinstring]: https://github.com/cryptocoinjs/coinstring 91 | 92 | 93 | [#14]: https://github.com/cryptocoinjs/eckey/pull/14 94 | 95 | [#13]: https://github.com/cryptocoinjs/eckey/issues/13 96 | 97 | [#12]: https://github.com/cryptocoinjs/eckey/pull/12 98 | 99 | [#11]: https://github.com/cryptocoinjs/eckey/pull/11 100 | 101 | [#10]: https://github.com/cryptocoinjs/eckey/issues/10 102 | 103 | [#9]: https://github.com/cryptocoinjs/eckey/issues/9 104 | 105 | [#8]: https://github.com/cryptocoinjs/eckey/issues/8 106 | 107 | [#7]: https://github.com/cryptocoinjs/eckey/issues/7 108 | 109 | [#6]: https://github.com/cryptocoinjs/eckey/issues/6 110 | 111 | [#5]: https://github.com/cryptocoinjs/eckey/pull/5 112 | 113 | [#4]: https://github.com/cryptocoinjs/eckey/pull/4 114 | 115 | [#3]: https://github.com/cryptocoinjs/eckey/issues/3 116 | 117 | [#2]: https://github.com/cryptocoinjs/eckey/pull/2 118 | 119 | [#1]: https://github.com/cryptocoinjs/eckey/issues/1 120 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 cryptocoinjs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | eckey 2 | ===== 3 | 4 | [![build status](https://secure.travis-ci.org/cryptocoinjs/eckey.png)](http://travis-ci.org/cryptocoinjs/eckey) 5 | [![Version](http://img.shields.io/npm/v/eckey.svg)](https://www.npmjs.org/package/eckey) 6 | 7 | JavaScript component to handle private key and public keys associated with elliptic curve cryptography. Used with crypto currencies such as Bitcoin, Litecoin, Dogecoin, etc. Works in both Node.js and the browser. 8 | 9 | 10 | Official documentation: 11 | 12 | http://cryptocoinjs.com/modules/currency/eckey/ 13 | -------------------------------------------------------------------------------- /lib/eckey.js: -------------------------------------------------------------------------------- 1 | var crypto = require('crypto') 2 | var secp256k1 = require('secp256k1') 3 | 4 | function ECKey (bytes, compressed) { 5 | if (!(this instanceof ECKey)) return new ECKey(bytes, compressed) 6 | 7 | this._compressed = typeof compressed === 'boolean' ? compressed : true 8 | if (bytes) this.privateKey = bytes 9 | } 10 | 11 | Object.defineProperty(ECKey.prototype, 'privateKey', { 12 | enumerable: true, configurable: true, 13 | get: function () { 14 | return this.key 15 | }, 16 | set: function (bytes) { 17 | var byteArr 18 | if (Buffer.isBuffer(bytes)) { 19 | this.key = bytes 20 | byteArr = [].slice.call(bytes) 21 | } else if (bytes instanceof Uint8Array) { 22 | byteArr = [].slice.call(bytes) 23 | this.key = Buffer.from(byteArr) 24 | } else if (Array.isArray(bytes)) { 25 | byteArr = bytes 26 | this.key = Buffer.from(byteArr) 27 | } else { 28 | throw new Error('Invalid type. private key bytes must be either a Buffer, Array, or Uint8Array.') 29 | } 30 | 31 | if (bytes.length !== 32) throw new Error('private key bytes must have a length of 32') 32 | 33 | // _exportKey => privateKey + (0x01 if compressed) 34 | if (this._compressed) { 35 | this._exportKey = Buffer.concat([ this.key, Buffer.from([0x01]) ]) 36 | } else { 37 | this._exportKey = Buffer.concat([ this.key ]) // clone key as opposed to passing a reference (relevant to Node.js only) 38 | } 39 | 40 | // reset 41 | this._publicKey = null 42 | this._pubKeyHash = null 43 | } 44 | }) 45 | 46 | Object.defineProperty(ECKey.prototype, 'privateExportKey', { 47 | get: function () { 48 | return this._exportKey 49 | } 50 | }) 51 | 52 | Object.defineProperty(ECKey.prototype, 'publicHash', { 53 | get: function () { 54 | return this.pubKeyHash 55 | } 56 | }) 57 | 58 | Object.defineProperty(ECKey.prototype, 'pubKeyHash', { 59 | get: function () { 60 | if (this._pubKeyHash) return this._pubKeyHash 61 | var sha = crypto.createHash('sha256').update(this.publicKey).digest() 62 | try { 63 | this._pubKeyHash = crypto.createHash('rmd160').update(sha).digest() 64 | } catch (e) { 65 | this._pubKeyHash = crypto.createHash('ripemd160').update(sha).digest() 66 | } 67 | return this._pubKeyHash 68 | } 69 | }) 70 | 71 | Object.defineProperty(ECKey.prototype, 'publicKey', { 72 | get: function () { 73 | if (!this._publicKey) this._publicKey = secp256k1.publicKeyCreate(this.key, this.compressed) 74 | return Buffer.from(this._publicKey) 75 | } 76 | }) 77 | 78 | Object.defineProperty(ECKey.prototype, 'compressed', { 79 | get: function () { 80 | return this._compressed 81 | }, 82 | set: function (val) { 83 | var c = !!val 84 | if (c === this._compressed) return 85 | 86 | // reset key stuff 87 | var pk = this.privateKey 88 | this._compressed = c 89 | this.privateKey = pk 90 | } 91 | }) 92 | 93 | ECKey.prototype.toString = function (format) { 94 | return this.privateKey.toString('hex') 95 | } 96 | 97 | module.exports = ECKey 98 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eckey", 3 | "version": "1.0.2", 4 | "description": "Handle private key and public keys associated with elliptic curve cryptography. Used with crypto currencies such as Bitcoin, Litecoin, Dogecoin, etc. Works in both Node.js and the browser.", 5 | "keywords": [ 6 | "cryptography", 7 | "crypto", 8 | "bitcoin", 9 | "litecoin", 10 | "elliptical", 11 | "curve", 12 | "digital", 13 | "sign", 14 | "signing" 15 | ], 16 | "devDependencies": { 17 | "crypto-browserify": "^3.2.5", 18 | "mocha": "2.x", 19 | "secure-random": "^1.0.0", 20 | "standard": "6.x" 21 | }, 22 | "repository": { 23 | "url": "https://github.com/cryptocoinjs/eckey", 24 | "type": "git" 25 | }, 26 | "main": "./lib/eckey.js", 27 | "dependencies": { 28 | "secp256k1": "^3.8.1" 29 | }, 30 | "scripts": { 31 | "lint": "standard", 32 | "test": "standard && mocha --ui bdd", 33 | "unit": "mocha --ui bdd" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/eckey.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | var assert = require('assert') 3 | var secureRandom = require('secure-random') 4 | var ECKey = require('../') 5 | 6 | describe('ECKey', function () { 7 | describe('+ ECKey()', function () { 8 | describe('> when input is a Buffer', function () { 9 | it('should create a new ECKey ', function () { 10 | var buf = secureRandom(32, {type: 'Buffer'}) 11 | var key = new ECKey(buf) 12 | assert.equal(key.privateKey.toString('hex'), buf.toString('hex')) 13 | assert.equal(key.compressed, true) 14 | }) 15 | }) 16 | 17 | describe('> when new isnt used', function () { 18 | it('should create a new ECKey', function () { 19 | var bytes = secureRandom(32, {type: 'Buffer'}) 20 | var buf = Buffer.from(bytes) 21 | var key = ECKey(buf) 22 | assert.equal(key.privateKey.toString('hex'), buf.toString('hex')) 23 | 24 | key = ECKey(buf, true) 25 | assert(key.compressed) 26 | 27 | key = ECKey(buf, false) 28 | assert(!key.compressed) 29 | }) 30 | }) 31 | 32 | describe('> when input is an Uint8Array', function () { 33 | it('should create a new ECKey ', function () { 34 | var bytes = secureRandom(32, {type: 'Uint8Array'}) 35 | assert(bytes instanceof Uint8Array) 36 | 37 | var key = new ECKey(bytes) 38 | assert.equal(key.privateKey.toString('hex'), Buffer.from(bytes).toString('hex')) 39 | assert.equal(key.compressed, true) 40 | }) 41 | }) 42 | 43 | describe('> when input is an Array', function () { 44 | it('should create a new ECKey ', function () { 45 | var bytes = secureRandom(32, {type: 'Array'}) 46 | assert(Array.isArray(bytes)) 47 | 48 | var key = new ECKey(bytes) 49 | assert.equal(key.privateKey.toString('hex'), Buffer.from(bytes).toString('hex')) 50 | assert.equal(key.compressed, true) 51 | }) 52 | }) 53 | 54 | describe('> when compressed is true', function () { 55 | var key = new ECKey(null, true) 56 | assert(key.compressed) 57 | 58 | var key2 = new ECKey(secureRandom(32), true) 59 | assert(key2.compressed) 60 | }) 61 | 62 | describe('> when bad data type', function () { 63 | it('should throw an error', function () { 64 | var data = new Uint16Array(16) 65 | 66 | assert.throws(function () { 67 | return new ECKey(data) 68 | }, /invalid type/i) 69 | }) 70 | }) 71 | }) 72 | 73 | describe('- compressed', function () { 74 | describe('> when false to true', function () { 75 | it('should change privateExportKey and all other affected fields', function () { 76 | var privateKey = Buffer.from('1184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd', 'hex') 77 | var key = new ECKey(privateKey, false) 78 | assert(!key.compressed) 79 | var pubKey = key.publicKey 80 | assert.notStrictEqual(key.privateExportKey.toString('hex').slice(-2), '01', 'ends with 01') 81 | 82 | key.compressed = true 83 | 84 | assert.notEqual(pubKey.toString('hex'), key.publicKey.toString('hex')) 85 | assert.strictEqual(key.privateExportKey.toString('hex').slice(-2), '01', 'ends with 01') 86 | }) 87 | }) 88 | 89 | describe('> when true to false', function () { 90 | it('should change privateExportKey and all other affected fields', function () { 91 | var privateKey = Buffer.from('1184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd', 'hex') 92 | var key = new ECKey(privateKey, true) 93 | assert(key.compressed) 94 | var pubKey = key.publicKey 95 | assert.strictEqual(key.privateExportKey.toString('hex').slice(-2), '01', 'ends with 01') 96 | 97 | key.compressed = false 98 | 99 | assert.notEqual(pubKey.toString('hex'), key.publicKey.toString('hex')) 100 | assert.notStrictEqual(key.privateExportKey.toString('hex').slice(-2), '01', 'ends with 01') 101 | }) 102 | }) 103 | }) 104 | 105 | describe('- privateKey', function () { 106 | it('should return the private key', function () { 107 | var privateKeyHex = '1184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd' 108 | var key = new ECKey([].slice.call(Buffer.from(privateKeyHex, 'hex'))) 109 | assert.equal(key.privateKey.toString('hex'), privateKeyHex) 110 | }) 111 | 112 | describe('> when length is not 32', function () { 113 | var key = new ECKey() 114 | it('should throw an error', function () { 115 | assert.throws(function () { 116 | key.privateKey = Buffer.from('ff33', 'hex') 117 | }, /length of 32/i) 118 | }) 119 | }) 120 | }) 121 | 122 | describe('- privateExportKey', function () { 123 | describe('> when not compressed', function () { 124 | it('should return the private key', function () { 125 | var privateKeyHex = '1184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd' 126 | var key = new ECKey(Buffer.from(privateKeyHex, 'hex'), false) 127 | assert.equal(key.privateExportKey.toString('hex'), privateKeyHex) 128 | }) 129 | }) 130 | 131 | describe('> when compressed', function () { 132 | it('should return the private key', function () { 133 | var privateKeyHex = '1184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd' 134 | var key = new ECKey(Buffer.from(privateKeyHex, 'hex'), true) 135 | assert.equal(key.compressed, true) 136 | assert.equal(key.privateExportKey.toString('hex'), privateKeyHex + '01') 137 | }) 138 | }) 139 | }) 140 | 141 | describe('- publicKey', function () { 142 | describe('> when not compressed', function () { 143 | it('should return the 65 byte public key', function () { 144 | var privateKeyHex = '1184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd' 145 | var publicKeyHex = '04d0988bfa799f7d7ef9ab3de97ef481cd0f75d2367ad456607647edde665d6f6fbdd594388756a7beaf73b4822bc22d36e9bda7db82df2b8b623673eefc0b7495' 146 | var key = new ECKey([].slice.call(Buffer.from(privateKeyHex, 'hex')), false) 147 | assert.equal(key.publicKey.length, 65) 148 | assert.equal(key.publicKey.toString('hex'), publicKeyHex) 149 | }) 150 | }) 151 | 152 | describe('> when compressed', function () { 153 | it('should return the 33 byte public key', function () { 154 | var privateKeyHex = '1184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd' 155 | var publicKeyHex = '03d0988bfa799f7d7ef9ab3de97ef481cd0f75d2367ad456607647edde665d6f6f' 156 | var key = new ECKey([].slice.call(Buffer.from(privateKeyHex, 'hex')), true) 157 | 158 | assert(key.compressed) 159 | assert.equal(key.publicKey.length, 33) 160 | assert.equal(key.publicKey.toString('hex'), publicKeyHex) 161 | }) 162 | }) 163 | }) 164 | 165 | describe('- publicHash', function () { 166 | it('should return the hash 160 of public key', function () { 167 | var key = new ECKey(Buffer.from('1184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd', 'hex'), false) 168 | assert.equal(key.publicHash.toString('hex'), '3c176e659bea0f29a3e9bf7880c112b1b31b4dc8') 169 | assert.equal(key.pubKeyHash.toString('hex'), '3c176e659bea0f29a3e9bf7880c112b1b31b4dc8') 170 | key.compressed = true 171 | assert.equal(key.publicHash.toString('hex'), 'a1c2f92a9dacbd2991c3897724a93f338e44bdc1') 172 | assert.equal(key.pubKeyHash.toString('hex'), 'a1c2f92a9dacbd2991c3897724a93f338e44bdc1') 173 | }) 174 | }) 175 | 176 | describe('- toString()', function () { 177 | it('should show the string representation in...', function () { 178 | var privateKeyBytes = [].slice.call(Buffer.from('1184CD2CDD640CA42CFC3A091C51D549B2F016D454B2774019C2B2D2E08529FD', 'hex')) 179 | var eckey = new ECKey(privateKeyBytes) 180 | var s = eckey.toString() 181 | assert.equal(s, '1184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd') 182 | }) 183 | }) 184 | }) 185 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --ui bdd 2 | --reporter spec 3 | --timeout 2000 4 | --check-leaks --------------------------------------------------------------------------------