mirror of
https://github.com/pezkuwichain/pezkuwi-common.git
synced 2026-06-14 01:51:05 +00:00
chore: update to version 14.0.11 and align website URLs
This commit is contained in:
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
import type { EncryptedJsonEncoding } from '@pezkuwi/util-crypto/types';
|
||||
/**
|
||||
* Decode a pair, taking into account the generation-specific formats and headers
|
||||
*
|
||||
* For divisor/headers, don't rely on the magic being static. These will
|
||||
* change between generations, aka with the long-awaited 4th generation
|
||||
* of the format. The external decode interface is the only way to use and decode these.
|
||||
**/
|
||||
export declare function decodePair(passphrase?: string, encrypted?: Uint8Array | null, _encType?: EncryptedJsonEncoding | EncryptedJsonEncoding[]): {
|
||||
publicKey: Uint8Array;
|
||||
secretKey: Uint8Array;
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
import { u8aEq } from '@pezkuwi/util';
|
||||
import { jsonDecryptData } from '@pezkuwi/util-crypto';
|
||||
import { PAIR_DIV, PAIR_HDR, PUB_LENGTH, SEC_LENGTH, SEED_LENGTH } from './defaults.js';
|
||||
const SEED_OFFSET = PAIR_HDR.length;
|
||||
/**
|
||||
* Decode a pair, taking into account the generation-specific formats and headers
|
||||
*
|
||||
* For divisor/headers, don't rely on the magic being static. These will
|
||||
* change between generations, aka with the long-awaited 4th generation
|
||||
* of the format. The external decode interface is the only way to use and decode these.
|
||||
**/
|
||||
export function decodePair(passphrase, encrypted, _encType) {
|
||||
const encType = Array.isArray(_encType) || _encType === undefined
|
||||
? _encType
|
||||
: [_encType];
|
||||
const decrypted = jsonDecryptData(encrypted, passphrase, encType);
|
||||
const header = decrypted.subarray(0, PAIR_HDR.length);
|
||||
// check the start header (generations 1-3)
|
||||
if (!u8aEq(header, PAIR_HDR)) {
|
||||
throw new Error('Invalid encoding header found in body');
|
||||
}
|
||||
// setup for generation 3 format
|
||||
let secretKey = decrypted.subarray(SEED_OFFSET, SEED_OFFSET + SEC_LENGTH);
|
||||
let divOffset = SEED_OFFSET + SEC_LENGTH;
|
||||
let divider = decrypted.subarray(divOffset, divOffset + PAIR_DIV.length);
|
||||
// old-style (generation 1 & 2), we have the seed here
|
||||
if (!u8aEq(divider, PAIR_DIV)) {
|
||||
divOffset = SEED_OFFSET + SEED_LENGTH;
|
||||
secretKey = decrypted.subarray(SEED_OFFSET, divOffset);
|
||||
divider = decrypted.subarray(divOffset, divOffset + PAIR_DIV.length);
|
||||
// check the divisior at this point (already checked for generation 3)
|
||||
if (!u8aEq(divider, PAIR_DIV)) {
|
||||
throw new Error('Invalid encoding divider found in body');
|
||||
}
|
||||
}
|
||||
const pubOffset = divOffset + PAIR_DIV.length;
|
||||
const publicKey = decrypted.subarray(pubOffset, pubOffset + PUB_LENGTH);
|
||||
return {
|
||||
publicKey,
|
||||
secretKey
|
||||
};
|
||||
}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
/** public/secret section divider (generation 1-3, will change in 4, don't rely on value) */
|
||||
export declare const PAIR_DIV: Uint8Array;
|
||||
/** public/secret start block (generation 1-3, will change in 4, don't rely on value) */
|
||||
export declare const PAIR_HDR: Uint8Array;
|
||||
/** length of a public key */
|
||||
export declare const PUB_LENGTH = 32;
|
||||
/** length of a salt */
|
||||
export declare const SALT_LENGTH = 32;
|
||||
/** length of a secret key */
|
||||
export declare const SEC_LENGTH = 64;
|
||||
/** length of a user-input seed */
|
||||
export declare const SEED_LENGTH = 32;
|
||||
@@ -0,0 +1,12 @@
|
||||
/** public/secret section divider (generation 1-3, will change in 4, don't rely on value) */
|
||||
export const PAIR_DIV = new Uint8Array([161, 35, 3, 33, 0]);
|
||||
/** public/secret start block (generation 1-3, will change in 4, don't rely on value) */
|
||||
export const PAIR_HDR = new Uint8Array([48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32]);
|
||||
/** length of a public key */
|
||||
export const PUB_LENGTH = 32;
|
||||
/** length of a salt */
|
||||
export const SALT_LENGTH = 32;
|
||||
/** length of a secret key */
|
||||
export const SEC_LENGTH = 64;
|
||||
/** length of a user-input seed */
|
||||
export const SEED_LENGTH = 32;
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
import type { PairInfo } from './types.js';
|
||||
/**
|
||||
* Encode a pair with the latest generation format (generation 3)
|
||||
**/
|
||||
export declare function encodePair({ publicKey, secretKey }: PairInfo, passphrase?: string): Uint8Array;
|
||||
@@ -0,0 +1,19 @@
|
||||
import { u8aConcat } from '@pezkuwi/util';
|
||||
import { naclEncrypt, scryptEncode, scryptToU8a } from '@pezkuwi/util-crypto';
|
||||
import { PAIR_DIV, PAIR_HDR } from './defaults.js';
|
||||
/**
|
||||
* Encode a pair with the latest generation format (generation 3)
|
||||
**/
|
||||
export function encodePair({ publicKey, secretKey }, passphrase) {
|
||||
if (!secretKey) {
|
||||
throw new Error('Expected a valid secretKey to be passed to encode');
|
||||
}
|
||||
const encoded = u8aConcat(PAIR_HDR, secretKey, PAIR_DIV, publicKey);
|
||||
if (!passphrase) {
|
||||
return encoded;
|
||||
}
|
||||
// this is only for generation 3 (previous generations are only handled in decoding)
|
||||
const { params, password, salt } = scryptEncode(passphrase);
|
||||
const { encrypted, nonce } = naclEncrypt(encoded, password.subarray(0, 32));
|
||||
return u8aConcat(scryptToU8a(salt, params), nonce, encrypted);
|
||||
}
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
import type { EncryptedJsonEncoding, KeypairType } from '@pezkuwi/util-crypto/types';
|
||||
import type { KeyringPair, KeyringPair$Meta } from '../types.js';
|
||||
import type { PairInfo } from './types.js';
|
||||
interface Setup {
|
||||
toSS58: (publicKey: Uint8Array) => string;
|
||||
type: KeypairType;
|
||||
}
|
||||
/**
|
||||
* @name createPair
|
||||
* @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.
|
||||
*
|
||||
* It has properties whose values are functions that may be called to perform account actions:
|
||||
*
|
||||
* - `address` function retrieves the address associated with the account.
|
||||
* - `decodedPkcs8` function is called with the account passphrase and account encoded public key.
|
||||
* It decodes the encoded public key using the passphrase provided to obtain the decoded account public key
|
||||
* and associated secret key that are then available in memory, and changes the account address stored in the
|
||||
* state of the pair to correspond to the address of the decoded public key.
|
||||
* - `encodePkcs8` function when provided with the correct passphrase associated with the account pair
|
||||
* and when the secret key is in memory (when the account pair is not locked) it returns an encoded
|
||||
* public key of the account.
|
||||
* - `meta` is the metadata that is stored in the state of the pair, either when it was originally
|
||||
* created or set via `setMeta`.
|
||||
* - `publicKey` returns the public key stored in memory for the pair.
|
||||
* - `sign` may be used to return a signature by signing a provided message with the secret
|
||||
* key (if it is in memory) using Nacl.
|
||||
* - `toJson` calls another `toJson` function and provides the state of the pair,
|
||||
* it generates arguments to be passed to the other `toJson` function including an encoded public key of the account
|
||||
* that it generates using the secret key from memory (if it has been made available in memory)
|
||||
* and the optionally provided passphrase argument. It passes a third boolean argument to `toJson`
|
||||
* indicating whether the public key has been encoded or not (if a passphrase argument was provided then it is encoded).
|
||||
* The `toJson` function that it calls returns a JSON object with properties including the `address`
|
||||
* and `meta` that are assigned with the values stored in the corresponding state variables of the account pair,
|
||||
* 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 declare function createPair({ toSS58, type }: Setup, { publicKey, secretKey }: PairInfo, meta?: KeyringPair$Meta, encoded?: Uint8Array | null, encTypes?: EncryptedJsonEncoding[]): KeyringPair;
|
||||
export {};
|
||||
@@ -0,0 +1,180 @@
|
||||
import { objectSpread, u8aConcat, u8aEmpty, u8aEq, u8aToHex, u8aToU8a } from '@pezkuwi/util';
|
||||
import { blake2AsU8a, ed25519PairFromSeed as ed25519FromSeed, ed25519Sign, ethereumEncode, keccakAsU8a, keyExtractPath, keyFromPath, secp256k1Compress, secp256k1Expand, secp256k1PairFromSeed as secp256k1FromSeed, secp256k1Sign, signatureVerify, sr25519PairFromSeed as sr25519FromSeed, sr25519Sign, sr25519VrfSign, sr25519VrfVerify } from '@pezkuwi/util-crypto';
|
||||
import { decodePair } from './decode.js';
|
||||
import { encodePair } from './encode.js';
|
||||
import { pairToJson } from './toJson.js';
|
||||
const SIG_TYPE_NONE = new Uint8Array();
|
||||
const TYPE_FROM_SEED = {
|
||||
ecdsa: secp256k1FromSeed,
|
||||
ed25519: ed25519FromSeed,
|
||||
ethereum: secp256k1FromSeed,
|
||||
sr25519: sr25519FromSeed
|
||||
};
|
||||
const TYPE_PREFIX = {
|
||||
ecdsa: new Uint8Array([2]),
|
||||
ed25519: new Uint8Array([0]),
|
||||
ethereum: new Uint8Array([2]),
|
||||
sr25519: new Uint8Array([1])
|
||||
};
|
||||
const TYPE_SIGNATURE = {
|
||||
ecdsa: (m, p) => secp256k1Sign(m, p, 'blake2'),
|
||||
ed25519: ed25519Sign,
|
||||
ethereum: (m, p) => secp256k1Sign(m, p, 'keccak'),
|
||||
sr25519: sr25519Sign
|
||||
};
|
||||
const TYPE_ADDRESS = {
|
||||
ecdsa: (p) => p.length > 32 ? blake2AsU8a(p) : p,
|
||||
ed25519: (p) => p,
|
||||
ethereum: (p) => p.length === 20 ? p : keccakAsU8a(secp256k1Expand(p)),
|
||||
sr25519: (p) => p
|
||||
};
|
||||
function isLocked(secretKey) {
|
||||
return !secretKey || u8aEmpty(secretKey);
|
||||
}
|
||||
function vrfHash(proof, context, extra) {
|
||||
return blake2AsU8a(u8aConcat(context || '', extra || '', proof));
|
||||
}
|
||||
/**
|
||||
* @name createPair
|
||||
* @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.
|
||||
*
|
||||
* It has properties whose values are functions that may be called to perform account actions:
|
||||
*
|
||||
* - `address` function retrieves the address associated with the account.
|
||||
* - `decodedPkcs8` function is called with the account passphrase and account encoded public key.
|
||||
* It decodes the encoded public key using the passphrase provided to obtain the decoded account public key
|
||||
* and associated secret key that are then available in memory, and changes the account address stored in the
|
||||
* state of the pair to correspond to the address of the decoded public key.
|
||||
* - `encodePkcs8` function when provided with the correct passphrase associated with the account pair
|
||||
* and when the secret key is in memory (when the account pair is not locked) it returns an encoded
|
||||
* public key of the account.
|
||||
* - `meta` is the metadata that is stored in the state of the pair, either when it was originally
|
||||
* created or set via `setMeta`.
|
||||
* - `publicKey` returns the public key stored in memory for the pair.
|
||||
* - `sign` may be used to return a signature by signing a provided message with the secret
|
||||
* key (if it is in memory) using Nacl.
|
||||
* - `toJson` calls another `toJson` function and provides the state of the pair,
|
||||
* it generates arguments to be passed to the other `toJson` function including an encoded public key of the account
|
||||
* that it generates using the secret key from memory (if it has been made available in memory)
|
||||
* and the optionally provided passphrase argument. It passes a third boolean argument to `toJson`
|
||||
* indicating whether the public key has been encoded or not (if a passphrase argument was provided then it is encoded).
|
||||
* The `toJson` function that it calls returns a JSON object with properties including the `address`
|
||||
* and `meta` that are assigned with the values stored in the corresponding state variables of the account pair,
|
||||
* 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 function createPair({ toSS58, type }, { publicKey, secretKey }, meta = {}, encoded = null, encTypes) {
|
||||
const decodePkcs8 = (passphrase, userEncoded) => {
|
||||
const decoded = decodePair(passphrase, userEncoded || encoded, encTypes);
|
||||
if (decoded.secretKey.length === 64) {
|
||||
publicKey = decoded.publicKey;
|
||||
secretKey = decoded.secretKey;
|
||||
}
|
||||
else {
|
||||
const pair = TYPE_FROM_SEED[type](decoded.secretKey);
|
||||
publicKey = pair.publicKey;
|
||||
secretKey = pair.secretKey;
|
||||
}
|
||||
};
|
||||
const recode = (passphrase) => {
|
||||
isLocked(secretKey) && encoded && decodePkcs8(passphrase, encoded);
|
||||
encoded = encodePair({ publicKey, secretKey }, passphrase); // re-encode, latest version
|
||||
encTypes = undefined; // swap to defaults, latest version follows
|
||||
return encoded;
|
||||
};
|
||||
const encodeAddress = () => {
|
||||
const raw = TYPE_ADDRESS[type](publicKey);
|
||||
return type === 'ethereum'
|
||||
? ethereumEncode(raw)
|
||||
: toSS58(raw);
|
||||
};
|
||||
return {
|
||||
get address() {
|
||||
return encodeAddress();
|
||||
},
|
||||
get addressRaw() {
|
||||
const raw = TYPE_ADDRESS[type](publicKey);
|
||||
return type === 'ethereum'
|
||||
? raw.slice(-20)
|
||||
: raw;
|
||||
},
|
||||
get isLocked() {
|
||||
return isLocked(secretKey);
|
||||
},
|
||||
get meta() {
|
||||
return meta;
|
||||
},
|
||||
get publicKey() {
|
||||
return publicKey;
|
||||
},
|
||||
get type() {
|
||||
return type;
|
||||
},
|
||||
// eslint-disable-next-line sort-keys
|
||||
decodePkcs8,
|
||||
derive: (suri, meta) => {
|
||||
if (type === 'ethereum') {
|
||||
throw new Error('Unable to derive on this keypair');
|
||||
}
|
||||
else if (isLocked(secretKey)) {
|
||||
throw new Error('Cannot derive on a locked keypair');
|
||||
}
|
||||
const { path } = keyExtractPath(suri);
|
||||
const derived = keyFromPath({ publicKey, secretKey }, path, type);
|
||||
return createPair({ toSS58, type }, derived, meta, null);
|
||||
},
|
||||
encodePkcs8: (passphrase) => {
|
||||
return recode(passphrase);
|
||||
},
|
||||
lock: () => {
|
||||
secretKey = new Uint8Array();
|
||||
},
|
||||
setMeta: (additional) => {
|
||||
meta = objectSpread({}, meta, additional);
|
||||
},
|
||||
sign: (message, options = {}) => {
|
||||
if (isLocked(secretKey)) {
|
||||
throw new Error('Cannot sign with a locked key pair');
|
||||
}
|
||||
return u8aConcat(options.withType
|
||||
? TYPE_PREFIX[type]
|
||||
: SIG_TYPE_NONE, TYPE_SIGNATURE[type](u8aToU8a(message), { publicKey, secretKey }));
|
||||
},
|
||||
toJson: (passphrase) => {
|
||||
// NOTE: For ecdsa and ethereum, the publicKey cannot be extracted from the address. For these
|
||||
// pass the hex-encoded publicKey through to the address portion of the JSON (before decoding)
|
||||
// unless the publicKey is already an address
|
||||
const address = ['ecdsa', 'ethereum'].includes(type)
|
||||
? publicKey.length === 20
|
||||
? u8aToHex(publicKey)
|
||||
: u8aToHex(secp256k1Compress(publicKey))
|
||||
: encodeAddress();
|
||||
return pairToJson(type, { address, meta }, recode(passphrase), !!passphrase);
|
||||
},
|
||||
unlock: (passphrase) => {
|
||||
return decodePkcs8(passphrase);
|
||||
},
|
||||
verify: (message, signature, signerPublic) => {
|
||||
return signatureVerify(message, signature, TYPE_ADDRESS[type](u8aToU8a(signerPublic))).isValid;
|
||||
},
|
||||
vrfSign: (message, context, extra) => {
|
||||
if (isLocked(secretKey)) {
|
||||
throw new Error('Cannot sign with a locked key pair');
|
||||
}
|
||||
if (type === 'sr25519') {
|
||||
return sr25519VrfSign(message, { secretKey }, context, extra);
|
||||
}
|
||||
const proof = TYPE_SIGNATURE[type](u8aToU8a(message), { publicKey, secretKey });
|
||||
return u8aConcat(vrfHash(proof, context, extra), proof);
|
||||
},
|
||||
vrfVerify: (message, vrfResult, signerPublic, context, extra) => {
|
||||
if (type === 'sr25519') {
|
||||
return sr25519VrfVerify(message, vrfResult, publicKey, context, extra);
|
||||
}
|
||||
const result = signatureVerify(message, u8aConcat(TYPE_PREFIX[type], vrfResult.subarray(32)), TYPE_ADDRESS[type](u8aToU8a(signerPublic)));
|
||||
return result.isValid && u8aEq(vrfResult.subarray(0, 32), vrfHash(vrfResult.subarray(32), context, extra));
|
||||
}
|
||||
};
|
||||
}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
import type { KeyringPair } from '../types.js';
|
||||
export declare function nobody(): KeyringPair;
|
||||
@@ -0,0 +1,40 @@
|
||||
const publicKey = new Uint8Array(32);
|
||||
const address = '5C4hrfjw9DjXZTzV3MwzrrAr9P1MJhSrvWGWqi1eSuyUpnhM';
|
||||
const meta = {
|
||||
isTesting: true,
|
||||
name: 'nobody'
|
||||
};
|
||||
const json = {
|
||||
address,
|
||||
encoded: '',
|
||||
encoding: {
|
||||
content: ['pkcs8', 'ed25519'],
|
||||
type: 'none',
|
||||
version: '0'
|
||||
},
|
||||
meta
|
||||
};
|
||||
const pair = {
|
||||
address,
|
||||
addressRaw: publicKey,
|
||||
decodePkcs8: (_passphrase, _encoded) => undefined,
|
||||
derive: (_suri, _meta) => pair,
|
||||
encodePkcs8: (_passphrase) => new Uint8Array(0),
|
||||
isLocked: true,
|
||||
lock: () => {
|
||||
// no locking, it is always locked
|
||||
},
|
||||
meta,
|
||||
publicKey,
|
||||
setMeta: (_meta) => undefined,
|
||||
sign: (_message) => new Uint8Array(64),
|
||||
toJson: (_passphrase) => json,
|
||||
type: 'ed25519',
|
||||
unlock: (_passphrase) => undefined,
|
||||
verify: (_message, _signature) => false,
|
||||
vrfSign: (_message, _context, _extra) => new Uint8Array(96),
|
||||
vrfVerify: (_message, _vrfResult, _context, _extra) => false
|
||||
};
|
||||
export function nobody() {
|
||||
return pair;
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
import type { KeypairType } from '@pezkuwi/util-crypto/types';
|
||||
import type { KeyringPair$Json, KeyringPair$Meta } from '../types.js';
|
||||
interface PairStateJson {
|
||||
address: string;
|
||||
meta: KeyringPair$Meta;
|
||||
}
|
||||
export declare function pairToJson(type: KeypairType, { address, meta }: PairStateJson, encoded: Uint8Array, isEncrypted: boolean): KeyringPair$Json;
|
||||
export {};
|
||||
@@ -0,0 +1,8 @@
|
||||
import { objectSpread } from '@pezkuwi/util';
|
||||
import { jsonEncryptFormat } from '@pezkuwi/util-crypto';
|
||||
export function pairToJson(type, { address, meta }, encoded, isEncrypted) {
|
||||
return objectSpread(jsonEncryptFormat(encoded, ['pkcs8', type], isEncrypted), {
|
||||
address,
|
||||
meta
|
||||
});
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
export interface PairInfo {
|
||||
publicKey: Uint8Array;
|
||||
secretKey?: Uint8Array | undefined;
|
||||
seed?: Uint8Array | null;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Reference in New Issue
Block a user