UNPKG

8.9 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.createPair = void 0;
4const util_1 = require("@polkadot/util");
5const util_crypto_1 = require("@polkadot/util-crypto");
6const decode_js_1 = require("./decode.js");
7const encode_js_1 = require("./encode.js");
8const toJson_js_1 = require("./toJson.js");
9const SIG_TYPE_NONE = new Uint8Array();
10const TYPE_FROM_SEED = {
11 ecdsa: util_crypto_1.secp256k1PairFromSeed,
12 ed25519: util_crypto_1.ed25519PairFromSeed,
13 ethereum: util_crypto_1.secp256k1PairFromSeed,
14 sr25519: util_crypto_1.sr25519PairFromSeed
15};
16const TYPE_PREFIX = {
17 ecdsa: new Uint8Array([2]),
18 ed25519: new Uint8Array([0]),
19 ethereum: new Uint8Array([2]),
20 sr25519: new Uint8Array([1])
21};
22const TYPE_SIGNATURE = {
23 ecdsa: (m, p) => (0, util_crypto_1.secp256k1Sign)(m, p, 'blake2'),
24 ed25519: util_crypto_1.ed25519Sign,
25 ethereum: (m, p) => (0, util_crypto_1.secp256k1Sign)(m, p, 'keccak'),
26 sr25519: util_crypto_1.sr25519Sign
27};
28const TYPE_ADDRESS = {
29 ecdsa: (p) => p.length > 32 ? (0, util_crypto_1.blake2AsU8a)(p) : p,
30 ed25519: (p) => p,
31 ethereum: (p) => p.length === 20 ? p : (0, util_crypto_1.keccakAsU8a)((0, util_crypto_1.secp256k1Expand)(p)),
32 sr25519: (p) => p
33};
34function isLocked(secretKey) {
35 return !secretKey || (0, util_1.u8aEmpty)(secretKey);
36}
37function vrfHash(proof, context, extra) {
38 return (0, util_crypto_1.blake2AsU8a)((0, util_1.u8aConcat)(context || '', extra || '', proof));
39}
40/**
41 * @name createPair
42 * @summary Creates a keyring pair object
43 * @description Creates a keyring pair object with provided account public key, metadata, and encoded arguments.
44 * The keyring pair stores the account state including the encoded address and associated metadata.
45 *
46 * It has properties whose values are functions that may be called to perform account actions:
47 *
48 * - `address` function retrieves the address associated with the account.
49 * - `decodedPkcs8` function is called with the account passphrase and account encoded public key.
50 * It decodes the encoded public key using the passphrase provided to obtain the decoded account public key
51 * and associated secret key that are then available in memory, and changes the account address stored in the
52 * state of the pair to correspond to the address of the decoded public key.
53 * - `encodePkcs8` function when provided with the correct passphrase associated with the account pair
54 * and when the secret key is in memory (when the account pair is not locked) it returns an encoded
55 * public key of the account.
56 * - `meta` is the metadata that is stored in the state of the pair, either when it was originally
57 * created or set via `setMeta`.
58 * - `publicKey` returns the public key stored in memory for the pair.
59 * - `sign` may be used to return a signature by signing a provided message with the secret
60 * key (if it is in memory) using Nacl.
61 * - `toJson` calls another `toJson` function and provides the state of the pair,
62 * it generates arguments to be passed to the other `toJson` function including an encoded public key of the account
63 * that it generates using the secret key from memory (if it has been made available in memory)
64 * and the optionally provided passphrase argument. It passes a third boolean argument to `toJson`
65 * indicating whether the public key has been encoded or not (if a passphrase argument was provided then it is encoded).
66 * The `toJson` function that it calls returns a JSON object with properties including the `address`
67 * and `meta` that are assigned with the values stored in the corresponding state variables of the account pair,
68 * an `encoded` property that is assigned with the encoded public key in hex format, and an `encoding`
69 * property that indicates whether the public key value of the `encoded` property is encoded or not.
70 */
71function createPair({ toSS58, type }, { publicKey, secretKey }, meta = {}, encoded = null, encTypes) {
72 const decodePkcs8 = (passphrase, userEncoded) => {
73 const decoded = (0, decode_js_1.decodePair)(passphrase, userEncoded || encoded, encTypes);
74 if (decoded.secretKey.length === 64) {
75 publicKey = decoded.publicKey;
76 secretKey = decoded.secretKey;
77 }
78 else {
79 const pair = TYPE_FROM_SEED[type](decoded.secretKey);
80 publicKey = pair.publicKey;
81 secretKey = pair.secretKey;
82 }
83 };
84 const recode = (passphrase) => {
85 isLocked(secretKey) && encoded && decodePkcs8(passphrase, encoded);
86 encoded = (0, encode_js_1.encodePair)({ publicKey, secretKey }, passphrase); // re-encode, latest version
87 encTypes = undefined; // swap to defaults, latest version follows
88 return encoded;
89 };
90 const encodeAddress = () => {
91 const raw = TYPE_ADDRESS[type](publicKey);
92 return type === 'ethereum'
93 ? (0, util_crypto_1.ethereumEncode)(raw)
94 : toSS58(raw);
95 };
96 return {
97 get address() {
98 return encodeAddress();
99 },
100 get addressRaw() {
101 const raw = TYPE_ADDRESS[type](publicKey);
102 return type === 'ethereum'
103 ? raw.slice(-20)
104 : raw;
105 },
106 get isLocked() {
107 return isLocked(secretKey);
108 },
109 get meta() {
110 return meta;
111 },
112 get publicKey() {
113 return publicKey;
114 },
115 get type() {
116 return type;
117 },
118 // eslint-disable-next-line sort-keys
119 decodePkcs8,
120 derive: (suri, meta) => {
121 if (type === 'ethereum') {
122 throw new Error('Unable to derive on this keypair');
123 }
124 else if (isLocked(secretKey)) {
125 throw new Error('Cannot derive on a locked keypair');
126 }
127 const { path } = (0, util_crypto_1.keyExtractPath)(suri);
128 const derived = (0, util_crypto_1.keyFromPath)({ publicKey, secretKey }, path, type);
129 return createPair({ toSS58, type }, derived, meta, null);
130 },
131 encodePkcs8: (passphrase) => {
132 return recode(passphrase);
133 },
134 lock: () => {
135 secretKey = new Uint8Array();
136 },
137 setMeta: (additional) => {
138 meta = (0, util_1.objectSpread)({}, meta, additional);
139 },
140 sign: (message, options = {}) => {
141 if (isLocked(secretKey)) {
142 throw new Error('Cannot sign with a locked key pair');
143 }
144 return (0, util_1.u8aConcat)(options.withType
145 ? TYPE_PREFIX[type]
146 : SIG_TYPE_NONE, TYPE_SIGNATURE[type]((0, util_1.u8aToU8a)(message), { publicKey, secretKey }));
147 },
148 toJson: (passphrase) => {
149 // NOTE: For ecdsa and ethereum, the publicKey cannot be extracted from the address. For these
150 // pass the hex-encoded publicKey through to the address portion of the JSON (before decoding)
151 // unless the publicKey is already an address
152 const address = ['ecdsa', 'ethereum'].includes(type)
153 ? publicKey.length === 20
154 ? (0, util_1.u8aToHex)(publicKey)
155 : (0, util_1.u8aToHex)((0, util_crypto_1.secp256k1Compress)(publicKey))
156 : encodeAddress();
157 return (0, toJson_js_1.pairToJson)(type, { address, meta }, recode(passphrase), !!passphrase);
158 },
159 unlock: (passphrase) => {
160 return decodePkcs8(passphrase);
161 },
162 verify: (message, signature, signerPublic) => {
163 return (0, util_crypto_1.signatureVerify)(message, signature, TYPE_ADDRESS[type]((0, util_1.u8aToU8a)(signerPublic))).isValid;
164 },
165 vrfSign: (message, context, extra) => {
166 if (isLocked(secretKey)) {
167 throw new Error('Cannot sign with a locked key pair');
168 }
169 if (type === 'sr25519') {
170 return (0, util_crypto_1.sr25519VrfSign)(message, { secretKey }, context, extra);
171 }
172 const proof = TYPE_SIGNATURE[type]((0, util_1.u8aToU8a)(message), { publicKey, secretKey });
173 return (0, util_1.u8aConcat)(vrfHash(proof, context, extra), proof);
174 },
175 vrfVerify: (message, vrfResult, signerPublic, context, extra) => {
176 if (type === 'sr25519') {
177 return (0, util_crypto_1.sr25519VrfVerify)(message, vrfResult, publicKey, context, extra);
178 }
179 const result = (0, util_crypto_1.signatureVerify)(message, (0, util_1.u8aConcat)(TYPE_PREFIX[type], vrfResult.subarray(32)), TYPE_ADDRESS[type]((0, util_1.u8aToU8a)(signerPublic)));
180 return result.isValid && (0, util_1.u8aEq)(vrfResult.subarray(0, 32), vrfHash(vrfResult.subarray(32), context, extra));
181 }
182 };
183}
184exports.createPair = createPair;