-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.ts
123 lines (97 loc) · 2.72 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { assert } from "$std/assert/mod.ts";
export function getRandomNumber(bytes = 32, modulus?: bigint) {
const array = new Uint8Array(bytes);
crypto.getRandomValues(array);
// See: https://stackoverflow.com/a/75259983
const hexString = Array.from(array)
.map((i) => i.toString(16).padStart(2, "0"))
.join("");
const number = BigInt(`0x${hexString}`);
if (modulus) {
return mod(number, modulus);
}
return number;
}
export function mod(a: bigint, b: bigint) {
const result = a % b;
return result >= 0 ? result : result + b;
}
// LSB -> MSB.
export function* toBinary(number: bigint) {
while (number) {
yield number & 1n;
number >>= 1n;
}
}
// See: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Pseudocode
// See: https://brilliant.org/wiki/extended-euclidean-algorithm
// Returns [gcd, x, y] such that `(a * x) + (b * y) = gcd` (`gcd` -> `gcd(a, b)`).
export function egcd(a: bigint, b: bigint) {
let x = 0n;
let y = 1n;
let u = 1n;
let v = 0n;
while (a !== 0n) {
const q = b / a;
const r = b % a;
const m = x - u * q;
const n = y - v * q;
b = a;
a = r;
x = u;
y = v;
u = m;
v = n;
}
const gcd = b;
return [gcd, x, y];
}
// Returns multiplicative inverse of `number` modulo `modulus`.
// Returns integer `x` s.th. `(number * x) % modulus === 1`.
export function inverseOf(number: bigint, modulus: bigint) {
const a = mod(number, modulus);
const [gcd, x, y] = egcd(a, modulus);
if (gcd !== 1n) {
// Either `number` is 0 or `modulus` is not prime.
throw new Error(
`${number} has no multiplicative inverse modulo ${modulus}...`,
);
}
assert(mod(number * x, modulus) === 1n);
assert(mod(number * x + modulus * y, modulus) === gcd);
return mod(x, modulus);
}
export function int2Hex(number: bigint, prefix = true, pad = true) {
const padding = pad ? 32 : 1;
const result = buf2hex(int2BytesBe(number, padding), false);
if (prefix) {
return `0x${result}`;
}
return result;
}
// See: https://stackoverflow.com/a/40031979
export function buf2hex(buffer: Uint8Array, prefix = true) {
const result = [...new Uint8Array(buffer)]
.map((x) => x.toString(16).padStart(2, "0"))
.join("");
if (prefix) {
return `0x${result}`;
}
return result;
}
// See: https://stackoverflow.com/a/56943145
export function int2BytesBe(int: bigint, padding = 32) {
return int2BytesLe(int, padding).reverse();
}
// See: https://stackoverflow.com/a/56943145
export function int2BytesLe(int: bigint, padding = 32) {
const result = new Uint8Array(padding);
let i = 0;
let bigint = int;
while (bigint > 0n) {
result[i] = Number(bigint % 256n);
bigint = bigint / 256n;
i += 1;
}
return result;
}