1 | // Copyright 2017-2022 @polkadot/util authors & contributors
|
2 | // SPDX-License-Identifier: Apache-2.0
|
3 | import { BN } from "../bn/bn.js";
|
4 | import { isBoolean } from "../is/boolean.js";
|
5 | /**
|
6 | * @name u8aToBn
|
7 | * @summary Creates a BN from a Uint8Array object.
|
8 | * @description
|
9 | * `UInt8Array` input values return the actual BN. `null` or `undefined` values returns an `0x0` value.
|
10 | * @param value The value to convert
|
11 | * @param options Options to pass while converting
|
12 | * @param options.isLe Convert using Little Endian (default)
|
13 | * @param options.isNegative Convert using two's complement
|
14 | * @example
|
15 | * <BR>
|
16 | *
|
17 | * ```javascript
|
18 | * import { u8aToBn } from '@polkadot/util';
|
19 | *
|
20 | * u8aToHex(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0xf])); // 0x68656c0f
|
21 | * ```
|
22 | */
|
23 |
|
24 | /** @deprecated Use u8aToBn (value?: string | null, options?: ToBnOptions) */
|
25 | function u8aToBn(value, options = {}) {
|
26 | // NOTE: This is the same process as followed in the hexToBn conversion
|
27 | // For Uint8Array, default to LE
|
28 | const {
|
29 | isLe = true,
|
30 | isNegative = false
|
31 | } = isBoolean(options) ? {
|
32 | isLe: options
|
33 | } : options;
|
34 | const count = value.length; // shortcut for <= u48 values - in this case the manual conversion
|
35 | // here seems to be more efficient than passing the full array
|
36 |
|
37 | if (count <= 6) {
|
38 | if (isNegative) {
|
39 | let result = 0;
|
40 |
|
41 | if (isLe) {
|
42 | // Most common case i{8, 16, 32} default LE SCALE-encoded
|
43 | // For <= 32, we also optimize the xor to a single op
|
44 | // (see the comments around unrolling in the next section)
|
45 | switch (count) {
|
46 | case 0:
|
47 | return new BN(0);
|
48 |
|
49 | case 1:
|
50 | result = value[0] ^ 0x000000ff;
|
51 | break;
|
52 |
|
53 | case 2:
|
54 | result = value[0] + (value[1] << 8) ^ 0x0000ffff;
|
55 | break;
|
56 |
|
57 | case 3:
|
58 | result = value[0] + (value[1] << 8) + (value[2] << 16) ^ 0x00ffffff;
|
59 | break;
|
60 |
|
61 | case 4:
|
62 | // for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
|
63 | // 32-bit, in the case where the top-most bit is set this yields a negative value
|
64 | result = value[0] + (value[1] << 8) + (value[2] << 16) + value[3] * 0x1000000 ^ 0xffffffff;
|
65 | break;
|
66 |
|
67 | case 5:
|
68 | result = (value[0] + (value[1] << 8) + (value[2] << 16) + value[3] * 0x1000000 ^ 0xffffffff) + (value[4] ^ 0xff) * 0x100000000;
|
69 | break;
|
70 |
|
71 | default:
|
72 | // 6
|
73 | result = (value[0] + (value[1] << 8) + (value[2] << 16) + value[3] * 0x1000000 ^ 0xffffffff) + (value[4] + (value[5] << 8) ^ 0x0000ffff) * 0x100000000;
|
74 | break;
|
75 | }
|
76 | } else {
|
77 | for (let i = 0; i < count; i++) {
|
78 | result = result * 0x100 + (value[i] ^ 0xff);
|
79 | }
|
80 | }
|
81 |
|
82 | return count ? new BN(result * -1 - 1) : new BN(0);
|
83 | } else if (isLe) {
|
84 | // Most common case - u{8, 16, 32} default LE SCALE-encoded
|
85 | //
|
86 | // There are some slight benefits in unrolling this specific loop,
|
87 | // however it comes with diminishing returns since here the actual
|
88 | // `new BN` does seem to take up the bulk of the time
|
89 | switch (count) {
|
90 | case 0:
|
91 | return new BN(0);
|
92 |
|
93 | case 1:
|
94 | return new BN(value[0]);
|
95 |
|
96 | case 2:
|
97 | return new BN(value[0] + (value[1] << 8));
|
98 |
|
99 | case 3:
|
100 | return new BN(value[0] + (value[1] << 8) + (value[2] << 16));
|
101 |
|
102 | case 4:
|
103 | // for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
|
104 | // 32-bit, in the case where the top-most bit is set this yields a negative value
|
105 | return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + value[3] * 0x1000000);
|
106 |
|
107 | case 5:
|
108 | return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] + (value[4] << 8)) * 0x1000000);
|
109 |
|
110 | default:
|
111 | // 6
|
112 | return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] + (value[4] << 8) + (value[5] << 16)) * 0x1000000);
|
113 | }
|
114 | } else {
|
115 | let result = 0;
|
116 |
|
117 | for (let i = 0; i < count; i++) {
|
118 | result = result * 0x100 + value[i];
|
119 | }
|
120 |
|
121 | return new BN(result);
|
122 | }
|
123 | }
|
124 |
|
125 | return isNegative ? new BN(value, isLe ? 'le' : 'be').fromTwos(value.length * 8) : new BN(value, isLe ? 'le' : 'be');
|
126 | }
|
127 |
|
128 | export { u8aToBn }; |
\ | No newline at end of file |