Helpers for 256/512 hashing (#1303)
* Helpers for 256/512 hashing * Adjust u8aToU8a (u8a-only check earlier) * Fix export * Simplify * revert
This commit is contained in:
@@ -3,7 +3,13 @@
|
||||
|
||||
import type { HexString } from '@polkadot/util/types';
|
||||
|
||||
import { u8aToHex } from '@polkadot/util';
|
||||
import { hasBigInt, u8aToHex, u8aToU8a } from '@polkadot/util';
|
||||
import { isReady } from '@polkadot/wasm-crypto';
|
||||
|
||||
interface DualHash {
|
||||
256: (u8a: Uint8Array) => Uint8Array;
|
||||
512: (u8a: Uint8Array) => Uint8Array;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function createAsHex <T extends (...args: any[]) => Uint8Array> (fn: T): (...args: Parameters<T>) => HexString {
|
||||
@@ -15,3 +21,13 @@ export function createBitHasher <T> (bitLength: T, fn: (data: HexString | Buffer
|
||||
return (data: HexString | Buffer | Uint8Array | string, onlyJs?: boolean): Uint8Array =>
|
||||
fn(data, bitLength, onlyJs);
|
||||
}
|
||||
|
||||
export function createDualHasher (wa: DualHash, js: DualHash): (value: HexString | Buffer | Uint8Array | string, bitLength?: 256 | 512, onlyJs?: boolean) => Uint8Array {
|
||||
return (value: HexString | Buffer | Uint8Array | string, bitLength: 256 | 512 = 256, onlyJs?: boolean): Uint8Array => {
|
||||
const u8a = u8aToU8a(value);
|
||||
|
||||
return !hasBigInt || (!onlyJs && isReady())
|
||||
? wa[bitLength](u8a)
|
||||
: js[bitLength](u8a);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,6 +9,16 @@ import { sha512 } from '@polkadot/x-noble-hashes/sha512';
|
||||
|
||||
type BitLength = 256 | 512;
|
||||
|
||||
const JS_HASH = {
|
||||
256: sha256,
|
||||
512: sha512
|
||||
};
|
||||
|
||||
const WA_MHAC = {
|
||||
256: hmacSha256,
|
||||
512: hmacSha512
|
||||
};
|
||||
|
||||
function createSha (bitLength: BitLength): (key: Uint8Array | string, data: Uint8Array, onlyJs?: boolean) => Uint8Array {
|
||||
return (key: Uint8Array | string, data: Uint8Array, onlyJs?: boolean): Uint8Array =>
|
||||
hmacShaAsU8a(key, data, bitLength, onlyJs);
|
||||
@@ -19,16 +29,11 @@ function createSha (bitLength: BitLength): (key: Uint8Array | string, data: Uint
|
||||
* @description creates a Hmac Sha (256/512) Uint8Array from the key & data
|
||||
*/
|
||||
export function hmacShaAsU8a (key: Uint8Array | string, data: Uint8Array, bitLength: BitLength = 256, onlyJs?: boolean): Uint8Array {
|
||||
const is256 = bitLength === 256;
|
||||
const u8aKey = u8aToU8a(key);
|
||||
|
||||
return !hasBigInt || (!onlyJs && isReady())
|
||||
? is256
|
||||
? hmacSha256(u8aKey, data)
|
||||
: hmacSha512(u8aKey, data)
|
||||
: is256
|
||||
? hmac(sha256, u8aKey, data)
|
||||
: hmac(sha512, u8aKey, data);
|
||||
? WA_MHAC[bitLength](u8aKey, data)
|
||||
: hmac(JS_HASH[bitLength], u8aKey, data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { HexString } from '@polkadot/util/types';
|
||||
|
||||
import { hasBigInt, u8aToU8a } from '@polkadot/util';
|
||||
import { isReady, keccak256, keccak512 } from '@polkadot/wasm-crypto';
|
||||
import { keccak256, keccak512 } from '@polkadot/wasm-crypto';
|
||||
import { keccak_256 as keccak256Js, keccak_512 as keccak512Js } from '@polkadot/x-noble-hashes/sha3';
|
||||
|
||||
import { createAsHex, createBitHasher } from '../helpers';
|
||||
|
||||
type BitLength = 256 | 512;
|
||||
import { createAsHex, createBitHasher, createDualHasher } from '../helpers';
|
||||
|
||||
/**
|
||||
* @name keccakAsU8a
|
||||
@@ -25,18 +20,11 @@ type BitLength = 256 | 512;
|
||||
* keccakAsU8a('123'); // => Uint8Array
|
||||
* ```
|
||||
*/
|
||||
export function keccakAsU8a (value: HexString | Buffer | Uint8Array | string, bitLength: BitLength = 256, onlyJs?: boolean): Uint8Array {
|
||||
const is256 = bitLength === 256;
|
||||
const u8a = u8aToU8a(value);
|
||||
|
||||
return !hasBigInt || (!onlyJs && isReady())
|
||||
? is256
|
||||
? keccak256(u8a)
|
||||
: keccak512(u8a)
|
||||
: is256
|
||||
? keccak256Js(u8a)
|
||||
: keccak512Js(u8a);
|
||||
}
|
||||
export const keccakAsU8a = createDualHasher(
|
||||
{ 256: keccak256, 512: keccak512 },
|
||||
{ 256: keccak256Js, 512: keccak512Js }
|
||||
);
|
||||
|
||||
/**
|
||||
* @name keccak256AsU8a
|
||||
|
||||
@@ -1,33 +1,20 @@
|
||||
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { HexString } from '@polkadot/util/types';
|
||||
|
||||
import { hasBigInt, u8aToU8a } from '@polkadot/util';
|
||||
import { isReady, sha256, sha512 } from '@polkadot/wasm-crypto';
|
||||
import { sha256, sha512 } from '@polkadot/wasm-crypto';
|
||||
import { sha256 as sha256Js } from '@polkadot/x-noble-hashes/sha256';
|
||||
import { sha512 as sha512Js } from '@polkadot/x-noble-hashes/sha512';
|
||||
|
||||
import { createBitHasher } from '../helpers';
|
||||
|
||||
type BitLength = 256 | 512;
|
||||
import { createBitHasher, createDualHasher } from '../helpers';
|
||||
|
||||
/**
|
||||
* @name shaAsU8a
|
||||
* @summary Creates a sha Uint8Array from the input.
|
||||
*/
|
||||
export function shaAsU8a (value: HexString | Buffer | Uint8Array | string, bitLength: BitLength = 256, onlyJs?: boolean): Uint8Array {
|
||||
const is256 = bitLength === 256;
|
||||
const u8a = u8aToU8a(value);
|
||||
|
||||
return !hasBigInt || (!onlyJs && isReady())
|
||||
? is256
|
||||
? sha256(u8a)
|
||||
: sha512(u8a)
|
||||
: is256
|
||||
? sha256Js(u8a)
|
||||
: sha512Js(u8a);
|
||||
}
|
||||
export const shaAsU8a = createDualHasher(
|
||||
{ 256: sha256, 512: sha512 },
|
||||
{ 256: sha256Js, 512: sha512Js }
|
||||
);
|
||||
|
||||
/**
|
||||
* @name sha256AsU8a
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { isFunction } from './function';
|
||||
import { isObject } from './object';
|
||||
|
||||
export function isOn <T> (fn: keyof T): (value?: unknown) => value is T {
|
||||
return (value?: unknown): value is T =>
|
||||
!!value && (isObject(value) || isFunction(value)) && isFunction((value as T)[fn]);
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { isFunction } from './function';
|
||||
import { isObject } from './object';
|
||||
import type { Observable } from '../types';
|
||||
|
||||
interface Observable {
|
||||
next: (...params: unknown[]) => unknown;
|
||||
}
|
||||
import { isOn } from './helpers';
|
||||
|
||||
/**
|
||||
* @name isBObservable
|
||||
@@ -22,9 +19,4 @@ interface Observable {
|
||||
* console.log('isObservable', isObservable(...));
|
||||
* ```
|
||||
*/
|
||||
export function isObservable (value: unknown): value is Observable {
|
||||
return (
|
||||
isObject(value) &&
|
||||
isFunction((value as Observable).next)
|
||||
);
|
||||
}
|
||||
export const isObservable = isOn<Observable>('next');
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
import type { ToBigInt } from '../types';
|
||||
|
||||
import { isFunction } from './function';
|
||||
import { isOn } from './helpers';
|
||||
|
||||
export function isToBigInt (value?: unknown): value is ToBigInt {
|
||||
return !!value && isFunction((value as ToBigInt).toBigInt);
|
||||
}
|
||||
export const isToBigInt = isOn<ToBigInt>('toBigInt');
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
import type { ToBn } from '../types';
|
||||
|
||||
import { isFunction } from './function';
|
||||
import { isOn } from './helpers';
|
||||
|
||||
export function isToBn (value?: unknown): value is ToBn {
|
||||
return !!value && isFunction((value as ToBn).toBn);
|
||||
}
|
||||
export const isToBn = isOn<ToBn>('toBn');
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
type Entries<T> = {
|
||||
[K in keyof T]: [K, T[K]]
|
||||
}[keyof T][];
|
||||
type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
|
||||
|
||||
/**
|
||||
* @name objectEntries
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
type Values<T extends object> = T[keyof T][];
|
||||
|
||||
/**
|
||||
* @name objectValues
|
||||
* @summary A version of Object.values that is typed for TS
|
||||
*/
|
||||
export function objectValues<T extends object> (obj: T): Values<T> {
|
||||
return Object.values(obj) as Values<T>;
|
||||
export function objectValues<T extends object> (obj: T): T[keyof T][] {
|
||||
return Object.values(obj) as T[keyof T][];
|
||||
}
|
||||
|
||||
@@ -85,3 +85,7 @@ export interface IBigIntConstructor {
|
||||
*/
|
||||
asUintN (bits: number, int: bigint): bigint;
|
||||
}
|
||||
|
||||
export interface Observable {
|
||||
next: (...params: unknown[]) => unknown;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,16 @@
|
||||
import { u8aToU8a } from '.';
|
||||
|
||||
describe('u8aToU8a', (): void => {
|
||||
it('returns an empty Uint8Array when null provided', (): void => {
|
||||
it('returns an empty Uint8Array when null/undefined/"" provided', (): void => {
|
||||
expect(
|
||||
u8aToU8a(null)
|
||||
).toHaveLength(0);
|
||||
expect(
|
||||
u8aToU8a()
|
||||
).toHaveLength(0);
|
||||
expect(
|
||||
u8aToU8a('')
|
||||
).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('returns a Uint8Array (hex input)', (): void => {
|
||||
@@ -24,14 +30,6 @@ describe('u8aToU8a', (): void => {
|
||||
).toEqual(new Uint8Array([97, 98, 99, 100, 101, 32, 102, 103, 104, 105, 106]));
|
||||
});
|
||||
|
||||
it('returns a Uint8Array (buffer input)', (): void => {
|
||||
expect(
|
||||
u8aToU8a(Buffer.from('80000a', 'hex'))
|
||||
).toEqual(
|
||||
new Uint8Array([128, 0, 10])
|
||||
);
|
||||
});
|
||||
|
||||
it('creates from Array', (): void => {
|
||||
expect(
|
||||
u8aToU8a([128, 0, 10, 11, 12])
|
||||
@@ -46,20 +44,25 @@ describe('u8aToU8a', (): void => {
|
||||
).toEqual(
|
||||
new Uint8Array([1, 2, 3, 128, 0, 10, 11, 12])
|
||||
);
|
||||
});
|
||||
|
||||
it('returns a Uint8Array as-is (u8a input)', (): void => {
|
||||
expect(
|
||||
u8aToU8a(new Uint8Array([128, 0, 10]))
|
||||
u8aToU8a(Buffer.from('80000a', 'hex'))
|
||||
).toEqual(
|
||||
new Uint8Array([128, 0, 10])
|
||||
);
|
||||
});
|
||||
|
||||
it('fails to create from unknown typed values', (): void => {
|
||||
it('returns a Uint8Array as-is (u8a input)', (): void => {
|
||||
const input = new Uint8Array([128, 0, 10]);
|
||||
|
||||
expect(
|
||||
u8aToU8a(input) === input
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('creates unknowns via string conversion', (): void => {
|
||||
expect(
|
||||
// this is where completely invalid data is being passed
|
||||
() => u8aToU8a(123 as unknown as Uint8Array)
|
||||
).toThrow('Unable to convert 123 (typeof number) to a Uint8Array');
|
||||
u8aToU8a(123 as unknown as Uint8Array)
|
||||
).toEqual(new Uint8Array([49, 50, 51]));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
|
||||
import type { U8aLike } from '../types';
|
||||
|
||||
import { assert } from '../assert';
|
||||
import { hexToU8a } from '../hex/toU8a';
|
||||
import { isBuffer } from '../is/buffer';
|
||||
import { isHex } from '../is/hex';
|
||||
import { isString } from '../is/string';
|
||||
import { isU8a } from '../is/u8a';
|
||||
import { stringToU8a } from '../string/toU8a';
|
||||
|
||||
@@ -27,17 +25,13 @@ import { stringToU8a } from '../string/toU8a';
|
||||
* ```
|
||||
*/
|
||||
export function u8aToU8a (value?: U8aLike | null): Uint8Array {
|
||||
if (!value) {
|
||||
return new Uint8Array();
|
||||
} else if (isHex(value)) {
|
||||
return hexToU8a(value);
|
||||
} else if (isString(value)) {
|
||||
return stringToU8a(value);
|
||||
} else if (Array.isArray(value) || isBuffer(value)) {
|
||||
return new Uint8Array(value);
|
||||
}
|
||||
|
||||
assert(isU8a(value), () => `Unable to convert ${value.toString()} (typeof ${typeof value}) to a Uint8Array`);
|
||||
|
||||
return value;
|
||||
return !value
|
||||
? new Uint8Array()
|
||||
: Array.isArray(value) || isBuffer(value)
|
||||
? new Uint8Array(value)
|
||||
: isU8a(value)
|
||||
? value
|
||||
: isHex(value)
|
||||
? hexToU8a(value)
|
||||
: stringToU8a(value);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user