diff --git a/.flowconfig b/.flowconfig index 0cff1d89d..b73426efe 100644 --- a/.flowconfig +++ b/.flowconfig @@ -13,5 +13,5 @@ all=warn [options] include_warnings=true -module.name_mapper='^@polkadot/util-\(crypto\|rlp\|triehash\)\(.*\)$' -> '/packages/util-\1/src\2' +module.name_mapper='^@polkadot/util-\(crypto\|keyring\|rlp\|triehash\)\(.*\)$' -> '/packages/util-\1/src\2' module.name_mapper='^@polkadot/util\(.*\)$' -> '/packages/util/src\1' diff --git a/README.md b/README.md index 0eb2569a3..110a56469 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ It is split up into a number of internal packages - - [packages/util](packages/util/) General utilities - [packages/util-crypto](packages/util-crypto/) Crypto and hashing utilities +- [packages/util-keyring](packages/util-crypto/) Keyring management - [packages/util-rlp](packages/util-rlp/) RLP encoding & decoding - [packages/util-triehash](packages/util-triehash/) Calculation of trie hashes diff --git a/jest.config.js b/jest.config.js index bd77b1f47..9a7e26241 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,7 +2,7 @@ const config = require('@polkadot/dev/config/jest'); module.exports = Object.assign({}, config, { moduleNameMapper: { - '@polkadot/util-(crypto|rlp|triehash)(.*)$': '/packages/util-$1/src/$2', + '@polkadot/util-(crypto|keyring|rlp|triehash)(.*)$': '/packages/util-$1/src/$2', '@polkadot/util(.*)$': '/packages/util/src/$1' } }); diff --git a/lerna.json b/lerna.json index 522b16d3f..ccc9b8fbc 100644 --- a/lerna.json +++ b/lerna.json @@ -10,5 +10,5 @@ "packages": [ "packages/*" ], - "version": "0.15.10" + "version": "0.16.0" } diff --git a/packages/util-crypto/package.json b/packages/util-crypto/package.json index 1d16e2171..430f552db 100644 --- a/packages/util-crypto/package.json +++ b/packages/util-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/util-crypto", - "version": "0.15.10", + "version": "0.16.0", "description": "A collection of useful crypto utilities for @polkadot", "main": "index.js", "keywords": [ diff --git a/packages/util-crypto/src/blake2/blake2b/asU8a.spec.js b/packages/util-crypto/src/blake2/blake2b/asU8a.spec.js index e2fc368b8..5757e4df2 100644 --- a/packages/util-crypto/src/blake2/blake2b/asU8a.spec.js +++ b/packages/util-crypto/src/blake2/blake2b/asU8a.spec.js @@ -5,20 +5,17 @@ const { blake2bAsU8a } = require('./index'); describe('blake2bAsU8a', () => { + it('creates the correct hash (default length)', () => { + expect( + blake2bAsU8a('abc') + ).toEqual(new Uint8Array([186, 128, 165, 63, 152, 28, 77, 13, 106, 39, 151, 182, 159, 18, 246, 233, 76, 33, 47, 20, 104, 90, 196, 183, 75, 18, 187, 111, 219, 255, 162, 209, 125, 135, 197, 57, 42, 171, 121, 45, 194, 82, 213, 222, 69, 51, 204, 149, 24, 211, 138, 168, 219, 241, 146, 90, 185, 35, 134, 237, 212, 0, 153, 35])); + }); + it('creates the correct hash', () => { expect( - blake2bAsU8a('abc', 512) + blake2bAsU8a('abc', 256) ).toEqual( - Uint8Array.from([ - 0xba, 0x80, 0xa5, 0x3f, 0x98, 0x1c, 0x4d, 0x0d, - 0x6a, 0x27, 0x97, 0xb6, 0x9f, 0x12, 0xf6, 0xe9, - 0x4c, 0x21, 0x2f, 0x14, 0x68, 0x5a, 0xc4, 0xb7, - 0x4b, 0x12, 0xbb, 0x6f, 0xdb, 0xff, 0xa2, 0xd1, - 0x7d, 0x87, 0xc5, 0x39, 0x2a, 0xab, 0x79, 0x2d, - 0xc2, 0x52, 0xd5, 0xde, 0x45, 0x33, 0xcc, 0x95, - 0x18, 0xd3, 0x8a, 0xa8, 0xdb, 0xf1, 0x92, 0x5a, - 0xb9, 0x23, 0x86, 0xed, 0xd4, 0x00, 0x99, 0x23 - ]) + new Uint8Array([189, 221, 129, 60, 99, 66, 57, 114, 49, 113, 239, 63, 238, 152, 87, 155, 148, 150, 78, 59, 177, 203, 62, 66, 114, 98, 200, 192, 104, 213, 35, 25]) ); }); }); diff --git a/packages/util-keyring/LICENSE b/packages/util-keyring/LICENSE new file mode 100644 index 000000000..3d150a620 --- /dev/null +++ b/packages/util-keyring/LICENSE @@ -0,0 +1,15 @@ +ISC License (ISC) + +Copyright 2017-2018 Jaco Greeff + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/util-keyring/README.md b/packages/util-keyring/README.md new file mode 100644 index 000000000..bc3aa7470 --- /dev/null +++ b/packages/util-keyring/README.md @@ -0,0 +1,13 @@ +[![polkadotjs](https://img.shields.io/badge/polkadot-js-orange.svg?style=flat-square)](https://polkadot.js.org) +![isc](https://img.shields.io/badge/license-ISC-lightgrey.svg?style=flat-square) +[![style](https://img.shields.io/badge/code%20style-semistandard-lightgrey.svg?style=flat-square)](https://github.com/Flet/semistandard) +[![npm](https://img.shields.io/npm/v/@polkadot/util-keyring.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/util-keyring) +[![travis](https://img.shields.io/travis/polkadot-js/client.svg?style=flat-square)](https://travis-ci.org/polkadot-js/client) +[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/client.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/client/maintainability) +[![coverage](https://img.shields.io/coveralls/polkadot-js/client.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/client?branch=master) +[![dependency](https://david-dm.org/polkadot-js/client.svg?style=flat-square&path=packages/util-keyring)](https://david-dm.org/polkadot-js/client?path=packages/util-keyring) +[![devDependency](https://david-dm.org/polkadot-js/client/dev-status.svg?style=flat-square&path=packages/util-keyring)](https://david-dm.org/polkadot-js/client?path=packages/util-keyring#info=devDependencies) + +# @polkadot/util-keyring + +Key management diff --git a/packages/util-keyring/docs/README.md b/packages/util-keyring/docs/README.md new file mode 100644 index 000000000..3b7b91d37 --- /dev/null +++ b/packages/util-keyring/docs/README.md @@ -0,0 +1,6 @@ +# Available interfaces + + + + +# Available methods \ No newline at end of file diff --git a/packages/util-keyring/package.json b/packages/util-keyring/package.json new file mode 100644 index 000000000..4b2208035 --- /dev/null +++ b/packages/util-keyring/package.json @@ -0,0 +1,38 @@ +{ + "name": "@polkadot/util-keyring", + "version": "0.16.0", + "description": "Keyring management", + "main": "index.js", + "engines": { + "node": ">=8.0" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/polkadot-js/client.git" + }, + "keywords": [ + "Polkadot", + "Keyring", + "ed25519" + ], + "author": "Jaco Greeff ", + "license": "ISC", + "bugs": { + "url": "https://github.com/polkadot-js/client/issues" + }, + "homepage": "https://github.com/polkadot-js/client/tree/master/packages/util-keyring#readme", + "scripts": { + "build": "polkadot-dev-build-babel", + "check": "eslint src && flow check", + "test": "echo \"Tests only available from root wrapper\"" + }, + "dependencies": { + "@polkadot/util": "^0.16.0", + "@polkadot/util-crypto": "^0.16.0", + "babel-runtime": "^6.26.0" + } +} diff --git a/packages/util-keyring/src/index.js b/packages/util-keyring/src/index.js new file mode 100644 index 000000000..106745af4 --- /dev/null +++ b/packages/util-keyring/src/index.js @@ -0,0 +1,37 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { KeyringInstance, KeyringPair } from './types'; + +type KeyringPairMap = { + [string]: KeyringPair +}; + +const naclKeypairFromSeed = require('@polkadot/util-crypto/nacl/keypair/fromSeed'); +const u8aToString = require('@polkadot/util/u8a/toString'); + +const createPair = require('./pair'); + +module.exports = function keyring (): KeyringInstance { + const pairs: KeyringPairMap = {}; + const getPairs = (): Array => + // flowlint-next-line unclear-type:off + ((Object.values(pairs): any): Array); + + return { + addFromSeed: (seed: Uint8Array | string): KeyringPair => { + const pair = createPair(naclKeypairFromSeed(seed)); + + pairs[pair.id] = pair; + + return pair; + }, + getPair: (publicKey: Uint8Array): ?KeyringPair => + pairs[u8aToString(publicKey)], + getPairs, + getPublicKeys: (): Array => + getPairs().map(({ publicKey }) => publicKey) + }; +}; diff --git a/packages/util-keyring/src/index.spec.js b/packages/util-keyring/src/index.spec.js new file mode 100644 index 000000000..41ad997ae --- /dev/null +++ b/packages/util-keyring/src/index.spec.js @@ -0,0 +1,43 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const index = require('./index'); + +describe('keypair', () => { + const publicKeyOne = new Uint8Array([47, 140, 97, 41, 216, 22, 207, 81, 195, 116, 188, 127, 8, 195, 230, 62, 209, 86, 207, 120, 174, 251, 74, 101, 80, 217, 123, 135, 153, 121, 119, 238]); + const publicKeyTwo = new Uint8Array([215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]); + const seedOne = '12345678901234567890123456789012'; + const seedTwo = '0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60'; + let keypair; + + beforeEach(() => { + keypair = index(); + + keypair.addFromSeed(seedOne); + }); + + it('adds the pair', () => { + expect( + keypair.addFromSeed(seedTwo) + ).toMatchObject({ + publicKey: publicKeyTwo + }); + }); + + it('allows publicKeys retrieval', () => { + keypair.addFromSeed(seedTwo); + + expect( + keypair.getPublicKeys() + ).toEqual([ publicKeyOne, publicKeyTwo ]); + }); + + it('allows retrieval of a specific item', () => { + expect( + keypair.getPair(publicKeyOne) + ).toMatchObject({ + publicKey: publicKeyOne + }); + }); +}); diff --git a/packages/util-keyring/src/pair.js b/packages/util-keyring/src/pair.js new file mode 100644 index 000000000..0e038408c --- /dev/null +++ b/packages/util-keyring/src/pair.js @@ -0,0 +1,22 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { KeypairType } from '@polkadot/util-crypto/types'; +import type { KeyringPair } from './types'; + +const naclSign = require('@polkadot/util-crypto/nacl/sign'); +const naclVerify = require('@polkadot/util-crypto/nacl/verify'); +const u8aToString = require('@polkadot/util/u8a/toString'); + +module.exports = function pair ({ publicKey, secretKey }: KeypairType): KeyringPair { + return { + id: u8aToString(publicKey), + publicKey, + sign: (message: Uint8Array): Uint8Array => + naclSign(message, secretKey), + verify: (message: Uint8Array, signature: Uint8Array): boolean => + naclVerify(message, signature, publicKey) + }; +}; diff --git a/packages/util-keyring/src/pair.spec.js b/packages/util-keyring/src/pair.spec.js new file mode 100644 index 000000000..69d36149d --- /dev/null +++ b/packages/util-keyring/src/pair.spec.js @@ -0,0 +1,44 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const keyring = require('./testing')(); + +// aligned with @polkadot/util-crypto tests +describe('pair', () => { + const SIGNATURE = new Uint8Array([28, 58, 206, 239, 249, 70, 59, 191, 166, 40, 219, 218, 235, 170, 25, 79, 10, 94, 9, 197, 34, 126, 1, 150, 246, 68, 28, 238, 36, 26, 172, 163, 168, 90, 202, 211, 126, 246, 57, 212, 43, 24, 88, 197, 240, 113, 118, 76, 37, 81, 91, 110, 236, 50, 144, 134, 100, 223, 220, 238, 34, 185, 211, 7]); + + it('has a publicKey', () => { + expect( + keyring.one.publicKey + ).toEqual( + new Uint8Array([47, 140, 97, 41, 216, 22, 207, 81, 195, 116, 188, 127, 8, 195, 230, 62, 209, 86, 207, 120, 174, 251, 74, 101, 80, 217, 123, 135, 153, 121, 119, 238]) + ); + }); + + it('allows signing', () => { + expect( + keyring.one.sign( + new Uint8Array([0x61, 0x62, 0x63, 0x64]) + ) + ).toEqual(SIGNATURE); + }); + + it('validates a correctly signed message', () => { + expect( + keyring.one.verify( + new Uint8Array([0x61, 0x62, 0x63, 0x64]), + SIGNATURE + ) + ).toEqual(true); + }); + + it('fails a correctly signed message (message changed)', () => { + expect( + keyring.one.verify( + new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]), + SIGNATURE + ) + ).toEqual(false); + }); +}); diff --git a/packages/util-keyring/src/testing.js b/packages/util-keyring/src/testing.js new file mode 100644 index 000000000..e245a8d01 --- /dev/null +++ b/packages/util-keyring/src/testing.js @@ -0,0 +1,43 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { KeyringPair } from './types'; + +type TestKeyring = { + [string]: KeyringPair +}; + +const createKeyring = require('./index'); + +const SEEDS = { + alice: + 'Alice ', + bob: + 'Bob ', + charlie: + 'Charlie ', + dave: + 'Dave ', + eve: + 'Eve ', + ferdie: + 'Ferdie ', + one: + '12345678901234567890123456789012', + two: + '0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60' +}; + +module.exports = function testKeyring (): TestKeyring { + const keyring = createKeyring(); + + return Object + .keys(SEEDS) + .reduce((result, key) => { + result[key] = keyring.addFromSeed(SEEDS[key]); + + return result; + }, {}); +}; diff --git a/packages/util-keyring/src/types.js b/packages/util-keyring/src/types.js new file mode 100644 index 000000000..5d672ed5b --- /dev/null +++ b/packages/util-keyring/src/types.js @@ -0,0 +1,19 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +export type KeyringPair = { + id: string, + publicKey: Uint8Array, + + sign (message: Uint8Array): Uint8Array, + verify (message: Uint8Array, signature: Uint8Array): boolean +}; + +export type KeyringInstance = { + addFromSeed (seed: Uint8Array | string): KeyringPair, + getPair (publicKey: Uint8Array): ?KeyringPair, + getPairs (): Array, + getPublicKeys (): Array +}; diff --git a/packages/util-rlp/package.json b/packages/util-rlp/package.json index e71503c7f..055e34757 100644 --- a/packages/util-rlp/package.json +++ b/packages/util-rlp/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/util-rlp", - "version": "0.15.10", + "version": "0.16.0", "description": "RLP encoding and decoding", "main": "index.js", "keywords": [ @@ -29,7 +29,7 @@ "test": "echo \"Tests only available from root wrapper\"" }, "dependencies": { - "@polkadot/util": "^0.15.10", + "@polkadot/util": "^0.16.0", "babel-runtime": "^6.26.0" }, "devDependencies": { diff --git a/packages/util-triehash/package.json b/packages/util-triehash/package.json index 00f157a03..150d86b38 100644 --- a/packages/util-triehash/package.json +++ b/packages/util-triehash/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/util-triehash", - "version": "0.15.10", + "version": "0.16.0", "description": "Creation of triehash values", "main": "index.js", "keywords": [ @@ -29,9 +29,9 @@ "test": "echo \"Tests only available from root wrapper\"" }, "dependencies": { - "@polkadot/util": "^0.15.10", - "@polkadot/util-crypto": "^0.15.10", - "@polkadot/util-rlp": "^0.15.10", + "@polkadot/util": "^0.16.0", + "@polkadot/util-crypto": "^0.16.0", + "@polkadot/util-rlp": "^0.16.0", "babel-runtime": "^6.26.0" } } diff --git a/packages/util/package.json b/packages/util/package.json index 1246cd02a..421b8716e 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/util", - "version": "0.15.10", + "version": "0.16.0", "description": "A collection of useful utilities for @polkadot", "main": "index.js", "keywords": [