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.
Files changed (113) hide show
  1. package/bnf/data/module.f.d.ts +6 -0
  2. package/bnf/data/module.f.js +57 -4
  3. package/bnf/data/test.f.d.ts +1 -0
  4. package/bnf/data/test.f.js +67 -1
  5. package/ci/module.f.d.ts +3 -0
  6. package/ci/module.f.js +169 -0
  7. package/ci/module.js +3 -0
  8. package/crypto/hmac/module.f.d.ts +5 -4
  9. package/crypto/hmac/module.f.js +9 -18
  10. package/crypto/hmac/test.f.d.ts +1 -0
  11. package/crypto/hmac/test.f.js +16 -8
  12. package/crypto/prime_field/module.f.d.ts +1 -1
  13. package/crypto/prime_field/module.f.js +4 -3
  14. package/crypto/prime_field/test.f.js +13 -13
  15. package/crypto/rfc6979/module.f.d.ts +15 -0
  16. package/crypto/rfc6979/module.f.js +98 -0
  17. package/crypto/rfc6979/test.f.d.ts +10 -0
  18. package/crypto/rfc6979/test.f.js +490 -0
  19. package/crypto/secp/module.f.d.ts +4 -4
  20. package/crypto/secp/module.f.js +1 -1
  21. package/crypto/secp/test.f.js +8 -8
  22. package/crypto/sha2/module.f.d.ts +11 -5
  23. package/crypto/sha2/module.f.js +4 -3
  24. package/crypto/sha2/test.f.d.ts +4 -1
  25. package/crypto/sha2/test.f.js +41 -31
  26. package/crypto/sign/module.f.d.ts +1 -1
  27. package/crypto/sign/module.f.js +3 -2
  28. package/dev/tf/all.test.js +9 -1
  29. package/djs/ast/module.f.d.ts +3 -3
  30. package/djs/ast/test.f.js +7 -8
  31. package/djs/parser/module.f.d.ts +3 -3
  32. package/djs/parser/module.f.js +4 -4
  33. package/djs/parser/test.f.js +76 -77
  34. package/djs/serializer/module.f.d.ts +8 -8
  35. package/djs/serializer/module.f.js +4 -7
  36. package/djs/serializer/test.f.js +8 -9
  37. package/djs/tokenizer/module.f.d.ts +2 -2
  38. package/djs/tokenizer/module.f.js +3 -5
  39. package/djs/tokenizer/test.f.js +8 -10
  40. package/djs/transpiler/module.f.d.ts +3 -3
  41. package/djs/transpiler/module.f.js +2 -0
  42. package/fsc/bnf.f.d.ts +1 -1
  43. package/fsc/bnf.f.js +39 -51
  44. package/fsc/json.f.d.ts +1 -1
  45. package/fsc/json.f.js +56 -81
  46. package/fsc/test.f.js +4 -6
  47. package/fsm/module.f.js +3 -3
  48. package/fsm/test.f.js +21 -25
  49. package/html/module.f.js +17 -4
  50. package/html/test.f.d.ts +7 -0
  51. package/html/test.f.js +37 -0
  52. package/issues/031-json.f.d.ts +1 -0
  53. package/js/tokenizer/module.f.d.ts +4 -4
  54. package/js/tokenizer/module.f.js +12 -17
  55. package/js/tokenizer/test.f.js +9 -11
  56. package/json/module.f.d.ts +6 -6
  57. package/json/module.f.js +5 -10
  58. package/json/parser/module.f.d.ts +4 -4
  59. package/json/parser/module.f.js +7 -4
  60. package/json/parser/test.f.js +47 -49
  61. package/json/serializer/module.f.d.ts +6 -6
  62. package/json/serializer/module.f.js +3 -2
  63. package/json/serializer/test.f.js +13 -13
  64. package/json/test.f.js +13 -15
  65. package/json/tokenizer/module.f.d.ts +4 -4
  66. package/json/tokenizer/module.f.js +6 -7
  67. package/json/tokenizer/test.f.js +7 -9
  68. package/package.json +5 -5
  69. package/text/ascii/test.f.js +2 -2
  70. package/text/module.f.d.ts +3 -2
  71. package/text/module.f.js +2 -2
  72. package/text/test.f.js +3 -3
  73. package/text/utf16/test.f.js +2 -2
  74. package/text/utf8/test.f.js +2 -2
  75. package/types/array/test.f.js +2 -2
  76. package/types/bigint/module.f.d.ts +6 -3
  77. package/types/bigint/module.f.js +12 -11
  78. package/types/bigint/test.f.d.ts +2 -0
  79. package/types/bigint/test.f.js +21 -2
  80. package/types/bit_vec/module.f.d.ts +66 -34
  81. package/types/bit_vec/module.f.js +97 -32
  82. package/types/bit_vec/test.f.d.ts +7 -0
  83. package/types/bit_vec/test.f.js +283 -62
  84. package/types/btree/find/test.f.js +9 -8
  85. package/types/btree/remove/test.f.js +4 -4
  86. package/types/btree/set/test.f.js +4 -4
  87. package/types/btree/test.f.js +7 -7
  88. package/types/byte_set/test.f.js +2 -2
  89. package/types/function/compare/module.f.d.ts +15 -1
  90. package/types/function/compare/module.f.js +1 -1
  91. package/types/function/compare/test.f.js +37 -4
  92. package/types/list/test.f.js +93 -93
  93. package/types/monoid/module.f.d.ts +4 -4
  94. package/types/monoid/module.f.js +3 -3
  95. package/types/monoid/test.f.js +3 -3
  96. package/types/nominal/module.f.d.ts +5 -0
  97. package/types/nominal/module.f.js +4 -0
  98. package/types/nominal/test.f.d.ts +5 -0
  99. package/types/nominal/test.f.js +53 -0
  100. package/types/number/module.f.js +2 -2
  101. package/types/range_map/test.f.js +21 -21
  102. package/types/sorted_list/test.f.js +10 -10
  103. package/types/sorted_set/test.f.js +14 -14
  104. package/types/string/module.f.js +2 -2
  105. package/types/string_set/module.f.js +3 -3
  106. package/bnf/func/module.f.d.ts +0 -148
  107. package/bnf/func/module.f.js +0 -132
  108. package/bnf/func/test.f.d.ts +0 -12
  109. package/bnf/func/test.f.js +0 -171
  110. package/bnf/func/testlib.f.d.ts +0 -25
  111. package/bnf/func/testlib.f.js +0 -150
  112. /package/{issues/31-json.f.d.ts → ci/module.d.ts} +0 -0
  113. /package/issues/{31-json.f.js → 031-json.f.js} +0 -0
@@ -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 {};
@@ -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
- const match = (name, cp) => {
206
- return f(map[name], cp);
207
- };
208
- return match;
261
+ return (name, cp) => f(map[name], cp);
209
262
  };
@@ -1,5 +1,6 @@
1
1
  declare const _default: {
2
2
  toData: (() => void)[];
3
+ emptyTags: (() => void)[];
3
4
  variantTest: () => void;
4
5
  dispatch: (() => void)[];
5
6
  parser: (() => void)[];
@@ -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));
@@ -0,0 +1,3 @@
1
+ import type { Io } from '../io/module.f.ts';
2
+ declare const _default: (io: Io) => Promise<number>;
3
+ export default _default;
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
@@ -0,0 +1,3 @@
1
+ import node from "../io/module.js";
2
+ import x from "./module.f.js";
3
+ await node(x);
@@ -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 Vec } from '../../types/bit_vec/module.f.ts';
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 SHA-2 hash function.
23
+ * Generates an HMAC (Hash-based Message Authentication Code) using the specified hash function.
23
24
  *
24
- * @param sha2 - The SHA-2 hash function implementation to use.
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: (sha2: Sha2) => (k: Vec) => (m: Vec) => Vec;
29
+ export declare const hmac: (hashFunc: Sha2) => Reduce;
@@ -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
- * 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.
32
+ * Generates an HMAC (Hash-based Message Authentication Code) using the specified hash function.
39
33
  *
40
- * @param sha2 - The SHA-2 hash function implementation to use.
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 = (sha2) => {
45
- const { blockLength } = sha2;
46
- const p = flip(padRepeat)(blockLength >> 3n);
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(sha2);
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));
@@ -1,6 +1,7 @@
1
1
  declare const _default: {
2
2
  example: () => void;
3
3
  sha256: () => void;
4
+ sha384: () => void;
4
5
  sha512: () => void;
5
6
  };
6
7
  export default _default;
@@ -1,23 +1,31 @@
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";
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)(msbUtf8('key'))(msbUtf8('The quick brown fox jumps over the lazy dog'));
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)(msbUtf8('key'))(msbUtf8('The quick brown fox jumps over the lazy dog'));
14
- if (r !== 0x1f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8n) {
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)(msbUtf8('key'))(msbUtf8('The quick brown fox jumps over the lazy dog'));
20
- if (r !== 0x1b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3an) {
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, mul, pow }: PrimeField) => (a: bigint) => bigint | null;
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, mul, pow }) => {
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 = pow(a)(sqrt_k);
75
- return mul(result)(result) === a ? result : null;
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(a)(0n) !== 1n) {
61
+ if (f.pow(0n)(a) !== 1n) {
62
62
  throw '**0';
63
63
  }
64
- if (f.pow(a)(1n) !== a) {
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(a)(f.middle)) !== 1n) {
69
+ if (f.abs(f.pow(f.middle)(a)) !== 1n) {
70
70
  throw '**middle';
71
71
  }
72
- if (f.pow(a)(f.sub(f.max)(1n)) !== f.reciprocal(a)) {
72
+ if (f.pow(f.sub(f.max)(1n))(a) !== f.reciprocal(a)) {
73
73
  throw '**(max-1)';
74
74
  }
75
- if (f.pow(a)(f.max) !== 1n) {
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(0n)(f.max) !== 0n) {
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(2n)(3n) !== 8n) {
93
+ if (f.pow(3n)(2n) !== 8n) {
94
94
  throw '2**3';
95
95
  }
96
- if (f.pow(2n)(128n) !== 1n << 128n) {
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(3n)(2n) !== 9n) {
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(3n)(100n) !== 3n ** 100n) {
107
+ if (f.pow(100n)(3n) !== 3n ** 100n) {
108
108
  throw '3**100';
109
109
  }
110
- if (f.pow(3n)(110n) !== 3n ** 110n) {
110
+ if (f.pow(110n)(3n) !== 3n ** 110n) {
111
111
  throw '3**110';
112
112
  }
113
- if (f.pow(3n)(120n) !== 3n ** 120n) {
113
+ if (f.pow(120n)(3n) !== 3n ** 120n) {
114
114
  throw '3**120';
115
115
  }
116
- if (f.pow(3n)(121n) !== 3n ** 121n) {
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;