# How to go between JS BigInts and TypedArrays

**Published**2018-12-13

We now have native `BigInt`

s in JavaScript (not just 64-bit integers,
but *any* arbitrary precision of integer with no pre-defined bit-width). Yay!

However, BigInts have a sordid past... and JavaScript has a sordid past,
so the new `BigInt`

primitives are shimmed in and both hold to old, unhelpful
JS conventions as well as break some new conventions because, well, it's just
how the cookie crumbled.

**TL;DR**:

For the impatient, this is what we're building up to:

`bnToBuf(bn)`

:

```
function bnToBuf(bn) {
var hex = BigInt(bn).toString(16);
if (hex.length % 2) { hex = '0' + hex; }
var len = hex.length / 2;
var u8 = new Uint8Array(len);
var i = 0;
var j = 0;
while (i < len) {
u8[i] = parseInt(hex.slice(j, j+2), 16);
i += 1;
j += 2;
}
return u8;
}
```

`bufToBn(buf)`

:

```
function bufToBn(buf) {
var hex = [];
u8 = Uint8Array.from(buf);
u8.forEach(function (i) {
var h = i.toString(16);
if (h.length % 2) { h = '0' + h; }
hex.push(h);
});
return BigInt('0x' + hex.join(''));
}
```

*Usage*:

```
bnToBuf('1234567890123456789012345678901234567890');
// Uint8Array [ 3, 160, 201, 32, 117, 192, 219, 243,
184, 172, 188, 95, 150, 206, 63, 10, 210 ]
bufToBn([ 3, 160, 201, 32, 117, 192, 219, 243,
184, 172, 188, 95, 150, 206, 63, 10, 210 ]);
// 1234567890123456789012345678901234567890n
```

And if you need to handle negative numbers, you'll need to take a look at How to Convert JS Signed BigInts to Hex

## BigInt64Arrays are not *exactly* TypedArrays

When you're glancing over the almost non-existent documentation for `BigInt`

you'll likely
come across `BigInt64Array`

and `BigUint64Array`

, which are mostly unrelated.

As the name implies, these ints are not *true* `BigInt`

s, but rather capped at 64-bits wide.

However, they aren't just `Number`

s either.

`Number`

s can only survive normal bitwise
operations up to 31-bits. With a little triple-shift trickery they can be coaxed into
behaving well will a full 32 bits, but the full width 52-bit integers is *not* supported.

These `BigInt64Array`

elements *will* work with many bitwise operations
(though signed / negative numbers are still problematic for some operations).

Also, they're **not compatible** with other `TypedArray`

s.

This snippet, for example, **won't work**:

```
var bns = BigInt64Array.from([ BigInt(1), BigInt(2), BigInt(3), BigInt(4) ]);
var u8 = Uint8Array.from(bns);
```

It throws an exception.

And despite being able to access it's `ArrayBuffer`

you can't use that either:

```
var u8 = Uint8Array.from(bns.buffer);
```

However, it turns out that if you do it *just right*, you can get access to
the bytes by calling `new`

:

```
var u8 = new Uint8Array(bns.buffer);
```

Likewise you can ever-so-carefully convince it to go into a `DataView`

as well:

```
var dv = new DataView(bns.buffer);
```

**Here's the rub**:

Even then you're capped to 64-bits. You can't even convert from a `BigInt`

as you might suspect:

```
BigInt64Array.from(BigInt('12345678901234567890123456781234567783456')); // BigInt64Array []
BigInt64Array.from([ BigInt('12345678901234567890123456781234567783456') ]);
// BigInt64Array [ -4657930579192962016 ]
```

## Converting from BigInts to Arrays/Buffers

So, ultimately, if you want to get a `BigInt`

that's larger than 64-bits wide into indidivual bytes,
you have to do it the old fashioned way - with hex (or binary strings):

```
function bnToBuf(bn) {
// The handy-dandy `toString(base)` works!!
var hex = BigInt(bn).toString(16);
// But it still follows the old behavior of giving
// invalid hex strings (due to missing padding),
// but we can easily add that back
if (hex.length % 2) { hex = '0' + hex; }
// The byteLength will be half of the hex string length
var len = hex.length / 2;
var u8 = new Uint8Array(len);
// And then we can iterate each element by one
// and each hex segment by two
var i = 0;
var j = 0;
while (i < len) {
u8[i] = parseInt(hex.slice(j, j+2), 16);
i += 1;
j += 2;
}
// Tada!!
return u8;
}
```

And thus we can handle integers of arbirary length in buffers, yay!

```
bnToBuf('1234567890123456789012345678901234567890')
// Uint8Array [ 3, 160, 201, 32, 117, 192, 219, 243,
184, 172, 188, 95, 150, 206, 63, 10, 210 ]
```

## Converting an ArrayBuffer to BigInt

By comparison, this is reverse is super simple.

```
function bufToBn(buf) {
var hex = [];
u8 = Uint8Array.from(buf);
u8.forEach(function (i) {
var h = i.toString(16);
if (h.length % 2) { h = '0' + h; }
hex.push(h);
});
return BigInt('0x' + hex.join(''));
}
```

There aren't any real gotchas - **unless you're working with signed BigInts**,
in which case you'll want to read up on that specifically.

I cover negative number encoding and decoding in the artciles on converting between hex and decimal listed below:

## Looking for more?

If you found this useful, and you're interested in solving related problems, take a look at these as well:

- BigInts land in Chrome and node.js
- Convert Hex to Decimal strings with JS BigInts
- Convert Decimal strings to Hex with JS BigInts
- BigInts and Base64 in JavaScript
- A Primer on Big Int Encoding

## References

- https://developers.google.com/web/updates/2018/05/bigint
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt

By AJ ONeal

**Thanks!**It's really motivating to know that people like you are benefiting from what I'm doing and want more of it. :)

Did I make your day?

Buy me a coffee

(you can learn about the bigger picture I'm working towards on my patreon page )