Adjust BE u8aTo{Bn, BigInt, Number} check (#1868)

* Adjust BE u8aTo{Bn, BigInt, Numer} check

* Adjust function names (liberal find-and-replace)
This commit is contained in:
Jaco
2023-08-22 20:50:50 +03:00
committed by GitHub
parent 3dce4fe04a
commit cf9082e03a
3 changed files with 54 additions and 51 deletions
+16 -15
View File
@@ -18,27 +18,28 @@ const U64_MAX = BigInt('0x10000000000000000');
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)
const u8a = isLe
? value
: value.slice().reverse();
const count = u8a.length;
if (!isLe) {
value = value.slice().reverse();
}
if (isNegative && count && (u8a[count - 1] & 0x80)) {
const count = value.length;
if (isNegative && count && (value[count - 1] & 0x80)) {
switch (count) {
case 0:
return BigInt(0);
case 1:
return BigInt(((u8a[0] ^ 0x0000_00ff) * -1) - 1);
return BigInt(((value[0] ^ 0x0000_00ff) * -1) - 1);
case 2:
return BigInt((((u8a[0] + (u8a[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
return BigInt((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
case 4:
return BigInt((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
return BigInt((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
}
const dvI = new DataView(u8a.buffer, u8a.byteOffset);
const dvI = new DataView(value.buffer, value.byteOffset);
if (count === 8) {
return dvI.getBigInt64(0, true);
@@ -52,7 +53,7 @@ export function u8aToBigInt (value: Uint8Array, { isLe = true, isNegative = fals
}
if (mod) {
result = (result * U8_MAX) + BigInt(u8a[0] ^ 0xff);
result = (result * U8_MAX) + BigInt(value[0] ^ 0xff);
}
return (result * -_1n) - _1n;
@@ -63,16 +64,16 @@ export function u8aToBigInt (value: Uint8Array, { isLe = true, isNegative = fals
return BigInt(0);
case 1:
return BigInt(u8a[0]);
return BigInt(value[0]);
case 2:
return BigInt(u8a[0] + (u8a[1] << 8));
return BigInt(value[0] + (value[1] << 8));
case 4:
return BigInt(u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00));
return BigInt(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00));
}
const dvI = new DataView(u8a.buffer, u8a.byteOffset);
const dvI = new DataView(value.buffer, value.byteOffset);
switch (count) {
case 8:
@@ -90,7 +91,7 @@ export function u8aToBigInt (value: Uint8Array, { isLe = true, isNegative = fals
}
if (mod) {
result = (result * U8_MAX) + BigInt(u8a[0]);
result = (result * U8_MAX) + BigInt(value[0]);
}
return result;
+20 -19
View File
@@ -26,14 +26,15 @@ import { BN } from '../bn/bn.js';
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)
const u8a = isLe
? value
: value.slice().reverse();
const count = u8a.length;
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 && (u8a[count - 1] & 0x80)) {
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) {
@@ -41,27 +42,27 @@ export function u8aToBn (value: Uint8Array, { isLe = true, isNegative = false }:
return new BN(0);
case 1:
return new BN(((u8a[0] ^ 0x0000_00ff) * -1) - 1);
return new BN(((value[0] ^ 0x0000_00ff) * -1) - 1);
case 2:
return new BN((((u8a[0] + (u8a[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
return new BN((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
case 3:
return new BN((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16)) ^ 0x00ff_ffff) * -1) - 1);
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((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
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(((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((u8a[4] ^ 0xff) * 0x1_00_00_00_00)) * -1) - 1);
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(((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((u8a[4] + (u8a[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00)) * -1) - 1);
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(u8a, 'le').fromTwos(count * 8);
return new BN(value, 'le').fromTwos(count * 8);
}
}
@@ -75,26 +76,26 @@ export function u8aToBn (value: Uint8Array, { isLe = true, isNegative = false }:
return new BN(0);
case 1:
return new BN(u8a[0]);
return new BN(value[0]);
case 2:
return new BN(u8a[0] + (u8a[1] << 8));
return new BN(value[0] + (value[1] << 8));
case 3:
return new BN(u8a[0] + (u8a[1] << 8) + (u8a[2] << 16));
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(u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00));
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00));
case 5:
return new BN(u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + ((u8a[3] + (u8a[4] << 8)) * 0x1_00_00_00));
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(u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + ((u8a[3] + (u8a[4] << 8) + (u8a[5] << 16)) * 0x1_00_00_00));
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(u8a, 'le');
return new BN(value, 'le');
}
}
+18 -17
View File
@@ -10,39 +10,40 @@ import type { ToBnOptions } from '../types.js';
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)
const u8a = isLe
? value
: value.slice().reverse();
const count = u8a.length;
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 && (u8a[count - 1] & 0x80)) {
if (isNegative && count && (value[count - 1] & 0x80)) {
switch (count) {
case 0:
return 0;
case 1:
return (((u8a[0] ^ 0x0000_00ff) * -1) - 1);
return (((value[0] ^ 0x0000_00ff) * -1) - 1);
case 2:
return ((((u8a[0] + (u8a[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
return ((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
case 3:
return ((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16)) ^ 0x00ff_ffff) * -1) - 1);
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 ((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
return ((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
case 5:
return (((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((u8a[4] ^ 0xff) * 0x1_00_00_00_00)) * -1) - 1);
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 (((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((u8a[4] + (u8a[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00)) * -1) - 1);
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');
@@ -54,24 +55,24 @@ export function u8aToNumber (value: Uint8Array, { isLe = true, isNegative = fals
return 0;
case 1:
return u8a[0];
return value[0];
case 2:
return u8a[0] + (u8a[1] << 8);
return value[0] + (value[1] << 8);
case 3:
return u8a[0] + (u8a[1] << 8) + (u8a[2] << 16);
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 u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00);
return value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00);
case 5:
return u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + ((u8a[3] + (u8a[4] << 8)) * 0x1_00_00_00);
return value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8)) * 0x1_00_00_00);
case 6:
return u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + ((u8a[3] + (u8a[4] << 8) + (u8a[5] << 16)) * 0x1_00_00_00);
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');