functionalscript 0.8.0 → 0.8.1
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/bnf/data/module.f.d.ts +6 -0
- package/bnf/data/module.f.js +57 -4
- package/bnf/data/test.f.d.ts +1 -0
- package/bnf/data/test.f.js +67 -1
- package/ci/module.f.d.ts +3 -0
- package/ci/module.f.js +169 -0
- package/ci/module.js +3 -0
- package/crypto/hmac/module.f.d.ts +5 -4
- package/crypto/hmac/module.f.js +9 -18
- package/crypto/hmac/test.f.d.ts +1 -0
- package/crypto/hmac/test.f.js +16 -8
- package/crypto/prime_field/module.f.d.ts +1 -1
- package/crypto/prime_field/module.f.js +4 -3
- package/crypto/prime_field/test.f.js +13 -13
- package/crypto/rfc6979/module.f.d.ts +15 -0
- package/crypto/rfc6979/module.f.js +98 -0
- package/crypto/rfc6979/test.f.d.ts +10 -0
- package/crypto/rfc6979/test.f.js +490 -0
- package/crypto/secp/module.f.d.ts +4 -4
- package/crypto/secp/module.f.js +1 -1
- package/crypto/secp/test.f.js +8 -8
- package/crypto/sha2/module.f.d.ts +11 -5
- package/crypto/sha2/module.f.js +4 -3
- package/crypto/sha2/test.f.d.ts +4 -1
- package/crypto/sha2/test.f.js +41 -31
- package/crypto/sign/module.f.d.ts +1 -1
- package/crypto/sign/module.f.js +3 -2
- package/dev/tf/all.test.js +9 -1
- package/djs/ast/module.f.d.ts +3 -3
- package/djs/ast/test.f.js +7 -8
- package/djs/parser/module.f.d.ts +3 -3
- package/djs/parser/module.f.js +4 -4
- package/djs/parser/test.f.js +76 -77
- package/djs/serializer/module.f.d.ts +8 -8
- package/djs/serializer/module.f.js +4 -7
- package/djs/serializer/test.f.js +8 -9
- package/djs/tokenizer/module.f.d.ts +2 -2
- package/djs/tokenizer/module.f.js +3 -5
- package/djs/tokenizer/test.f.js +8 -10
- package/djs/transpiler/module.f.d.ts +3 -3
- package/djs/transpiler/module.f.js +2 -0
- package/fsc/bnf.f.d.ts +1 -1
- package/fsc/bnf.f.js +39 -51
- package/fsc/json.f.d.ts +1 -1
- package/fsc/json.f.js +56 -81
- package/fsc/test.f.js +4 -6
- package/fsm/module.f.js +3 -3
- package/fsm/test.f.js +21 -25
- package/html/module.f.js +17 -4
- package/html/test.f.d.ts +7 -0
- package/html/test.f.js +37 -0
- package/issues/031-json.f.d.ts +1 -0
- package/js/tokenizer/module.f.d.ts +4 -4
- package/js/tokenizer/module.f.js +12 -17
- package/js/tokenizer/test.f.js +9 -11
- package/json/module.f.d.ts +6 -6
- package/json/module.f.js +5 -10
- package/json/parser/module.f.d.ts +4 -4
- package/json/parser/module.f.js +7 -4
- package/json/parser/test.f.js +47 -49
- package/json/serializer/module.f.d.ts +6 -6
- package/json/serializer/module.f.js +3 -2
- package/json/serializer/test.f.js +13 -13
- package/json/test.f.js +13 -15
- package/json/tokenizer/module.f.d.ts +4 -4
- package/json/tokenizer/module.f.js +6 -7
- package/json/tokenizer/test.f.js +7 -9
- package/package.json +5 -5
- package/text/ascii/test.f.js +2 -2
- package/text/module.f.d.ts +3 -2
- package/text/module.f.js +2 -2
- package/text/test.f.js +3 -3
- package/text/utf16/test.f.js +2 -2
- package/text/utf8/test.f.js +2 -2
- package/types/array/test.f.js +2 -2
- package/types/bigint/module.f.d.ts +6 -3
- package/types/bigint/module.f.js +12 -11
- package/types/bigint/test.f.d.ts +2 -0
- package/types/bigint/test.f.js +21 -2
- package/types/bit_vec/module.f.d.ts +66 -34
- package/types/bit_vec/module.f.js +97 -32
- package/types/bit_vec/test.f.d.ts +7 -0
- package/types/bit_vec/test.f.js +283 -62
- package/types/btree/find/test.f.js +9 -8
- package/types/btree/remove/test.f.js +4 -4
- package/types/btree/set/test.f.js +4 -4
- package/types/btree/test.f.js +7 -7
- package/types/byte_set/test.f.js +2 -2
- package/types/function/compare/module.f.d.ts +15 -1
- package/types/function/compare/module.f.js +1 -1
- package/types/function/compare/test.f.js +37 -4
- package/types/list/test.f.js +93 -93
- package/types/monoid/module.f.d.ts +4 -4
- package/types/monoid/module.f.js +3 -3
- package/types/monoid/test.f.js +3 -3
- package/types/nominal/module.f.d.ts +5 -0
- package/types/nominal/module.f.js +4 -0
- package/types/nominal/test.f.d.ts +5 -0
- package/types/nominal/test.f.js +53 -0
- package/types/number/module.f.js +2 -2
- package/types/range_map/test.f.js +21 -21
- package/types/sorted_list/test.f.js +10 -10
- package/types/sorted_set/test.f.js +14 -14
- package/types/string/module.f.js +2 -2
- package/types/string_set/module.f.js +3 -3
- package/bnf/func/module.f.d.ts +0 -148
- package/bnf/func/module.f.js +0 -132
- package/bnf/func/test.f.d.ts +0 -12
- package/bnf/func/test.f.js +0 -171
- package/bnf/func/testlib.f.d.ts +0 -25
- package/bnf/func/testlib.f.js +0 -150
- /package/{issues/31-json.f.d.ts → ci/module.d.ts} +0 -0
- /package/issues/{31-json.f.js → 031-json.f.js} +0 -0
package/bnf/data/module.f.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type Rule = Variant | Sequence | TerminalRange;
|
|
|
11
11
|
/** The full grammar */
|
|
12
12
|
export type RuleSet = Readonly<Record<string, Rule>>;
|
|
13
13
|
type EmptyTag = string | true | undefined;
|
|
14
|
+
type EmptyTagEntry = string | boolean;
|
|
14
15
|
type DispatchRule = {
|
|
15
16
|
readonly emptyTag: EmptyTag;
|
|
16
17
|
readonly rangeMap: Dispatch;
|
|
@@ -25,6 +26,10 @@ type DispatchRuleCollection = {
|
|
|
25
26
|
type DispatchMap = {
|
|
26
27
|
readonly [id in string]: DispatchRule;
|
|
27
28
|
};
|
|
29
|
+
type EmptyTagMap = {
|
|
30
|
+
readonly [id in string]: EmptyTagEntry;
|
|
31
|
+
};
|
|
32
|
+
export type DescentMatchRule = (r: Rule, s: readonly CodePoint[], idx: number) => MatchResult;
|
|
28
33
|
/**
|
|
29
34
|
* Represents a parsed Abstract Syntax Tree (AST) sequence.
|
|
30
35
|
*/
|
|
@@ -52,6 +57,7 @@ export type Match = (name: string, s: readonly CodePoint[]) => MatchResult;
|
|
|
52
57
|
export type MatchRule = (dr: DispatchRule, s: readonly CodePoint[]) => MatchResult;
|
|
53
58
|
export declare const toData: (fr: FRule) => readonly [RuleSet, string];
|
|
54
59
|
export declare const dispatchMap: (ruleSet: RuleSet) => DispatchMap;
|
|
60
|
+
export declare const createEmptyTagMap: (data: readonly [RuleSet, string]) => EmptyTagMap;
|
|
55
61
|
export declare const parser: (fr: FRule) => Match;
|
|
56
62
|
export declare const parserRuleSet: (ruleSet: RuleSet) => Match;
|
|
57
63
|
export {};
|
package/bnf/data/module.f.js
CHANGED
|
@@ -161,6 +161,62 @@ export const dispatchMap = (ruleSet) => {
|
|
|
161
161
|
}
|
|
162
162
|
return result;
|
|
163
163
|
};
|
|
164
|
+
const emptyTagMapAdd = (ruleSet) => (map) => (name) => {
|
|
165
|
+
if (name in map) {
|
|
166
|
+
return [ruleSet, map, map[name]];
|
|
167
|
+
}
|
|
168
|
+
const rule = ruleSet[name];
|
|
169
|
+
if (typeof rule === 'number') {
|
|
170
|
+
return [ruleSet, { ...map, [name]: false }, false];
|
|
171
|
+
}
|
|
172
|
+
else if (rule instanceof Array) {
|
|
173
|
+
map = { ...map, [name]: true };
|
|
174
|
+
let emptyTag = rule.length == 0;
|
|
175
|
+
for (const item of rule) {
|
|
176
|
+
const [, newMap, itemEmptyTag] = emptyTagMapAdd(ruleSet)(map)(item);
|
|
177
|
+
map = newMap;
|
|
178
|
+
if (emptyTag === false) {
|
|
179
|
+
emptyTag = itemEmptyTag !== false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return [ruleSet, { ...map, [name]: emptyTag }, emptyTag];
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
map = { ...map, [name]: true };
|
|
186
|
+
const entries = Object.entries(rule);
|
|
187
|
+
let emptyTag = false;
|
|
188
|
+
for (const [tag, item] of entries) {
|
|
189
|
+
const [, newMap, itemEmptyTag] = emptyTagMapAdd(ruleSet)(map)(item);
|
|
190
|
+
map = newMap;
|
|
191
|
+
if (itemEmptyTag !== false) {
|
|
192
|
+
emptyTag = tag;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return [ruleSet, { ...map, [name]: emptyTag }, emptyTag];
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
export const createEmptyTagMap = (data) => {
|
|
199
|
+
return emptyTagMapAdd(data[0])({})(data[1])[1];
|
|
200
|
+
};
|
|
201
|
+
// export const parserDescent = (fr: FRule): Match => {
|
|
202
|
+
// const data = toData(fr)
|
|
203
|
+
// const getEmptyTag = (rule: Rule): EmptyTag => {
|
|
204
|
+
// return todo()
|
|
205
|
+
// }
|
|
206
|
+
// const f: DescentMatchRule = (r, cp, idx): MatchResult => {
|
|
207
|
+
// const mrSuccess = (tag: AstTag, sequence: AstSequence, r: Remainder): MatchResult => [{tag, sequence}, true, r]
|
|
208
|
+
// const mrFail = (tag: AstTag, sequence: AstSequence, r: Remainder): MatchResult => [{tag, sequence}, false, r]
|
|
209
|
+
// if (idx >= cp.length) {
|
|
210
|
+
// const emptyTag = getEmptyTag(r)
|
|
211
|
+
// return mrSuccess(emptyTag, [], emptyTag === undefined ? null : cp)
|
|
212
|
+
// }
|
|
213
|
+
// return todo()
|
|
214
|
+
// }
|
|
215
|
+
// const match: Match = (name, cp): MatchResult => {
|
|
216
|
+
// return f(data[0][name], cp, 0)
|
|
217
|
+
// }
|
|
218
|
+
// return match
|
|
219
|
+
// }
|
|
164
220
|
export const parser = (fr) => {
|
|
165
221
|
const data = toData(fr);
|
|
166
222
|
return parserRuleSet(data[0]);
|
|
@@ -202,8 +258,5 @@ export const parserRuleSet = (ruleSet) => {
|
|
|
202
258
|
}
|
|
203
259
|
return mrSuccess(tag, seq, r);
|
|
204
260
|
};
|
|
205
|
-
|
|
206
|
-
return f(map[name], cp);
|
|
207
|
-
};
|
|
208
|
-
return match;
|
|
261
|
+
return (name, cp) => f(map[name], cp);
|
|
209
262
|
};
|
package/bnf/data/test.f.d.ts
CHANGED
package/bnf/data/test.f.js
CHANGED
|
@@ -5,7 +5,7 @@ import { toArray } from "../../types/list/module.f.js";
|
|
|
5
5
|
import { sort } from "../../types/object/module.f.js";
|
|
6
6
|
import { join0Plus, max, option, range, remove, repeat, repeat0Plus, set } from "../module.f.js";
|
|
7
7
|
import { classic, deterministic } from "../testlib.f.js";
|
|
8
|
-
import { dispatchMap, parser, parserRuleSet, toData } from "./module.f.js";
|
|
8
|
+
import { dispatchMap, parser, parserRuleSet, toData, createEmptyTagMap } from "./module.f.js";
|
|
9
9
|
export default {
|
|
10
10
|
toData: [
|
|
11
11
|
() => {
|
|
@@ -87,6 +87,72 @@ export default {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
],
|
|
90
|
+
emptyTags: [
|
|
91
|
+
() => {
|
|
92
|
+
const stringRule = 'true';
|
|
93
|
+
const data = toData(stringRule);
|
|
94
|
+
const emptyTags = createEmptyTagMap(data);
|
|
95
|
+
const result = JSON.stringify(emptyTags);
|
|
96
|
+
if (result !== '{"0":false,"1":false,"2":false,"3":false,"":false}') {
|
|
97
|
+
throw result;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
() => {
|
|
101
|
+
const terminalRangeRule = range('AF');
|
|
102
|
+
const data = toData(terminalRangeRule);
|
|
103
|
+
const emptyTags = createEmptyTagMap(data);
|
|
104
|
+
const result = JSON.stringify(emptyTags);
|
|
105
|
+
if (result !== '{"":false}') {
|
|
106
|
+
throw result;
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
() => {
|
|
110
|
+
const varintRule = { true: 'true', false: 'false' };
|
|
111
|
+
const data = toData(varintRule);
|
|
112
|
+
const emptyTags = createEmptyTagMap(data);
|
|
113
|
+
const result = JSON.stringify(emptyTags);
|
|
114
|
+
if (result !== '{"0":false,"1":false,"2":false,"3":false,"4":false,"5":false,"6":false,"7":false,"8":false,"9":false,"":false}') {
|
|
115
|
+
throw result;
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
() => {
|
|
119
|
+
const emptyRule = '';
|
|
120
|
+
const data = toData(emptyRule);
|
|
121
|
+
const emptyTags = createEmptyTagMap(data);
|
|
122
|
+
const result = JSON.stringify(emptyTags);
|
|
123
|
+
if (result !== '{"":true}') {
|
|
124
|
+
throw result;
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
() => {
|
|
128
|
+
const emptyRule = '';
|
|
129
|
+
const varintRule = { true: 'true', e: emptyRule };
|
|
130
|
+
const data = toData(varintRule);
|
|
131
|
+
const emptyTags = createEmptyTagMap(data);
|
|
132
|
+
const result = JSON.stringify(emptyTags);
|
|
133
|
+
if (result !== '{"0":false,"1":false,"2":false,"3":false,"4":false,"5":true,"":"e"}') {
|
|
134
|
+
throw result;
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
() => {
|
|
138
|
+
const repeatRule = repeat0Plus(option('a'));
|
|
139
|
+
const data = toData(repeatRule);
|
|
140
|
+
const emptyTags = createEmptyTagMap(data);
|
|
141
|
+
const result = JSON.stringify(emptyTags);
|
|
142
|
+
if (result !== '{"0":"none","1":false,"2":false,"3":true,"r":"none","":true}') {
|
|
143
|
+
throw result;
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
() => {
|
|
147
|
+
const repeatRule = repeat0Plus(set(' \n\r\t'));
|
|
148
|
+
const data = toData(repeatRule);
|
|
149
|
+
const emptyTags = createEmptyTagMap(data);
|
|
150
|
+
const result = JSON.stringify(emptyTags);
|
|
151
|
+
if (result !== '{"0":false,"1":false,"2":false,"3":false,"4":false,"5":true,"r":"none","":true}') {
|
|
152
|
+
throw result;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
],
|
|
90
156
|
variantTest: () => {
|
|
91
157
|
const varintRule = { a: 'a', b: 'b' };
|
|
92
158
|
const result = stringify(sort)(toData(varintRule));
|
package/ci/module.f.d.ts
ADDED
package/ci/module.f.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
const os = ['ubuntu', 'macos', 'windows'];
|
|
2
|
+
const architecture = ['intel', 'arm'];
|
|
3
|
+
// https://docs.github.com/en/actions/reference/runners/github-hosted-runners#standard-github-hosted-runners-for-public-repositories
|
|
4
|
+
const images = {
|
|
5
|
+
ubuntu: {
|
|
6
|
+
intel: 'ubuntu-latest',
|
|
7
|
+
arm: 'ubuntu-24.04-arm'
|
|
8
|
+
},
|
|
9
|
+
macos: {
|
|
10
|
+
intel: 'macos-15-intel',
|
|
11
|
+
arm: 'macos-latest'
|
|
12
|
+
},
|
|
13
|
+
windows: {
|
|
14
|
+
intel: 'windows-latest',
|
|
15
|
+
arm: 'windows-11-arm',
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const install = (step) => ({ type: 'install', step });
|
|
19
|
+
const test = (step) => ({ type: 'test', step });
|
|
20
|
+
const installOnWindowsArm = ({ def, name, path }) => (v) => (a) => install(v === 'windows' && a === 'arm'
|
|
21
|
+
? { run: `irm ${path}/install.ps1 | iex; "$env:USERPROFILE\\.${name}\\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append` }
|
|
22
|
+
: def);
|
|
23
|
+
const installBun = installOnWindowsArm({
|
|
24
|
+
def: { uses: 'oven-sh/setup-bun@v1' },
|
|
25
|
+
name: 'bun',
|
|
26
|
+
path: 'bun.sh'
|
|
27
|
+
});
|
|
28
|
+
const installDeno = installOnWindowsArm({
|
|
29
|
+
def: { uses: 'denoland/setup-deno@v2', with: { 'deno-version': '2' } },
|
|
30
|
+
name: 'deno',
|
|
31
|
+
path: 'deno.land'
|
|
32
|
+
});
|
|
33
|
+
const cargoTest = (target, config) => {
|
|
34
|
+
const to = target ? ` --target ${target}` : '';
|
|
35
|
+
const co = config ? ` --config ${config}` : '';
|
|
36
|
+
const main = `cargo test${to}${co}`;
|
|
37
|
+
return [
|
|
38
|
+
test({ run: main }),
|
|
39
|
+
test({ run: `${main} --release` })
|
|
40
|
+
];
|
|
41
|
+
};
|
|
42
|
+
const customTarget = (target) => [
|
|
43
|
+
{ type: 'rust', target },
|
|
44
|
+
...cargoTest(target)
|
|
45
|
+
];
|
|
46
|
+
const wasmTarget = (target) => [
|
|
47
|
+
...customTarget(target),
|
|
48
|
+
...cargoTest(target, '.cargo/config.wasmer.toml')
|
|
49
|
+
];
|
|
50
|
+
const clean = (steps) => [
|
|
51
|
+
...steps,
|
|
52
|
+
test({ run: 'git reset --hard HEAD && git clean -fdx' })
|
|
53
|
+
];
|
|
54
|
+
const installNode = (version) => ({ uses: 'actions/setup-node@v6', with: { 'node-version': version } });
|
|
55
|
+
const basicNode = (version) => (extra) => clean([
|
|
56
|
+
install(installNode(version)),
|
|
57
|
+
test({ run: 'npm ci' }),
|
|
58
|
+
...extra,
|
|
59
|
+
]);
|
|
60
|
+
const node = (version) => (extra) => basicNode(version)([
|
|
61
|
+
test({ run: 'npm test' }),
|
|
62
|
+
test({ run: 'npm run fst' }),
|
|
63
|
+
...extra,
|
|
64
|
+
]);
|
|
65
|
+
const findTgz = (v) => v === 'windows' ? '(Get-ChildItem *.tgz).FullName' : './*.tgz';
|
|
66
|
+
const toSteps = (m) => {
|
|
67
|
+
const filter = (st) => m.flatMap((mt) => mt.type === st ? [mt.step] : []);
|
|
68
|
+
const aptGet = m.flatMap(v => v.type === 'apt-get' ? [v.package] : []).join(' ');
|
|
69
|
+
const rust = m.find(v => v.type === 'rust') !== undefined;
|
|
70
|
+
const targets = m.flatMap(v => v.type === 'rust' && v.target !== undefined ? [v.target] : []).join(',');
|
|
71
|
+
return [
|
|
72
|
+
...(aptGet !== '' ? [{ run: `sudo apt-get update && sudo apt-get install -y ${aptGet}` }] : []),
|
|
73
|
+
...(rust ? [{
|
|
74
|
+
// wasm32-wasip1-threads doesn't work on Rust 1.91 in the release mode.
|
|
75
|
+
// See https://github.com/sergey-shandar/wasmtime-crash
|
|
76
|
+
uses: 'dtolnay/rust-toolchain@1.90.0',
|
|
77
|
+
with: {
|
|
78
|
+
components: 'rustfmt,clippy',
|
|
79
|
+
targets
|
|
80
|
+
}
|
|
81
|
+
}] : []),
|
|
82
|
+
...filter('install'),
|
|
83
|
+
{ uses: 'actions/checkout@v5' },
|
|
84
|
+
...filter('test'),
|
|
85
|
+
];
|
|
86
|
+
};
|
|
87
|
+
const nodes = ['20', '22', '25'];
|
|
88
|
+
const nodeTest = (v) => v === '20' ? 'run test20' : 'test';
|
|
89
|
+
const nodeSteps = (v) => [
|
|
90
|
+
install(installNode(v)),
|
|
91
|
+
test({ run: 'npm ci' }),
|
|
92
|
+
test({ run: `npm ${nodeTest(v)}` }),
|
|
93
|
+
];
|
|
94
|
+
const ubuntu = (ms) => ({
|
|
95
|
+
'runs-on': 'ubuntu-latest',
|
|
96
|
+
steps: toSteps(ms)
|
|
97
|
+
});
|
|
98
|
+
const nodeVersions = Object.fromEntries(nodes.map(v => [`node${v}`, ubuntu(nodeSteps(v))]));
|
|
99
|
+
const steps = (v) => (a) => {
|
|
100
|
+
const result = [
|
|
101
|
+
// Rust
|
|
102
|
+
test({ run: 'cargo fmt -- --check' }),
|
|
103
|
+
test({ run: 'cargo clippy -- -D warnings' }),
|
|
104
|
+
...cargoTest(),
|
|
105
|
+
install({ uses: 'bytecodealliance/actions/wasmtime/setup@v1' }),
|
|
106
|
+
install({ uses: 'wasmerio/setup-wasmer@v1' }),
|
|
107
|
+
...wasmTarget('wasm32-wasip1'),
|
|
108
|
+
...wasmTarget('wasm32-wasip2'),
|
|
109
|
+
...wasmTarget('wasm32-unknown-unknown'),
|
|
110
|
+
...wasmTarget('wasm32-wasip1-threads'),
|
|
111
|
+
...(a !== 'intel' ? [] :
|
|
112
|
+
v === 'windows' ?
|
|
113
|
+
customTarget('i686-pc-windows-msvc') :
|
|
114
|
+
v === 'ubuntu' ? [
|
|
115
|
+
{ type: 'apt-get', package: 'libc6-dev-i386' },
|
|
116
|
+
...customTarget('i686-unknown-linux-gnu'),
|
|
117
|
+
] :
|
|
118
|
+
[]),
|
|
119
|
+
// Node.js
|
|
120
|
+
...node('24')([
|
|
121
|
+
// TypeScript Preview
|
|
122
|
+
install({ run: 'npm install -g @typescript/native-preview' }),
|
|
123
|
+
test({ run: 'tsgo' }),
|
|
124
|
+
// Playwright
|
|
125
|
+
install({ run: 'npm install -g playwright' }),
|
|
126
|
+
install({ run: 'playwright install --with-deps' }),
|
|
127
|
+
...['chromium', 'firefox', 'webkit'].map(browser => (test({ run: `npx playwright test --browser=${browser}` }))),
|
|
128
|
+
// publishing
|
|
129
|
+
test({ run: 'npm pack' }),
|
|
130
|
+
test({ run: `npm install -g ${findTgz(v)}` }),
|
|
131
|
+
test({ run: 'fsc issues/demo/data/tree.json _tree.f.js' }),
|
|
132
|
+
test({ run: 'fst' }),
|
|
133
|
+
test({ run: 'npm uninstall functionalscript -g' }),
|
|
134
|
+
]),
|
|
135
|
+
// Deno
|
|
136
|
+
...clean([
|
|
137
|
+
installDeno(v)(a),
|
|
138
|
+
test({ run: 'deno install' }),
|
|
139
|
+
test({ run: 'deno task test' }),
|
|
140
|
+
test({ run: 'deno task fst' }),
|
|
141
|
+
test({ run: 'deno publish --dry-run' }),
|
|
142
|
+
]),
|
|
143
|
+
// Bun
|
|
144
|
+
...clean([
|
|
145
|
+
installBun(v)(a),
|
|
146
|
+
test({ run: 'bun test --timeout 20000' }),
|
|
147
|
+
test({ run: 'bun ./dev/tf/module.ts' }),
|
|
148
|
+
]),
|
|
149
|
+
];
|
|
150
|
+
return toSteps(result);
|
|
151
|
+
};
|
|
152
|
+
const jobs = {
|
|
153
|
+
...Object.fromEntries([
|
|
154
|
+
...os.flatMap(v => architecture.map(a => [`${v}-${a}`, {
|
|
155
|
+
'runs-on': images[v][a],
|
|
156
|
+
steps: steps(v)(a),
|
|
157
|
+
}]))
|
|
158
|
+
]),
|
|
159
|
+
...nodeVersions,
|
|
160
|
+
};
|
|
161
|
+
const gha = {
|
|
162
|
+
name: 'CI',
|
|
163
|
+
on: { pull_request: {} },
|
|
164
|
+
jobs,
|
|
165
|
+
};
|
|
166
|
+
export default async (io) => {
|
|
167
|
+
io.fs.writeFileSync('.github/workflows/ci.yml', JSON.stringify(gha, null, ' '));
|
|
168
|
+
return 0;
|
|
169
|
+
};
|
package/ci/module.js
ADDED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Provides an implementation of HMAC (Hash-based Message Authentication Code).
|
|
3
3
|
*
|
|
4
4
|
* https://en.wikipedia.org/wiki/HMAC
|
|
5
|
+
* https://www.rfc-editor.org/rfc/rfc2104
|
|
5
6
|
*
|
|
6
7
|
* @module
|
|
7
8
|
*
|
|
@@ -16,13 +17,13 @@
|
|
|
16
17
|
* if (r !== vec(256n)(0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8n)) { throw r }
|
|
17
18
|
* ```
|
|
18
19
|
*/
|
|
19
|
-
import { type
|
|
20
|
+
import { type Reduce } from '../../types/bit_vec/module.f.ts';
|
|
20
21
|
import { type Sha2 } from '../sha2/module.f.ts';
|
|
21
22
|
/**
|
|
22
|
-
* Generates an HMAC (Hash-based Message Authentication Code) using the specified
|
|
23
|
+
* Generates an HMAC (Hash-based Message Authentication Code) using the specified hash function.
|
|
23
24
|
*
|
|
24
|
-
* @param
|
|
25
|
+
* @param hashFunc - The hash function implementation to use.
|
|
25
26
|
* @returns - A function that takes a key and returns another function
|
|
26
27
|
* that takes a message and computes the HMAC.
|
|
27
28
|
*/
|
|
28
|
-
export declare const hmac: (
|
|
29
|
+
export declare const hmac: (hashFunc: Sha2) => Reduce;
|
package/crypto/hmac/module.f.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Provides an implementation of HMAC (Hash-based Message Authentication Code).
|
|
3
3
|
*
|
|
4
4
|
* https://en.wikipedia.org/wiki/HMAC
|
|
5
|
+
* https://www.rfc-editor.org/rfc/rfc2104
|
|
5
6
|
*
|
|
6
7
|
* @module
|
|
7
8
|
*
|
|
@@ -16,12 +17,9 @@
|
|
|
16
17
|
* if (r !== vec(256n)(0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8n)) { throw r }
|
|
17
18
|
* ```
|
|
18
19
|
*/
|
|
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";
|
|
20
|
+
import { length, msb, vec, vec8, repeat } from "../../types/bit_vec/module.f.js";
|
|
23
21
|
import { computeSync } from "../sha2/module.f.js";
|
|
24
|
-
const { concat } = msb;
|
|
22
|
+
const { concat, xor } = msb;
|
|
25
23
|
/**
|
|
26
24
|
* Outer padding.
|
|
27
25
|
*/
|
|
@@ -31,25 +29,18 @@ const oPad = vec8(0x5cn);
|
|
|
31
29
|
*/
|
|
32
30
|
const iPad = vec8(0x36n);
|
|
33
31
|
/**
|
|
34
|
-
*
|
|
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.
|
|
32
|
+
* Generates an HMAC (Hash-based Message Authentication Code) using the specified hash function.
|
|
39
33
|
*
|
|
40
|
-
* @param
|
|
34
|
+
* @param hashFunc - The hash function implementation to use.
|
|
41
35
|
* @returns - A function that takes a key and returns another function
|
|
42
36
|
* that takes a message and computes the HMAC.
|
|
43
37
|
*/
|
|
44
|
-
export const hmac = (
|
|
45
|
-
const { blockLength } =
|
|
46
|
-
const p =
|
|
38
|
+
export const hmac = (hashFunc) => {
|
|
39
|
+
const { blockLength } = hashFunc;
|
|
40
|
+
const p = repeat(blockLength >> 3n);
|
|
47
41
|
const ip = p(iPad);
|
|
48
42
|
const op = p(oPad);
|
|
49
|
-
const c = computeSync(
|
|
50
|
-
const vbl = vec(blockLength);
|
|
51
|
-
// a and b should have the same size
|
|
52
|
-
const xor = (a) => (b) => vbl(a ^ b);
|
|
43
|
+
const c = computeSync(hashFunc);
|
|
53
44
|
return k => {
|
|
54
45
|
const k1 = length(k) > blockLength ? c([k]) : k;
|
|
55
46
|
const k2 = concat(k1)(vec(blockLength - length(k1))(0n));
|
package/crypto/hmac/test.f.d.ts
CHANGED
package/crypto/hmac/test.f.js
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { vec } from "../../types/bit_vec/module.f.js";
|
|
3
|
-
import { sha256, sha512 } from "../sha2/module.f.js";
|
|
1
|
+
import { utf8 } from "../../text/module.f.js";
|
|
2
|
+
import { length, uint, vec } from "../../types/bit_vec/module.f.js";
|
|
3
|
+
import { sha256, sha384, sha512 } from "../sha2/module.f.js";
|
|
4
4
|
import { hmac } from "./module.f.js";
|
|
5
5
|
export default {
|
|
6
6
|
example: () => {
|
|
7
|
-
const r = hmac(sha256)(
|
|
7
|
+
const r = hmac(sha256)(utf8('key'))(utf8('The quick brown fox jumps over the lazy dog'));
|
|
8
8
|
if (r !== vec(256n)(0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8n)) {
|
|
9
9
|
throw r;
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
12
|
sha256: () => {
|
|
13
|
-
const r = hmac(sha256)(
|
|
14
|
-
if (r !==
|
|
13
|
+
const r = hmac(sha256)(utf8('key'))(utf8('The quick brown fox jumps over the lazy dog'));
|
|
14
|
+
if (uint(r) !== 0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8n) {
|
|
15
15
|
throw r;
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
|
+
sha384: () => {
|
|
19
|
+
const k = vec(384n)(0n);
|
|
20
|
+
const m = vec(904n)(0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010069c7548c21d0dfea6b9a51c9ead4e27c33d3b3f180316e5bcab92c933f0e4dbc9a9083505bc92276aec4be312696ef7bf3bf603f4bbd381196a029f340585312n);
|
|
21
|
+
const r = hmac(sha384)(k)(m);
|
|
22
|
+
if (r !== vec(384n)(0x8f858157ce005cd52fd8e8f1a46b55e6cfae21c8c183d9c2f7504bedf450609edd7d3c6171dc0bdd2d2444faa28f18ban)) {
|
|
23
|
+
throw uint(r).toString(16);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
18
26
|
sha512: () => {
|
|
19
|
-
const r = hmac(sha512)(
|
|
20
|
-
if (r !==
|
|
27
|
+
const r = hmac(sha512)(utf8('key'))(utf8('The quick brown fox jumps over the lazy dog'));
|
|
28
|
+
if (r !== vec(512n)(0xb42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3an)) {
|
|
21
29
|
throw r;
|
|
22
30
|
}
|
|
23
31
|
}
|
|
@@ -37,4 +37,4 @@ export declare const prime_field: (p: bigint) => PrimeField;
|
|
|
37
37
|
* if (root !== 2n) { throw root }
|
|
38
38
|
* ```
|
|
39
39
|
*/
|
|
40
|
-
export declare const sqrt: ({ p,
|
|
40
|
+
export declare const sqrt: ({ p, pow, pow2 }: PrimeField) => (a: bigint) => bigint | null;
|
|
@@ -65,13 +65,14 @@ export const prime_field = (p) => {
|
|
|
65
65
|
* if (root !== 2n) { throw root }
|
|
66
66
|
* ```
|
|
67
67
|
*/
|
|
68
|
-
export const sqrt = ({ p,
|
|
68
|
+
export const sqrt = ({ p, pow, pow2 }) => {
|
|
69
69
|
if ((p & 3n) !== 3n) {
|
|
70
70
|
throw 'sqrt';
|
|
71
71
|
}
|
|
72
72
|
const sqrt_k = (p + 1n) >> 2n;
|
|
73
|
+
const psk = pow(sqrt_k);
|
|
73
74
|
return a => {
|
|
74
|
-
const result =
|
|
75
|
-
return
|
|
75
|
+
const result = psk(a);
|
|
76
|
+
return pow2(result) === a ? result : null;
|
|
76
77
|
};
|
|
77
78
|
};
|
|
@@ -58,21 +58,21 @@ export default {
|
|
|
58
58
|
},
|
|
59
59
|
pow: () => {
|
|
60
60
|
const test = a => {
|
|
61
|
-
if (f.pow(
|
|
61
|
+
if (f.pow(0n)(a) !== 1n) {
|
|
62
62
|
throw '**0';
|
|
63
63
|
}
|
|
64
|
-
if (f.pow(
|
|
64
|
+
if (f.pow(1n)(a) !== a) {
|
|
65
65
|
throw '**1';
|
|
66
66
|
}
|
|
67
67
|
// https://en.wikipedia.org/wiki/Fermat%27s_little_theorem
|
|
68
68
|
// a^(p-1) % p = 1
|
|
69
|
-
if (f.abs(f.pow(
|
|
69
|
+
if (f.abs(f.pow(f.middle)(a)) !== 1n) {
|
|
70
70
|
throw '**middle';
|
|
71
71
|
}
|
|
72
|
-
if (f.pow(
|
|
72
|
+
if (f.pow(f.sub(f.max)(1n))(a) !== f.reciprocal(a)) {
|
|
73
73
|
throw '**(max-1)';
|
|
74
74
|
}
|
|
75
|
-
if (f.pow(
|
|
75
|
+
if (f.pow(f.max)(a) !== 1n) {
|
|
76
76
|
throw '**max';
|
|
77
77
|
}
|
|
78
78
|
};
|
|
@@ -80,7 +80,7 @@ export default {
|
|
|
80
80
|
if (f.pow(0n)(0n) !== 1n) {
|
|
81
81
|
throw '0**0';
|
|
82
82
|
}
|
|
83
|
-
if (f.pow(
|
|
83
|
+
if (f.pow(f.max)(0n) !== 0n) {
|
|
84
84
|
throw '0**max';
|
|
85
85
|
}
|
|
86
86
|
// 1
|
|
@@ -90,30 +90,30 @@ export default {
|
|
|
90
90
|
if (f.pow(2n)(2n) !== 4n) {
|
|
91
91
|
throw '2**2';
|
|
92
92
|
}
|
|
93
|
-
if (f.pow(
|
|
93
|
+
if (f.pow(3n)(2n) !== 8n) {
|
|
94
94
|
throw '2**3';
|
|
95
95
|
}
|
|
96
|
-
if (f.pow(
|
|
96
|
+
if (f.pow(128n)(2n) !== 1n << 128n) {
|
|
97
97
|
throw '2**128';
|
|
98
98
|
}
|
|
99
99
|
// 3
|
|
100
100
|
test(3n);
|
|
101
|
-
if (f.pow(
|
|
101
|
+
if (f.pow(2n)(3n) !== 9n) {
|
|
102
102
|
throw '3**2';
|
|
103
103
|
}
|
|
104
104
|
if (f.pow(3n)(3n) !== 27n) {
|
|
105
105
|
throw '3**3';
|
|
106
106
|
}
|
|
107
|
-
if (f.pow(
|
|
107
|
+
if (f.pow(100n)(3n) !== 3n ** 100n) {
|
|
108
108
|
throw '3**100';
|
|
109
109
|
}
|
|
110
|
-
if (f.pow(
|
|
110
|
+
if (f.pow(110n)(3n) !== 3n ** 110n) {
|
|
111
111
|
throw '3**110';
|
|
112
112
|
}
|
|
113
|
-
if (f.pow(
|
|
113
|
+
if (f.pow(120n)(3n) !== 3n ** 120n) {
|
|
114
114
|
throw '3**120';
|
|
115
115
|
}
|
|
116
|
-
if (f.pow(
|
|
116
|
+
if (f.pow(121n)(3n) !== 3n ** 121n) {
|
|
117
117
|
throw '3**121';
|
|
118
118
|
}
|
|
119
119
|
//
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Vec } from '../../types/bit_vec/module.f.ts';
|
|
2
|
+
import type { Curve } from '../secp/module.f.ts';
|
|
3
|
+
import { type Sha2 } from '../sha2/module.f.ts';
|
|
4
|
+
export type All = {
|
|
5
|
+
readonly q: bigint;
|
|
6
|
+
readonly qlen: bigint;
|
|
7
|
+
readonly bits2int: (b: Vec) => bigint;
|
|
8
|
+
readonly int2octets: (x: bigint) => Vec;
|
|
9
|
+
readonly bits2octets: (b: Vec) => Vec;
|
|
10
|
+
};
|
|
11
|
+
export declare const all: (q: bigint) => All;
|
|
12
|
+
export declare const fromCurve: (c: Curve) => All;
|
|
13
|
+
export declare const concat: (...x: readonly Vec[]) => Vec;
|
|
14
|
+
export declare const computeK: ({ q, bits2int, qlen, int2octets, bits2octets }: All) => (hf: Sha2) => (x: bigint) => (m: Vec) => bigint;
|
|
15
|
+
export declare const sign: (a: All) => (hf: Sha2) => (x: bigint) => (m: Vec) => bigint;
|