noble-hashes: BigInt syntax errors in unsupported environments

… you are not going to like this one, bear with me 😃

Ok, I started pulling this in. Basically in my case I still need to support some ancient environments as well, which is not that much of an issue, basically on my hashing wrappers I do the following -

import { blake2b as blake2bJs } from '@noble/hashes/lib/blake2b';

// wasm
import { blake2b as blake2bWasm } from '@polkadot/wasm-crypto'; 

export function blake2 (u8a: Uint8Array): Uint8Array {
  return typeof BigInt !== 'undefined'
    ? blake2bJs(u8a)
    : blake2bWasm(u8a);
}

So effectively there is some fallback in there. (The above is typed from memory as illustration, but shows the point. Normally when wasm is initialized, it actually is the preferred route in my case. The same applies to eg fallback to blake2-js when BigInt is not available)

Anyway, all good. Now however the issue is the following - on some older environments, such as for instance React Native, it even throws up when trying to parse the modules, e.g. this is problematic (although not used at runtime) https://github.com/paulmillr/noble-hashes/blob/main/src/_u64.ts#L1

I did a quick search for the 32n e.g. /\dn/ and there are actually not that many. So for instance, we could get around it with the following …

// _64.ts 
// suggested adjustments as an example, some files will need adjusting 
// yes, it is, well ... horrid :(
export const _BigInt: (value: string | number | bigint | boolean) => bigint =
  typeof BigInt !== 'undefined'
    ? BigInt
    : () => undefined as unknown as bigint;

const U32_MASK64 = _BigInt(2 ** 32 - 1);

const _32n = _BigInt(32);

export function fromBig(n: bigint, le = false) {
  if (le) return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) };
  return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
}

The above is problematic, obviously since it will give undefined results in non-BigInt environments. In BigInt environments there is no extra overhead, well, maybe slightly at library load. However for non-BigInt-envs inside functions it does use BigInt which would throw up at runtime.

At this point the TL;DR is -

  1. I’m making sure that at runtime, the BigInt libs are not used (if not available)
  2. I still have support issue where library users now complain that it doesn’t compile in their environments

So my options are -

  1. Having to debug all user environments to figure out why
  2. Documenting all of it
  3. Making a PR here with “some” hacks like above

None of the options are fun atm 😃 Other suggestions welcome.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 19 (19 by maintainers)

Most upvoted comments

yeah, I don’t want runtime impacts for stuff that’s used by 1% of users. I don’t see big disadvantages in changing 1n to BigInt(1) tho.