Initial rebrand: @polkadot -> @pezkuwi (14 packages)

- Package namespace: @polkadot/* -> @pezkuwi/*
- Repository: polkadot-js/common -> pezkuwichain/pezkuwi-common
- Author: Pezkuwi Team <team@pezkuwichain.io>

Core packages:
- @pezkuwi/util (utilities)
- @pezkuwi/util-crypto (crypto primitives)
- @pezkuwi/keyring (account management)
- @pezkuwi/networks (chain metadata)
- @pezkuwi/hw-ledger (Ledger hardware wallet)
- @pezkuwi/x-* (10 polyfill packages)

Total: 14 packages
Upstream: polkadot-js/common v14.0.1
This commit is contained in:
2026-01-05 14:00:34 +03:00
commit ec06da0ebc
687 changed files with 48096 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { perf } from '../test/index.js';
import { u8aCmp } from './index.js';
const ltest = new Uint8Array(32768);
const stest = new Uint8Array(256);
const ztest = new Uint8Array(64);
for (let i = 0, count = ltest.length; i < count; i++) {
if (i < ztest.length) {
ztest[i] = i % 256;
}
if (i < stest.length) {
stest[i] = i % 256;
}
ltest[i] = i % 256;
}
describe('u8aCmp', (): void => {
it('has the same result as localCompare (equal length)', (): void => {
const a = 'test abc';
const b = 'test def';
expect(
u8aCmp(a, b)
).toEqual(a.localeCompare(b));
expect(
u8aCmp(b, a)
).toEqual(b.localeCompare(a));
});
it('has the same result as localCompare (diff length)', (): void => {
const a = 'test';
const b = 'test abc';
expect(
u8aCmp(a, b)
).toEqual(a.localeCompare(b));
expect(
u8aCmp(b, a)
).toEqual(b.localeCompare(a));
});
it('compares between string and Uint8Array', (): void => {
expect(
u8aCmp(
'0x12345678',
new Uint8Array([0x12, 0x34, 0x56, 0x78])
)
).toEqual(0);
});
perf('u8aCmp (64 cmp)', 100_000, [[ztest, ztest]], u8aCmp);
perf('u8aCmp (256 cmp)', 50_000, [[stest, stest]], u8aCmp);
perf('u8aCmp (32k cmp)', 500, [[ltest, ltest]], u8aCmp);
});
+50
View File
@@ -0,0 +1,50 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { u8aToU8a } from './toU8a.js';
/**
* @name u8aCmp
* @summary Compares two Uint8Arrays for sorting.
* @description
* For `UInt8Array` (or hex string) input values returning -1, 0 or +1
* @example
* <BR>
*
* ```javascript
* import { u8aCmp } from '@pezkuwi/util';
*
* u8aCmp(new Uint8Array([0x67, 0x65]), new Uint8Array([0x68, 0x65])); // -1
* u8aCmp(new Uint8Array([0x68, 0x65]), new Uint8Array([0x68, 0x65])); // 0
* u8aCmp(new Uint8Array([0x69, 0x65]), new Uint8Array([0x68, 0x65])); // +1
* ```
*/
export function u8aCmp (a: string | Uint8Array, b: string | Uint8Array): number {
const u8aa = u8aToU8a(a);
const u8ab = u8aToU8a(b);
let i = 0;
while (true) {
const overA = i >= u8aa.length;
const overB = i >= u8ab.length;
if (overA && overB) {
// both ends reached
return 0;
} else if (overA) {
// a has no more data, b has data
return -1;
} else if (overB) {
// b has no more data, a has data
return 1;
} else if (u8aa[i] !== u8ab[i]) {
// the number in this index doesn't match
// (we don't use u8aa[i] - u8ab[i] since that doesn't match with localeCompare)
return u8aa[i] > u8ab[i]
? 1
: -1;
}
i++;
}
}
+42
View File
@@ -0,0 +1,42 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { getRandomValues } from '@pezkuwi/x-randomvalues';
import { arrayRange } from '../array/index.js';
import { perf } from '../test/index.js';
import { u8aConcat, u8aConcatStrict } from './index.js';
const ptest = arrayRange(10).map(() => getRandomValues(new Uint8Array(32)));
describe('u8aConcat', (): void => {
it('concatenates arrays', (): void => {
expect(
u8aConcat(
new Uint8Array([1, 2, 3, 4]),
new Uint8Array([5, 6]),
new Uint8Array([7, 8, 9])
)
).toEqual(
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9])
);
});
it('concatenates arrays & hex values', (): void => {
expect(
u8aConcat(
new Uint8Array([1, 2, 3, 4]),
'0x0506',
'0x070809'
)
).toEqual(
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9])
);
});
perf('u8aConcat', 10000, [[ptest]], u8aConcat);
perf('u8aConcatStrict', 10000, [[[ptest]]], u8aConcatStrict);
perf('u8aConcatStrict (len)', 10000, [[[ptest], 320]], u8aConcatStrict);
});
+60
View File
@@ -0,0 +1,60 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { U8aLike } from '../types.js';
import { u8aToU8a } from './toU8a.js';
/**
* @name u8aConcat
* @summary Creates a concatenated Uint8Array from the inputs.
* @description
* Concatenates the input arrays into a single `UInt8Array`.
* @example
* <BR>
*
* ```javascript
* import { { u8aConcat } from '@pezkuwi/util';
*
* u8aConcat(
* new Uint8Array([1, 2, 3]),
* new Uint8Array([4, 5, 6])
* ); // [1, 2, 3, 4, 5, 6]
* ```
*/
export function u8aConcat (...list: readonly U8aLike[]): Uint8Array {
const count = list.length;
const u8as = new Array<Uint8Array>(count);
let length = 0;
for (let i = 0; i < count; i++) {
u8as[i] = u8aToU8a(list[i]);
length += u8as[i].length;
}
return u8aConcatStrict(u8as, length);
}
/**
* @name u8aConcatStrict
* @description A strict version of [[u8aConcat]], accepting only Uint8Array inputs
*/
export function u8aConcatStrict (u8as: readonly Uint8Array[], length = 0): Uint8Array {
const count = u8as.length;
let offset = 0;
if (!length) {
for (let i = 0; i < count; i++) {
length += u8as[i].length;
}
}
const result = new Uint8Array(length);
for (let i = 0; i < count; i++) {
result.set(u8as[i], offset);
offset += u8as[i].length;
}
return result;
}
+34
View File
@@ -0,0 +1,34 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { U8aLike } from '../types.js';
import { u8aToU8a } from './toU8a.js';
/**
* @name u8aConcat
* @summary Creates a concatenated Uint8Array from the inputs.
* @description
* Concatenates the input arrays into a single `UInt8Array`.
* @example
* <BR>
*
* ```javascript
* import { { u8aConcat } from '@pezkuwi/util';
*
* u8aConcat(
* new Uint8Array([1, 2, 3]),
* new Uint8Array([4, 5, 6])
* ); // [1, 2, 3, 4, 5, 6]
* ```
*/
export function u8aConcat (...list: readonly U8aLike[]): Uint8Array {
const count = list.length;
const u8as = new Array<Uint8Array>(count);
for (let i = 0; i < count; i++) {
u8as[i] = u8aToU8a(list[i]);
}
return Uint8Array.from(Buffer.concat(u8as));
}
+46
View File
@@ -0,0 +1,46 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { perf } from '../test/index.js';
import { u8aEmpty } from './index.js';
describe('u8aEmpty', (): void => {
it('returns true on zero length', (): void => {
expect(
u8aEmpty(new Uint8Array())
).toEqual(true);
});
it('returns true on all zero values', (): void => {
expect(
u8aEmpty(new Uint8Array([0, 0, 0, 0, 0, 0]))
).toEqual(true);
});
it('returns false when value is found', (): void => {
expect(
u8aEmpty(new Uint8Array([0, 0, 0, 0, 0, 1]))
).toEqual(false);
});
it('returns false when value is found (256)', (): void => {
const test = new Uint8Array(256);
expect(
u8aEmpty(test)
).toEqual(true);
test[128] = 1;
expect(
u8aEmpty(test)
).toEqual(false);
});
perf('u8aEmpty (32 cmp)', 1_000_000, [[new Uint8Array(32)]], u8aEmpty);
perf('u8aEmpty (64 cmp)', 500_000, [[new Uint8Array(64)]], u8aEmpty);
perf('u8aEmpty (128 cmp)', 250_000, [[new Uint8Array(128)]], u8aEmpty);
perf('u8aEmpty (256 cmp)', 125_000, [[new Uint8Array(256)]], u8aEmpty);
});
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/**
* @name u8aEmpty
* @summary Tests for a `Uint8Array` for emptyness
* @description
* Checks to see if the input `Uint8Array` has zero length or contains all 0 values.
*/
export function u8aEmpty (value: Uint8Array): boolean {
const len = value.length | 0;
// on smaller sizes, the byte-by-byte compare is faster than allocating
// another object for DataView (on very large arrays the DataView is faster)
for (let i = 0; i < len; i++) {
if (value[i] | 0) {
return false;
}
}
return true;
}
+113
View File
@@ -0,0 +1,113 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { perf } from '../test/index.js';
import { u8aEq } from './index.js';
const ltest = new Uint8Array(32768);
const stest = new Uint8Array(256);
const ztest = new Uint8Array(64);
for (let i = 0, count = ltest.length; i < count; i++) {
if (i < ztest.length) {
ztest[i] = i % 256;
}
if (i < stest.length) {
stest[i] = i % 256;
}
ltest[i] = i % 256;
}
describe('u8aEq', (): void => {
it('returns false when the lengths do not match', (): void => {
expect(
u8aEq(
new Uint8Array([1, 2, 3]),
new Uint8Array([1, 2])
)
).toEqual(false);
});
it('returns false when the contents do not match', (): void => {
expect(
u8aEq(
new Uint8Array([1, 2, 3]),
new Uint8Array([1, 2, 4])
)
).toEqual(false);
});
it('returns true when the contents do match', (): void => {
expect(
u8aEq(
new Uint8Array([1, 2, 3]),
new Uint8Array([1, 2, 3])
)
).toEqual(true);
});
it('returns false when the contents do not match (with u32 start)', (): void => {
expect(
u8aEq(
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3]),
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 4])
)
).toEqual(false);
});
it('returns true when the contents do match (with u32 start)', (): void => {
expect(
u8aEq(
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3]),
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3])
)
).toEqual(true);
});
it('returns false when the contents do not match (u32 only)', (): void => {
expect(
u8aEq(
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]),
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 9])
)
).toEqual(false);
});
it('returns true when the contents do match (u32 only)', (): void => {
expect(
u8aEq(
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]),
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8])
)
).toEqual(true);
});
it('returns true with equalvalent hex & Uint8array', (): void => {
expect(
u8aEq(
'0x010203',
new Uint8Array([1, 2, 3])
)
).toEqual(true);
});
it('works on aubarray values', (): void => {
const a = new Uint8Array(16);
for (let i = 0, count = a.length; i < count; i++) {
a[i] = i;
}
expect(
u8aEq(a.subarray(0, 5), a.subarray(0, 5))
).toEqual(true);
});
perf('u8aEq (64 cmp)', 200_000, [[ztest, ztest]], u8aEq);
perf('u8aEq (256 cmp)', 200_000, [[stest, stest]], u8aEq);
perf('u8aEq (32k cmp)', 10_000, [[ltest, ltest]], u8aEq);
});
+46
View File
@@ -0,0 +1,46 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { u8aToU8a } from './toU8a.js';
/**
* @name u8aEq
* @summary Compares two Uint8Arrays for equality.
* @description
* For `UInt8Array` (or hex string) input values true if there is a match.
* @example
* <BR>
*
* ```javascript
* import { u8aEq } from '@pezkuwi/util';
*
* u8aEq(new Uint8Array([0x68, 0x65]), new Uint8Array([0x68, 0x65])); // true
* ```
*/
export function u8aEq (a: string | Uint8Array, b: string | Uint8Array): boolean {
const u8aa = u8aToU8a(a);
const u8ab = u8aToU8a(b);
if (u8aa.length === u8ab.length) {
const dvA = new DataView(u8aa.buffer, u8aa.byteOffset);
const dvB = new DataView(u8ab.buffer, u8ab.byteOffset);
const mod = (u8aa.length % 4) | 0;
const length = (u8aa.length - mod) | 0;
for (let i = 0; i < length; i += 4) {
if (dvA.getUint32(i) !== dvB.getUint32(i)) {
return false;
}
}
for (let i = length, count = u8aa.length; i < count; i++) {
if (u8aa[i] !== u8ab[i]) {
return false;
}
}
return true;
}
return false;
}
+34
View File
@@ -0,0 +1,34 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { u8aFixLength } from './index.js';
describe('u8aFixLength', (): void => {
it('returns bitLength === -1 as-is', (): void => {
expect(
u8aFixLength(
new Uint8Array([0x12, 0x34, 0x56, 0x78])
)
).toEqual(new Uint8Array([0x12, 0x34, 0x56, 0x78]));
});
it('does not change when bitlength === length', (): void => {
expect(
u8aFixLength(new Uint8Array([0x12, 0x34, 0x56, 0x78]), 32)
).toEqual(new Uint8Array([0x12, 0x34, 0x56, 0x78]));
});
it('trims values when bitLength > length', (): void => {
expect(
u8aFixLength(new Uint8Array([0x12, 0x34, 0x56, 0x78]), 16)
).toEqual(new Uint8Array([0x12, 0x34]));
});
it('adds zeros when bitLength < length (withPadded)', (): void => {
expect(
u8aFixLength(new Uint8Array([0x12, 0x34]), 32)
).toEqual(new Uint8Array([0, 0, 0x12, 0x34]));
});
});
+34
View File
@@ -0,0 +1,34 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/**
* @name u8aFixLength
* @summary Shifts a Uint8Array to a specific bitLength
* @description
* Returns a uint8Array with the specified number of bits contained in the return value. (If bitLength is -1, length checking is not done). Values with more bits are trimmed to the specified length.
* @example
* <BR>
*
* ```javascript
* import { u8aFixLength } from '@pezkuwi/util';
*
* u8aFixLength('0x12') // => 0x12
* u8aFixLength('0x12', 16) // => 0x0012
* u8aFixLength('0x1234', 8) // => 0x12
* ```
*/
export function u8aFixLength (value: Uint8Array, bitLength = -1, atStart = false): Uint8Array {
const byteLength = Math.ceil(bitLength / 8);
if (bitLength === -1 || value.length === byteLength) {
return value;
} else if (value.length > byteLength) {
return value.subarray(0, byteLength);
}
const result = new Uint8Array(byteLength);
result.set(value, atStart ? 0 : (byteLength - value.length));
return result;
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/**
* @summary Utility methods to convert to and from `Uint8Array` objects
*/
export { u8aCmp } from './cmp.js';
export { u8aConcat, u8aConcatStrict } from './concat.js';
export { u8aEmpty } from './empty.js';
export { u8aEq } from './eq.js';
export { u8aFixLength } from './fixLength.js';
export { u8aSorted } from './sorted.js';
export { u8aToBigInt } from './toBigInt.js';
export { u8aToBn } from './toBn.js';
export { u8aToBuffer } from './toBuffer.js';
export { u8aToFloat } from './toFloat.js';
export { u8aToHex } from './toHex.js';
export { u8aToNumber } from './toNumber.js';
export { u8aToString } from './toString.js';
export { u8aToU8a } from './toU8a.js';
export { U8A_WRAP_ETHEREUM, U8A_WRAP_POSTFIX, U8A_WRAP_PREFIX, u8aIsWrapped, u8aUnwrapBytes, u8aWrapBytes } from './wrap.js';
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { u8aSorted } from './index.js';
describe('u8aSorted', (): void => {
it('sorts a simple set of u8a', (): void => {
expect(
u8aSorted([new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6]), new Uint8Array([2, 3, 4])])
).toEqual([new Uint8Array([1, 2, 3]), new Uint8Array([2, 3, 4]), new Uint8Array([4, 5, 6])]);
});
it('sorts a simple set of u8a (not the same lengths)', (): void => {
expect(
u8aSorted([new Uint8Array([1, 2, 3, 4]), new Uint8Array([4, 5, 6]), new Uint8Array([1, 2, 3, 5])])
).toEqual([new Uint8Array([1, 2, 3, 4]), new Uint8Array([1, 2, 3, 5]), new Uint8Array([4, 5, 6])]);
});
});
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { u8aCmp } from './cmp.js';
/**
* @name u8aSorted
* @summary Sorts an array of Uint8Arrays
* @description
* For input `UInt8Array[]` return the sorted result
* @example
* <BR>
*
* ```javascript
* import { u8aSorted} from '@pezkuwi/util';
*
* u8aSorted([new Uint8Array([0x69]), new Uint8Array([0x68])]); // [0x68, 0x69]
* ```
*/
export function u8aSorted (u8as: Uint8Array[]): Uint8Array[] {
return u8as.sort(u8aCmp);
}
+106
View File
@@ -0,0 +1,106 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { TESTS } from '../bi/toU8a.spec.js';
import { perf } from '../test/index.js';
import { u8aToBigInt } from './index.js';
// test-cases are the same as in u8aToBn
describe('u8aToBigInt', (): void => {
it('converts little-endian by default', (): void => {
expect(
u8aToBigInt(
new Uint8Array([0x12, 0x34])
).toString(16)
).toBe('3412');
});
describe('empty creation', (): void => {
it('handles unsigned (le)', (): void => {
expect(
u8aToBigInt(
new Uint8Array(),
{ isLe: true }
).toString(16)
).toBe('0');
});
it('handles signed (le)', (): void => {
expect(
u8aToBigInt(
new Uint8Array(),
{ isLe: true, isNegative: true }
).toString(16)
).toBe('0');
});
it('handles unsigned (be)', (): void => {
expect(
u8aToBigInt(
new Uint8Array(),
{ isLe: false }
).toString(16)
).toBe('0');
});
it('handles signed (be)', (): void => {
expect(
u8aToBigInt(
new Uint8Array(),
{ isLe: false, isNegative: true }
).toString(16)
).toBe('0');
});
});
it('handles overflows correctly (little-endian)', (): void => {
expect(
u8aToBigInt(
new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0]),
{ isLe: true }
)
).toBe(256n);
});
describe('length tests', (): void => {
[true, false].forEach((isLe) => {
for (let i = 1; i < 32; i++) {
const tu8a = [0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78];
const tstr = tu8a.map((n) => n.toString(16));
it(`converts values with bitLength=${i * 8}, isLe=${isLe}`, (): void => {
expect(
u8aToBigInt(
new Uint8Array(tu8a.slice(0, i)),
{ isLe }
).toString(16)
).toBe(
isLe
? tstr.slice(0, i).reverse().join('')
: tstr.slice(0, i).join('')
);
});
}
});
});
describe('conversion tests', (): void => {
TESTS.forEach(([isLe, isNegative, numarr, strval], i): void => {
it(`#${i}: creates ${strval} (bitLength=${numarr.length * 8}, isLe=${isLe}, isNegative=${isNegative})`, (): void => {
expect(
u8aToBigInt(
new Uint8Array(numarr),
{ isLe, isNegative }
).toString()
).toBe(strval);
});
});
});
perf('u8aToBigInt (i32)', 750_000, [[new Uint8Array([0x9c, 0x9c, 0x9c, 0x9c])]], (v: Uint8Array) => u8aToBigInt(v, { isNegative: true }));
perf('u8aToBigInt (u32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
perf('u8aToBigInt (u64)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
perf('u8aToBigInt (u128)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
});
+100
View File
@@ -0,0 +1,100 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ToBnOptions } from '../types.js';
import { BigInt } from '@pezkuwi/x-bigint';
import { _1n } from '../bi/consts.js';
const U8_MAX = BigInt(256);
const U16_MAX = BigInt(256 * 256);
const U64_MAX = BigInt('0x10000000000000000');
/**
* @name u8aToBigInt
* @summary Creates a BigInt from a Uint8Array object.
*/
export function u8aToBigInt (value: Uint8Array, { isLe = true, isNegative = false }: ToBnOptions = {}): bigint {
// slice + reverse is expensive, however SCALE is LE by default so this is the path
// we are most interested in (the BE is added for the sake of being comprehensive)
if (!isLe) {
value = value.slice().reverse();
}
const count = value.length;
if (isNegative && count && (value[count - 1] & 0x80)) {
switch (count) {
case 0:
return BigInt(0);
case 1:
return BigInt(((value[0] ^ 0x0000_00ff) * -1) - 1);
case 2:
return BigInt((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
case 4:
return BigInt((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
}
const dvI = new DataView(value.buffer, value.byteOffset);
if (count === 8) {
return dvI.getBigInt64(0, true);
}
let result = BigInt(0);
const mod = count % 2;
for (let i = count - 2; i >= mod; i -= 2) {
result = (result * U16_MAX) + BigInt(dvI.getUint16(i, true) ^ 0xffff);
}
if (mod) {
result = (result * U8_MAX) + BigInt(value[0] ^ 0xff);
}
return (result * -_1n) - _1n;
}
switch (count) {
case 0:
return BigInt(0);
case 1:
return BigInt(value[0]);
case 2:
return BigInt(value[0] + (value[1] << 8));
case 4:
return BigInt(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00));
}
const dvI = new DataView(value.buffer, value.byteOffset);
switch (count) {
case 8:
return dvI.getBigUint64(0, true);
case 16:
return (dvI.getBigUint64(8, true) * U64_MAX) + dvI.getBigUint64(0, true);
default: {
let result = BigInt(0);
const mod = count % 2;
for (let i = count - 2; i >= mod; i -= 2) {
result = (result * U16_MAX) + BigInt(dvI.getUint16(i, true));
}
if (mod) {
result = (result * U8_MAX) + BigInt(value[0]);
}
return result;
}
}
}
+106
View File
@@ -0,0 +1,106 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { TESTS } from '../bi/toU8a.spec.js';
import { perf } from '../test/index.js';
import { u8aToBn } from './index.js';
// test-cases are the same as in u8aToBigInt
describe('u8aToBn', (): void => {
it('converts little-endian by default', (): void => {
expect(
u8aToBn(
new Uint8Array([0x12, 0x34])
).toString(16)
).toBe('3412');
});
describe('empty creation', (): void => {
it('handles unsigned (le)', (): void => {
expect(
u8aToBn(
new Uint8Array(),
{ isLe: true }
).toString(16)
).toBe('0');
});
it('handles signed (le)', (): void => {
expect(
u8aToBn(
new Uint8Array(),
{ isLe: true, isNegative: true }
).toString(16)
).toBe('0');
});
it('handles unsigned (be)', (): void => {
expect(
u8aToBn(
new Uint8Array(),
{ isLe: false }
).toString(16)
).toBe('0');
});
it('handles signed (be)', (): void => {
expect(
u8aToBn(
new Uint8Array(),
{ isLe: false, isNegative: true }
).toString(16)
).toBe('0');
});
});
it('handles overflows correctly (little-endian)', (): void => {
expect(
u8aToBn(
new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0]),
{ isLe: true }
).toNumber()
).toBe(256);
});
describe('length tests', (): void => {
[true, false].forEach((isLe) => {
for (let i = 1; i < 32; i++) {
const tu8a = [0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78];
const tstr = tu8a.map((n) => n.toString(16));
it(`converts values with bitLength=${i * 8}, isLe=${isLe}`, (): void => {
expect(
u8aToBn(
new Uint8Array(tu8a.slice(0, i)),
{ isLe }
).toString(16)
).toBe(
isLe
? tstr.slice(0, i).reverse().join('')
: tstr.slice(0, i).join('')
);
});
}
});
});
describe('conversion tests', (): void => {
TESTS.forEach(([isLe, isNegative, numarr, strval], i): void => {
it(`#${i}: creates ${strval} (bitLength=${numarr.length * 8}, isLe=${isLe}, isNegative=${isNegative})`, (): void => {
expect(
u8aToBn(
new Uint8Array(numarr),
{ isLe, isNegative }
).toString()
).toBe(strval);
});
});
});
perf('u8aToBn (i32)', 750_000, [[new Uint8Array([0x9c, 0x9c, 0x9c, 0x9c])]], (v: Uint8Array) => u8aToBn(v, { isNegative: true }));
perf('u8aToBn (u32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
perf('u8aToBn (u64)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
perf('u8aToBn (u128)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
});
+101
View File
@@ -0,0 +1,101 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ToBnOptions } from '../types.js';
import { BN } from '../bn/bn.js';
/**
* @name u8aToBn
* @summary Creates a BN from a Uint8Array object.
* @description
* `UInt8Array` input values return the actual BN. `null` or `undefined` values returns an `0x0` value.
* @param value The value to convert
* @param options Options to pass while converting
* @param options.isLe Convert using Little Endian (default)
* @param options.isNegative Convert using two's complement
* @example
* <BR>
*
* ```javascript
* import { u8aToBn } from '@pezkuwi/util';
*
* u8aToHex(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0xf])); // 0x68656c0f
* ```
*/
export function u8aToBn (value: Uint8Array, { isLe = true, isNegative = false }: ToBnOptions = {}): BN {
// slice + reverse is expensive, however SCALE is LE by default so this is the path
// we are most interested in (the BE is added for the sake of being comprehensive)
if (!isLe) {
value = value.slice().reverse();
}
const count = value.length;
// shortcut for <= u48 values - in this case the manual conversion
// here seems to be more efficient than passing the full array
if (isNegative && count && (value[count - 1] & 0x80)) {
// Most common case i{8, 16, 32} default LE SCALE-encoded
// For <= 32, we also optimize the xor to a single op
switch (count) {
case 0:
return new BN(0);
case 1:
return new BN(((value[0] ^ 0x0000_00ff) * -1) - 1);
case 2:
return new BN((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
case 3:
return new BN((((value[0] + (value[1] << 8) + (value[2] << 16)) ^ 0x00ff_ffff) * -1) - 1);
case 4:
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
// 32-bit, in the case where the top-most bit is set this yields a negative value
return new BN((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
case 5:
return new BN(((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((value[4] ^ 0xff) * 0x1_00_00_00_00)) * -1) - 1);
case 6:
return new BN(((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((value[4] + (value[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00)) * -1) - 1);
default:
return new BN(value, 'le').fromTwos(count * 8);
}
}
// Most common case - u{8, 16, 32} default LE SCALE-encoded
//
// There are some slight benefits in unrolling this specific loop,
// however it comes with diminishing returns since here the actual
// `new BN` does seem to take up the bulk of the time
switch (count) {
case 0:
return new BN(0);
case 1:
return new BN(value[0]);
case 2:
return new BN(value[0] + (value[1] << 8));
case 3:
return new BN(value[0] + (value[1] << 8) + (value[2] << 16));
case 4:
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
// 32-bit, in the case where the top-most bit is set this yields a negative value
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00));
case 5:
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8)) * 0x1_00_00_00));
case 6:
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8) + (value[5] << 16)) * 0x1_00_00_00));
default:
return new BN(value, 'le');
}
}
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { u8aToBuffer } from './index.js';
describe('u8aToBuffer', (): void => {
it('returns [] when the buffer is null', (): void => {
expect(
u8aToBuffer(null)
).toEqual(Buffer.from([]));
});
it('returns the Buffer value for the Uint8Array', (): void => {
expect(
u8aToBuffer(new Uint8Array([128, 0, 10]))
).toEqual(Buffer.from([128, 0, 10]));
});
});
+28
View File
@@ -0,0 +1,28 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BufferClass, BufferObject } from '../types.js';
import { xglobal } from '@pezkuwi/x-global';
import { hasBuffer } from '../has.js';
/**
* @name u8aToBuffer
* @summary Creates a Buffer object from a hex string.
* @description
* `null` inputs returns an empty `Buffer` result. `UInt8Array` input values return the actual bytes value converted to a `Buffer`. Anything that is not a `UInt8Array` throws an error.
* @example
* <BR>
*
* ```javascript
* import { u8aToBuffer } from '@pezkuwi/util';
*
* console.log('Buffer', u8aToBuffer(new Uint8Array([1, 2, 3])));
* ```
*/
export function u8aToBuffer <T = BufferObject> (value?: Uint8Array | null): T {
return hasBuffer
? (xglobal.Buffer as unknown as BufferClass).from(value || [])
: new Uint8Array(value || []) as T;
}
+86
View File
@@ -0,0 +1,86 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { hexToU8a } from '../hex/index.js';
import { u8aToFloat } from './index.js';
describe('u8aToFloat', (): void => {
it('throws on invalid bitLength', (): void => {
expect(
() => u8aToFloat(hexToU8a('0x00000000'), { bitLength: 48 as 32 })
).toThrow();
});
it('throws on invalid input length', (): void => {
expect(
() => u8aToFloat(new Uint8Array())
).toThrow();
});
describe('32-bit', (): void => {
it('correctly decodes +0.0', (): void => {
expect(
u8aToFloat(hexToU8a('0x00000000'))
).toEqual(+0.0);
});
it('correctly decodes -0.0', (): void => {
expect(
u8aToFloat(hexToU8a('0x00000080'))
).toEqual(-0.0);
});
it('correctly decodes -0.0 (BE)', (): void => {
expect(
u8aToFloat(hexToU8a('0x80000000'), { isLe: false })
).toEqual(-0.0);
});
it('decoded NaN', (): void => {
expect(
u8aToFloat(hexToU8a('0x0000c07f'))
).toEqual(Number.NaN);
});
// https://www.h-schmidt.net/FloatConverter/IEEE754.html
it('decodes a known number', (): void => {
expect(
u8aToFloat(hexToU8a('0x79e9f642')).toFixed(3)
).toEqual('123.456');
});
it('decodes a known number (BE)', (): void => {
expect(
u8aToFloat(hexToU8a('0x42f6e979'), { isLe: false }).toFixed(3)
).toEqual('123.456');
});
});
describe('64-bit', (): void => {
it('correctly decodes +0.0', (): void => {
expect(
u8aToFloat(hexToU8a('0x0000000000000000'), { bitLength: 64 })
).toEqual(+0.0);
});
it('correctly decodes -0.0', (): void => {
expect(
u8aToFloat(hexToU8a('0x0000000000000080'), { bitLength: 64 })
).toEqual(-0.0);
});
it('correctly decodes -0.0 (BE)', (): void => {
expect(
u8aToFloat(hexToU8a('0x8000000000000000'), { bitLength: 64, isLe: false })
).toEqual(-0.0);
});
it('correctly decodes NaN', (): void => {
expect(
u8aToFloat(hexToU8a('0x000000000000f87f'), { bitLength: 64 })
).toEqual(Number.NaN);
});
});
});
+26
View File
@@ -0,0 +1,26 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
interface Options {
bitLength?: 32 | 64;
isLe?: boolean;
}
/**
* @name u8aToFloat
* @description Converts a Uint8Array value into the float (either 32 or 64-bit)
* representation.
*/
export function u8aToFloat (value: Uint8Array, { bitLength = 32, isLe = true }: Options = {}): number {
if (bitLength !== 32 && bitLength !== 64) {
throw new Error('Invalid bitLength provided, expected 32 or 64');
} else if (value.length < (bitLength / 8)) {
throw new Error(`Invalid input buffer provided, expected at least ${bitLength / 8} bytes, found ${value.length}`);
}
const dv = new DataView(value.buffer, value.byteOffset);
return bitLength === 32
? dv.getFloat32(0, isLe)
: dv.getFloat64(0, isLe);
}
+94
View File
@@ -0,0 +1,94 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { perfCmp } from '../test/index.js';
import { u8aToHex } from './index.js';
import { u8aToHex as u8aToHexBuffer } from './toHexBuffer.js';
const ptest32k = new Uint8Array(32768);
const ptest256 = new Uint8Array(256);
for (let i = 0, count = ptest32k.length; i < count; i++) {
if (i < ptest256.length) {
ptest256[1] = i % 256;
}
ptest32k[i] = i % 256;
}
describe('u8aToHex', (): void => {
it('returns empty as 0x', (): void => {
expect(
u8aToHex()
).toEqual('0x');
});
it('returns empty as "" (unprefixed)', (): void => {
expect(
u8aToHex(null, -1, false)
).toEqual('');
});
it('returns the hex value for the array', (): void => {
expect(
u8aToHex(
new Uint8Array([128, 0, 10])
)
).toEqual('0x80000a');
});
it('returns the hex value for the array (unprefixed)', (): void => {
expect(
u8aToHex(
new Uint8Array([128, 0, 10]),
-1,
false
)
).toEqual('80000a');
});
it('handles starting zeros correctly', (): void => {
expect(
u8aToHex(
new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0])
)
).toEqual('0x0001000000000000');
});
it('returns the hex value where allowed < max', (): void => {
expect(
u8aToHex(
new Uint8Array(Uint8Array.from([128, 0, 10, 11]), 64)
)
).toEqual('0x80000a0b');
});
it('returns the trimmed hex value where allowed >= max', (): void => {
expect(
u8aToHex(
new Uint8Array([128, 0, 10, 11, 12, 13]),
32
)
).toEqual('0x8000…0c0d');
});
it('converts known bytes to their correct values', (): void => {
expect(
// hello world
u8aToHex(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64]))
).toEqual('0x68656c6c6f20776f726c64');
});
perfCmp('u8aToHex (32k)', ['u8aToHexBuffer', 'u8aToHex'], 1000, [[ptest32k]], (s: Uint8Array, isSecond) =>
isSecond
? u8aToHex(s)
: u8aToHexBuffer(s)
);
perfCmp('u8aToHex (128)', ['u8aToHexBuffer', 'u8aToHex'], 200_000, [[ptest256]], (s: Uint8Array, isSecond) =>
isSecond
? u8aToHex(s)
: u8aToHexBuffer(s)
);
});
+68
View File
@@ -0,0 +1,68 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { HexString } from '../types.js';
const U8 = new Array<string>(256);
const U16 = new Array<string>(256 * 256);
for (let n = 0; n < 256; n++) {
U8[n] = n.toString(16).padStart(2, '0');
}
for (let i = 0; i < 256; i++) {
const s = i << 8;
for (let j = 0; j < 256; j++) {
U16[s | j] = U8[i] + U8[j];
}
}
/** @internal */
function hex (value: Uint8Array, result: HexString): HexString {
const mod = (value.length % 2) | 0;
const length = (value.length - mod) | 0;
for (let i = 0; i < length; i += 2) {
result += U16[(value[i] << 8) | value[i + 1]];
}
if (mod) {
result += U8[value[length] | 0];
}
return result;
}
/**
* @name u8aToHex
* @summary Creates a hex string from a Uint8Array object.
* @description
* `UInt8Array` input values return the actual hex string. `null` or `undefined` values returns an `0x` string.
* @example
* <BR>
*
* ```javascript
* import { u8aToHex } from '@pezkuwi/util';
*
* u8aToHex(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0xf])); // 0x68656c0f
* ```
*/
export function u8aToHex (value?: Uint8Array | null, bitLength = -1, isPrefixed = true): HexString {
// this is not 100% correct sinmce we support isPrefixed = false....
const empty = isPrefixed
? '0x'
: '' as HexString;
if (!value?.length) {
return empty;
} else if (bitLength > 0) {
const length = Math.ceil(bitLength / 8);
if (value.length > length) {
return `${hex(value.subarray(0, length / 2), empty)}${hex(value.subarray(value.length - length / 2), '' as HexString)}`;
}
}
return hex(value, empty);
}
+63
View File
@@ -0,0 +1,63 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { u8aToHex } from './toHexBuffer.js';
describe('u8aToHex', (): void => {
it('returns empty as 0x', (): void => {
expect(
u8aToHex()
).toEqual('0x');
});
it('returns empty as "" (unprefixed)', (): void => {
expect(
u8aToHex(null, -1, false)
).toEqual('');
});
it('returns the hex value for the array', (): void => {
expect(
u8aToHex(
new Uint8Array([128, 0, 10])
)
).toEqual('0x80000a');
});
it('returns the hex value for the array (unprefixed)', (): void => {
expect(
u8aToHex(
new Uint8Array([128, 0, 10]),
-1,
false
)
).toEqual('80000a');
});
it('handles starting zeros correctly', (): void => {
expect(
u8aToHex(
new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0])
)
).toEqual('0x0001000000000000');
});
it('returns the hex value where allowed < max', (): void => {
expect(
u8aToHex(
new Uint8Array(Uint8Array.from([128, 0, 10, 11]), 64)
)
).toEqual('0x80000a0b');
});
it('returns the trimmed hex value where allowed >= max', (): void => {
expect(
u8aToHex(
new Uint8Array([128, 0, 10, 11, 12, 13]),
32
)
).toEqual('0x8000…0c0d');
});
});
+30
View File
@@ -0,0 +1,30 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { HexString } from '../types.js';
/**
* @name u8aToHex
* @summary Creates a hex string from a Uint8Array object.
* @description
* `UInt8Array` input values return the actual hex string. `null` or `undefined` values returns an `0x` string.
* @example
* <BR>
*
* ```javascript
* import { u8aToHex } from '@pezkuwi/util';
*
* u8aToHex(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0xf])); // 0x68656c0f
* ```
*/
export function u8aToHex (value?: Uint8Array | null, bitLength = -1, isPrefixed = true): HexString {
const length = Math.ceil(bitLength / 8);
return `${isPrefixed ? '0x' : ''}${
!value?.length
? ''
: (bitLength > 0 && value.length > length)
? `${Buffer.from(value.subarray(0, length / 2)).toString('hex')}${Buffer.from(value.subarray(value.length - length / 2)).toString('hex')}`
: Buffer.from(value).toString('hex')
}` as HexString;
}
+47
View File
@@ -0,0 +1,47 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { TESTS } from '../bi/toU8a.spec.js';
import { perf } from '../test/index.js';
import { u8aToNumber } from './index.js';
const TESTS_NUM = TESTS.filter(([,, numarr]) => numarr.length <= 6);
describe('u8aToNumber', (): void => {
describe('empty creation', (): void => {
it('handles unsigned (le)', (): void => {
expect(
u8aToNumber(
new Uint8Array()
)
).toBe(0);
});
it('handles signed (le)', (): void => {
expect(
u8aToNumber(
new Uint8Array(),
{ isNegative: true }
)
).toBe(0);
});
});
describe('conversion tests', (): void => {
TESTS_NUM.forEach(([isLe, isNegative, numarr, strval], i): void => {
it(`#${i}: creates ${strval} (bitLength=${numarr.length * 8}, isLe=${isLe}, isNegative=${isNegative})`, (): void => {
expect(
u8aToNumber(
new Uint8Array(numarr),
{ isLe, isNegative }
).toString()
).toBe(strval);
});
});
});
perf('u8aToNumber (i32)', 750_000, [[new Uint8Array([0x9c, 0x9c, 0x9c, 0x9c])]], (v: Uint8Array) => u8aToNumber(v, { isNegative: true }));
perf('u8aToNumber (u32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToNumber);
});
+80
View File
@@ -0,0 +1,80 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ToBnOptions } from '../types.js';
/**
* @name u8aToNumber
* @summary Creates a number from a Uint8Array object.
*/
export function u8aToNumber (value: Uint8Array, { isLe = true, isNegative = false }: ToBnOptions = {}): number {
// slice + reverse is expensive, however SCALE is LE by default so this is the path
// we are most interested in (the BE is added for the sake of being comprehensive)
if (!isLe) {
value = value.slice().reverse();
}
const count = value.length;
// When the value is a i{8, 16, 24, 32, 40, 40} values and the top-most bit
// indicates a signed value, we use a two's complement conversion. If one of these
// flags are not set, we just do a normal unsigned conversion (the same shortcut
// applies in both the u8aTo{BigInt, Bn} conversions as well)
if (isNegative && count && (value[count - 1] & 0x80)) {
switch (count) {
case 0:
return 0;
case 1:
return (((value[0] ^ 0x0000_00ff) * -1) - 1);
case 2:
return ((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
case 3:
return ((((value[0] + (value[1] << 8) + (value[2] << 16)) ^ 0x00ff_ffff) * -1) - 1);
case 4:
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
// 32-bit, in the case where the top-most bit is set this yields a negative value
return ((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
case 5:
return (((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((value[4] ^ 0xff) * 0x1_00_00_00_00)) * -1) - 1);
case 6:
return (((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((value[4] + (value[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00)) * -1) - 1);
default:
throw new Error('Value more than 48-bits cannot be reliably converted');
}
}
switch (count) {
case 0:
return 0;
case 1:
return value[0];
case 2:
return value[0] + (value[1] << 8);
case 3:
return value[0] + (value[1] << 8) + (value[2] << 16);
case 4:
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
// 32-bit, in the case where the top-most bit is set this yields a negative value
return value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00);
case 5:
return value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8)) * 0x1_00_00_00);
case 6:
return value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8) + (value[5] << 16)) * 0x1_00_00_00);
default:
throw new Error('Value more than 48-bits cannot be reliably converted');
}
}
+36
View File
@@ -0,0 +1,36 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { u8aToString } from './index.js';
describe('u8aToString', (): void => {
it('decodes to an empty string for undefined', (): void => {
expect(
u8aToString()
).toEqual('');
});
it('decodes to an empty string for empty buffer', (): void => {
expect(
u8aToString(new Uint8Array())
).toEqual('');
});
it('decodes the Uint8Array correctly (ru)', (): void => {
expect(
u8aToString(
new Uint8Array([208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130, 44, 32, 208, 188, 208, 184, 209, 128, 33])
)
).toEqual('Привет, мир!');
});
it('decodes the Uint8Array correctly (en)', (): void => {
expect(
u8aToString(
new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64])
)
).toEqual('hello world');
});
});
+26
View File
@@ -0,0 +1,26 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { TextDecoder } from '@pezkuwi/x-textdecoder';
const decoder = new TextDecoder('utf-8');
/**
* @name u8aToString
* @summary Creates a utf-8 string from a Uint8Array object.
* @description
* `UInt8Array` input values return the actual decoded utf-8 string. `null` or `undefined` values returns an empty string.
* @example
* <BR>
*
* ```javascript
* import { u8aToString } from '@pezkuwi/util';
*
* u8aToString(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f])); // hello
* ```
*/
export function u8aToString (value?: Uint8Array | null): string {
return value
? decoder.decode(value)
: '';
}
+63
View File
@@ -0,0 +1,63 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import type { U8aLike } from '../types.js';
import { perf } from '../test/index.js';
import { u8aToU8a } from './index.js';
const TESTS: [input: U8aLike | null | undefined, output: Uint8Array][] = [
['0x80000a', new Uint8Array([128, 0, 10])],
['abcde fghij', new Uint8Array([97, 98, 99, 100, 101, 32, 102, 103, 104, 105, 106])],
[[128, 0, 10, 11, 12], new Uint8Array([128, 0, 10, 11, 12])],
[Buffer.from([1, 2, 3, 128, 0, 10, 11, 12]), new Uint8Array([1, 2, 3, 128, 0, 10, 11, 12])],
[Buffer.from('80000a', 'hex'), new Uint8Array([128, 0, 10])],
// this is where completely invalid data is being passed
[123 as unknown as Uint8Array, new Uint8Array([49, 50, 51])]
];
describe('u8aToU8a', (): void => {
it('returns an empty Uint8Array when null/undefined/"" provided', (): void => {
expect(u8aToU8a(null)).toHaveLength(0);
expect(
u8aToU8a()
).toHaveLength(0);
expect(
u8aToU8a('')
).toHaveLength(0);
expect(
u8aToU8a('')
).toEqual(new Uint8Array());
});
it('Throw error on null/undefined values on strict checking', () => {
expect(() => u8aToU8a(undefined, true)).toThrow('u8aToU8a: Expected non-null, non-undefined value');
expect(() => u8aToU8a(null, true)).toThrow('u8aToU8a: Expected non-null, non-undefined value');
});
it('returns a Uint8Array as-is (u8a input)', (): void => {
const input = new Uint8Array([128, 0, 10]);
expect(
u8aToU8a(input)
).toEqual(input);
});
describe('conversion tests', (): void => {
TESTS.forEach(([input, output], i): void => {
it(`#${i}: converts ${input as string} (typeof=${typeof input})`, (): void => {
expect(
u8aToU8a(input)
).toEqual(
output
);
});
});
});
perf('u8aToU8a (hex)', 250_000, [['0x1234']], u8aToU8a);
perf('u8aToU8a (str)', 250_000, [['test']], u8aToU8a);
perf('u8aToU8a (u8a)', 1_000_000, [[new Uint8Array()]], u8aToU8a);
});
+46
View File
@@ -0,0 +1,46 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { U8aLike } from '../types.js';
import { hexToU8a } from '../hex/toU8a.js';
import { isBuffer } from '../is/buffer.js';
import { isHex } from '../is/hex.js';
import { isU8a } from '../is/u8a.js';
import { stringToU8a } from '../string/toU8a.js';
/**
* @name u8aToU8a
* @summary Creates a Uint8Array value from a Uint8Array, Buffer, string or hex input.
* @description
* `null` or `undefined` inputs returns a `[]` result, Uint8Array values returns the value, hex strings returns a Uint8Array representation.
* If `strict` is true, `null` or `undefined` will throw an error instead of returning an empty array.
* Supports input types: Uint8Array, Buffer, hex string, string, or number array.
* @example
* <BR>
*
* ```javascript
* import { u8aToU8a } from '@pezkuwi/util';
*
* u8aToU8a(new Uint8Array([0x12, 0x34]); // => Uint8Array([0x12, 0x34])
* u8aToU8a(0x1234); // => Uint8Array([0x12, 0x34])
* ```
*/
export function u8aToU8a (value?: U8aLike | null, strict = false): Uint8Array {
if (strict && (value === null || value === undefined)) {
throw new Error('u8aToU8a: Expected non-null, non-undefined value');
}
return isU8a(value)
// NOTE isBuffer needs to go here since it actually extends
// Uint8Array on Node.js environments, so all Buffer are Uint8Array,
// but Uint8Array is not Buffer
? isBuffer(value)
? new Uint8Array(value)
: value
: isHex(value)
? hexToU8a(value)
: Array.isArray(value)
? new Uint8Array(value)
: stringToU8a(value);
}
+139
View File
@@ -0,0 +1,139 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
// Originally from https://github.com/polkadot-js/extension/pull/743
import { u8aConcat, u8aEq, u8aToString } from '@pezkuwi/util';
import { U8A_WRAP_ETHEREUM, U8A_WRAP_POSTFIX, U8A_WRAP_PREFIX, u8aUnwrapBytes, u8aWrapBytes } from './wrap.js';
const TEST_DATA = 'this is just some random message that we expect to be wrapped along the way';
const TEST_ETH = u8aConcat(U8A_WRAP_ETHEREUM, TEST_DATA);
const TEST_WRAP_EMPTY = `${u8aToString(U8A_WRAP_PREFIX)}${u8aToString(U8A_WRAP_POSTFIX)}`;
const TEST_WRAP_FULL = `${u8aToString(U8A_WRAP_PREFIX)}${TEST_DATA}${u8aToString(U8A_WRAP_POSTFIX)}`;
const TEST_WARP_HALF_PRE = `${u8aToString(U8A_WRAP_PREFIX)}${TEST_DATA}`;
const TEST_WRAP_HALF_POST = `${TEST_DATA}${u8aToString(U8A_WRAP_POSTFIX)}`;
describe('u8aWrapBytes', (): void => {
it('wraps empty bytes', (): void => {
expect(
u8aEq(
u8aWrapBytes(new Uint8Array()),
u8aConcat(U8A_WRAP_PREFIX, U8A_WRAP_POSTFIX)
)
).toBe(true);
});
it('wraps when no wrapping is detected', (): void => {
expect(
u8aToString(
u8aWrapBytes(TEST_DATA)
)
).toEqual(TEST_WRAP_FULL);
});
it('wraps when only start wrap is detected', (): void => {
expect(
u8aToString(
u8aWrapBytes(TEST_WARP_HALF_PRE)
)
).toEqual(`${u8aToString(U8A_WRAP_PREFIX)}${TEST_WARP_HALF_PRE}${u8aToString(U8A_WRAP_POSTFIX)}`);
});
it('wraps when only end wrap is detected', (): void => {
expect(
u8aToString(
u8aWrapBytes(TEST_WRAP_HALF_POST)
)
).toEqual(`${u8aToString(U8A_WRAP_PREFIX)}${TEST_WRAP_HALF_POST}${u8aToString(U8A_WRAP_POSTFIX)}`);
});
it('does not re-wrap when a wrap is already present', (): void => {
expect(
u8aToString(
u8aWrapBytes(TEST_WRAP_FULL)
)
).toEqual(TEST_WRAP_FULL);
});
it('does not re-wrap when a wrap (empty data) is already present', (): void => {
expect(
u8aToString(
u8aWrapBytes(TEST_WRAP_EMPTY)
)
).toEqual(TEST_WRAP_EMPTY);
});
});
describe('unwrapBytes', (): void => {
it('unwraps empty bytes', (): void => {
expect(
u8aEq(
u8aUnwrapBytes(new Uint8Array()),
new Uint8Array()
)
).toBe(true);
});
it('unwraps when no wrapping is detected', (): void => {
expect(
u8aToString(
u8aUnwrapBytes(TEST_DATA)
)
).toEqual(TEST_DATA);
});
it('unwraps when no wrapping is detected (only start)', (): void => {
expect(
u8aToString(
u8aUnwrapBytes(TEST_WARP_HALF_PRE)
)
).toEqual(TEST_WARP_HALF_PRE);
});
it('unwraps when no wrapping is detected (only end)', (): void => {
expect(
u8aToString(
u8aUnwrapBytes(TEST_WRAP_HALF_POST)
)
).toEqual(TEST_WRAP_HALF_POST);
});
it('unwraps when a wrap is present', (): void => {
expect(
u8aToString(
u8aUnwrapBytes(TEST_WRAP_FULL)
)
).toEqual(TEST_DATA);
});
it('unwraps when a an empty wrap is present', (): void => {
expect(
u8aToString(
u8aUnwrapBytes(TEST_WRAP_EMPTY)
)
).toEqual('');
});
describe('Ethereum-style', (): void => {
it('does not wrap an Ethereum wrap', (): void => {
expect(
u8aEq(
u8aWrapBytes(TEST_ETH),
TEST_ETH
)
).toBe(true);
});
it('does not unwrap an Ethereum wrap', (): void => {
expect(
u8aEq(
u8aUnwrapBytes(TEST_ETH),
TEST_ETH
)
).toBe(true);
});
});
});
+65
View File
@@ -0,0 +1,65 @@
// Copyright 2017-2025 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
// Originally from https://github.com/polkadot-js/extension/pull/743
import type { U8aLike } from '../types.js';
import { u8aConcatStrict } from './concat.js';
import { u8aEq } from './eq.js';
import { u8aToU8a } from './toU8a.js';
/** @internal */
export const U8A_WRAP_ETHEREUM = /*#__PURE__*/ u8aToU8a('\x19Ethereum Signed Message:\n');
/** @internal */
export const U8A_WRAP_PREFIX = /*#__PURE__*/ u8aToU8a('<Bytes>');
/** @internal */
export const U8A_WRAP_POSTFIX = /*#__PURE__*/ u8aToU8a('</Bytes>');
const WRAP_LEN = U8A_WRAP_PREFIX.length + U8A_WRAP_POSTFIX.length;
/** @internal */
export function u8aIsWrapped (u8a: Uint8Array, withEthereum: boolean): boolean {
return (
(
u8a.length >= WRAP_LEN &&
u8aEq(u8a.subarray(0, U8A_WRAP_PREFIX.length), U8A_WRAP_PREFIX) &&
u8aEq(u8a.slice(-U8A_WRAP_POSTFIX.length), U8A_WRAP_POSTFIX)
) ||
(
withEthereum &&
u8a.length >= U8A_WRAP_ETHEREUM.length &&
u8aEq(u8a.subarray(0, U8A_WRAP_ETHEREUM.length), U8A_WRAP_ETHEREUM)
)
);
}
/**
* @name u8aUnwrapBytes
* @description Removes all <Bytes>...</Bytes> wrappers from the supplied value
*/
export function u8aUnwrapBytes (bytes: U8aLike): Uint8Array {
const u8a = u8aToU8a(bytes);
// we don't want to unwrap Ethereum-style wraps
return u8aIsWrapped(u8a, false)
? u8a.subarray(U8A_WRAP_PREFIX.length, u8a.length - U8A_WRAP_POSTFIX.length)
: u8a;
}
/**
* @name u8aWrapBytes
* @description
* Adds a <Bytes>...</Bytes> wrapper to the supplied value, if
* - We don't already have a Bytes wrapper
* - The message is not an Ethereum-style message
*/
export function u8aWrapBytes (bytes: U8aLike): Uint8Array {
const u8a = u8aToU8a(bytes);
return u8aIsWrapped(u8a, true)
? u8a
: u8aConcatStrict([U8A_WRAP_PREFIX, u8a, U8A_WRAP_POSTFIX]);
}