diff --git a/packages/ripple-keypairs/package.json b/packages/ripple-keypairs/package.json index da8d2428..3fec5432 100644 --- a/packages/ripple-keypairs/package.json +++ b/packages/ripple-keypairs/package.json @@ -24,18 +24,18 @@ "assert-diff": "^1.0.1", "babel": "^5.8.20", "babel-core": "^5.8.20", - "babel-eslint": "^4.0.5", + "babel-eslint": "^6.0.0", "babel-loader": "^5.3.2", "codecov.io": "^0.1.6", "coveralls": "~2.11.4", - "eslint": "^1.2.1", + "eslint": "2.7.0", "eventemitter2": "^0.4.14", "istanbul": "~0.3.5", "lodash": "^3.10.0", "map-stream": "~0.1.0", "mocha": "~2.3.3", "nock": "^2.13.0", - "ripple-lib": "^0.12.4" + "ripple-lib": "^0.17.0" }, "scripts": { "build": "gulp", diff --git a/packages/ripple-keypairs/src/index.js b/packages/ripple-keypairs/src/index.js index e2465a7c..1be9fc90 100644 --- a/packages/ripple-keypairs/src/index.js +++ b/packages/ripple-keypairs/src/index.js @@ -1,109 +1,110 @@ -'use strict'; -const assert = require('assert'); -const brorand = require('brorand'); -const hashjs = require('hash.js'); -const elliptic = require('elliptic'); -const Ed25519 = elliptic.eddsa('ed25519'); -const Secp256k1 = elliptic.ec('secp256k1'); -const addressCodec = require('ripple-address-codec'); -const derivePrivateKey = require('./secp256k1').derivePrivateKey; +'use strict' // eslint-disable-line strict + +const assert = require('assert') +const brorand = require('brorand') +const hashjs = require('hash.js') +const elliptic = require('elliptic') +const Ed25519 = elliptic.eddsa('ed25519') +const Secp256k1 = elliptic.ec('secp256k1') +const addressCodec = require('ripple-address-codec') +const derivePrivateKey = require('./secp256k1').derivePrivateKey const accountPublicFromPublicGenerator = require('./secp256k1') - .accountPublicFromPublicGenerator; -const utils = require('./utils'); -const hexToBytes = utils.hexToBytes; -const bytesToHex = utils.bytesToHex; + .accountPublicFromPublicGenerator +const utils = require('./utils') +const hexToBytes = utils.hexToBytes +const bytesToHex = utils.bytesToHex function generateSeed(options = {}) { - assert(!options.entropy || options.entropy.length >= 16, 'entropy too short'); - const entropy = options.entropy ? options.entropy.slice(0, 16) : brorand(16); - const type = options.algorithm === 'ed25519' ? 'ed25519' : 'secp256k1'; - return addressCodec.encodeSeed(entropy, type); + assert(!options.entropy || options.entropy.length >= 16, 'entropy too short') + const entropy = options.entropy ? options.entropy.slice(0, 16) : brorand(16) + const type = options.algorithm === 'ed25519' ? 'ed25519' : 'secp256k1' + return addressCodec.encodeSeed(entropy, type) } function hash(message) { - return hashjs.sha512().update(message).digest().slice(0, 32); + return hashjs.sha512().update(message).digest().slice(0, 32) } const secp256k1 = { deriveKeypair: function(entropy, options) { - const prefix = '00'; + const prefix = '00' const privateKey = prefix + derivePrivateKey(entropy, options) - .toString(16, 64).toUpperCase(); + .toString(16, 64).toUpperCase() const publicKey = bytesToHex(Secp256k1.keyFromPrivate( - privateKey.slice(2)).getPublic().encodeCompressed()); - return {privateKey, publicKey}; + privateKey.slice(2)).getPublic().encodeCompressed()) + return {privateKey, publicKey} }, sign: function(message, privateKey) { return bytesToHex(Secp256k1.sign(hash(message), - hexToBytes(privateKey), {canonical: true}).toDER()); + hexToBytes(privateKey), {canonical: true}).toDER()) }, verify: function(message, signature, publicKey) { - return Secp256k1.verify(hash(message), signature, hexToBytes(publicKey)); + return Secp256k1.verify(hash(message), signature, hexToBytes(publicKey)) } -}; +} const ed25519 = { deriveKeypair: function(entropy) { - const prefix = 'ED'; - const rawPrivateKey = hash(entropy); - const privateKey = prefix + bytesToHex(rawPrivateKey); + const prefix = 'ED' + const rawPrivateKey = hash(entropy) + const privateKey = prefix + bytesToHex(rawPrivateKey) const publicKey = prefix + bytesToHex( - Ed25519.keyFromSecret(rawPrivateKey).pubBytes()); - return {privateKey, publicKey}; + Ed25519.keyFromSecret(rawPrivateKey).pubBytes()) + return {privateKey, publicKey} }, sign: function(message, privateKey) { // caution: Ed25519.sign interprets all strings as hex, stripping // any non-hex characters without warning - assert(Array.isArray(message), 'message must be array of octets'); + assert(Array.isArray(message), 'message must be array of octets') return bytesToHex(Ed25519.sign( - message, hexToBytes(privateKey).slice(1)).toBytes()); + message, hexToBytes(privateKey).slice(1)).toBytes()) }, verify: function(message, signature, publicKey) { return Ed25519.verify(message, hexToBytes(signature), - hexToBytes(publicKey).slice(1)); + hexToBytes(publicKey).slice(1)) } -}; +} function select(algorithm) { - const methods = {'ecdsa-secp256k1': secp256k1, ed25519}; - return methods[algorithm]; + const methods = {'ecdsa-secp256k1': secp256k1, ed25519} + return methods[algorithm] } function deriveKeypair(seed, options) { - const decoded = addressCodec.decodeSeed(seed); - const algorithm = decoded.type === 'ed25519' ? 'ed25519' : 'ecdsa-secp256k1'; - return select(algorithm).deriveKeypair(decoded.bytes, options); + const decoded = addressCodec.decodeSeed(seed) + const algorithm = decoded.type === 'ed25519' ? 'ed25519' : 'ecdsa-secp256k1' + return select(algorithm).deriveKeypair(decoded.bytes, options) } function getAlgorithmFromKey(key) { - const bytes = hexToBytes(key); + const bytes = hexToBytes(key) return (bytes.length === 33 && bytes[0] === 0xED) ? - 'ed25519' : 'ecdsa-secp256k1'; + 'ed25519' : 'ecdsa-secp256k1' } function sign(messageHex, privateKey) { - const algorithm = getAlgorithmFromKey(privateKey); - return select(algorithm).sign(hexToBytes(messageHex), privateKey); + const algorithm = getAlgorithmFromKey(privateKey) + return select(algorithm).sign(hexToBytes(messageHex), privateKey) } function verify(messageHex, signature, publicKey) { - const algorithm = getAlgorithmFromKey(publicKey); - return select(algorithm).verify(hexToBytes(messageHex), signature, publicKey); + const algorithm = getAlgorithmFromKey(publicKey) + return select(algorithm).verify(hexToBytes(messageHex), signature, publicKey) } function deriveAddressFromBytes(publicKeyBytes) { return addressCodec.encodeAccountID( - utils.computePublicKeyHash(publicKeyBytes)); + utils.computePublicKeyHash(publicKeyBytes)) } function deriveAddress(publicKey) { - return deriveAddressFromBytes(hexToBytes(publicKey)); + return deriveAddressFromBytes(hexToBytes(publicKey)) } function deriveNodeAddress(publicKey) { - const generatorBytes = addressCodec.decodeNodePublic(publicKey); - const accountPublicBytes = accountPublicFromPublicGenerator(generatorBytes); - return deriveAddressFromBytes(accountPublicBytes); + const generatorBytes = addressCodec.decodeNodePublic(publicKey) + const accountPublicBytes = accountPublicFromPublicGenerator(generatorBytes) + return deriveAddressFromBytes(accountPublicBytes) } module.exports = { @@ -113,4 +114,4 @@ module.exports = { verify, deriveAddress, deriveNodeAddress -}; +} diff --git a/packages/ripple-keypairs/src/secp256k1.js b/packages/ripple-keypairs/src/secp256k1.js index c5f3c53f..db3ec753 100644 --- a/packages/ripple-keypairs/src/secp256k1.js +++ b/packages/ripple-keypairs/src/secp256k1.js @@ -1,26 +1,26 @@ -'use strict'; +'use strict' // eslint-disable-line strict -const elliptic = require('elliptic'); -const secp256k1 = elliptic.ec('secp256k1'); -const Sha512 = require('./sha512'); +const elliptic = require('elliptic') +const secp256k1 = elliptic.ec('secp256k1') +const Sha512 = require('./sha512') function deriveScalar(bytes, discrim) { - const order = secp256k1.curve.n; + const order = secp256k1.curve.n for (let i = 0; i <= 0xFFFFFFFF; i++) { // We hash the bytes to find a 256 bit number, looping until we are sure it // is less than the order of the curve. - const hasher = new Sha512().add(bytes); + const hasher = new Sha512().add(bytes) // If the optional discriminator index was passed in, update the hash. if (discrim !== undefined) { - hasher.addU32(discrim); + hasher.addU32(discrim) } - hasher.addU32(i); - const key = hasher.first256BN(); + hasher.addU32(i) + const key = hasher.first256BN() if (key.cmpn(0) > 0 && key.cmp(order) < 0) { - return key; + return key } } - throw new Error('impossible unicorn ;)'); + throw new Error('impossible unicorn ;)') } /** @@ -33,33 +33,33 @@ function deriveScalar(bytes, discrim) { * */ function derivePrivateKey(seed, opts = {}) { - const root = opts.validator; - const order = secp256k1.curve.n; + const root = opts.validator + const order = secp256k1.curve.n // This private generator represents the `root` private key, and is what's // used by validators for signing when a keypair is generated from a seed. - const privateGen = deriveScalar(seed); + const privateGen = deriveScalar(seed) if (root) { // As returned by validation_create for a given seed - return privateGen; + return privateGen } - const publicGen = secp256k1.g.mul(privateGen); + const publicGen = secp256k1.g.mul(privateGen) // A seed can generate many keypairs as a function of the seed and a uint32. // Almost everyone just uses the first account, `0`. - const accountIndex = opts.accountIndex || 0; + const accountIndex = opts.accountIndex || 0 return deriveScalar(publicGen.encodeCompressed(), accountIndex) - .add(privateGen).mod(order); + .add(privateGen).mod(order) } function accountPublicFromPublicGenerator(publicGenBytes) { - const rootPubPoint = secp256k1.curve.decodePoint(publicGenBytes); - const scalar = deriveScalar(publicGenBytes, 0); - const point = secp256k1.g.mul(scalar); - const offset = rootPubPoint.add(point); - return offset.encodeCompressed(); + const rootPubPoint = secp256k1.curve.decodePoint(publicGenBytes) + const scalar = deriveScalar(publicGenBytes, 0) + const point = secp256k1.g.mul(scalar) + const offset = rootPubPoint.add(point) + return offset.encodeCompressed() } module.exports = { derivePrivateKey, accountPublicFromPublicGenerator -}; +} diff --git a/packages/ripple-keypairs/src/sha512.js b/packages/ripple-keypairs/src/sha512.js index 5c47a557..fa54970e 100644 --- a/packages/ripple-keypairs/src/sha512.js +++ b/packages/ripple-keypairs/src/sha512.js @@ -1,27 +1,27 @@ -'use strict'; +'use strict' // eslint-disable-line strict -const hashjs = require('hash.js'); -const BigNum = require('bn.js'); +const hashjs = require('hash.js') +const BigNum = require('bn.js') module.exports = class Sha512 { constructor() { - this.hash = hashjs.sha512(); + this.hash = hashjs.sha512() } add(bytes) { - this.hash.update(bytes); - return this; + this.hash.update(bytes) + return this } addU32(i) { return this.add([(i >>> 24) & 0xFF, (i >>> 16) & 0xFF, - (i >>> 8) & 0xFF, i & 0xFF]); + (i >>> 8) & 0xFF, i & 0xFF]) } finish() { - return this.hash.digest(); + return this.hash.digest() } first256() { - return this.finish().slice(0, 32); + return this.finish().slice(0, 32) } first256BN() { - return new BigNum(this.first256()); + return new BigNum(this.first256()) } -}; +} diff --git a/packages/ripple-keypairs/src/utils.js b/packages/ripple-keypairs/src/utils.js index 482aa049..392cae77 100644 --- a/packages/ripple-keypairs/src/utils.js +++ b/packages/ripple-keypairs/src/utils.js @@ -1,28 +1,29 @@ -'use strict'; -const assert = require('assert'); -const hashjs = require('hash.js'); -const BN = require('bn.js'); +'use strict' // eslint-disable-line strict + +const assert = require('assert') +const hashjs = require('hash.js') +const BN = require('bn.js') function bytesToHex(a) { return a.map(function(byteValue) { - const hex = byteValue.toString(16).toUpperCase(); - return hex.length > 1 ? hex : '0' + hex; - }).join(''); + const hex = byteValue.toString(16).toUpperCase() + return hex.length > 1 ? hex : '0' + hex + }).join('') } function hexToBytes(a) { - assert(a.length % 2 === 0); - return (new BN(a, 16)).toArray(null, a.length / 2); + assert(a.length % 2 === 0) + return (new BN(a, 16)).toArray(null, a.length / 2) } function computePublicKeyHash(publicKeyBytes) { - const hash256 = hashjs.sha256().update(publicKeyBytes).digest(); - const hash160 = hashjs.ripemd160().update(hash256).digest(); - return hash160; + const hash256 = hashjs.sha256().update(publicKeyBytes).digest() + const hash160 = hashjs.ripemd160().update(hash256).digest() + return hash160 } function seedFromPhrase(phrase) { - return hashjs.sha512().update(phrase).digest().slice(0, 16); + return hashjs.sha512().update(phrase).digest().slice(0, 16) } module.exports = { @@ -30,4 +31,4 @@ module.exports = { hexToBytes, computePublicKeyHash, seedFromPhrase -}; +} diff --git a/packages/ripple-keypairs/test/api-test.js b/packages/ripple-keypairs/test/api-test.js index b5793afe..3f78290f 100644 --- a/packages/ripple-keypairs/test/api-test.js +++ b/packages/ripple-keypairs/test/api-test.js @@ -1,98 +1,99 @@ -'use strict'; -const assert = require('assert'); -const fixtures = require('./fixtures/api.json'); -const api = require('../src'); -const decodeSeed = require('ripple-address-codec').decodeSeed; -const entropy = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; +'use strict' // eslint-disable-line strict + +const assert = require('assert') +const fixtures = require('./fixtures/api.json') +const api = require('../src') +const decodeSeed = require('ripple-address-codec').decodeSeed +const entropy = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] describe('api', () => { it('generateSeed - secp256k1', () => { - assert.strictEqual(api.generateSeed({entropy}), fixtures.secp256k1.seed); - }); + assert.strictEqual(api.generateSeed({entropy}), fixtures.secp256k1.seed) + }) it('generateSeed - secp256k1, random', () => { - const seed = api.generateSeed(); - assert(seed.charAt(0) === 's'); - const {type, bytes} = decodeSeed(seed); - assert(type === 'secp256k1'); - assert(bytes.length === 16); - }); + const seed = api.generateSeed() + assert(seed.charAt(0) === 's') + const {type, bytes} = decodeSeed(seed) + assert(type === 'secp256k1') + assert(bytes.length === 16) + }) it('generateSeed - ed25519', () => { assert.strictEqual(api.generateSeed({entropy, algorithm: 'ed25519'}), - fixtures.ed25519.seed); - }); + fixtures.ed25519.seed) + }) it('generateSeed - ed25519, random', () => { - const seed = api.generateSeed({algorithm: 'ed25519'}); - assert(seed.slice(0, 3) === 'sEd'); - const {type, bytes} = decodeSeed(seed); - assert(type === 'ed25519'); - assert(bytes.length === 16); - }); + const seed = api.generateSeed({algorithm: 'ed25519'}) + assert(seed.slice(0, 3) === 'sEd') + const {type, bytes} = decodeSeed(seed) + assert(type === 'ed25519') + assert(bytes.length === 16) + }) it('deriveKeypair - secp256k1', () => { - const keypair = api.deriveKeypair(fixtures.secp256k1.seed); - assert.deepEqual(keypair, fixtures.secp256k1.keypair); - }); + const keypair = api.deriveKeypair(fixtures.secp256k1.seed) + assert.deepEqual(keypair, fixtures.secp256k1.keypair) + }) it('deriveKeypair - ed25519', () => { - const keypair = api.deriveKeypair(fixtures.ed25519.seed); - assert.deepEqual(keypair, fixtures.ed25519.keypair); - }); + const keypair = api.deriveKeypair(fixtures.ed25519.seed) + assert.deepEqual(keypair, fixtures.ed25519.keypair) + }) it('deriveAddress - secp256k1 public key', () => { - const address = api.deriveAddress(fixtures.secp256k1.keypair.publicKey); - assert.strictEqual(address, fixtures.secp256k1.address); - }); + const address = api.deriveAddress(fixtures.secp256k1.keypair.publicKey) + assert.strictEqual(address, fixtures.secp256k1.address) + }) it('deriveAddress - ed25519 public key', () => { - const address = api.deriveAddress(fixtures.ed25519.keypair.publicKey); - assert.strictEqual(address, fixtures.ed25519.address); - }); + const address = api.deriveAddress(fixtures.ed25519.keypair.publicKey) + assert.strictEqual(address, fixtures.ed25519.address) + }) it('sign - secp256k1', () => { - const privateKey = fixtures.secp256k1.keypair.privateKey; - const message = fixtures.secp256k1.message; - const messageHex = (new Buffer(message, 'utf8')).toString('hex'); - const signature = api.sign(messageHex, privateKey); - assert.strictEqual(signature, fixtures.secp256k1.signature); - }); + const privateKey = fixtures.secp256k1.keypair.privateKey + const message = fixtures.secp256k1.message + const messageHex = (new Buffer(message, 'utf8')).toString('hex') + const signature = api.sign(messageHex, privateKey) + assert.strictEqual(signature, fixtures.secp256k1.signature) + }) it('verify - secp256k1', () => { - const signature = fixtures.secp256k1.signature; - const publicKey = fixtures.secp256k1.keypair.publicKey; - const message = fixtures.secp256k1.message; - const messageHex = (new Buffer(message, 'utf8')).toString('hex'); - assert(api.verify(messageHex, signature, publicKey)); - }); + const signature = fixtures.secp256k1.signature + const publicKey = fixtures.secp256k1.keypair.publicKey + const message = fixtures.secp256k1.message + const messageHex = (new Buffer(message, 'utf8')).toString('hex') + assert(api.verify(messageHex, signature, publicKey)) + }) it('sign - ed25519', () => { - const privateKey = fixtures.ed25519.keypair.privateKey; - const message = fixtures.ed25519.message; - const messageHex = (new Buffer(message, 'utf8')).toString('hex'); - const signature = api.sign(messageHex, privateKey); - assert.strictEqual(signature, fixtures.ed25519.signature); - }); + const privateKey = fixtures.ed25519.keypair.privateKey + const message = fixtures.ed25519.message + const messageHex = (new Buffer(message, 'utf8')).toString('hex') + const signature = api.sign(messageHex, privateKey) + assert.strictEqual(signature, fixtures.ed25519.signature) + }) it('verify - ed25519', () => { - const signature = fixtures.ed25519.signature; - const publicKey = fixtures.ed25519.keypair.publicKey; - const message = fixtures.ed25519.message; - const messageHex = (new Buffer(message, 'utf8')).toString('hex'); - assert(api.verify(messageHex, signature, publicKey)); - }); + const signature = fixtures.ed25519.signature + const publicKey = fixtures.ed25519.keypair.publicKey + const message = fixtures.ed25519.message + const messageHex = (new Buffer(message, 'utf8')).toString('hex') + assert(api.verify(messageHex, signature, publicKey)) + }) it('deriveNodeAddress', () => { - const x = 'n9KHn8NfbBsZV5q8bLfS72XyGqwFt5mgoPbcTV4c6qKiuPTAtXYk'; - const y = 'rU7bM9ENDkybaxNrefAVjdLTyNLuue1KaJ'; - assert.strictEqual(api.deriveNodeAddress(x), y); - }); + const x = 'n9KHn8NfbBsZV5q8bLfS72XyGqwFt5mgoPbcTV4c6qKiuPTAtXYk' + const y = 'rU7bM9ENDkybaxNrefAVjdLTyNLuue1KaJ' + assert.strictEqual(api.deriveNodeAddress(x), y) + }) it('Random Address', () => { - const seed = api.generateSeed(); - const keypair = api.deriveKeypair(seed); - const address = api.deriveAddress(keypair.publicKey); - assert(address[0] === 'r'); - }); -}); + const seed = api.generateSeed() + const keypair = api.deriveKeypair(seed) + const address = api.deriveAddress(keypair.publicKey) + assert(address[0] === 'r') + }) +}) diff --git a/packages/ripple-keypairs/test/utils-test.js b/packages/ripple-keypairs/test/utils-test.js index 90ea05aa..8c0a78cc 100644 --- a/packages/ripple-keypairs/test/utils-test.js +++ b/packages/ripple-keypairs/test/utils-test.js @@ -1,13 +1,14 @@ -'use strict'; -const assert = require('assert'); -const utils = require('../src/utils'); +'use strict' // eslint-disable-line strict + +const assert = require('assert') +const utils = require('../src/utils') describe('utils', () => { it('hexToBytes - zero', () => { - assert.deepEqual(utils.hexToBytes('000000'), [0, 0, 0]); - }); + assert.deepEqual(utils.hexToBytes('000000'), [0, 0, 0]) + }) it('hexToBytes - DEADBEEF', () => { - assert.deepEqual(utils.hexToBytes('DEADBEEF'), [222, 173, 190, 239]); - }); -}); + assert.deepEqual(utils.hexToBytes('DEADBEEF'), [222, 173, 190, 239]) + }) +})