admin管理员组

文章数量:1307006

I need to get the bytes of a big integer in JavaScript.

I've tried a couple of big integer libraries, but the one that actually offered this function wouldn't work.

I am not quite sure how to implement this myself, given a string containing a large number, which is generally what the libraries give access to.

Is there a library that works and allows to do this? Or is it actually not hard, and I am just missing something?

I need to get the bytes of a big integer in JavaScript.

I've tried a couple of big integer libraries, but the one that actually offered this function wouldn't work.

I am not quite sure how to implement this myself, given a string containing a large number, which is generally what the libraries give access to.

Is there a library that works and allows to do this? Or is it actually not hard, and I am just missing something?

Share Improve this question asked Jan 30, 2018 at 12:45 user2503048user2503048 1,0411 gold badge12 silver badges28 bronze badges 2
  • This is quite hard. Namingly, you need a reversed double dabble implemention – Jonas Wilms Commented Jan 30, 2018 at 12:50
  • 2 What bytes are you talking about, and what do you need them for? How are you even representing your "big integer"? This question is not answerable if you don't include the desired byte format or tell us which library you want to use. – Bergi Commented Jan 30, 2018 at 13:42
Add a ment  | 

4 Answers 4

Reset to default 4

I was googling for quick and elegant solution of this problem in JavaScript, but the only what I found was the method of conversion, based on intermediate hex-string. What is suboptimal for sure and that code also didn't work for me, unfortunately. So, I implemented my own code and wanted to post it as an answer to my own question, but found this one.

Explanation

First of all, I will answer to the opposite question, since it is more illustrative.

Reading BigInteger from a bytes array

What is an array of bytes for us? This is a number in 256-base numeral system, which we want to convert to more convenient for us 10-base (decimal) system. For instance, let's take an array of bytes
[AA][BB][CC][DD] (1 byte is 8 bits or 2 hexadecimal digits).

Depending on the side we start from (see https://en.wikipedia/wiki/Endianness), we can read it as:

  • (AA*1 + BB*256 + CC*256^2 + DD*256^3) in little-endian
  • or (DD*1 + CC*256 + BB*256^2 + AA*256^3) in big-endian.

Let's use little-endian here. So, our number encoded by the array [AA][BB][CC][DD] is:

AA + BB*256 + CC*256^2 + DD*256^3  
= 170 + 187*256 + 204*65536 + 221*16777216  
= 170 + 47872 + 13369344 + 3707764736  
= 3721182122

Writing BigInteger to a bytes array

For writing a number into an array of bytes we have to perform an opposite operation, i.e. having a number in decimal system to find all digits of it in 256-base numeral system. Let's take the same number: 3721182122

To find it's least significant byte (https://en.wikipedia/wiki/Bit_numbering#Least_significant_byte), we have to just divide it by 256. The remainder represents higher digits. So, we divide the remainder again by 256 and so on, until we receive 0 remainder:

3721182122 = 14535867*256 + 170  
14535867 = 56780*256 + 187  
56780 = 221*256 + 204  
221 = 0*256 + 221  

So, the result is [170][187][204][221] in decimal, [AA][BB][CC][DD] in hex.

Solution in JavaScript

Now, here is this algorithm encoded in NodeJS with big-integer library.

const BigInteger = require('big-integer');

const zero = BigInteger(0);
const one = BigInteger(1);
const n256 = BigInteger(256);

function fromLittleEndian(bytes) {
    let result = zero;
    let base = one;
    bytes.forEach(function (byte) {
        result = result.add(base.multiply(BigInteger(byte)));
        base = base.multiply(n256);
    });
    return result;
}

function fromBigEndian(bytes) {
  return fromLittleEndian(bytes.reverse());
}

function toLittleEndian(bigNumber) {
    let result = new Uint8Array(32);
    let i = 0;
    while (bigNumber.greater(zero)) {
        result[i] = bigNumber.mod(n256);
        bigNumber = bigNumber.divide(n256);
        i += 1;
    }
    return result;
}

function toBigEndian(bytes) {
  return toLittleEndian(bytes).reverse();
}

console.log('Reading BigInteger from an array of bytes');
let bigInt = fromLittleEndian(new Uint8Array([170, 187, 204, 221]));
console.log(bigInt.toString());

console.log('Writing BigInteger to an array of bytes');
let bytes = toLittleEndian(bigInt);
console.log(bytes);

Benchmark

I have written small benchmark for this approach. Anybody is wele to modify it for his own conversion method and to pare with my one.

https://repl.it/repls/EvenSturdyEquipment

Set "i" to be your BigInt's value. You can see the bytes by looking at "a" after running this:

i=11111n;n=1500;a=new Uint8Array(n);while(i>0){a[--n]=Number(i&255n);i>>=8n}

You can also extract the BigInt back out from the Uint8Array:

a.reduce((p,c)=>BigInt(p)*256n+BigInt(c))
export function bigintToUint8Array(value: bigint): Uint8Array {
    const hex = value.toString(16);
    const len = Math.ceil(hex.length / 2);
    const u8 = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
        u8[len - i - 1] = parseInt(hex.substr(i * 2, 2), 16);
    }
    return u8;
}

I've got a version that works with BigInt that's supported by the browser:

const big0 = BigInt(0)
const big1 = BigInt(1)
const big8 = BigInt(8)


  bigToUint8Array(big: bigint) {
    if (big < big0) {
      const bits: bigint = (BigInt(big.toString(2).length) / big8 + big1) * big8
      const prefix1: bigint = big1 << bits
      big += prefix1
    }
    let hex = big.toString(16)
    if (hex.length % 2) {
      hex = '0' + hex
    }
    const len = hex.length / 2
    const 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
  }

I've got a BigDecimal implementation that works with sending & receiving bytes as arbitary precision big decimal: https://jackieli.dev/posts/bigint-to-uint8array/

本文标签: javascriptBigInteger to a Uint8Array of bytesStack Overflow