Schnorrkel support (#297)

* Initial schnorrkel support

* Start conversion of actual keyring

* Wrap encoding/decoding (needs another check)

* Manage encoding version & types with passthrough

* Update to version with working sign

* Cleanup pair interface (with seed)

* Fix failing tests

* Align naclSign signature

* Update tests for nacl (with TS conversion)

* Bump version with CHANGELOG

* Remove unneeded dep

* Use KeyringOptions instead of PairType

* Do isNumber check on addressPrefix
This commit is contained in:
Jaco Greeff
2019-02-13 16:46:33 +01:00
committed by GitHub
parent 0f53f0ebf0
commit 2aba82e569
60 changed files with 693 additions and 293 deletions
@@ -6,7 +6,7 @@
import testingPairs from '../testingPairs';
import decode from './decode';
const keyring = testingPairs();
const keyring = testingPairs({ type: 'ed25519' });
describe('decode', () => {
it('decodes an address', () => {
@@ -6,7 +6,7 @@
import testingPairs from '../testingPairs';
import encode from './encode';
const keyring = testingPairs();
const keyring = testingPairs({ type: 'ed25519' });
describe('encode', () => {
it('encodes an address to a valid value', () => {
-61
View File
@@ -1,61 +0,0 @@
// Copyright 2017-2019 @polkadot/keyring authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { hexToU8a, stringToU8a } from '@polkadot/util/index';
import Keyring from './index';
import setPrefix from './address/setPrefix';
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 = stringToU8a('12345678901234567890123456789012');
const seedTwo = hexToU8a('0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60');
let keypair;
beforeEach(() => {
keypair = new Keyring();
keypair.addFromSeed(seedOne);
setPrefix(42);
});
it('adds the pair', () => {
expect(
keypair.addFromSeed(seedTwo).publicKey()
).toEqual(publicKeyTwo);
});
it('adds from a mnemonic', () => {
setPrefix(68);
expect(
keypair.addFromMnemonic('moral movie very draw assault whisper awful rebuild speed purity repeat card').address()
).toEqual('7pDZKLEixRnF6Q5jzr7DsCEiNPt3d6Rknc14SyUcnRwTQK14');
});
it('allows publicKeys retrieval', () => {
keypair.addFromSeed(seedTwo);
expect(
keypair.getPublicKeys()
).toEqual([ publicKeyOne, publicKeyTwo ]);
});
it('allows retrieval of a specific item', () => {
expect(
keypair.getPair(publicKeyOne).publicKey()
).toEqual(publicKeyOne);
});
it('allows adding from JSON', () => {
expect(
keypair.addFromJson(
JSON.parse('{"address":"5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ","encoded":"0xb4a14995d25ab609f3686e9fa45f1fb237cd833f33f00d4b12c51858ca070d96972e47d73aae5eeb0fc06f923826cf0943fdb02c2c2ee30ef52a7912663053940d1da4da66b3a3f520ae07422c1c94b2d95690fca9d1f4a997623bb2923a8833280e19e7f72c3c5cfa343974e60e2b3dc53b404fdaf330756daad5e4e3","encoding":{"content":"pkcs8","type":"xsalsa20-poly1305","version":"0"},"meta":{"isTesting":true,"name":"alice"}}')
).publicKey()
).toEqual(
new Uint8Array([209, 114, 167, 76, 218, 76, 134, 89, 18, 195, 43, 160, 168, 10, 87, 174, 105, 171, 174, 65, 14, 92, 203, 89, 222, 232, 78, 47, 68, 50, 219, 79])
);
});
});
+63
View File
@@ -0,0 +1,63 @@
// Copyright 2017-2019 @polkadot/keyring authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { hexToU8a, stringToU8a } from '@polkadot/util/index';
import Keyring from './index';
import setPrefix from './address/setPrefix';
describe('keypair', () => {
describe('ed25519', () => {
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 = stringToU8a('12345678901234567890123456789012');
const seedTwo = hexToU8a('0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60');
let keypair: Keyring;
beforeEach(() => {
keypair = new Keyring({ type: 'ed25519' });
keypair.addFromSeed(seedOne, {});
setPrefix(42);
});
it('adds the pair', () => {
expect(
keypair.addFromSeed(seedTwo, {}).publicKey()
).toEqual(publicKeyTwo);
});
it('adds from a mnemonic', () => {
setPrefix(68);
expect(
keypair.addFromMnemonic('moral movie very draw assault whisper awful rebuild speed purity repeat card', {}).address()
).toEqual('7pDZKLEixRnF6Q5jzr7DsCEiNPt3d6Rknc14SyUcnRwTQK14');
});
it('allows publicKeys retrieval', () => {
keypair.addFromSeed(seedTwo, {});
expect(
keypair.getPublicKeys()
).toEqual([ publicKeyOne, publicKeyTwo ]);
});
it('allows retrieval of a specific item', () => {
expect(
keypair.getPair(publicKeyOne).publicKey()
).toEqual(publicKeyOne);
});
it('allows adding from JSON', () => {
expect(
keypair.addFromJson(
JSON.parse('{"address":"5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ","encoded":"0xb4a14995d25ab609f3686e9fa45f1fb237cd833f33f00d4b12c51858ca070d96972e47d73aae5eeb0fc06f923826cf0943fdb02c2c2ee30ef52a7912663053940d1da4da66b3a3f520ae07422c1c94b2d95690fca9d1f4a997623bb2923a8833280e19e7f72c3c5cfa343974e60e2b3dc53b404fdaf330756daad5e4e3","encoding":{"content":"pkcs8","type":"xsalsa20-poly1305","version":"0"},"meta":{"isTesting":true,"name":"alice"}}')
).publicKey()
).toEqual(
new Uint8Array([209, 114, 167, 76, 218, 76, 134, 89, 18, 195, 43, 160, 168, 10, 87, 174, 105, 171, 174, 65, 14, 92, 203, 89, 222, 232, 78, 47, 68, 50, 219, 79])
);
});
});
});
+19 -82
View File
@@ -2,10 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { KeyringInstance, KeyringPair, KeyringPair$Json, KeyringPair$Meta } from './types';
import { KeyringInstance, KeyringPair, KeyringPair$Json, KeyringPair$Meta, KeyringOptions, PairType } from './types';
import { hexToU8a } from '@polkadot/util/index';
import { mnemonicToSeed , naclKeypairFromSeed } from '@polkadot/util-crypto/index';
import { assert, hexToU8a, isNumber } from '@polkadot/util/index';
import { mnemonicToSeed , naclKeypairFromSeed as naclFromSeed, schnorrkelKeypairFromSeed as schnorrkelFromSeed } from '@polkadot/util-crypto/index';
import { decodeAddress, encodeAddress, setAddressPrefix } from './address';
import createPair from './pair';
@@ -26,14 +26,18 @@ import Pairs from './pairs';
* dictionary is achieved using `removePair`. Retrieval of all the stored pairs via `getPairs` or perform
* lookup of a pair for a given account address or public key using `getPair`. JSON metadata associated with
* an account may be obtained using `toJson` accompanied by the account passphrase.
* @example See [Polkadot-JS Common Keyring Examples](https://polkadot.js.org/api/common/examples/keyring/) and the [Polkadot-JS Apps ui-keyring package](https://github.com/polkadot-js/apps/tree/master/packages/ui-keyring)
* where it is implemented.
*/
export default class Keyring implements KeyringInstance {
private _pairs: Pairs;
private _type: PairType;
constructor (options: KeyringOptions) {
assert(options && ['ed25519', 'sr25519'].includes(options.type || 'undefined'), `Expected a keyring type of either 'ed25519' or 'sr25519', found '${options.type}`);
constructor () {
this._pairs = new Pairs();
this._type = options.type as PairType;
setAddressPrefix(isNumber(options.addressPrefix) ? options.addressPrefix : 42);
}
decodeAddress = decodeAddress;
@@ -58,9 +62,8 @@ export default class Keyring implements KeyringInstance {
* of an account backup), and then generates a keyring pair from them that it passes to
* `addPair` to stores in a keyring pair dictionary the public key of the generated pair as a key and the pair as the associated value.
*/
addFromAddress (address: string | Uint8Array, meta?: KeyringPair$Meta, defaultEncoded?: Uint8Array): KeyringPair {
// @ts-ignore no secretKey - cannot unlock
return this.addPair(createPair({ publicKey: this.decodeAddress(address) }, meta, defaultEncoded));
addFromAddress (address: string | Uint8Array, meta: KeyringPair$Meta, encoded: Uint8Array | null): KeyringPair {
return this.addPair(createPair(this._type, { publicKey: this.decodeAddress(address) }, meta, encoded));
}
/**
@@ -70,8 +73,6 @@ export default class Keyring implements KeyringInstance {
* @description Allows user to provide a json object argument that contains account information (that may be obtained from the json file
* of an account backup), and then generates a keyring pair from it that it passes to
* `addPair` to stores in a keyring pair dictionary the public key of the generated pair as a key and the pair as the associated value.
* @example
* Refer to an actual implementation in [Polkadot-JS ui-keyring > account > save](https://github.com/polkadot-js/apps/blob/master/packages/ui-keyring/src/account/save.ts#L15)
*/
addFromJson ({ address, encoded, meta }: KeyringPair$Json): KeyringPair {
return this.addFromAddress(address, meta, hexToU8a(encoded));
@@ -86,7 +87,7 @@ export default class Keyring implements KeyringInstance {
* of an account backup), and then generates a keyring pair from it that it passes to
* `addPair` to stores in a keyring pair dictionary the public key of the generated pair as a key and the pair as the associated value.
*/
addFromMnemonic (mnemonic: string, meta?: KeyringPair$Meta): KeyringPair {
addFromMnemonic (mnemonic: string, meta: KeyringPair$Meta): KeyringPair {
return this.addFromSeed(mnemonicToSeed(mnemonic), meta);
}
@@ -97,26 +98,13 @@ export default class Keyring implements KeyringInstance {
* @description Stores in a keyring pair dictionary the public key of the pair as a key and the pair as the associated value.
* Allows user to provide the account seed as an argument, and then generates a keyring pair from it that it passes to
* `addPair` to store in a keyring pair dictionary the public key of the generated pair as a key and the pair as the associated value.
* @example
* <BR>
*
* ```javascript
* import Keyring from '@polkadot/keyring';
* import stringToU8a from '@polkadot/util/string/toU8a';
*
* const ALICE_SEED = 'Alice'.padEnd(32, ' ');
*
* // Create an instance of the Keyring
* const keyring = new Keyring();
*
* // Add Alice to our keyring pair dictionary (with the known seed for the account)
* const pairAlice = keyring.addFromSeed(stringToU8a(ALICE_SEED));
* ```
*
* Refer to an actual implementation in [Polkadot-JS ui-keyring > account > create](https://github.com/polkadot-js/apps/blob/master/packages/ui-keyring/src/account/create.ts#L11)
*/
addFromSeed (seed: Uint8Array, meta?: KeyringPair$Meta): KeyringPair {
return this.addPair(createPair(naclKeypairFromSeed(seed), meta));
addFromSeed (seed: Uint8Array, meta: KeyringPair$Meta): KeyringPair {
const keypair = this._type === 'sr25519'
? schnorrkelFromSeed(seed)
: naclFromSeed(seed);
return this.addPair(createPair(this._type, { ...keypair, seed }, meta, null));
}
/**
@@ -125,31 +113,6 @@ export default class Keyring implements KeyringInstance {
* @summary Retrieves an account keyring pair from the Keyring Pair Dictionary, given an account address
* @description Returns a keyring pair value from the keyring pair dictionary by performing
* a key lookup using the provided account address or public key (after decoding it).
* @example
* <BR>
*
* ```javascript
* import Keyring from '@polkadot/keyring';
* import stringToU8a from '@polkadot/util/string/toU8a';
*
* const ALICE_SEED = 'Alice'.padEnd(32, ' ');
*
* // Create an instance of the Keyring
* const keyring = new Keyring();
*
* // Add Alice to our keyring pair dictionary (with the known seed for the account)
* const pairAlice = keyring.addFromSeed(stringToU8a(ALICE_SEED));
*
* // Retrieve the same pair that is stored in the keyring pair dictionary by
* // providing the account address as an argument, and also the public key as an argument.
* // The pairs that are returned should both be the same value as `pairAlice` above
* const pairAliceRetrievedWithAddress = keyring.getPair(pairAlice.address());
* const pairAliceRetrievedWithPublicKey = keyring.getPair(pairAlice.publicKey());
*
* // Check if all returned pairs are the same
* console.log(`Are all pairs the same? : ` +
* `${pairAlice === pairAliceRetrievedWithAddress === pairAliceRetrievedWithPublicKey}`);
* ```
*/
getPair (address: string | Uint8Array): KeyringPair {
return this._pairs.get(address);
@@ -160,28 +123,6 @@ export default class Keyring implements KeyringInstance {
* @signature getPairs (): Array<KeyringPair>
* @summary Retrieves all account keyring pairs from the Keyring Pair Dictionary
* @description Returns an array list of all the keyring pair values that are stored in the keyring pair dictionary.
* @example
* <BR>
*
* ```javascript
* import testKeyring from '@polkadot/keyring/testing';
*
* // Create an instance of Keyring that includes test accounts
* const keyring = testingPairs();
*
* keyring
* .getPairs()
* .forEach((pair) => {
* const address = pair.address();
*
* keyring.addPair(address, {
* address,
* meta: pair.getMeta()
* });
* });
* ```
*
* Refer to an actual implementation in [Polkadot-JS ui-keyring > loadAll](https://github.com/polkadot-js/apps/blob/master/packages/ui-keyring/src/loadAll.ts)
*/
getPairs (): Array<KeyringPair> {
return this._pairs.all();
@@ -205,8 +146,6 @@ export default class Keyring implements KeyringInstance {
* @name removePair
* @signature removePair (address: string | Uint8Array): void
* @description Deletes the provided input address or public key from the stored Keyring Pair Dictionary.
* @example
* Refer to an actual implementation in [Polkadot-JS ui-keyring > account > forget](https://github.com/polkadot-js/apps/blob/master/packages/ui-keyring/src/account/forget.ts)
*/
removePair (address: string | Uint8Array): void {
this._pairs.remove(address);
@@ -220,8 +159,6 @@ export default class Keyring implements KeyringInstance {
* when valid address or public key and when the account passphrase is provided if the account secret
* is not already unlocked and available in memory. Note that in [Polkadot-JS Apps](https://github.com/polkadot-js/apps) the user
* may backup their account to a JSON file that contains this information.
* @example
* Refer to an actual implementation in [Polkadot-JS ui-keyring > account > save](https://github.com/polkadot-js/apps/blob/master/packages/ui-keyring/src/account/save.ts#L9)
*/
toJson (address: string | Uint8Array, passphrase?: string): KeyringPair$Json {
return this._pairs.get(address).toJson(passphrase);
@@ -4,7 +4,7 @@
import testingPairs from '../testingPairs';
const keyring = testingPairs();
const keyring = testingPairs({ type: 'ed25519' });
describe('decode', () => {
it('fails when no data provided', () => {
@@ -14,9 +14,11 @@ describe('decode', () => {
});
it('returns correct publicKey from encoded', () => {
const PASS = 'testing';
expect(
() => keyring.alice.decodePkcs8(
'testing', keyring.alice.encodePkcs8('testing')
PASS, keyring.alice.encodePkcs8(PASS)
)
).not.toThrow();
});
+19 -16
View File
@@ -2,44 +2,47 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { assert, stringToU8a, u8aConcat, u8aFixLength } from '@polkadot/util/index';
import { naclDecrypt, naclKeypairFromSeed } from '@polkadot/util-crypto/index';
import { assert, stringToU8a, u8aFixLength } from '@polkadot/util/index';
import { naclDecrypt } from '@polkadot/util-crypto/index';
import { PKCS8_DIVIDER, PKCS8_HEADER } from './defaults';
import { KEY_LENGTH, NONCE_LENGTH, PKCS8_DIVIDER, PKCS8_HEADER } from './defaults';
const KEY_LENGTH = 32;
const SEED_OFFSET = PKCS8_HEADER.length;
const DIV_OFFSET = SEED_OFFSET + KEY_LENGTH;
const PUBLIC_OFFSET = SEED_OFFSET + KEY_LENGTH + PKCS8_DIVIDER.length;
const PUBLIC_OFFSET = DIV_OFFSET + PKCS8_DIVIDER.length;
export default function decode (passphrase?: string, _encrypted?: Uint8Array) {
type DecodeResult = {
publicKey: Uint8Array,
seed: Uint8Array
};
export default function decode (passphrase?: string, _encrypted?: Uint8Array | null): DecodeResult {
assert(_encrypted, `No encrypted data available to decode`);
const encrypted = (_encrypted as Uint8Array);
const encoded = passphrase
? (naclDecrypt(
encrypted.subarray(24),
encrypted.subarray(0, 24),
u8aFixLength(stringToU8a(passphrase), 256, true)) as Uint8Array)
encrypted.subarray(NONCE_LENGTH),
encrypted.subarray(0, NONCE_LENGTH),
u8aFixLength(stringToU8a(passphrase), 256, true)
) as Uint8Array)
: encrypted;
assert(encoded, `Unable to unencrypt using the supplied passphrase`);
const header = encoded.subarray(0, PKCS8_HEADER.length);
const divider = encoded.subarray(DIV_OFFSET, DIV_OFFSET + PKCS8_DIVIDER.length);
assert(header.toString() === PKCS8_HEADER.toString(), 'Invalid Pkcs8 header found in body');
const divider = encoded.subarray(DIV_OFFSET, DIV_OFFSET + PKCS8_DIVIDER.length);
assert(divider.toString() === PKCS8_DIVIDER.toString(), 'Invalid Pkcs8 divider found in body');
const publicKey = encoded.subarray(PUBLIC_OFFSET, PUBLIC_OFFSET + KEY_LENGTH);
const seed = encoded.subarray(SEED_OFFSET, SEED_OFFSET + KEY_LENGTH);
const secretKey = u8aConcat(seed, publicKey);
const validate = naclKeypairFromSeed(seed);
assert(validate.publicKey.toString() === publicKey.toString(), 'Pkcs8 decoded publicKeys are not matching');
const publicKey = encoded.subarray(PUBLIC_OFFSET, PUBLIC_OFFSET + KEY_LENGTH);
return {
publicKey,
secretKey
seed
};
}
+6
View File
@@ -4,8 +4,14 @@
const PKCS8_DIVIDER = new Uint8Array([161, 35, 3, 33, 0]);
const PKCS8_HEADER = new Uint8Array([48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32]);
const KEY_LENGTH = 32;
const SEC_LENGTH = 64;
const NONCE_LENGTH = 24;
export {
KEY_LENGTH,
SEC_LENGTH,
NONCE_LENGTH,
PKCS8_DIVIDER,
PKCS8_HEADER
};
@@ -8,7 +8,7 @@ import { PKCS8_DIVIDER, PKCS8_HEADER } from './defaults';
const PKCS8_LENGTH = PKCS8_DIVIDER.length + PKCS8_HEADER.length + 64;
const ENCODED_LENGTH = 125;
const keyring = testingPairs();
const keyring = testingPairs({ type: 'ed25519' });
describe('encode', () => {
it('returns PKCS8 when no passphrase supplied', () => {
+6 -4
View File
@@ -2,17 +2,19 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { stringToU8a, u8aConcat, u8aFixLength } from '@polkadot/util/index';
import { stringToU8a, u8aConcat, u8aFixLength, assert } from '@polkadot/util/index';
import { naclEncrypt } from '@polkadot/util-crypto/index';
import { PKCS8_DIVIDER, PKCS8_HEADER } from './defaults';
export default function encode (secretKey: Uint8Array, passphrase?: string): Uint8Array {
export default function encode (publicKey: Uint8Array, seed?: Uint8Array | null, passphrase?: string): Uint8Array {
assert(seed, 'Expected a valid seed to be passed to encode');
const encoded = u8aConcat(
PKCS8_HEADER,
secretKey.subarray(0, 32),
seed as Uint8Array,
PKCS8_DIVIDER,
secretKey.subarray(32, 64)
publicKey
);
if (!passphrase) {
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2017-2019 @polkadot/keyring authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { KeyringPair$Meta } from '../types';
import { PairState } from './types';
export default function getMeta (state: PairState): KeyringPair$Meta {
return state.meta;
}
@@ -4,7 +4,7 @@
import testingPairs from '../testingPairs';
const keyring = testingPairs();
const keyring = testingPairs({ type: 'ed25519' });
describe('pair', () => {
const SIGNATURE = new Uint8Array([80, 191, 198, 147, 225, 207, 75, 88, 126, 39, 129, 109, 191, 38, 72, 181, 75, 254, 81, 143, 244, 79, 237, 38, 236, 141, 28, 252, 134, 26, 169, 234, 79, 33, 153, 158, 151, 34, 175, 188, 235, 20, 35, 135, 83, 120, 139, 211, 233, 130, 1, 208, 201, 215, 73, 80, 56, 98, 185, 196, 11, 8, 193, 14]);
+33 -23
View File
@@ -3,21 +3,18 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { KeypairType } from '@polkadot/util-crypto/types';
import { KeyringPair, KeyringPair$Json, KeyringPair$Meta } from '../types';
import { PairState } from './types';
import { KeyringPair, KeyringPair$Json, KeyringPair$Meta, PairType } from '../types';
import { PairInfo } from './types';
import { naclSign, naclVerify } from '@polkadot/util-crypto/index';
import { naclKeypairFromSeed as naclFromSeed, naclSign, naclVerify, schnorrkelKeypairFromSeed as schnorrkelFromSeed, schnorrkelSign, schnorrkelVerify } from '@polkadot/util-crypto/index';
import { encodeAddress } from '../address';
import decode from './decode';
import encode from './encode';
import getMeta from './getMeta';
import setMeta from './setMeta';
import toJson from './toJson';
/**
* @name pair
* @signature pair ({ publicKey, secretKey }: KeypairType, meta: KeyringPair$Meta = {}, defaultEncoded?: Uint8Array): KeyringPair
* @summary Creates a keyring pair object
* @description Creates a keyring pair object with provided account public key, metadata, and encoded arguments.
* The keyring pair stores the account state including the encoded address and associated metadata.
@@ -47,25 +44,37 @@ import toJson from './toJson';
* an `encoded` property that is assigned with the encoded public key in hex format, and an `encoding`
* property that indicates whether the public key value of the `encoded` property is encoded or not.
*/
export default function pair ({ publicKey, secretKey }: KeypairType, meta: KeyringPair$Meta = {}, defaultEncoded?: Uint8Array): KeyringPair {
const state: PairState = {
meta: { ...meta },
publicKey
};
export default function pair (type: PairType, { publicKey, seed }: PairInfo, meta: KeyringPair$Meta = {}, encoded: Uint8Array | null): KeyringPair {
const fromSeed = (seed: Uint8Array) =>
type === 'sr25519'
? schnorrkelFromSeed(seed)
: naclFromSeed(seed);
const sign = (message: Uint8Array, pair: Partial<KeypairType>) =>
type === 'sr25519'
? schnorrkelSign(message, pair)
: naclSign(message, pair);
const verify = (message: Uint8Array, signature: Uint8Array) =>
type === 'sr25519'
? schnorrkelVerify(message, signature, publicKey)
: naclVerify(message, signature, publicKey);
let secretKey: Uint8Array | undefined = seed
? fromSeed(seed).secretKey
: undefined;
return {
address: (): string =>
encodeAddress(state.publicKey),
decodePkcs8: (passphrase?: string, encoded?: Uint8Array): void => {
const decoded = decode(passphrase, encoded || defaultEncoded);
encodeAddress(publicKey),
decodePkcs8: (passphrase?: string, _encoded?: Uint8Array | null): void => {
const decoded = decode(passphrase, _encoded || encoded);
state.publicKey = decoded.publicKey;
secretKey = decoded.secretKey;
publicKey = decoded.publicKey;
seed = decoded.seed;
secretKey = fromSeed(seed).secretKey;
},
encodePkcs8: (passphrase?: string): Uint8Array =>
encode(secretKey, passphrase),
encode(publicKey, seed, passphrase),
getMeta: (): KeyringPair$Meta =>
getMeta(state),
meta,
isLocked: (): boolean =>
(!secretKey || secretKey.length === 0),
lock: (): void => {
@@ -73,13 +82,14 @@ export default function pair ({ publicKey, secretKey }: KeypairType, meta: Keyri
},
publicKey: (): Uint8Array =>
publicKey,
setMeta: (meta: KeyringPair$Meta): void =>
setMeta(state, meta),
setMeta: (_meta: KeyringPair$Meta): void => {
meta = meta;
},
sign: (message: Uint8Array): Uint8Array =>
naclSign(message, secretKey),
sign(message, { publicKey, secretKey }),
toJson: (passphrase?: string): KeyringPair$Json =>
toJson(state, encode(secretKey, passphrase), !!passphrase),
toJson({ meta, publicKey }, encode(publicKey, seed, passphrase), !!passphrase),
verify: (message: Uint8Array, signature: Uint8Array): boolean =>
naclVerify(message, signature, publicKey)
verify(message, signature)
};
}
-13
View File
@@ -1,13 +0,0 @@
// Copyright 2017-2019 @polkadot/keyring authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { KeyringPair$Meta } from '../types';
import { PairState } from './types';
export default function setMeta (state: PairState, meta: KeyringPair$Meta): void {
state.meta = {
...state.meta,
...meta
};
}
@@ -4,7 +4,7 @@
import testingPairs from '../testingPairs';
const keyring = testingPairs();
const keyring = testingPairs({ type: 'ed25519' });
describe('toJson', () => {
it('creates an unencoded output with no passphrase', () => {
@@ -16,7 +16,7 @@ describe('toJson', () => {
encoding: {
content: 'pkcs8',
type: 'none',
version: '0'
version: '1'
},
meta: {
name: 'alice',
@@ -34,7 +34,7 @@ describe('toJson', () => {
encoding: {
content: 'pkcs8',
type: 'xsalsa20-poly1305',
version: '0'
version: '1'
}
});
});
+7 -4
View File
@@ -2,14 +2,17 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { KeyringPair$Json } from '../types';
import { PairState } from './types';
import { KeyringPair$Json, KeyringPair$Meta } from '../types';
import { u8aToHex } from '@polkadot/util/index';
import { encodeAddress } from '../address';
export default function toJson ({ publicKey, meta }: PairState, encoded: Uint8Array, isEncrypted: boolean): KeyringPair$Json {
type PairStateJson = KeyringPair$Meta & {
publicKey: Uint8Array
};
export default function toJson ({ publicKey, meta }: PairStateJson, encoded: Uint8Array, isEncrypted: boolean): KeyringPair$Json {
return {
address: encodeAddress(publicKey),
encoded: u8aToHex(encoded),
@@ -18,7 +21,7 @@ export default function toJson ({ publicKey, meta }: PairState, encoded: Uint8Ar
type: isEncrypted
? 'xsalsa20-poly1305'
: 'none',
version: '0'
version: '1'
},
meta
};
+3 -5
View File
@@ -2,9 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { KeyringPair$Meta } from '../types';
export type PairState = {
meta: KeyringPair$Meta,
publicKey: Uint8Array
export type PairInfo = {
publicKey: Uint8Array,
seed?: Uint8Array
};
+3 -18
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { KeyringInstance } from './types';
import { KeyringInstance, KeyringOptions } from './types';
import { stringToU8a } from '@polkadot/util/index';
@@ -38,24 +38,9 @@ const SEEDS: { [index: string ]: Uint8Array } = {
* @summary Create an instance of Keyring pre-populated with locked test accounts
* @description The test accounts (i.e. alice, bob, dave, eve, ferdie)
* are available on the dev chain and each test account is initialised with DOT funds.
* @example
* <BR>
*
* ```javascript
* import testKeyring from '@polkadot/keyring/testing';
*
* // Create an instance of Keyring that includes test accounts
* const keyring = testingPairs();
*
* // Retrieve the address of one of the test accounts
* const addressAlice = keyring.alice.address();
*
* // Retrieve the public key of one of the test accounts
* const publicKeyAlice = keyring.alice.publicKey();
* ```
*/
export default function testKeyring (): KeyringInstance {
const keyring = new Keyring();
export default function testKeyring (options: KeyringOptions): KeyringInstance {
const keyring = new Keyring(options);
Object
.keys(SEEDS)
+3 -3
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { KeyringPair } from './types';
import { KeyringPair, KeyringOptions } from './types';
import createKeyring from './testing';
import nobody from './pair/nobody';
@@ -11,8 +11,8 @@ type TestKeyringMap = {
[index: string]: KeyringPair
};
export default function testKeyringPairs (): TestKeyringMap {
const keyring = createKeyring();
export default function testKeyringPairs (options: KeyringOptions): TestKeyringMap {
const keyring = createKeyring(options);
const pairs = keyring.getPairs();
return pairs.reduce((result, pair) => {
+19 -8
View File
@@ -4,18 +4,29 @@
import { Prefix } from './address/types';
export type PairType = 'ed25519' | 'sr25519';
export type KeyringOptions = {
addressPrefix?: Prefix,
type?: PairType
};
export type KeyringPair$Meta = {
[index: string]: any
};
export type KeyringPair$JsonVersion = '0' | '1';
export type KeyringPair$JsonEncoding = {
content: 'pkcs8' | 'none',
type: 'xsalsa20-poly1305' | 'none',
version: KeyringPair$JsonVersion
};
export type KeyringPair$Json = {
address: string,
encoded: string,
encoding: {
content: 'pkcs8' | 'none',
type: 'xsalsa20-poly1305' | 'none',
version: '0'
},
encoding: KeyringPair$JsonEncoding,
meta: KeyringPair$Meta
};
@@ -46,9 +57,9 @@ export interface KeyringInstance {
setAddressPrefix (prefix: Prefix): void;
addPair (pair: KeyringPair): KeyringPair;
addFromAddress (address: string | Uint8Array, meta?: KeyringPair$Meta): KeyringPair;
addFromMnemonic (mnemonic: string, meta?: KeyringPair$Meta): KeyringPair;
addFromSeed (seed: Uint8Array, meta?: KeyringPair$Meta): KeyringPair;
addFromAddress (address: string | Uint8Array, meta: KeyringPair$Meta, encoded: Uint8Array | null): KeyringPair;
addFromMnemonic (mnemonic: string, meta: KeyringPair$Meta): KeyringPair;
addFromSeed (seed: Uint8Array, meta: KeyringPair$Meta): KeyringPair;
addFromJson (pair: KeyringPair$Json): KeyringPair;
getPair (address: string | Uint8Array): KeyringPair;
getPairs (): Array<KeyringPair>;