_u64.ts 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
  2. const _32n = /* @__PURE__ */ BigInt(32);
  3. // We are not using BigUint64Array, because they are extremely slow as per 2022
  4. function fromBig(n: bigint, le = false) {
  5. if (le) return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) };
  6. return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
  7. }
  8. function split(lst: bigint[], le = false) {
  9. let Ah = new Uint32Array(lst.length);
  10. let Al = new Uint32Array(lst.length);
  11. for (let i = 0; i < lst.length; i++) {
  12. const { h, l } = fromBig(lst[i], le);
  13. [Ah[i], Al[i]] = [h, l];
  14. }
  15. return [Ah, Al];
  16. }
  17. const toBig = (h: number, l: number) => (BigInt(h >>> 0) << _32n) | BigInt(l >>> 0);
  18. // for Shift in [0, 32)
  19. const shrSH = (h: number, _l: number, s: number) => h >>> s;
  20. const shrSL = (h: number, l: number, s: number) => (h << (32 - s)) | (l >>> s);
  21. // Right rotate for Shift in [1, 32)
  22. const rotrSH = (h: number, l: number, s: number) => (h >>> s) | (l << (32 - s));
  23. const rotrSL = (h: number, l: number, s: number) => (h << (32 - s)) | (l >>> s);
  24. // Right rotate for Shift in (32, 64), NOTE: 32 is special case.
  25. const rotrBH = (h: number, l: number, s: number) => (h << (64 - s)) | (l >>> (s - 32));
  26. const rotrBL = (h: number, l: number, s: number) => (h >>> (s - 32)) | (l << (64 - s));
  27. // Right rotate for shift===32 (just swaps l&h)
  28. const rotr32H = (_h: number, l: number) => l;
  29. const rotr32L = (h: number, _l: number) => h;
  30. // Left rotate for Shift in [1, 32)
  31. const rotlSH = (h: number, l: number, s: number) => (h << s) | (l >>> (32 - s));
  32. const rotlSL = (h: number, l: number, s: number) => (l << s) | (h >>> (32 - s));
  33. // Left rotate for Shift in (32, 64), NOTE: 32 is special case.
  34. const rotlBH = (h: number, l: number, s: number) => (l << (s - 32)) | (h >>> (64 - s));
  35. const rotlBL = (h: number, l: number, s: number) => (h << (s - 32)) | (l >>> (64 - s));
  36. // JS uses 32-bit signed integers for bitwise operations which means we cannot
  37. // simple take carry out of low bit sum by shift, we need to use division.
  38. function add(Ah: number, Al: number, Bh: number, Bl: number) {
  39. const l = (Al >>> 0) + (Bl >>> 0);
  40. return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 };
  41. }
  42. // Addition with more than 2 elements
  43. const add3L = (Al: number, Bl: number, Cl: number) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
  44. const add3H = (low: number, Ah: number, Bh: number, Ch: number) =>
  45. (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0;
  46. const add4L = (Al: number, Bl: number, Cl: number, Dl: number) =>
  47. (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
  48. const add4H = (low: number, Ah: number, Bh: number, Ch: number, Dh: number) =>
  49. (Ah + Bh + Ch + Dh + ((low / 2 ** 32) | 0)) | 0;
  50. const add5L = (Al: number, Bl: number, Cl: number, Dl: number, El: number) =>
  51. (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
  52. const add5H = (low: number, Ah: number, Bh: number, Ch: number, Dh: number, Eh: number) =>
  53. (Ah + Bh + Ch + Dh + Eh + ((low / 2 ** 32) | 0)) | 0;
  54. // prettier-ignore
  55. export {
  56. fromBig, split, toBig,
  57. shrSH, shrSL,
  58. rotrSH, rotrSL, rotrBH, rotrBL,
  59. rotr32H, rotr32L,
  60. rotlSH, rotlSL, rotlBH, rotlBL,
  61. add, add3L, add3H, add4L, add4H, add5H, add5L,
  62. };
  63. // prettier-ignore
  64. const u64 = {
  65. fromBig, split, toBig,
  66. shrSH, shrSL,
  67. rotrSH, rotrSL, rotrBH, rotrBL,
  68. rotr32H, rotr32L,
  69. rotlSH, rotlSL, rotlBH, rotlBL,
  70. add, add3L, add3H, add4L, add4H, add5H, add5L,
  71. };
  72. export default u64;