functionalscript 0.4.2 → 0.4.4
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/README.md +1 -1
- package/bnf/data/module.f.d.ts +12 -0
- package/bnf/data/module.f.js +85 -0
- package/bnf/data/test.f.d.ts +4 -0
- package/bnf/data/test.f.js +8 -0
- package/bnf/module.f.d.ts +55 -0
- package/bnf/module.f.js +98 -0
- package/bnf/test.f.d.ts +4 -0
- package/bnf/test.f.js +7 -0
- package/bnf/testlib.f.d.ts +3 -0
- package/bnf/{tag/test.f.js → testlib.f.js} +48 -44
- 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/secp/module.f.d.ts +8 -0
- package/crypto/secp/module.f.js +30 -0
- package/crypto/secp/test.f.d.ts +3 -0
- package/crypto/secp/test.f.js +67 -3
- 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/djs/ast/module.f.d.ts +10 -0
- package/djs/ast/module.f.js +52 -0
- package/djs/ast/test.f.d.ts +8 -0
- package/djs/ast/test.f.js +41 -0
- package/djs/module.f.d.ts +5 -15
- package/djs/module.f.js +1 -62
- package/djs/parser/module.f.d.ts +9 -9
- package/djs/parser/module.f.js +7 -8
- package/djs/parser/test.f.js +97 -97
- package/djs/serializer/module.f.d.ts +8 -4
- package/djs/serializer/module.f.js +9 -27
- package/djs/{test.f.d.ts → serializer/test.f.d.ts} +3 -3
- package/djs/{test.f.js → serializer/test.f.js} +13 -13
- package/djs/tokenizer/test.f.js +2 -2
- package/djs/transpiler/module.f.d.ts +15 -0
- package/djs/transpiler/module.f.js +57 -0
- package/djs/transpiler/test.f.d.ts +8 -0
- package/djs/transpiler/test.f.js +74 -0
- package/io/module.f.d.ts +12 -0
- package/io/virtual-io.f.d.ts +3 -0
- package/io/virtual-io.f.js +10 -0
- package/js/tokenizer/test.f.js +2 -2
- package/json/module.f.d.ts +2 -1
- package/json/tokenizer/test.f.js +2 -2
- package/nanvm-lib/tests/test.f.js +4 -4
- package/package.json +2 -2
- package/path/module.f.d.ts +2 -0
- package/path/module.f.js +34 -0
- package/path/test.f.d.ts +5 -0
- package/path/test.f.js +49 -0
- package/text/sgr/module.f.d.ts +19 -1
- package/text/sgr/module.f.js +26 -1
- package/text/sgr/test.f.d.ts +2 -0
- package/text/sgr/test.f.js +8 -0
- package/text/utf16/module.f.d.ts +116 -0
- package/text/utf16/module.f.js +285 -0
- package/text/utf16/test.f.d.ts +4 -0
- package/text/utf16/test.f.js +28 -0
- package/types/bigint/module.f.d.ts +83 -2
- package/types/bigint/module.f.js +98 -2
- package/types/bigint/test.f.d.ts +4 -0
- package/types/bigint/test.f.js +66 -6
- package/types/bit_vec/module.f.d.ts +1 -1
- package/types/monoid/module.f.d.ts +3 -1
- package/types/monoid/module.f.js +2 -0
- 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
- package/types/object/module.f.d.ts +18 -0
- package/types/object/module.f.js +1 -1
- package/bnf/tag/module.f.d.ts +0 -30
- package/bnf/tag/module.f.js +0 -37
- /package/{bnf/tag/test.f.d.ts → io/module.f.js} +0 -0
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Learn more about
|
|
|
19
19
|
- [Purely Functional Programming in JavaScript](https://blog.bitsrc.io/purely-functional-programming-in-javascript-91114b1b2dff?sk=5f7132e56902f38fcf4c6164bfa681ed),
|
|
20
20
|
- [FunctionalScript and I/O](https://medium.com/@sergeyshandar/functionalscript-5cf817345376?sk=30b32189a81d1a2dad16c2244f32328d).
|
|
21
21
|
|
|
22
|
-
This repository is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) and distributted under
|
|
22
|
+
This repository is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) and distributted under [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html#license-text). Let us know if you need another license by sending an [email](mailto:sergey.oss@proton.me).
|
|
23
23
|
|
|
24
24
|
## Vision
|
|
25
25
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Rule as FRule } from '../module.f.ts';
|
|
2
|
+
export type TerminalRange = number;
|
|
3
|
+
export type Sequence = readonly string[];
|
|
4
|
+
export type Variant = {
|
|
5
|
+
readonly [k in string]: string;
|
|
6
|
+
};
|
|
7
|
+
export type Rule = Variant | Sequence | TerminalRange;
|
|
8
|
+
export type RuleSet = Readonly<Record<string, Rule>>;
|
|
9
|
+
export declare const toData: (fr: FRule) => readonly [RuleSet, string];
|
|
10
|
+
/**
|
|
11
|
+
* Either `{ variantItem: id }` or `id`.
|
|
12
|
+
*/
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { stringToCodePointList } from "../../text/utf16/module.f.js";
|
|
2
|
+
import { toArray } from "../../types/list/module.f.js";
|
|
3
|
+
const { entries } = Object;
|
|
4
|
+
const find = (map) => (fr) => {
|
|
5
|
+
for (const [k, v] of entries(map)) {
|
|
6
|
+
if (v === fr) {
|
|
7
|
+
return k;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return undefined;
|
|
11
|
+
};
|
|
12
|
+
const newName = (map, name) => {
|
|
13
|
+
let i = 0;
|
|
14
|
+
let result = name;
|
|
15
|
+
while (result in map) {
|
|
16
|
+
result = name + i;
|
|
17
|
+
++i;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
const sequence = (list) => map => {
|
|
22
|
+
let result = [];
|
|
23
|
+
let set = {};
|
|
24
|
+
for (const fr of list) {
|
|
25
|
+
const [map1, set1, id] = toDataAdd(map)(fr);
|
|
26
|
+
map = map1;
|
|
27
|
+
set = { ...set, ...set1 };
|
|
28
|
+
result = [...result, id];
|
|
29
|
+
}
|
|
30
|
+
return [map, set, result];
|
|
31
|
+
};
|
|
32
|
+
const variant = (fr) => map => {
|
|
33
|
+
let set = {};
|
|
34
|
+
let rule = {};
|
|
35
|
+
for (const [k, v] of entries(fr)) {
|
|
36
|
+
const [m1, s, id] = toDataAdd(map)(v);
|
|
37
|
+
map = m1;
|
|
38
|
+
set = { ...set, ...s };
|
|
39
|
+
rule = { ...rule, [k]: id };
|
|
40
|
+
}
|
|
41
|
+
return [map, set, rule];
|
|
42
|
+
};
|
|
43
|
+
const data = (dr) => {
|
|
44
|
+
switch (typeof dr) {
|
|
45
|
+
case 'string': {
|
|
46
|
+
return sequence(toArray(stringToCodePointList(dr)));
|
|
47
|
+
}
|
|
48
|
+
case 'number':
|
|
49
|
+
return m => [m, {}, dr];
|
|
50
|
+
default:
|
|
51
|
+
if (dr instanceof Array) {
|
|
52
|
+
return sequence(dr);
|
|
53
|
+
}
|
|
54
|
+
return variant(dr);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const toDataAdd = (map) => (fr) => {
|
|
58
|
+
{
|
|
59
|
+
const id = find(map)(fr);
|
|
60
|
+
if (id !== undefined) {
|
|
61
|
+
return [map, {}, id];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const [dr, tmpId] = typeof fr === 'function' ? [fr(), fr.name] : [fr, ''];
|
|
65
|
+
const newRule = data(dr);
|
|
66
|
+
const id = newName(map, tmpId);
|
|
67
|
+
const map1 = { ...map, [id]: fr };
|
|
68
|
+
const [map2, set, rule] = newRule(map1);
|
|
69
|
+
return [map2, { ...set, [id]: rule }, id];
|
|
70
|
+
};
|
|
71
|
+
export const toData = (fr) => {
|
|
72
|
+
const [, ruleSet, id] = toDataAdd({})(fr);
|
|
73
|
+
return [ruleSet, id];
|
|
74
|
+
};
|
|
75
|
+
// type Dispatch = RangeMapArray<string>;
|
|
76
|
+
/**
|
|
77
|
+
* Either `{ variantItem: id }` or `id`.
|
|
78
|
+
*/
|
|
79
|
+
/*
|
|
80
|
+
type DispatchRule = SingleProperty<> | string
|
|
81
|
+
|
|
82
|
+
type Dispatch = RangeMapArray<DispatchRule>
|
|
83
|
+
|
|
84
|
+
type DispatchMap = { readonly[id in string]: Dispatch }
|
|
85
|
+
*/
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type Array2 } from '../types/array/module.f.ts';
|
|
2
|
+
export type TerminalRange = number;
|
|
3
|
+
export type Sequence = readonly Rule[];
|
|
4
|
+
export type Variant = {
|
|
5
|
+
readonly [k in string]: Rule;
|
|
6
|
+
};
|
|
7
|
+
export type DataRule = Variant | Sequence | TerminalRange | string;
|
|
8
|
+
export type LazyRule = () => DataRule;
|
|
9
|
+
export type Rule = DataRule | LazyRule;
|
|
10
|
+
export declare const max: string;
|
|
11
|
+
export declare const rangeEncode: (a: number, b: number) => TerminalRange;
|
|
12
|
+
export declare const oneEncode: (a: number) => TerminalRange;
|
|
13
|
+
export declare const rangeDecode: (r: number) => Array2<number>;
|
|
14
|
+
export declare const toSequence: (s: string) => readonly TerminalRange[];
|
|
15
|
+
export declare const str: (s: string) => readonly TerminalRange[] | TerminalRange;
|
|
16
|
+
export declare const set: (s: string) => RangeVariant;
|
|
17
|
+
export declare const range: (ab: string) => TerminalRange;
|
|
18
|
+
/**
|
|
19
|
+
* A set of terminal ranges compatible with the `Variant` rule.
|
|
20
|
+
*/
|
|
21
|
+
export type RangeVariant = {
|
|
22
|
+
readonly [k in string]: TerminalRange;
|
|
23
|
+
};
|
|
24
|
+
export declare const rangeToId: (r: TerminalRange) => string;
|
|
25
|
+
export declare const remove: (range: TerminalRange, removeSet: RangeVariant) => RangeVariant;
|
|
26
|
+
export type None = readonly [];
|
|
27
|
+
export declare const none: None;
|
|
28
|
+
export type Option<S> = {
|
|
29
|
+
none: None;
|
|
30
|
+
some: S;
|
|
31
|
+
};
|
|
32
|
+
export declare const option: <S extends Rule>(some: S) => Option<S>;
|
|
33
|
+
export type Repeat0Plus<T> = () => Option<readonly [T, Repeat0Plus<T>]>;
|
|
34
|
+
/**
|
|
35
|
+
* Repeat zero or more times.
|
|
36
|
+
*
|
|
37
|
+
* https://english.stackexchange.com/questions/506480/single-word-quantifiers-for-zero-or-more-like-cardinalities
|
|
38
|
+
* - zero or more - any, 0Plus
|
|
39
|
+
* - one or more - several, 1Plus
|
|
40
|
+
*
|
|
41
|
+
* Also see: https://arbs.nzcer.org.nz/types-numbers
|
|
42
|
+
*/
|
|
43
|
+
export declare const repeat0Plus: <T extends Rule>(some: T) => Repeat0Plus<T>;
|
|
44
|
+
export type Repeat1Plus<T> = readonly [T, Repeat0Plus<T>];
|
|
45
|
+
/**
|
|
46
|
+
* Repeat one or more times.
|
|
47
|
+
*/
|
|
48
|
+
export declare const repeat1Plus: <T extends Rule>(some: T) => Repeat1Plus<T>;
|
|
49
|
+
export type Join1Plus<T, S> = readonly [T, Repeat0Plus<readonly [S, T]>];
|
|
50
|
+
export declare const join1Plus: <T extends Rule, S extends Rule>(some: T, separator: S) => Join1Plus<T, S>;
|
|
51
|
+
export type Join0Plus<T, S> = Option<readonly [T, Repeat0Plus<readonly [S, T]>]>;
|
|
52
|
+
export declare const join0Plus: <T extends Rule, S extends Rule>(some: T, separator: S) => Rule;
|
|
53
|
+
export type Repeat<T> = readonly T[];
|
|
54
|
+
export declare const repeat: (n: number) => <T extends Rule>(some: T) => Repeat<T>;
|
|
55
|
+
export declare const isEmpty: (rule: Rule) => boolean;
|
package/bnf/module.f.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { codePointListToString, stringToCodePointList } from "../text/utf16/module.f.js";
|
|
2
|
+
import { isArray2 } from "../types/array/module.f.js";
|
|
3
|
+
import { map, toArray, repeat as listRepeat } from "../types/list/module.f.js";
|
|
4
|
+
//
|
|
5
|
+
const { fromEntries, values } = Object;
|
|
6
|
+
const { fromCodePoint } = String;
|
|
7
|
+
/**
|
|
8
|
+
* Two 24 bit numbers can be fit into one JS number (53 bit).
|
|
9
|
+
*/
|
|
10
|
+
const offset = 24;
|
|
11
|
+
const mask = (1 << offset) - 1;
|
|
12
|
+
const isValid = (r) => r >= 0 && r <= mask;
|
|
13
|
+
export const max = codePointListToString([0x10FFFF]);
|
|
14
|
+
export const rangeEncode = (a, b) => {
|
|
15
|
+
if (!isValid(a) || !isValid(b) || a > b) {
|
|
16
|
+
throw `Invalid range ${a} ${b}.`;
|
|
17
|
+
}
|
|
18
|
+
return (a << offset) | b;
|
|
19
|
+
};
|
|
20
|
+
export const oneEncode = (a) => rangeEncode(a, a);
|
|
21
|
+
export const rangeDecode = (r) => [r >> offset, r & mask];
|
|
22
|
+
const mapOneEncode = map(oneEncode);
|
|
23
|
+
export const toSequence = (s) => toArray(mapOneEncode(stringToCodePointList(s)));
|
|
24
|
+
export const str = (s) => {
|
|
25
|
+
const x = toSequence(s);
|
|
26
|
+
return x.length === 1 ? x[0] : x;
|
|
27
|
+
};
|
|
28
|
+
const mapEntry = map((v) => [fromCodePoint(v), oneEncode(v)]);
|
|
29
|
+
export const set = (s) => fromEntries(toArray(mapEntry(stringToCodePointList(s))));
|
|
30
|
+
export const range = (ab) => {
|
|
31
|
+
const a = toArray(stringToCodePointList(ab));
|
|
32
|
+
if (!isArray2(a)) {
|
|
33
|
+
throw `Invalid range ${ab}.`;
|
|
34
|
+
}
|
|
35
|
+
return rangeEncode(...a);
|
|
36
|
+
};
|
|
37
|
+
export const rangeToId = (r) => {
|
|
38
|
+
const ab = rangeDecode(r);
|
|
39
|
+
const [a, b] = ab;
|
|
40
|
+
const cp = a === b ? [a] : ab;
|
|
41
|
+
return fromCodePoint(...cp);
|
|
42
|
+
};
|
|
43
|
+
const rangeToEntry = (r) => [rangeToId(r), r];
|
|
44
|
+
const toVariantRangeSet = (r) => fromEntries(r.map(rangeToEntry));
|
|
45
|
+
const removeOne = (list, ab) => {
|
|
46
|
+
const [a, b] = rangeDecode(ab);
|
|
47
|
+
let result = [];
|
|
48
|
+
for (const ab0 of list) {
|
|
49
|
+
const [a0, b0] = rangeDecode(ab0);
|
|
50
|
+
if (a0 < a) {
|
|
51
|
+
// [a0
|
|
52
|
+
// ]a
|
|
53
|
+
result = [...result, rangeEncode(a0, Math.min(b0, a - 1))];
|
|
54
|
+
}
|
|
55
|
+
if (b < b0) {
|
|
56
|
+
// b0]
|
|
57
|
+
// b[
|
|
58
|
+
result = [...result, rangeEncode(Math.max(b + 1, a0), b0)];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
};
|
|
63
|
+
export const remove = (range, removeSet) => {
|
|
64
|
+
let result = [range];
|
|
65
|
+
for (const r of values(removeSet)) {
|
|
66
|
+
result = removeOne(result, r);
|
|
67
|
+
}
|
|
68
|
+
return toVariantRangeSet(result);
|
|
69
|
+
};
|
|
70
|
+
export const none = [];
|
|
71
|
+
export const option = (some) => ({
|
|
72
|
+
none,
|
|
73
|
+
some,
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* Repeat zero or more times.
|
|
77
|
+
*
|
|
78
|
+
* https://english.stackexchange.com/questions/506480/single-word-quantifiers-for-zero-or-more-like-cardinalities
|
|
79
|
+
* - zero or more - any, 0Plus
|
|
80
|
+
* - one or more - several, 1Plus
|
|
81
|
+
*
|
|
82
|
+
* Also see: https://arbs.nzcer.org.nz/types-numbers
|
|
83
|
+
*/
|
|
84
|
+
export const repeat0Plus = (some) => {
|
|
85
|
+
const r = () => option([some, r]);
|
|
86
|
+
return r;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Repeat one or more times.
|
|
90
|
+
*/
|
|
91
|
+
export const repeat1Plus = (some) => [some, repeat0Plus(some)];
|
|
92
|
+
export const join1Plus = (some, separator) => [some, repeat0Plus([separator, some])];
|
|
93
|
+
export const join0Plus = (some, separator) => option(join1Plus(some, separator));
|
|
94
|
+
export const repeat = (n) => (some) => toArray(listRepeat(some)(n));
|
|
95
|
+
export const isEmpty = (rule) => {
|
|
96
|
+
const d = typeof rule === 'function' ? rule() : rule;
|
|
97
|
+
return d === '' || (d instanceof Array && d.length === 0);
|
|
98
|
+
};
|
package/bnf/test.f.d.ts
ADDED
package/bnf/test.f.js
ADDED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const
|
|
1
|
+
import { join0Plus, max, none, option, range, remove, repeat, repeat0Plus, set } from "./module.f.js";
|
|
2
|
+
export const classic = () => {
|
|
3
3
|
const json = () => [element];
|
|
4
4
|
const value = () => ({
|
|
5
5
|
object,
|
|
@@ -34,9 +34,9 @@ const _classic = () => {
|
|
|
34
34
|
characters: [character, characters],
|
|
35
35
|
});
|
|
36
36
|
const character = () => ({
|
|
37
|
-
0:
|
|
38
|
-
1:
|
|
39
|
-
2:
|
|
37
|
+
0: 0x20_000021,
|
|
38
|
+
1: 0x23_00005B,
|
|
39
|
+
2: 0x5D_10FFFF,
|
|
40
40
|
escape: ['\\', escape],
|
|
41
41
|
});
|
|
42
42
|
const escape = () => ({
|
|
@@ -63,7 +63,7 @@ const _classic = () => {
|
|
|
63
63
|
'0': '0',
|
|
64
64
|
onenine,
|
|
65
65
|
});
|
|
66
|
-
const onenine = range('
|
|
66
|
+
const onenine = range('19');
|
|
67
67
|
const fraction = () => ({
|
|
68
68
|
none,
|
|
69
69
|
digits: ['.', digits],
|
|
@@ -86,53 +86,57 @@ const _classic = () => {
|
|
|
86
86
|
});
|
|
87
87
|
return json;
|
|
88
88
|
};
|
|
89
|
-
const
|
|
90
|
-
const onenine = range('
|
|
91
|
-
const digit =
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
89
|
+
export const deterministic = () => {
|
|
90
|
+
const onenine = range('19');
|
|
91
|
+
const digit = range('09');
|
|
92
|
+
const string = [
|
|
93
|
+
'"',
|
|
94
|
+
repeat0Plus({
|
|
95
|
+
...remove(range(` ${max}`), set('"\\')),
|
|
96
|
+
escape: [
|
|
97
|
+
'\\',
|
|
98
|
+
{
|
|
99
|
+
...set('"\\/bfnrt'),
|
|
100
|
+
u: [
|
|
101
|
+
'u',
|
|
102
|
+
...repeat(4)({
|
|
103
|
+
digit,
|
|
104
|
+
AF: range('AF'),
|
|
105
|
+
af: range('af'),
|
|
106
|
+
})
|
|
107
|
+
],
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
}),
|
|
111
|
+
'"'
|
|
112
|
+
];
|
|
113
|
+
const digits0 = repeat0Plus(digit);
|
|
113
114
|
const digits = [digit, digits0];
|
|
114
|
-
const
|
|
115
|
-
|
|
115
|
+
const number = [
|
|
116
|
+
option('-'),
|
|
117
|
+
{
|
|
118
|
+
0: '0',
|
|
116
119
|
onenine: [onenine, digits0],
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
const
|
|
120
|
+
},
|
|
121
|
+
option(['.', digits]),
|
|
122
|
+
option([set('Ee'), option(set('+-')), digits])
|
|
123
|
+
];
|
|
124
|
+
const ws = repeat0Plus(set(' \n\r\t'));
|
|
125
|
+
const commaJoin0Plus = ([open, close], a) => [
|
|
126
|
+
open,
|
|
127
|
+
ws,
|
|
128
|
+
join0Plus([a, ws], [',', ws]),
|
|
129
|
+
close,
|
|
130
|
+
];
|
|
123
131
|
const value = () => ({
|
|
124
|
-
object,
|
|
125
|
-
array,
|
|
132
|
+
object: commaJoin0Plus('{}', [string, ws, ':', ws, value]),
|
|
133
|
+
array: commaJoin0Plus('[]', value),
|
|
126
134
|
string,
|
|
127
135
|
number,
|
|
128
136
|
true: 'true',
|
|
129
137
|
false: 'false',
|
|
130
138
|
null: 'null'
|
|
131
139
|
});
|
|
132
|
-
const commaJoin0 = ([open, close], a) => [open, ws, join0([a, ws], [',', ws]), close];
|
|
133
|
-
const array = commaJoin0('[]', value);
|
|
134
|
-
const member = [string, ws, ':', ws, value];
|
|
135
|
-
const object = commaJoin0('{}', member);
|
|
136
140
|
const json = [ws, value, ws];
|
|
137
141
|
return json;
|
|
138
142
|
};
|
|
@@ -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
|
+
};
|
|
@@ -65,4 +65,12 @@ export declare const secp256k1: Init;
|
|
|
65
65
|
* https://neuromancer.sk/std/secg/secp256r1
|
|
66
66
|
*/
|
|
67
67
|
export declare const secp256r1: Init;
|
|
68
|
+
/**
|
|
69
|
+
* https://neuromancer.sk/std/secg/secp384r1
|
|
70
|
+
*/
|
|
71
|
+
export declare const secp384r1: Init;
|
|
72
|
+
/**
|
|
73
|
+
* https://neuromancer.sk/std/secg/secp521r1
|
|
74
|
+
*/
|
|
75
|
+
export declare const secp521r1: Init;
|
|
68
76
|
export {};
|
package/crypto/secp/module.f.js
CHANGED
|
@@ -124,3 +124,33 @@ export const secp256r1 = {
|
|
|
124
124
|
],
|
|
125
125
|
n: 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n,
|
|
126
126
|
};
|
|
127
|
+
/**
|
|
128
|
+
* https://neuromancer.sk/std/secg/secp384r1
|
|
129
|
+
*/
|
|
130
|
+
export const secp384r1 = {
|
|
131
|
+
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,
|
|
132
|
+
a: [
|
|
133
|
+
0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefn, //< b
|
|
134
|
+
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffcn, //< a
|
|
135
|
+
],
|
|
136
|
+
g: [
|
|
137
|
+
0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7n, //< x
|
|
138
|
+
0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fn, //< y
|
|
139
|
+
],
|
|
140
|
+
n: 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973n,
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* https://neuromancer.sk/std/secg/secp521r1
|
|
144
|
+
*/
|
|
145
|
+
export const secp521r1 = {
|
|
146
|
+
p: 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
|
|
147
|
+
a: [
|
|
148
|
+
0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00n, //< b
|
|
149
|
+
0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcn, //< a
|
|
150
|
+
],
|
|
151
|
+
g: [
|
|
152
|
+
0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66n,
|
|
153
|
+
0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650n,
|
|
154
|
+
],
|
|
155
|
+
n: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409n
|
|
156
|
+
};
|