Additional bigint utilities (#1194)
* Additional bigint utilities
* Adjust tests
* biTo{Hex, U8a}
* Adjust
* Ordering
* biSqrt
* Fix toU8a
* Extensible BigInt
* Class TS issues....
* Move type def to types
* Update packages/util/src/bi/sqrt.spec.ts
* max/min
* min/max tests
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { isBigInt } from '../is';
|
||||
import { BigIntClass } from '.';
|
||||
|
||||
describe('BigIntClass', (): void => {
|
||||
it('has the correct valueOf', (): void => {
|
||||
expect(
|
||||
typeof new BigIntClass(0).valueOf()
|
||||
).toEqual('bigint');
|
||||
});
|
||||
|
||||
it('has the correct instanceof', (): void => {
|
||||
expect(
|
||||
isBigInt(new BigIntClass(0))
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('has a top-level toString method', (): void => {
|
||||
const test = new BigIntClass(16);
|
||||
|
||||
expect(test.toString()).toEqual('16');
|
||||
expect(test.toString(16)).toEqual('10');
|
||||
});
|
||||
|
||||
it('cane be added together', (): void => {
|
||||
expect(new BigIntClass(16) + new BigIntClass(10)).toEqual(26n);
|
||||
});
|
||||
|
||||
it('has the correct type for inherited', (): void => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
class Test extends BigIntClass implements BigInt {
|
||||
}
|
||||
|
||||
expect(isBigInt(new Test(0x16))).toEqual(true);
|
||||
});
|
||||
|
||||
it('inhertited class has own methods', (): void => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
class Test extends BigIntClass {
|
||||
toHex (): string {
|
||||
return `0x${(this as unknown as bigint).toString(16)}`;
|
||||
}
|
||||
}
|
||||
|
||||
expect(new Test(0x16).toHex()).toEqual('0x16');
|
||||
});
|
||||
|
||||
it('inhertited class still acts like bigint', (): void => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
class Test extends BigIntClass {
|
||||
// nothing
|
||||
}
|
||||
|
||||
const test = new Test(0x16n);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
expect(test.toString(16)).toEqual('16');
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
expect(test * 2n).toEqual(44n);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { IBigIntConstructor } from '../types';
|
||||
|
||||
// See https://stackoverflow.com/questions/58207487/extend-object-wrappers-for-modern-primitives
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
export class BigIntImpl extends BigInt implements BigInt {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
constructor (value: string | number | bigint | boolean): bigint {
|
||||
const self = Object(BigInt(value)) as bigint;
|
||||
|
||||
Object.setPrototypeOf(self, new.target.prototype);
|
||||
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
export const BigIntClass = BigIntImpl as IBigIntConstructor;
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* @name BI_MILLION
|
||||
* @summary BigInt constant for 1,000,000.
|
||||
*/
|
||||
export const BI_MILLION = BigInt(1_000_000);
|
||||
|
||||
/**
|
||||
* @name BI_BILLION
|
||||
* @summary BigInt constant for 1,000,000,000.
|
||||
*/
|
||||
export const BI_BILLION = BigInt(1_000_000_000);
|
||||
|
||||
/**
|
||||
* @name BI_QUINTILL
|
||||
* @summary BigInt constant for 1,000,000,000,000,000,000.
|
||||
*/
|
||||
export const BI_QUINTILL = BI_BILLION * BI_BILLION;
|
||||
|
||||
/**
|
||||
* @name BI_MAX_INTEGER
|
||||
* @summary BigInt constant for MAX_SAFE_INTEGER
|
||||
*/
|
||||
export const BI_MAX_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* @summary Utility methods to convert to and from `bigint` objects
|
||||
*/
|
||||
|
||||
export * from './consts';
|
||||
|
||||
export { BigIntClass } from './class';
|
||||
export { biSqrt } from './sqrt';
|
||||
export { biToBigInt } from './toBigInt';
|
||||
export { biMax } from './max';
|
||||
export { biMin } from './min';
|
||||
export { biToHex } from './toHex';
|
||||
export { biToU8a } from './toU8a';
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { biMax } from '.';
|
||||
|
||||
describe('biMax', (): void => {
|
||||
it('finds maximum', (): void => {
|
||||
expect(
|
||||
biMax(1n, 2n, 3n)
|
||||
).toEqual(3n);
|
||||
});
|
||||
|
||||
it('finds maximum', (): void => {
|
||||
expect(
|
||||
biMax(2n, 3n, 1n)
|
||||
).toEqual(3n);
|
||||
});
|
||||
|
||||
it('returns a single item', (): void => {
|
||||
expect(
|
||||
biMax(1n)
|
||||
).toEqual(1n);
|
||||
});
|
||||
|
||||
it('fails when no items are available', (): void => {
|
||||
expect(
|
||||
() => biMax()
|
||||
).toThrow(/Must provide one or more bigint arguments/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { assert } from '../assert';
|
||||
|
||||
/**
|
||||
* @name biMax
|
||||
* @summary Finds and returns the highest value in an array of bigint.
|
||||
*/
|
||||
export function biMax (...items: bigint[]): bigint {
|
||||
assert(items.length >= 1, 'Must provide one or more bigint arguments');
|
||||
|
||||
let result = items[0];
|
||||
|
||||
for (let i = 1; i < items.length; i++) {
|
||||
if (items[i] > result) {
|
||||
result = items[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { biMin } from '.';
|
||||
|
||||
describe('biMin', (): void => {
|
||||
it('finds BN minimum', (): void => {
|
||||
expect(
|
||||
biMin(2n, 1n, 3n)
|
||||
).toEqual(1n);
|
||||
});
|
||||
|
||||
it('returns a single item', (): void => {
|
||||
expect(
|
||||
biMin(1n)
|
||||
).toEqual(1n);
|
||||
});
|
||||
|
||||
it('fails when no items are available', (): void => {
|
||||
expect(
|
||||
() => biMin()
|
||||
).toThrow(/Must provide one or more bigint arguments/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { assert } from '../assert';
|
||||
|
||||
/**
|
||||
* @name biMin
|
||||
* @summary Finds and returns the lowest value in an array of bigint.
|
||||
*/
|
||||
export function biMin (...items: bigint[]): bigint {
|
||||
assert(items.length >= 1, 'Must provide one or more bigint arguments');
|
||||
|
||||
let result = items[0];
|
||||
|
||||
for (let i = 1; i < items.length; i++) {
|
||||
if (items[i] < result) {
|
||||
result = items[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { BN } from '../bn';
|
||||
import { biSqrt } from '.';
|
||||
|
||||
const TESTS: [string | number | BN | bigint, string | number][] = [
|
||||
[0, 0],
|
||||
[1, 1],
|
||||
[4, 2],
|
||||
[256 * 256, 256],
|
||||
[Number.MAX_SAFE_INTEGER, 94906265],
|
||||
[new BN(Number.MAX_SAFE_INTEGER).iaddn(256), 94906265],
|
||||
[12345678n * 12345679n, 12345678],
|
||||
// test cases below from https://github.com/Aisse-258/bigint-isqrt/blob/f5254b9750841959022461c1353437a07a08f501/test/sqrt-test.js
|
||||
[
|
||||
'54866395443885995655625',
|
||||
'234235768925'
|
||||
],
|
||||
[
|
||||
'82120471531550314555681345949499512621827274120673745141541602816614526075010755373654280259022317599142038423759320355177481886719814621305828811322920076213800348341464996337890625',
|
||||
'9062034624274524065844376014975805577107171799890766992670739972241112960081909332275390625'
|
||||
],
|
||||
[
|
||||
'2068290204957779940494571454815902632050207752627007664813877111611972735314294907791993008455381265730624848057015476004143868408297250386512042711005577373327434315310235583583151773358353534031397385969275475421659036494173765903706963544628565027679444680637920371210258368358706248446698622704138943704561842220533563976838506992543814273403403362954987589637283890281226038798503294069403370486523697009383229578343444337394508531937972775639593763364402389410142290440075517598007930025487176173228232153685095699851764630884360483051570513804913157899314303269924424908606245851172031453725690942288677622973423417902662711606364188470325930406288190754356367655606430407552275285889968860367977288564364154999338284288438279464648663835830140826171534470717958048887869721791862539529444820484648908879364324577951008050851801647916673254009490596379549192296404841454780884358889449367135382779230574781333008561195244620152128505091883408484094800737142399855337799331037607433934520934135669364954550499058123797911762228642423567268540444910163468496805547450495819213412636594319148417857753712526066272727725420886898680432958409892237191284583904066400736417812258327303739879128916456683685232170600928808798462776174857486589598776587550843543720784829419478239563366491666155716208452087857080883906200829769222868347286071365156305396955420561718593130305703074908891135467193627721682044757187980688062367562451981939375400543212890625',
|
||||
'45478458691536369397924851088318871329614555665525810477032568598360481742967756704524034986984134271202405190906906195123751965012732122548540879928668891416468847696038707003466943811913626146981446753434347552196868717612248915137033581428310504778371173112125038060138252719589122657221314190626986951627417768579641354255445988772645883238873672997347648890137913979299598785628581961589739331483895853398160785485300758458294999124984266041998145956341386549681176624661615465976970855592467853824812945820721933491609237311130118125761849911376495970746282571994312288380577879004620824004760109618074670810797544446334767103935754106103208789391060008291027361311679876439695844637933763721093782805837690830230712890625'
|
||||
]
|
||||
];
|
||||
|
||||
describe('biSqrt', (): void => {
|
||||
it('fails on < 0 roots', (): void => {
|
||||
expect(
|
||||
() => biSqrt(-1n)
|
||||
).toThrow(/negative numbers is not supported/);
|
||||
});
|
||||
|
||||
TESTS.forEach(([value, expected], index): void => {
|
||||
it(`calcs for test #${index}`, (): void => {
|
||||
expect(biSqrt(value) === BigInt(expected)).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { BN } from '../bn';
|
||||
import type { ToBigInt, ToBn } from '../types';
|
||||
|
||||
import { assert } from '../assert';
|
||||
import { BI_MAX_INTEGER } from './consts';
|
||||
import { biToBigInt } from './toBigInt';
|
||||
|
||||
const SQRT_MAX_SAFE_INTEGER = 94906265n;
|
||||
|
||||
/**
|
||||
* @name biSqrt
|
||||
* @summary Calculates the integer square root of a bigint
|
||||
*/
|
||||
export function biSqrt <ExtToBn extends ToBn | ToBigInt> (value: ExtToBn | BN | bigint | string | number | null): bigint {
|
||||
const n = biToBigInt(value);
|
||||
|
||||
assert(n >= 0n, 'square root of negative numbers is not supported');
|
||||
|
||||
// https://stackoverflow.com/questions/53683995/javascript-big-integer-square-root/
|
||||
// shortcut <= 2^53 - 1 to use the JS utils
|
||||
if (n <= BI_MAX_INTEGER) {
|
||||
return BigInt(Math.floor(Math.sqrt(Number(n))));
|
||||
}
|
||||
|
||||
// Use sqrt(MAX_SAFE_INTEGER) as starting point. since we already know the
|
||||
// output will be larger than this, we expect this to be a safe start
|
||||
let x0 = SQRT_MAX_SAFE_INTEGER;
|
||||
|
||||
while (true) {
|
||||
const x1 = ((n / x0) + x0) >> 1n;
|
||||
|
||||
if (x0 === x1 || (x0 === (x1 - 1n))) {
|
||||
return x0;
|
||||
}
|
||||
|
||||
x0 = x1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { BN } from '../bn';
|
||||
import { biToBigInt } from '.';
|
||||
|
||||
describe('biToBigInt', (): void => {
|
||||
it('converts null values to 0x00', (): void => {
|
||||
expect(
|
||||
biToBigInt(null)
|
||||
).toEqual(0n);
|
||||
});
|
||||
|
||||
it('converts 0x values to 0x00', (): void => {
|
||||
expect(
|
||||
biToBigInt('0x')
|
||||
).toEqual(0n);
|
||||
});
|
||||
|
||||
it('converts BN values to bigint', (): void => {
|
||||
expect(
|
||||
biToBigInt(new BN(128))
|
||||
).toEqual(128n);
|
||||
});
|
||||
|
||||
it('converts BigInt values to bigint', (): void => {
|
||||
expect(
|
||||
biToBigInt(128821n)
|
||||
).toEqual(128821n);
|
||||
});
|
||||
|
||||
it('converts number values to bigint', (): void => {
|
||||
expect(
|
||||
biToBigInt(128)
|
||||
).toEqual(128n);
|
||||
});
|
||||
|
||||
it('converts string to bigint', (): void => {
|
||||
expect(
|
||||
biToBigInt('123')
|
||||
).toEqual(123n);
|
||||
});
|
||||
|
||||
it('converts hex to bigint', (): void => {
|
||||
expect(
|
||||
biToBigInt('0x0123')
|
||||
).toEqual(0x123n);
|
||||
});
|
||||
|
||||
it('converts Compact to bigint (via toBn)', (): void => {
|
||||
expect(
|
||||
biToBigInt({
|
||||
something: 'test',
|
||||
toBn: () => new BN(1234)
|
||||
})
|
||||
).toEqual(1234n);
|
||||
});
|
||||
|
||||
it('converts Compact to bigint (via toBigInt)', (): void => {
|
||||
expect(
|
||||
biToBigInt({
|
||||
something: 'test',
|
||||
toBigInt: () => 1234n
|
||||
})
|
||||
).toEqual(1234n);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { BN } from '../bn/bn';
|
||||
import type { HexString, ToBigInt, ToBn } from '../types';
|
||||
|
||||
import { hexToBigInt } from '../hex/toBigInt';
|
||||
import { isBn } from '../is/bn';
|
||||
import { isHex } from '../is/hex';
|
||||
import { isToBigInt } from '../is/toBigInt';
|
||||
import { isToBn } from '../is/toBn';
|
||||
|
||||
/**
|
||||
* @name biToBigInt
|
||||
* @summary Creates a bigInt value from a BN, bigint, string (base 10 or hex) or number input.
|
||||
*/
|
||||
export function biToBigInt <ExtToBn extends ToBigInt | ToBn> (value?: HexString | ExtToBn | BN | bigint | string | number | null): bigint {
|
||||
return typeof value === 'bigint'
|
||||
? value
|
||||
: !value
|
||||
? BigInt(0)
|
||||
: isHex(value)
|
||||
? hexToBigInt(value.toString())
|
||||
: isBn(value)
|
||||
? BigInt(value.toString())
|
||||
: isToBigInt(value)
|
||||
? value.toBigInt()
|
||||
: isToBn(value)
|
||||
? BigInt(value.toBn().toString())
|
||||
: BigInt(value);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { biToHex } from '.';
|
||||
|
||||
describe('biToHex', (): void => {
|
||||
it('converts null values to 0x00', (): void => {
|
||||
expect(
|
||||
biToHex(null)
|
||||
).toBe('0x00');
|
||||
});
|
||||
|
||||
it('converts values to a prefixed hex representation', (): void => {
|
||||
expect(
|
||||
biToHex(128)
|
||||
).toBe('0x80');
|
||||
});
|
||||
|
||||
it('converts values to a prefixed hex representation (bitLength)', (): void => {
|
||||
expect(
|
||||
biToHex(128n, { bitLength: 16 })
|
||||
).toBe('0x0080');
|
||||
});
|
||||
|
||||
it('converts values to a prefixed hex representation (bitLength + le)', (): void => {
|
||||
expect(
|
||||
biToHex(128, { bitLength: 16, isLe: true })
|
||||
).toBe('0x8000');
|
||||
});
|
||||
|
||||
it('converts values to a prefixed hex representation (LE)', (): void => {
|
||||
expect(
|
||||
biToHex(128, { bitLength: 16, isLe: true })
|
||||
).toBe('0x8000');
|
||||
});
|
||||
|
||||
it('handles negative numbers', (): void => {
|
||||
expect(
|
||||
biToHex(-1234, { isNegative: true })
|
||||
).toBe('0xfb2e');
|
||||
});
|
||||
|
||||
it('handles negative numbers (with bitLength)', (): void => {
|
||||
expect(
|
||||
biToHex(-1234, { bitLength: 32, isNegative: true })
|
||||
).toBe('0xfffffb2e');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { BN } from '../bn/bn';
|
||||
import type { HexString, ToBigInt, ToBn, ToBnOptions } from '../types';
|
||||
|
||||
import { objectSpread } from '../object/spread';
|
||||
import { u8aToHex } from '../u8a';
|
||||
import { biToU8a } from './toU8a';
|
||||
|
||||
interface Options extends ToBnOptions {
|
||||
bitLength?: number;
|
||||
}
|
||||
|
||||
const ZERO_STR = '0x00';
|
||||
|
||||
/**
|
||||
* @name biToHex
|
||||
* @summary Creates a hex value from a bigint object.
|
||||
*/
|
||||
export function biToHex <ExtToBn extends ToBn | ToBigInt> (value?: ExtToBn | BN | bigint | number | null, options?: Options): HexString {
|
||||
if (!value) {
|
||||
return ZERO_STR;
|
||||
}
|
||||
|
||||
return u8aToHex(
|
||||
biToU8a(value, objectSpread(
|
||||
// We spread here, the default for hex values is BE (JSONRPC via substrate)
|
||||
{ isLe: false, isNegative: false },
|
||||
options
|
||||
))
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { biToU8a } from '.';
|
||||
|
||||
describe('biToU8a', (): void => {
|
||||
it('converts null values to 0x00', (): void => {
|
||||
expect(
|
||||
biToU8a(null)
|
||||
).toEqual(new Uint8Array());
|
||||
});
|
||||
|
||||
it('converts null values to 0x00000000 (bitLength)', (): void => {
|
||||
expect(
|
||||
biToU8a(null, { bitLength: 32 })
|
||||
).toEqual(new Uint8Array([0, 0, 0, 0]));
|
||||
});
|
||||
|
||||
it('converts values to a prefixed hex representation', (): void => {
|
||||
expect(
|
||||
biToU8a(0x123456n, { isLe: false })
|
||||
).toEqual(new Uint8Array([0x12, 0x34, 0x56]));
|
||||
});
|
||||
|
||||
it('converts values to a prefixed hex representation (bitLength)', (): void => {
|
||||
expect(
|
||||
biToU8a(0x123456n, { bitLength: 32, isLe: false })
|
||||
).toEqual(new Uint8Array([0x00, 0x12, 0x34, 0x56]));
|
||||
});
|
||||
|
||||
it('converts using little endian (as set)', (): void => {
|
||||
expect(
|
||||
biToU8a(0x123456n, { bitLength: 32, isLe: true })
|
||||
).toEqual(new Uint8Array([0x56, 0x34, 0x12, 0x00]));
|
||||
});
|
||||
|
||||
it('converts negative numbers', (): void => {
|
||||
expect(
|
||||
biToU8a(-1234n, { isNegative: true })
|
||||
).toEqual(new Uint8Array([46, 251]));
|
||||
});
|
||||
|
||||
it('converts negative numbers (BE)', (): void => {
|
||||
expect(
|
||||
biToU8a(-1234n, { isLe: false, isNegative: true })
|
||||
).toEqual(new Uint8Array([251, 46]));
|
||||
});
|
||||
|
||||
it('converts negative numbers (bitLength)', (): void => {
|
||||
expect(
|
||||
biToU8a(-1234n, { bitLength: 32, isNegative: true })
|
||||
).toEqual(new Uint8Array([46, 251, 255, 255]));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { BN } from '../bn/bn';
|
||||
import type { ToBigInt, ToBn, ToBnOptions } from '../types';
|
||||
|
||||
import { objectSpread } from '../object/spread';
|
||||
import { biToBigInt } from './toBigInt';
|
||||
|
||||
interface Options extends ToBnOptions {
|
||||
bitLength?: number;
|
||||
}
|
||||
|
||||
const DIV = 256n;
|
||||
|
||||
function createEmpty ({ bitLength = 0 }: Options): Uint8Array {
|
||||
return bitLength === -1
|
||||
? new Uint8Array()
|
||||
: new Uint8Array(Math.ceil(bitLength / 8));
|
||||
}
|
||||
|
||||
function toU8a (value: bigint, { isLe, isNegative }: Options): Uint8Array {
|
||||
const arr: number[] = [];
|
||||
|
||||
if (isNegative) {
|
||||
value = (value + 1n) * -1n;
|
||||
}
|
||||
|
||||
while (value !== 0n) {
|
||||
const mod = value % DIV;
|
||||
const val = Number(
|
||||
isNegative
|
||||
? mod ^ 0xffn
|
||||
: mod
|
||||
);
|
||||
|
||||
if (isLe) {
|
||||
arr.push(val);
|
||||
} else {
|
||||
arr.unshift(val);
|
||||
}
|
||||
|
||||
value = (value - mod) / DIV;
|
||||
}
|
||||
|
||||
return Uint8Array.from(arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name biToU8a
|
||||
* @summary Creates a Uint8Array object from a bigint.
|
||||
*/
|
||||
export function biToU8a <ExtToBn extends ToBn | ToBigInt> (value?: ExtToBn | BN | bigint | number | null, options?: Options): Uint8Array {
|
||||
const opts: Options = objectSpread(
|
||||
{ bitLength: -1, isLe: true, isNegative: false },
|
||||
options
|
||||
);
|
||||
|
||||
const valueBi = biToBigInt(value);
|
||||
|
||||
if (valueBi === 0n) {
|
||||
return createEmpty(opts);
|
||||
}
|
||||
|
||||
const u8a = toU8a(valueBi, opts);
|
||||
|
||||
if (opts.bitLength === -1) {
|
||||
return u8a;
|
||||
}
|
||||
|
||||
const byteLength = Math.ceil((opts.bitLength || 0) / 8);
|
||||
const output = new Uint8Array(byteLength);
|
||||
|
||||
if (opts.isNegative) {
|
||||
output.fill(0xff);
|
||||
}
|
||||
|
||||
output.set(u8a, opts.isLe ? 0 : byteLength - u8a.length);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { HexString, ToBn } from '../types';
|
||||
import type { HexString, ToBigInt, ToBn } from '../types';
|
||||
|
||||
import { hexToBn } from '../hex/toBn';
|
||||
import { isBigInt } from '../is/bigInt';
|
||||
import { isHex } from '../is/hex';
|
||||
import { isToBigInt } from '../is/toBigInt';
|
||||
import { isToBn } from '../is/toBn';
|
||||
import { BN } from './bn';
|
||||
|
||||
@@ -25,18 +26,18 @@ import { BN } from './bn';
|
||||
* bnToBn(new BN(0x1234)); // => BN(0x1234)
|
||||
* ```
|
||||
*/
|
||||
export function bnToBn <ExtToBn extends ToBn> (value?: HexString | ExtToBn | BN | bigint | string | number | null): BN {
|
||||
if (!value) {
|
||||
return new BN(0);
|
||||
} else if (isHex(value)) {
|
||||
return hexToBn(value.toString());
|
||||
} else if (isBigInt(value)) {
|
||||
return new BN(value.toString());
|
||||
}
|
||||
|
||||
export function bnToBn <ExtToBn extends ToBigInt | ToBn> (value?: HexString | ExtToBn | BN | bigint | string | number | null): BN {
|
||||
return BN.isBN(value)
|
||||
? value
|
||||
: isToBn(value)
|
||||
? value.toBn()
|
||||
: new BN(value);
|
||||
: !value
|
||||
? new BN(0)
|
||||
: isHex(value)
|
||||
? hexToBn(value.toString())
|
||||
: isBigInt(value)
|
||||
? new BN(value.toString())
|
||||
: isToBn(value)
|
||||
? value.toBn()
|
||||
: isToBigInt(value)
|
||||
? new BN(value.toBigInt().toString())
|
||||
: new BN(value);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export { packageInfo } from './packageInfo';
|
||||
|
||||
export * from './array';
|
||||
export * from './assert';
|
||||
export * from './bi';
|
||||
export * from './bn';
|
||||
export * from './buffer';
|
||||
export * from './compact';
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
* ```
|
||||
*/
|
||||
export function isBigInt (value: unknown): value is bigint {
|
||||
return typeof value === 'bigint';
|
||||
return typeof value === 'bigint' || value instanceof BigInt;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export { isObject } from './object';
|
||||
export { isObservable } from './observable';
|
||||
export { isString } from './string';
|
||||
export { isTestChain } from './testChain';
|
||||
export { isToBigInt } from './toBigInt';
|
||||
export { isToBn } from './toBn';
|
||||
export { isU8a } from './u8a';
|
||||
export { isUndefined } from './undefined';
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { isToBigInt } from '.';
|
||||
|
||||
describe('isToBigInt', (): void => {
|
||||
it('is false on no value', (): void => {
|
||||
expect(isToBigInt()).toEqual(false);
|
||||
});
|
||||
|
||||
it('is false on non-compact value', (): void => {
|
||||
expect(isToBigInt(123)).toEqual(false);
|
||||
});
|
||||
|
||||
it('is true when compact-like signature is found', (): void => {
|
||||
expect(isToBigInt({
|
||||
toBigInt: () => BigInt(1)
|
||||
})).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright 2017-2021 @polkadot/util authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ToBigInt } from '../types';
|
||||
|
||||
import { isFunction } from './function';
|
||||
|
||||
export function isToBigInt (value?: unknown): value is ToBigInt {
|
||||
return !!value && isFunction((value as ToBigInt).toBigInt);
|
||||
}
|
||||
@@ -9,6 +9,10 @@ export interface Constructor<T = any> {
|
||||
new(...value: any[]): T;
|
||||
}
|
||||
|
||||
export interface ToBigInt {
|
||||
toBigInt: () => bigint;
|
||||
}
|
||||
|
||||
export interface ToBn {
|
||||
toBn: () => BN;
|
||||
}
|
||||
@@ -61,3 +65,23 @@ export type HexDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
|
||||
export type HexString = `0x${string}`;
|
||||
|
||||
export type U8aLike = HexString | number[] | Buffer | Uint8Array | AnyString;
|
||||
|
||||
export interface IBigIntConstructor {
|
||||
new (value: string | number | bigint | boolean): bigint;
|
||||
|
||||
/**
|
||||
* Interprets the low bits of a BigInt as a 2's-complement signed integer.
|
||||
* All higher bits are discarded.
|
||||
* @param bits The number of low bits to use
|
||||
* @param int The BigInt whose bits to extract
|
||||
*/
|
||||
asIntN (bits: number, int: bigint): bigint;
|
||||
|
||||
/**
|
||||
* Interprets the low bits of a BigInt as an unsigned integer.
|
||||
* All higher bits are discarded.
|
||||
* @param bits The number of low bits to use
|
||||
* @param int The BigInt whose bits to extract
|
||||
*/
|
||||
asUintN (bits: number, int: bigint): bigint;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import type { ToBnOptions } from '../types';
|
||||
|
||||
import { objectSpread } from '../object/spread';
|
||||
|
||||
const U8_MULT = 256n;
|
||||
const U16_MUL = U8_MULT * U8_MULT;
|
||||
const U8_MAX = 256n;
|
||||
const U16_MAX = U8_MAX * U8_MAX;
|
||||
|
||||
function xor (input: Uint8Array): Uint8Array {
|
||||
const result = new Uint8Array(input.length);
|
||||
@@ -33,11 +33,11 @@ function toBigInt (input: Uint8Array): bigint {
|
||||
let result = BigInt(0);
|
||||
|
||||
for (let i = 0; i < length; i += 2) {
|
||||
result = (result * U16_MUL) + BigInt(dvI.getUint16(i));
|
||||
result = (result * U16_MAX) + BigInt(dvI.getUint16(i));
|
||||
}
|
||||
|
||||
if (mod) {
|
||||
result = (result * U8_MULT) + BigInt(dvI.getUint8(length));
|
||||
result = (result * U8_MAX) + BigInt(dvI.getUint8(length));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user