functionalscript 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/crypto/hmac/module.f.d.ts +28 -0
- package/crypto/hmac/module.f.js +60 -0
- package/crypto/hmac/test.f.d.ts +6 -0
- package/crypto/hmac/test.f.js +24 -0
- package/crypto/sha2/module.f.d.ts +10 -0
- package/crypto/sha2/module.f.js +11 -2
- package/crypto/sha2/test.f.js +28 -21
- package/package.json +1 -1
- package/types/bigint/module.f.d.ts +83 -2
- package/types/bigint/module.f.js +115 -9
- package/types/bigint/test.f.d.ts +4 -0
- package/types/bigint/test.f.js +110 -5
- package/types/bit_vec/module.f.d.ts +1 -1
- package/types/number/module.f.d.ts +4 -0
- package/types/number/module.f.js +16 -0
- package/types/number/test.f.d.ts +1 -0
- package/types/number/test.f.js +19 -3
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides an implementation of HMAC (Hash-based Message Authentication Code).
|
|
3
|
+
*
|
|
4
|
+
* https://en.wikipedia.org/wiki/HMAC
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { vec } from '../../types/bit_vec/module.f.ts'
|
|
12
|
+
* import { msbUtf8 } from '../../text/module.f.ts'
|
|
13
|
+
* import { sha256 } from '../sha2/module.f.ts'
|
|
14
|
+
*
|
|
15
|
+
* const r = hmac(sha256)(msbUtf8('key'))(msbUtf8('The quick brown fox jumps over the lazy dog'))
|
|
16
|
+
* if (r !== vec(256n)(0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8n)) { throw r }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import { type Vec } from '../../types/bit_vec/module.f.ts';
|
|
20
|
+
import { type Sha2 } from '../sha2/module.f.ts';
|
|
21
|
+
/**
|
|
22
|
+
* Generates an HMAC (Hash-based Message Authentication Code) using the specified SHA-2 hash function.
|
|
23
|
+
*
|
|
24
|
+
* @param sha2 - The SHA-2 hash function implementation to use.
|
|
25
|
+
* @returns - A function that takes a key and returns another function
|
|
26
|
+
* that takes a message and computes the HMAC.
|
|
27
|
+
*/
|
|
28
|
+
export declare const hmac: (sha2: Sha2) => (k: Vec) => (m: Vec) => Vec;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides an implementation of HMAC (Hash-based Message Authentication Code).
|
|
3
|
+
*
|
|
4
|
+
* https://en.wikipedia.org/wiki/HMAC
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { vec } from '../../types/bit_vec/module.f.ts'
|
|
12
|
+
* import { msbUtf8 } from '../../text/module.f.ts'
|
|
13
|
+
* import { sha256 } from '../sha2/module.f.ts'
|
|
14
|
+
*
|
|
15
|
+
* const r = hmac(sha256)(msbUtf8('key'))(msbUtf8('The quick brown fox jumps over the lazy dog'))
|
|
16
|
+
* if (r !== vec(256n)(0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8n)) { throw r }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import { length } from "../../types/bit_vec/module.f.js";
|
|
20
|
+
import { empty, msb, vec, vec8 } from "../../types/bit_vec/module.f.js";
|
|
21
|
+
import { flip } from "../../types/function/module.f.js";
|
|
22
|
+
import { repeat } from "../../types/monoid/module.f.js";
|
|
23
|
+
import { computeSync } from "../sha2/module.f.js";
|
|
24
|
+
const { concat } = msb;
|
|
25
|
+
/**
|
|
26
|
+
* Outer padding.
|
|
27
|
+
*/
|
|
28
|
+
const oPad = vec8(0x5cn);
|
|
29
|
+
/**
|
|
30
|
+
* Inner padding.
|
|
31
|
+
*/
|
|
32
|
+
const iPad = vec8(0x36n);
|
|
33
|
+
/**
|
|
34
|
+
* Repeats a vector to create a padded block of the desired length.
|
|
35
|
+
*/
|
|
36
|
+
const padRepeat = repeat({ identity: empty, operation: concat });
|
|
37
|
+
/**
|
|
38
|
+
* Generates an HMAC (Hash-based Message Authentication Code) using the specified SHA-2 hash function.
|
|
39
|
+
*
|
|
40
|
+
* @param sha2 - The SHA-2 hash function implementation to use.
|
|
41
|
+
* @returns - A function that takes a key and returns another function
|
|
42
|
+
* that takes a message and computes the HMAC.
|
|
43
|
+
*/
|
|
44
|
+
export const hmac = (sha2) => {
|
|
45
|
+
const { blockLength } = sha2;
|
|
46
|
+
const p = flip(padRepeat)(blockLength >> 3n);
|
|
47
|
+
const ip = p(iPad);
|
|
48
|
+
const op = p(oPad);
|
|
49
|
+
const c = computeSync(sha2);
|
|
50
|
+
const vbl = vec(blockLength);
|
|
51
|
+
const xor = (a) => (b) => vbl(a ^ b);
|
|
52
|
+
return k => m => {
|
|
53
|
+
const k1 = length(k) > blockLength ? c([k]) : k;
|
|
54
|
+
const k2 = concat(k1)(vec(blockLength - length(k1))(0n));
|
|
55
|
+
const xk2 = xor(k2);
|
|
56
|
+
const f = (p, msg) => c([xk2(p), msg]);
|
|
57
|
+
const m1 = f(ip, m);
|
|
58
|
+
return f(op, m1);
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { msbUtf8 } from "../../text/module.f.js";
|
|
2
|
+
import { vec } from "../../types/bit_vec/module.f.js";
|
|
3
|
+
import { sha256, sha512 } from "../sha2/module.f.js";
|
|
4
|
+
import { hmac } from "./module.f.js";
|
|
5
|
+
export default {
|
|
6
|
+
example: () => {
|
|
7
|
+
const r = hmac(sha256)(msbUtf8('key'))(msbUtf8('The quick brown fox jumps over the lazy dog'));
|
|
8
|
+
if (r !== vec(256n)(0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8n)) {
|
|
9
|
+
throw r;
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
sha256: () => {
|
|
13
|
+
const r = hmac(sha256)(msbUtf8('key'))(msbUtf8('The quick brown fox jumps over the lazy dog'));
|
|
14
|
+
if (r !== 0x1f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8n) {
|
|
15
|
+
throw r;
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
sha512: () => {
|
|
19
|
+
const r = hmac(sha512)(msbUtf8('key'))(msbUtf8('The quick brown fox jumps over the lazy dog'));
|
|
20
|
+
if (r !== 0x1b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3an) {
|
|
21
|
+
throw r;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Array16, Array8 } from '../../types/array/module.f.ts';
|
|
2
2
|
import { type Vec } from '../../types/bit_vec/module.f.ts';
|
|
3
|
+
import { type List } from '../../types/list/module.f.ts';
|
|
3
4
|
export type V8 = Array8<bigint>;
|
|
4
5
|
export type V16 = Array16<bigint>;
|
|
5
6
|
/**
|
|
@@ -40,6 +41,14 @@ export type Base = {
|
|
|
40
41
|
* ```
|
|
41
42
|
*/
|
|
42
43
|
export type Sha2 = {
|
|
44
|
+
/**
|
|
45
|
+
* A hash length.
|
|
46
|
+
*/
|
|
47
|
+
readonly hashLength: bigint;
|
|
48
|
+
/**
|
|
49
|
+
* An internal block length.
|
|
50
|
+
*/
|
|
51
|
+
readonly blockLength: bigint;
|
|
43
52
|
/**
|
|
44
53
|
* Initial state of the SHA-2 algorithm.
|
|
45
54
|
*/
|
|
@@ -60,6 +69,7 @@ export type Sha2 = {
|
|
|
60
69
|
*/
|
|
61
70
|
readonly end: (state: State) => bigint;
|
|
62
71
|
};
|
|
72
|
+
export declare const computeSync: ({ append, init, end }: Sha2) => (list: List<Vec>) => Vec;
|
|
63
73
|
export declare const base32: Base;
|
|
64
74
|
export declare const base64: Base;
|
|
65
75
|
/** SHA-256 */
|
package/crypto/sha2/module.f.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { mask } from "../../types/bigint/module.f.js";
|
|
2
2
|
import { vec, length, empty, msb } from "../../types/bit_vec/module.f.js";
|
|
3
|
+
import { flip } from "../../types/function/module.f.js";
|
|
4
|
+
import { fold } from "../../types/list/module.f.js";
|
|
3
5
|
const { concat, popFront, front } = msb;
|
|
4
6
|
const lastOne = vec(1n)(1n);
|
|
5
7
|
const base = ({ logBitLen, k, bs0, bs1, ss0, ss1 }) => {
|
|
@@ -138,6 +140,7 @@ const base = ({ logBitLen, k, bs0, bs1, ss0, ss1 }) => {
|
|
|
138
140
|
},
|
|
139
141
|
end: (hashLength) => {
|
|
140
142
|
const offset = (bitLength << 3n) - hashLength;
|
|
143
|
+
const result = vec(hashLength);
|
|
141
144
|
return (state) => {
|
|
142
145
|
const { len, remainder } = state;
|
|
143
146
|
let { hash } = state;
|
|
@@ -148,12 +151,14 @@ const base = ({ logBitLen, k, bs0, bs1, ss0, ss1 }) => {
|
|
|
148
151
|
hash = compress(hash)(u);
|
|
149
152
|
u = 0n;
|
|
150
153
|
}
|
|
151
|
-
return fromV8(compress(hash)(u | (len + rLen))) >> offset;
|
|
154
|
+
return result(fromV8(compress(hash)(u | (len + rLen))) >> offset);
|
|
152
155
|
};
|
|
153
156
|
}
|
|
154
157
|
};
|
|
155
158
|
};
|
|
156
|
-
const sha2 = ({ append, end }, hash, hashLength) => ({
|
|
159
|
+
const sha2 = ({ append, end, chunkLength }, hash, hashLength) => ({
|
|
160
|
+
hashLength,
|
|
161
|
+
blockLength: chunkLength,
|
|
157
162
|
init: {
|
|
158
163
|
hash,
|
|
159
164
|
len: 0n,
|
|
@@ -162,6 +167,10 @@ const sha2 = ({ append, end }, hash, hashLength) => ({
|
|
|
162
167
|
append,
|
|
163
168
|
end: end(hashLength),
|
|
164
169
|
});
|
|
170
|
+
export const computeSync = ({ append, init, end }) => {
|
|
171
|
+
const f = fold(flip(append))(init);
|
|
172
|
+
return (list) => end(f(list));
|
|
173
|
+
};
|
|
165
174
|
export const base32 = base({
|
|
166
175
|
logBitLen: 5n,
|
|
167
176
|
k: [
|
package/crypto/sha2/test.f.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { msbUtf8 } from "../../text/module.f.js";
|
|
2
2
|
import { empty, msb, vec } from "../../types/bit_vec/module.f.js";
|
|
3
|
+
import { map } from "../../types/list/module.f.js";
|
|
3
4
|
import { repeat } from "../../types/monoid/module.f.js";
|
|
4
|
-
import { base32, base64, sha224, sha256, sha384, sha512, sha512x224, sha512x256, } from "./module.f.js";
|
|
5
|
+
import { base32, base64, computeSync, sha224, sha256, sha384, sha512, sha512x224, sha512x256, } from "./module.f.js";
|
|
5
6
|
const { concat: beConcat } = msb;
|
|
6
7
|
const checkEmpty = ({ init, end }) => (x) => {
|
|
7
8
|
const result = end(init);
|
|
@@ -22,7 +23,7 @@ export default {
|
|
|
22
23
|
const result = fromV8(compress(sha256.init.hash)(e));
|
|
23
24
|
const x = 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855n;
|
|
24
25
|
if (result !== x) {
|
|
25
|
-
throw [result, x];
|
|
26
|
+
throw [result.toString(16), x.toString(16)];
|
|
26
27
|
}
|
|
27
28
|
},
|
|
28
29
|
s224: () => {
|
|
@@ -70,29 +71,35 @@ export default {
|
|
|
70
71
|
}
|
|
71
72
|
},
|
|
72
73
|
sha2: {
|
|
73
|
-
sha256: () => checkEmpty(sha256)(
|
|
74
|
-
sha224: () => checkEmpty(sha224)(
|
|
75
|
-
sha512: () => checkEmpty(sha512)(
|
|
76
|
-
sha384: () => checkEmpty(sha384)(
|
|
77
|
-
sha512x256: () => checkEmpty(sha512x256)(
|
|
78
|
-
sha512x224: () => checkEmpty(sha512x224)(
|
|
74
|
+
sha256: () => checkEmpty(sha256)(0x1e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855n),
|
|
75
|
+
sha224: () => checkEmpty(sha224)(0x1d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42fn),
|
|
76
|
+
sha512: () => checkEmpty(sha512)(0x1cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3en),
|
|
77
|
+
sha384: () => checkEmpty(sha384)(0x138b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95bn),
|
|
78
|
+
sha512x256: () => checkEmpty(sha512x256)(0x1c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967an),
|
|
79
|
+
sha512x224: () => checkEmpty(sha512x224)(0x16ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4n),
|
|
79
80
|
},
|
|
80
81
|
utf8: [
|
|
81
82
|
() => {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
const e = 0x1730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525n;
|
|
84
|
+
{
|
|
85
|
+
const s = msbUtf8("The quick brown fox jumps over the lazy dog");
|
|
86
|
+
const h = computeSync(sha224)([s]);
|
|
87
|
+
if (h !== e) {
|
|
88
|
+
throw h;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
{
|
|
92
|
+
const s = ['The', ' quick', ' brown', ' fox', ' jumps', ' over', ' the', ' lazy', ' dog'];
|
|
93
|
+
const h = computeSync(sha224)(map(msbUtf8)(s));
|
|
94
|
+
if (h !== e) {
|
|
95
|
+
throw h;
|
|
96
|
+
}
|
|
88
97
|
}
|
|
89
98
|
},
|
|
90
99
|
() => {
|
|
91
100
|
const s = msbUtf8("The quick brown fox jumps over the lazy dog.");
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const h = sha224.end(state);
|
|
95
|
-
if (h !== 0x619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4cn) {
|
|
101
|
+
const h = computeSync(sha224)([s]);
|
|
102
|
+
if (h !== 0x1619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4cn) {
|
|
96
103
|
throw h;
|
|
97
104
|
}
|
|
98
105
|
},
|
|
@@ -104,7 +111,7 @@ export default {
|
|
|
104
111
|
let state = sha256.init;
|
|
105
112
|
state = sha256.append(state)(s);
|
|
106
113
|
const h = sha256.end(state);
|
|
107
|
-
if (h !==
|
|
114
|
+
if (h !== 0x1b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9n) {
|
|
108
115
|
throw h;
|
|
109
116
|
}
|
|
110
117
|
}
|
|
@@ -117,7 +124,7 @@ export default {
|
|
|
117
124
|
let state = sha256.init;
|
|
118
125
|
state = sha256.append(state)(r);
|
|
119
126
|
const h = sha256.end(state);
|
|
120
|
-
if (h >> 224n !==
|
|
127
|
+
if (h >> 224n !== 0x18a83665fn) {
|
|
121
128
|
throw h;
|
|
122
129
|
}
|
|
123
130
|
},
|
|
@@ -126,7 +133,7 @@ export default {
|
|
|
126
133
|
let state = sha256.init;
|
|
127
134
|
state = sha256.append(state)(r);
|
|
128
135
|
const h = sha256.end(state);
|
|
129
|
-
if (h !==
|
|
136
|
+
if (h !== 0x13138bb9bc78df27c473ecfd1410f7bd45ebac1f59cf3ff9cfe4db77aab7aedd3n) {
|
|
130
137
|
throw h;
|
|
131
138
|
}
|
|
132
139
|
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Utility functions for working with `bigint` values.
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*
|
|
@@ -14,17 +14,67 @@
|
|
|
14
14
|
* const bitCount = bitLength(255n) // 8n
|
|
15
15
|
* const bitmask = mask(5n) // 31n
|
|
16
16
|
* const m = min(3n)(13n) // 3n
|
|
17
|
+
* const c = combination([3n, 2n, 1n]) // 60n
|
|
17
18
|
* ```
|
|
18
19
|
*/
|
|
19
20
|
import { type Sign } from '../function/compare/module.f.ts';
|
|
20
21
|
import type * as Operator from '../function/operator/module.f.ts';
|
|
21
22
|
import { type List } from '../list/module.f.ts';
|
|
23
|
+
/**
|
|
24
|
+
* Type representing a unary operation on `bigint`.
|
|
25
|
+
*/
|
|
22
26
|
export type Unary = Operator.Unary<bigint, bigint>;
|
|
27
|
+
/**
|
|
28
|
+
* Type representing a reduction operation on `bigint` values.
|
|
29
|
+
*/
|
|
23
30
|
export type Reduce = Operator.Reduce<bigint>;
|
|
31
|
+
/**
|
|
32
|
+
* Adds two `bigint` values.
|
|
33
|
+
*
|
|
34
|
+
* @param a - The first bigint value.
|
|
35
|
+
* @returns A function that takes the second bigint value and returns the sum.
|
|
36
|
+
*/
|
|
24
37
|
export declare const addition: Reduce;
|
|
38
|
+
/**
|
|
39
|
+
* Calculates the sum of a list of `bigint` values.
|
|
40
|
+
*
|
|
41
|
+
* @param input - A list of bigint values.
|
|
42
|
+
* @returns The sum of all values in the list.
|
|
43
|
+
*/
|
|
25
44
|
export declare const sum: (input: List<bigint>) => bigint;
|
|
45
|
+
/**
|
|
46
|
+
* Multiplies two `bigint` values.
|
|
47
|
+
*
|
|
48
|
+
* @param a - The first bigint value.
|
|
49
|
+
* @returns A function that takes the second bigint value and returns the product.
|
|
50
|
+
*/
|
|
51
|
+
export declare const multiple: Reduce;
|
|
52
|
+
/**
|
|
53
|
+
* Calculates the product of a list of `bigint` values.
|
|
54
|
+
*
|
|
55
|
+
* @param input - A list of bigint values.
|
|
56
|
+
* @returns The product of all values in the list.
|
|
57
|
+
*/
|
|
58
|
+
export declare const product: (input: List<bigint>) => bigint;
|
|
59
|
+
/**
|
|
60
|
+
* Calculates the absolute value of a `bigint`.
|
|
61
|
+
*
|
|
62
|
+
* @param a - The bigint value.
|
|
63
|
+
* @returns The absolute value of the input bigint.
|
|
64
|
+
*/
|
|
26
65
|
export declare const abs: Unary;
|
|
66
|
+
/**
|
|
67
|
+
* Determines the sign of a `bigint`.
|
|
68
|
+
* @param a - The bigint value.
|
|
69
|
+
* @returns `1` if positive, `-1` if negative, and `0` if zero.
|
|
70
|
+
*/
|
|
27
71
|
export declare const sign: (a: bigint) => Sign;
|
|
72
|
+
/**
|
|
73
|
+
* Serializes a `bigint` to a string representation.
|
|
74
|
+
*
|
|
75
|
+
* @param a - The bigint value.
|
|
76
|
+
* @returns A string representation of the bigint (e.g., '123n').
|
|
77
|
+
*/
|
|
28
78
|
export declare const serialize: (a: bigint) => string;
|
|
29
79
|
/**
|
|
30
80
|
* Calculates the base-2 logarithm (floor).
|
|
@@ -81,6 +131,37 @@ export declare const bitLength: (v: bigint) => bigint;
|
|
|
81
131
|
*/
|
|
82
132
|
export declare const mask: (len: bigint) => bigint;
|
|
83
133
|
/**
|
|
84
|
-
*
|
|
134
|
+
* Returns the smaller of two `bigint` values.
|
|
135
|
+
*
|
|
136
|
+
* @param a - The first bigint.
|
|
137
|
+
* @returns A function that takes the second bigint and returns the smaller value.
|
|
85
138
|
*/
|
|
86
139
|
export declare const min: (a: bigint) => (b: bigint) => bigint;
|
|
140
|
+
/**
|
|
141
|
+
* Returns the larger of two `bigint` values.
|
|
142
|
+
*
|
|
143
|
+
* @param a - The first bigint.
|
|
144
|
+
* @returns A function that takes the second bigint and returns the larger value.
|
|
145
|
+
*/
|
|
146
|
+
export declare const max: (a: bigint) => (b: bigint) => bigint;
|
|
147
|
+
/**
|
|
148
|
+
* Calculates the partial factorial `b!/a!`.
|
|
149
|
+
*
|
|
150
|
+
* @param a - The starting bigint value.
|
|
151
|
+
* @returns A function that takes `b` and computes `b!/a!`.
|
|
152
|
+
*/
|
|
153
|
+
export declare const partialFactorial: (a: bigint) => (b: bigint) => bigint;
|
|
154
|
+
/**
|
|
155
|
+
* Calculates the factorial of a `bigint`.
|
|
156
|
+
*
|
|
157
|
+
* @param b - The bigint value.
|
|
158
|
+
* @returns The factorial of the input.
|
|
159
|
+
*/
|
|
160
|
+
export declare const factorial: (b: bigint) => bigint;
|
|
161
|
+
/**
|
|
162
|
+
* Calculates the number of combinations for a list of `bigint` values.
|
|
163
|
+
*
|
|
164
|
+
* @param k - A list of bigint values.
|
|
165
|
+
* @returns The number of combinations.
|
|
166
|
+
*/
|
|
167
|
+
export declare const combination: (...k: readonly bigint[]) => bigint;
|
package/types/bigint/module.f.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Utility functions for working with `bigint` values.
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*
|
|
@@ -14,15 +14,61 @@
|
|
|
14
14
|
* const bitCount = bitLength(255n) // 8n
|
|
15
15
|
* const bitmask = mask(5n) // 31n
|
|
16
16
|
* const m = min(3n)(13n) // 3n
|
|
17
|
+
* const c = combination([3n, 2n, 1n]) // 60n
|
|
17
18
|
* ```
|
|
18
19
|
*/
|
|
19
20
|
import { unsafeCmp } from "../function/compare/module.f.js";
|
|
20
21
|
import { reduce } from "../list/module.f.js";
|
|
22
|
+
/**
|
|
23
|
+
* Adds two `bigint` values.
|
|
24
|
+
*
|
|
25
|
+
* @param a - The first bigint value.
|
|
26
|
+
* @returns A function that takes the second bigint value and returns the sum.
|
|
27
|
+
*/
|
|
21
28
|
export const addition = a => b => a + b;
|
|
29
|
+
/**
|
|
30
|
+
* Calculates the sum of a list of `bigint` values.
|
|
31
|
+
*
|
|
32
|
+
* @param input - A list of bigint values.
|
|
33
|
+
* @returns The sum of all values in the list.
|
|
34
|
+
*/
|
|
22
35
|
export const sum = reduce(addition)(0n);
|
|
36
|
+
/**
|
|
37
|
+
* Multiplies two `bigint` values.
|
|
38
|
+
*
|
|
39
|
+
* @param a - The first bigint value.
|
|
40
|
+
* @returns A function that takes the second bigint value and returns the product.
|
|
41
|
+
*/
|
|
42
|
+
export const multiple = a => b => a * b;
|
|
43
|
+
/**
|
|
44
|
+
* Calculates the product of a list of `bigint` values.
|
|
45
|
+
*
|
|
46
|
+
* @param input - A list of bigint values.
|
|
47
|
+
* @returns The product of all values in the list.
|
|
48
|
+
*/
|
|
49
|
+
export const product = reduce(multiple)(1n);
|
|
50
|
+
/**
|
|
51
|
+
* Calculates the absolute value of a `bigint`.
|
|
52
|
+
*
|
|
53
|
+
* @param a - The bigint value.
|
|
54
|
+
* @returns The absolute value of the input bigint.
|
|
55
|
+
*/
|
|
23
56
|
export const abs = a => a >= 0 ? a : -a;
|
|
57
|
+
/**
|
|
58
|
+
* Determines the sign of a `bigint`.
|
|
59
|
+
* @param a - The bigint value.
|
|
60
|
+
* @returns `1` if positive, `-1` if negative, and `0` if zero.
|
|
61
|
+
*/
|
|
24
62
|
export const sign = (a) => unsafeCmp(a)(0n);
|
|
63
|
+
/**
|
|
64
|
+
* Serializes a `bigint` to a string representation.
|
|
65
|
+
*
|
|
66
|
+
* @param a - The bigint value.
|
|
67
|
+
* @returns A string representation of the bigint (e.g., '123n').
|
|
68
|
+
*/
|
|
25
69
|
export const serialize = (a) => `${a}n`;
|
|
70
|
+
const { isFinite } = Number;
|
|
71
|
+
const { log2: mathLog2 } = Math;
|
|
26
72
|
/**
|
|
27
73
|
* Calculates the base-2 logarithm (floor).
|
|
28
74
|
*
|
|
@@ -52,7 +98,7 @@ export const log2 = (v) => {
|
|
|
52
98
|
let result = -1n;
|
|
53
99
|
// `bigints` higher than 2**1023 may lead to `Inf` during conversion to `number`.
|
|
54
100
|
// For example: `Number((1n << 1024n) - (1n << 970n)) === Inf`.
|
|
55
|
-
let i =
|
|
101
|
+
let i = 0x400n;
|
|
56
102
|
while (true) {
|
|
57
103
|
const n = v >> i;
|
|
58
104
|
if (n === 0n) {
|
|
@@ -68,7 +114,7 @@ export const log2 = (v) => {
|
|
|
68
114
|
//
|
|
69
115
|
// We know that `v` is not 0 so it doesn't make sense to check `n` when `i` is 0.
|
|
70
116
|
// Because of this, We check if `i` is greater than 1023 before we divide it by 2.
|
|
71
|
-
while (i !==
|
|
117
|
+
while (i !== 0x400n) {
|
|
72
118
|
i >>= 1n;
|
|
73
119
|
const n = v >> i;
|
|
74
120
|
if (n !== 0n) {
|
|
@@ -79,12 +125,20 @@ export const log2 = (v) => {
|
|
|
79
125
|
//
|
|
80
126
|
// 3. Remainder Phase.
|
|
81
127
|
//
|
|
82
|
-
// We know that `v` is less than `1n <<
|
|
128
|
+
// We know that `v` is less than `1n << 1024` so we can calculate a remainder using
|
|
83
129
|
// `Math.log2`.
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
130
|
+
const nl = mathLog2(Number(v));
|
|
131
|
+
if (isFinite(nl)) {
|
|
132
|
+
const rem = BigInt(nl | 0);
|
|
133
|
+
// (v >> rem) is either `0` or `1`, and it's used as a correction for
|
|
134
|
+
// Math.log2 rounding.
|
|
135
|
+
return result + rem + (v >> rem);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// nl is Inf, it means log2(v) === 0x3FF and we add +1 to compensate for initial
|
|
139
|
+
// `result = -1n`.
|
|
140
|
+
return result + 0x400n;
|
|
141
|
+
}
|
|
88
142
|
};
|
|
89
143
|
/**
|
|
90
144
|
* Calculates the bit length of a given BigInt.
|
|
@@ -129,6 +183,58 @@ export const bitLength = (v) => {
|
|
|
129
183
|
*/
|
|
130
184
|
export const mask = (len) => (1n << len) - 1n;
|
|
131
185
|
/**
|
|
132
|
-
*
|
|
186
|
+
* Returns the smaller of two `bigint` values.
|
|
187
|
+
*
|
|
188
|
+
* @param a - The first bigint.
|
|
189
|
+
* @returns A function that takes the second bigint and returns the smaller value.
|
|
133
190
|
*/
|
|
134
191
|
export const min = (a) => (b) => a < b ? a : b;
|
|
192
|
+
/**
|
|
193
|
+
* Returns the larger of two `bigint` values.
|
|
194
|
+
*
|
|
195
|
+
* @param a - The first bigint.
|
|
196
|
+
* @returns A function that takes the second bigint and returns the larger value.
|
|
197
|
+
*/
|
|
198
|
+
export const max = (a) => (b) => a < b ? b : a;
|
|
199
|
+
/**
|
|
200
|
+
* Calculates the partial factorial `b!/a!`.
|
|
201
|
+
*
|
|
202
|
+
* @param a - The starting bigint value.
|
|
203
|
+
* @returns A function that takes `b` and computes `b!/a!`.
|
|
204
|
+
*/
|
|
205
|
+
export const partialFactorial = (a) => (b) => {
|
|
206
|
+
let result = b;
|
|
207
|
+
while (true) {
|
|
208
|
+
--b;
|
|
209
|
+
if (b <= a) {
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
result *= b;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Calculates the factorial of a `bigint`.
|
|
217
|
+
*
|
|
218
|
+
* @param b - The bigint value.
|
|
219
|
+
* @returns The factorial of the input.
|
|
220
|
+
*/
|
|
221
|
+
export const factorial = partialFactorial(1n);
|
|
222
|
+
/**
|
|
223
|
+
* Calculates the number of combinations for a list of `bigint` values.
|
|
224
|
+
*
|
|
225
|
+
* @param k - A list of bigint values.
|
|
226
|
+
* @returns The number of combinations.
|
|
227
|
+
*/
|
|
228
|
+
export const combination = (...k) => {
|
|
229
|
+
let s = 0n;
|
|
230
|
+
let m = 1n;
|
|
231
|
+
let p = 1n;
|
|
232
|
+
for (let i of k) {
|
|
233
|
+
s += i;
|
|
234
|
+
if (i >= m) {
|
|
235
|
+
[i, m] = [m, i];
|
|
236
|
+
}
|
|
237
|
+
p *= factorial(i);
|
|
238
|
+
}
|
|
239
|
+
return partialFactorial(m)(s) / p;
|
|
240
|
+
};
|
package/types/bigint/test.f.d.ts
CHANGED
package/types/bigint/test.f.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sum, abs, serialize, log2, bitLength, mask, min } from "./module.f.js";
|
|
1
|
+
import { sum, abs, serialize, log2, bitLength, mask, min, combination, factorial } from "./module.f.js";
|
|
2
2
|
const oldLog2 = (v) => {
|
|
3
3
|
if (v <= 0n) {
|
|
4
4
|
return -1n;
|
|
@@ -64,6 +64,50 @@ export const clz32Log2 = (v) => {
|
|
|
64
64
|
}
|
|
65
65
|
return result - BigInt(Math.clz32(Number(v)));
|
|
66
66
|
};
|
|
67
|
+
const m1023log2 = (v) => {
|
|
68
|
+
if (v <= 0n) {
|
|
69
|
+
return -1n;
|
|
70
|
+
}
|
|
71
|
+
//
|
|
72
|
+
// 1. Fast Doubling.
|
|
73
|
+
//
|
|
74
|
+
let result = -1n;
|
|
75
|
+
// `bigints` higher than 2**1023 may lead to `Inf` during conversion to `number`.
|
|
76
|
+
// For example: `Number((1n << 1024n) - (1n << 970n)) === Inf`.
|
|
77
|
+
let i = 1023n;
|
|
78
|
+
while (true) {
|
|
79
|
+
const n = v >> i;
|
|
80
|
+
if (n === 0n) {
|
|
81
|
+
// overshot
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
v = n;
|
|
85
|
+
result += i;
|
|
86
|
+
i <<= 1n;
|
|
87
|
+
}
|
|
88
|
+
//
|
|
89
|
+
// 2. Binary Search.
|
|
90
|
+
//
|
|
91
|
+
// We know that `v` is not 0 so it doesn't make sense to check `n` when `i` is 0.
|
|
92
|
+
// Because of this, We check if `i` is greater than 1023 before we divide it by 2.
|
|
93
|
+
while (i !== 1023n) {
|
|
94
|
+
i >>= 1n;
|
|
95
|
+
const n = v >> i;
|
|
96
|
+
if (n !== 0n) {
|
|
97
|
+
result += i;
|
|
98
|
+
v = n;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//
|
|
102
|
+
// 3. Remainder Phase.
|
|
103
|
+
//
|
|
104
|
+
// We know that `v` is less than `1n << 1023` so we can calculate a remainder using
|
|
105
|
+
// `Math.log2`.
|
|
106
|
+
const rem = BigInt(Math.log2(Number(v)) | 0);
|
|
107
|
+
// (v >> rem) is either `0` or `1`, and it's used as a correction for
|
|
108
|
+
// Math.log2 rounding.
|
|
109
|
+
return result + rem + (v >> rem);
|
|
110
|
+
};
|
|
67
111
|
const benchmark = f => () => {
|
|
68
112
|
let e = 1048575n;
|
|
69
113
|
let c = 1n << e;
|
|
@@ -130,14 +174,19 @@ export default {
|
|
|
130
174
|
if (m !== 3n) {
|
|
131
175
|
throw m;
|
|
132
176
|
}
|
|
177
|
+
const c = combination(3n, 2n, 1n); // 60n
|
|
178
|
+
if (c !== 60n) {
|
|
179
|
+
throw c;
|
|
180
|
+
}
|
|
133
181
|
},
|
|
134
182
|
benchmark: () => {
|
|
135
183
|
const list = {
|
|
136
|
-
strBinLog2,
|
|
137
|
-
strHexLog2,
|
|
184
|
+
// strBinLog2,
|
|
185
|
+
// strHexLog2,
|
|
138
186
|
str32Log2,
|
|
139
|
-
oldLog2,
|
|
140
|
-
clz32Log2,
|
|
187
|
+
// oldLog2,
|
|
188
|
+
// clz32Log2,
|
|
189
|
+
// m1023log2,
|
|
141
190
|
log2,
|
|
142
191
|
};
|
|
143
192
|
const transform = (b) => Object.fromEntries(Object.entries(list).map(([k, f]) => [k, b(f)]));
|
|
@@ -346,5 +395,61 @@ export default {
|
|
|
346
395
|
}
|
|
347
396
|
},
|
|
348
397
|
]
|
|
398
|
+
},
|
|
399
|
+
factorial: () => {
|
|
400
|
+
{
|
|
401
|
+
const r = factorial(3n);
|
|
402
|
+
if (r !== 6n) {
|
|
403
|
+
throw r;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
{
|
|
407
|
+
const r = factorial(5n);
|
|
408
|
+
if (r !== 120n) {
|
|
409
|
+
throw r;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
combination: () => {
|
|
414
|
+
const r = combination(2n, 3n);
|
|
415
|
+
if (r != 120n / (2n * 6n)) {
|
|
416
|
+
throw r;
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
combination50x50: () => {
|
|
420
|
+
{
|
|
421
|
+
const r = combination(1n, 1n);
|
|
422
|
+
if (r !== 2n) {
|
|
423
|
+
throw r;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
{
|
|
427
|
+
const r = combination(2n, 2n);
|
|
428
|
+
if (r !== 6n) {
|
|
429
|
+
throw r;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
{
|
|
433
|
+
const r = combination(3n, 3n);
|
|
434
|
+
if (r !== 20n) {
|
|
435
|
+
throw r;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
{
|
|
439
|
+
const r = combination(4n, 4n);
|
|
440
|
+
if (r !== 70n) {
|
|
441
|
+
throw r;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
combination3: () => {
|
|
446
|
+
const r = combination(2n, 3n, 4n, 2n);
|
|
447
|
+
// 2! * 3! * 4! * 2! : 2! * 2! * 3!
|
|
448
|
+
// 2+3+4+2 = 5*6*7*8*9*10*11
|
|
449
|
+
// e = 5 * 6 * 7 * 8 * 9 * 10 * 11 / (2n * 2n * 6n) =
|
|
450
|
+
// e = 5 * 7 * 2 * 9 * 10 * 11 = 69300
|
|
451
|
+
if (r !== 69300n) {
|
|
452
|
+
throw r;
|
|
453
|
+
}
|
|
349
454
|
}
|
|
350
455
|
};
|
|
@@ -4,3 +4,7 @@ export declare const sum: (input: List<number>) => number;
|
|
|
4
4
|
export declare const min: (input: List<number>) => number | null;
|
|
5
5
|
export declare const max: (input: List<number>) => number | null;
|
|
6
6
|
export declare const cmp: (a: number) => (b: number) => Sign;
|
|
7
|
+
/**
|
|
8
|
+
* Count a number of ones in 32 bit number
|
|
9
|
+
*/
|
|
10
|
+
export declare const countOnes: (n: number) => number;
|
package/types/number/module.f.js
CHANGED
|
@@ -5,3 +5,19 @@ export const sum = reduce(addition)(0);
|
|
|
5
5
|
export const min = reduce(minOp)(null);
|
|
6
6
|
export const max = reduce(maxOp)(null);
|
|
7
7
|
export const cmp = unsafeCmp;
|
|
8
|
+
const mo = [
|
|
9
|
+
[0x5555_5555, 1],
|
|
10
|
+
[0x3333_3333, 2],
|
|
11
|
+
[0x0F0F_0F0F, 4],
|
|
12
|
+
[0x00FF_00FF, 8],
|
|
13
|
+
[0x0000_FFFF, 16],
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Count a number of ones in 32 bit number
|
|
17
|
+
*/
|
|
18
|
+
export const countOnes = (n) => {
|
|
19
|
+
for (const [mask, offset] of mo) {
|
|
20
|
+
n = (n & mask) + ((n >> offset) & mask);
|
|
21
|
+
}
|
|
22
|
+
return n;
|
|
23
|
+
};
|
package/types/number/test.f.d.ts
CHANGED
package/types/number/test.f.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sum, min, max, cmp } from "./module.f.js";
|
|
1
|
+
import { sum, min, max, cmp, countOnes } from "./module.f.js";
|
|
2
2
|
export default {
|
|
3
3
|
sum: () => {
|
|
4
4
|
const result = sum([2, 3, 4, 5]);
|
|
@@ -34,7 +34,7 @@ export default {
|
|
|
34
34
|
},
|
|
35
35
|
standard: () => {
|
|
36
36
|
const check = a => b => {
|
|
37
|
-
if (BigInt(Number(a))
|
|
37
|
+
if (BigInt(Number(a)) !== b) {
|
|
38
38
|
throw [a, b];
|
|
39
39
|
}
|
|
40
40
|
};
|
|
@@ -119,5 +119,21 @@ export default {
|
|
|
119
119
|
// 4_3210_FEDC_BA98_7654_3210_FEDC_BA98_7654_3210_FEDC_BA98_7654_3210_1234
|
|
120
120
|
check(104002482718319358n)(104002482718319360n);
|
|
121
121
|
check(142693895881191444n)(142693895881191440n);
|
|
122
|
-
}
|
|
122
|
+
},
|
|
123
|
+
countOnes: [
|
|
124
|
+
() => {
|
|
125
|
+
// 1121 2231 = 5 + 8 = 13
|
|
126
|
+
const r = countOnes(0x1234_5678);
|
|
127
|
+
if (r !== 13) {
|
|
128
|
+
throw r;
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
() => {
|
|
132
|
+
// 2232 3340 = 9 + 10 = 19
|
|
133
|
+
const r = countOnes(0x9ABC_DEF0);
|
|
134
|
+
if (r !== 19) {
|
|
135
|
+
throw r;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
]
|
|
123
139
|
};
|