cesr-ts 0.4.0 → 0.6.0
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/esm/src/adapters/async-iterable.js +8 -0
- package/esm/src/adapters/effection.js +6 -0
- package/esm/src/annotate/annotator.js +12 -0
- package/esm/src/annotate/cli.js +12 -0
- package/esm/src/annotate/comments.js +5 -1
- package/esm/src/annotate/denot.js +6 -0
- package/esm/src/annotate/render.js +15 -3
- package/esm/src/core/bytes.js +9 -0
- package/esm/src/core/errors.js +3 -0
- package/esm/src/core/parser-engine.js +1 -1
- package/esm/src/core/parser-frame-parser.js +22 -18
- package/esm/src/core/vocabulary.js +47 -0
- package/esm/src/index.js +5 -0
- package/esm/src/parser/attachment-parser.js +4 -0
- package/esm/src/parser/cold-start.js +6 -0
- package/esm/src/parser/group-dispatch.js +2 -2
- package/esm/src/primitives/aggor.js +374 -30
- package/esm/src/primitives/bexter.js +2 -3
- package/esm/src/primitives/blinder.js +6 -0
- package/esm/src/primitives/byte-like.js +19 -0
- package/esm/src/primitives/cigar.js +17 -3
- package/esm/src/primitives/cipher.js +91 -6
- package/esm/src/primitives/codex.js +39 -6
- package/esm/src/primitives/compactor.js +307 -3
- package/esm/src/primitives/counter.js +6 -2
- package/esm/src/primitives/dater.js +1 -2
- package/esm/src/primitives/decimer.js +7 -11
- package/esm/src/primitives/decrypter.js +123 -7
- package/esm/src/primitives/diger.js +57 -3
- package/esm/src/primitives/disclosure.js +300 -0
- package/esm/src/primitives/encrypter.js +130 -7
- package/esm/src/primitives/hydrate.js +49 -0
- package/esm/src/primitives/ilker.js +2 -3
- package/esm/src/primitives/indexer.js +21 -4
- package/esm/src/primitives/labeler.js +1 -2
- package/esm/src/primitives/mapper.js +612 -35
- package/esm/src/primitives/matter.js +133 -3
- package/esm/src/primitives/mediar.js +6 -0
- package/esm/src/primitives/noncer.js +2 -3
- package/esm/src/primitives/number.js +1 -2
- package/esm/src/primitives/pather.js +102 -5
- package/esm/src/primitives/prefixer.js +1 -2
- package/esm/src/primitives/primitive.js +14 -0
- package/esm/src/primitives/registry.js +2 -0
- package/esm/src/primitives/saider.js +80 -3
- package/esm/src/primitives/salter.js +96 -2
- package/esm/src/primitives/sealed-box.js +41 -0
- package/esm/src/primitives/seqner.js +1 -2
- package/esm/src/primitives/siger.js +58 -3
- package/esm/src/primitives/signer.js +243 -9
- package/esm/src/primitives/streamer.js +28 -0
- package/esm/src/primitives/structing.js +727 -0
- package/esm/src/primitives/structor.js +20 -0
- package/esm/src/primitives/tagger.js +1 -2
- package/esm/src/primitives/texter.js +1 -2
- package/esm/src/primitives/tholder.js +552 -10
- package/esm/src/primitives/traitor.js +2 -3
- package/esm/src/primitives/verfer.js +50 -6
- package/esm/src/primitives/verser.js +16 -6
- package/esm/src/router/router-stub.js +1 -0
- package/esm/src/serder/native.js +1326 -0
- package/esm/src/serder/serder.js +1558 -59
- package/esm/src/serder/serdery.js +92 -7
- package/esm/src/serder/smell.js +26 -1
- package/esm/src/tables/codex-utils.js +2 -0
- package/esm/src/tables/counter-codex.js +2 -0
- package/esm/src/tables/counter-groups.js +6 -0
- package/esm/src/tables/versions.js +4 -0
- package/esm/src/version.js +5 -2
- package/package.json +5 -2
- package/types/src/adapters/async-iterable.d.ts +8 -0
- package/types/src/adapters/async-iterable.d.ts.map +1 -1
- package/types/src/adapters/effection.d.ts +7 -0
- package/types/src/adapters/effection.d.ts.map +1 -1
- package/types/src/annotate/annotator.d.ts +12 -0
- package/types/src/annotate/annotator.d.ts.map +1 -1
- package/types/src/annotate/cli.d.ts +13 -0
- package/types/src/annotate/cli.d.ts.map +1 -1
- package/types/src/annotate/comments.d.ts +4 -0
- package/types/src/annotate/comments.d.ts.map +1 -1
- package/types/src/annotate/denot.d.ts +6 -0
- package/types/src/annotate/denot.d.ts.map +1 -1
- package/types/src/annotate/render.d.ts.map +1 -1
- package/types/src/annotate/types.d.ts +2 -0
- package/types/src/annotate/types.d.ts.map +1 -1
- package/types/src/bench/parser-benchmark.d.ts +3 -0
- package/types/src/bench/parser-benchmark.d.ts.map +1 -1
- package/types/src/core/bytes.d.ts +9 -0
- package/types/src/core/bytes.d.ts.map +1 -1
- package/types/src/core/errors.d.ts +3 -0
- package/types/src/core/errors.d.ts.map +1 -1
- package/types/src/core/parser-engine.d.ts +4 -0
- package/types/src/core/parser-engine.d.ts.map +1 -1
- package/types/src/core/parser-frame-parser.d.ts.map +1 -1
- package/types/src/core/types.d.ts +2 -0
- package/types/src/core/types.d.ts.map +1 -1
- package/types/src/core/vocabulary.d.ts +48 -0
- package/types/src/core/vocabulary.d.ts.map +1 -0
- package/types/src/index.d.ts +5 -0
- package/types/src/index.d.ts.map +1 -1
- package/types/src/parser/attachment-parser.d.ts +4 -0
- package/types/src/parser/attachment-parser.d.ts.map +1 -1
- package/types/src/parser/cold-start.d.ts +6 -0
- package/types/src/parser/cold-start.d.ts.map +1 -1
- package/types/src/parser/group-dispatch.d.ts.map +1 -1
- package/types/src/primitives/aggor.d.ts +100 -13
- package/types/src/primitives/aggor.d.ts.map +1 -1
- package/types/src/primitives/bexter.d.ts.map +1 -1
- package/types/src/primitives/blinder.d.ts +6 -0
- package/types/src/primitives/blinder.d.ts.map +1 -1
- package/types/src/primitives/byte-like.d.ts +7 -0
- package/types/src/primitives/byte-like.d.ts.map +1 -0
- package/types/src/primitives/cigar.d.ts +11 -1
- package/types/src/primitives/cigar.d.ts.map +1 -1
- package/types/src/primitives/cipher.d.ts +73 -2
- package/types/src/primitives/cipher.d.ts.map +1 -1
- package/types/src/primitives/codex.d.ts +34 -4
- package/types/src/primitives/codex.d.ts.map +1 -1
- package/types/src/primitives/compactor.d.ts +94 -2
- package/types/src/primitives/compactor.d.ts.map +1 -1
- package/types/src/primitives/counter.d.ts.map +1 -1
- package/types/src/primitives/dater.d.ts.map +1 -1
- package/types/src/primitives/decimer.d.ts.map +1 -1
- package/types/src/primitives/decrypter.d.ts +64 -3
- package/types/src/primitives/decrypter.d.ts.map +1 -1
- package/types/src/primitives/diger.d.ts +16 -0
- package/types/src/primitives/diger.d.ts.map +1 -1
- package/types/src/primitives/disclosure.d.ts +201 -0
- package/types/src/primitives/disclosure.d.ts.map +1 -0
- package/types/src/primitives/encrypter.d.ts +66 -4
- package/types/src/primitives/encrypter.d.ts.map +1 -1
- package/types/src/primitives/hydrate.d.ts +20 -0
- package/types/src/primitives/hydrate.d.ts.map +1 -0
- package/types/src/primitives/ilker.d.ts.map +1 -1
- package/types/src/primitives/indexer.d.ts.map +1 -1
- package/types/src/primitives/labeler.d.ts.map +1 -1
- package/types/src/primitives/mapper.d.ts +132 -11
- package/types/src/primitives/mapper.d.ts.map +1 -1
- package/types/src/primitives/matter.d.ts +33 -1
- package/types/src/primitives/matter.d.ts.map +1 -1
- package/types/src/primitives/mediar.d.ts +6 -0
- package/types/src/primitives/mediar.d.ts.map +1 -1
- package/types/src/primitives/noncer.d.ts.map +1 -1
- package/types/src/primitives/number.d.ts.map +1 -1
- package/types/src/primitives/pather.d.ts +21 -0
- package/types/src/primitives/pather.d.ts.map +1 -1
- package/types/src/primitives/prefixer.d.ts.map +1 -1
- package/types/src/primitives/primitive.d.ts +26 -0
- package/types/src/primitives/primitive.d.ts.map +1 -1
- package/types/src/primitives/registry.d.ts +3 -0
- package/types/src/primitives/registry.d.ts.map +1 -1
- package/types/src/primitives/saider.d.ts +41 -0
- package/types/src/primitives/saider.d.ts.map +1 -1
- package/types/src/primitives/salter.d.ts +56 -1
- package/types/src/primitives/salter.d.ts.map +1 -1
- package/types/src/primitives/sealed-box.d.ts +29 -0
- package/types/src/primitives/sealed-box.d.ts.map +1 -0
- package/types/src/primitives/seqner.d.ts.map +1 -1
- package/types/src/primitives/siger.d.ts +14 -0
- package/types/src/primitives/siger.d.ts.map +1 -1
- package/types/src/primitives/signer.d.ts +80 -4
- package/types/src/primitives/signer.d.ts.map +1 -1
- package/types/src/primitives/streamer.d.ts +31 -0
- package/types/src/primitives/streamer.d.ts.map +1 -0
- package/types/src/primitives/structing.d.ts +4114 -0
- package/types/src/primitives/structing.d.ts.map +1 -0
- package/types/src/primitives/structor.d.ts +6 -0
- package/types/src/primitives/structor.d.ts.map +1 -1
- package/types/src/primitives/tagger.d.ts.map +1 -1
- package/types/src/primitives/texter.d.ts.map +1 -1
- package/types/src/primitives/tholder.d.ts +150 -5
- package/types/src/primitives/tholder.d.ts.map +1 -1
- package/types/src/primitives/traitor.d.ts.map +1 -1
- package/types/src/primitives/unknown.d.ts +1 -0
- package/types/src/primitives/unknown.d.ts.map +1 -1
- package/types/src/primitives/verfer.d.ts +12 -0
- package/types/src/primitives/verfer.d.ts.map +1 -1
- package/types/src/primitives/verser.d.ts +14 -3
- package/types/src/primitives/verser.d.ts.map +1 -1
- package/types/src/router/router-stub.d.ts +3 -0
- package/types/src/router/router-stub.d.ts.map +1 -1
- package/types/src/serder/native.d.ts +115 -0
- package/types/src/serder/native.d.ts.map +1 -0
- package/types/src/serder/serder.d.ts +187 -9
- package/types/src/serder/serder.d.ts.map +1 -1
- package/types/src/serder/serdery.d.ts +42 -0
- package/types/src/serder/serdery.d.ts.map +1 -1
- package/types/src/serder/smell.d.ts +22 -0
- package/types/src/serder/smell.d.ts.map +1 -1
- package/types/src/tables/codex-utils.d.ts +3 -0
- package/types/src/tables/codex-utils.d.ts.map +1 -1
- package/types/src/tables/counter-codex.d.ts +4 -0
- package/types/src/tables/counter-codex.d.ts.map +1 -1
- package/types/src/tables/counter-groups.d.ts +6 -0
- package/types/src/tables/counter-groups.d.ts.map +1 -1
- package/types/src/tables/counter.tables.generated.d.ts.map +1 -1
- package/types/src/tables/indexer.codex.generated.d.ts.map +1 -1
- package/types/src/tables/matter.codex.generated.d.ts.map +1 -1
- package/types/src/tables/table-types.d.ts +6 -0
- package/types/src/tables/table-types.d.ts.map +1 -1
- package/types/src/tables/versions.d.ts +6 -0
- package/types/src/tables/versions.d.ts.map +1 -1
- package/types/src/version.d.ts +5 -2
- package/types/src/version.d.ts.map +1 -1
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
import { codexValues, invertCodex } from "../tables/codex-utils.js";
|
|
2
|
-
import { IdrDex, IdxBthSigDex, IdxCrtSigDex, IdxSigDex
|
|
2
|
+
import { IdrDex, IdxBthSigDex, IdxCrtSigDex, IdxSigDex } from "../tables/indexer.codex.generated.js";
|
|
3
3
|
import { BexDex, CiXAllQB64Dex, CiXDex, CiXFixQB64Dex, CiXVarDex, CiXVarQB2Dex, CiXVarQB64Dex, CiXVarStrmDex, DecDex, DigDex, EscapeDex, LabelDex, MtrDex, NonceDex, NonTransDex, NumDex, PreDex, PreNonDigDex, TagDex, TexDex, } from "../tables/matter.codex.generated.js";
|
|
4
4
|
import { TraitDex } from "../tables/trait.codex.generated.js";
|
|
5
5
|
import { Protocols } from "../tables/versions.js";
|
|
6
6
|
/**
|
|
7
7
|
* Derived readability layer over the generated KERIpy-parity codex objects.
|
|
8
8
|
*
|
|
9
|
-
* Canonical names such as `MtrDex
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Canonical names such as `MtrDex` and `IdrDex` are the primary source of
|
|
10
|
+
* truth for the shared Matter/Indexer code spaces. Semantic families such as
|
|
11
|
+
* `PreDex`, `DigDex`, `NonceDex`, and `IdxSigDex` are KERIpy-style subset
|
|
12
|
+
* views over those same base codices, not separate versioned registries.
|
|
13
|
+
*
|
|
14
|
+
* The sets exported here are convenience views for primitive-family validation
|
|
15
|
+
* and TS ergonomics. Counter codices are the separate genus/version-aware
|
|
16
|
+
* layer; Matter and Indexer family subsets are not.
|
|
12
17
|
*/
|
|
13
18
|
export { BexDex, CiXAllQB64Dex, CiXDex, CiXFixQB64Dex, CiXVarDex, CiXVarQB2Dex, CiXVarQB64Dex, CiXVarStrmDex, DecDex, DigDex, EscapeDex, IdrDex, IdxBthSigDex, IdxCrtSigDex, IdxSigDex, LabelDex, MtrDex, NonceDex, NonTransDex, NumDex, PreDex, PreNonDigDex, TagDex, TexDex, TraitDex, };
|
|
19
|
+
/**
|
|
20
|
+
* Derived matter/indexer family views used by semantic primitive validators.
|
|
21
|
+
*
|
|
22
|
+
* Maintainer rule:
|
|
23
|
+
* - generated codex objects such as `MtrDex`, `PreDex`, and `IdrDex` remain
|
|
24
|
+
* the authority
|
|
25
|
+
* - these exported sets are readability helpers layered over that authority
|
|
26
|
+
*/
|
|
14
27
|
export const BEXTER_CODES = codexValues(BexDex);
|
|
15
28
|
export const TEXTER_CODES = codexValues(TexDex);
|
|
16
29
|
export const DECIMAL_CODES = codexValues(DecDex);
|
|
@@ -20,9 +33,18 @@ export const NUMBER_CODES = codexValues(NumDex);
|
|
|
20
33
|
export const TAG_CODES = codexValues(TagDex);
|
|
21
34
|
export const LABELER_CODES = codexValues(LabelDex);
|
|
22
35
|
export const PREFIX_CODES = codexValues(PreDex);
|
|
23
|
-
export const
|
|
36
|
+
export const NON_TRANSFERABLE_CODES = codexValues(NonTransDex);
|
|
24
37
|
export const NON_DIGEST_PREFIX_CODES = codexValues(PreNonDigDex);
|
|
25
38
|
export const ESCAPE_CODES = codexValues(EscapeDex);
|
|
39
|
+
/**
|
|
40
|
+
* X25519 cipher-family helper sets keyed by plaintext hydration rules.
|
|
41
|
+
*
|
|
42
|
+
* KERIpy correspondence:
|
|
43
|
+
* - stream families preserve whole sniffable CESR streams
|
|
44
|
+
* - qb64 families preserve fully qualified text material
|
|
45
|
+
* - qb2 families preserve binary CESR encodings
|
|
46
|
+
* - fixed qb64 families name the common salt/seed payloads directly
|
|
47
|
+
*/
|
|
26
48
|
export const CIPHER_X25519_VARIABLE_STREAM_CODES = codexValues(CiXVarStrmDex);
|
|
27
49
|
export const CIPHER_X25519_QB64_VARIABLE_CODES = codexValues(CiXVarQB64Dex);
|
|
28
50
|
export const CIPHER_X25519_FIXED_QB64_CODES = codexValues(CiXFixQB64Dex);
|
|
@@ -45,6 +67,13 @@ export const THOLDER_CODES = new Set([
|
|
|
45
67
|
...THOLDER_NUMERIC_CODES,
|
|
46
68
|
...THOLDER_WEIGHTED_CODES,
|
|
47
69
|
]);
|
|
70
|
+
/**
|
|
71
|
+
* Executable primitive suite families.
|
|
72
|
+
*
|
|
73
|
+
* These are the small semantic validation sets consumed by `Signer`,
|
|
74
|
+
* `Salter`, `Encrypter`, `Decrypter`, and detached-signature primitives, not
|
|
75
|
+
* alternative registries separate from the generated KERIpy parity codices.
|
|
76
|
+
*/
|
|
48
77
|
export const SIGNER_CODES = new Set([
|
|
49
78
|
MtrDex.Ed25519_Seed,
|
|
50
79
|
MtrDex.ECDSA_256k1_Seed,
|
|
@@ -63,8 +92,12 @@ export const TRAIT_TAGS = new Set([
|
|
|
63
92
|
...codexValues(TraitDex),
|
|
64
93
|
]);
|
|
65
94
|
export const VERSER_CODES = new Set([MtrDex.Tag7, MtrDex.Tag10]);
|
|
66
|
-
export const VERSER_PROTOCOLS = new Set(
|
|
95
|
+
export const VERSER_PROTOCOLS = new Set([
|
|
96
|
+
...Object.values(Protocols),
|
|
97
|
+
"OCSR",
|
|
98
|
+
]);
|
|
67
99
|
const MATTER_CODEX_NAMES = invertCodex(MtrDex);
|
|
100
|
+
/** Project one matter code back to its generated codex member name. */
|
|
68
101
|
export function matterCodexName(code) {
|
|
69
102
|
return MATTER_CODEX_NAMES.get(code);
|
|
70
103
|
}
|
|
@@ -1,10 +1,314 @@
|
|
|
1
|
-
import { UnknownCodeError } from "../core/errors.js";
|
|
1
|
+
import { DeserializeError, UnknownCodeError } from "../core/errors.js";
|
|
2
2
|
import { COMPACTOR_CODES } from "../tables/counter-groups.js";
|
|
3
|
-
import { parseMapperBody } from "./mapper.js";
|
|
3
|
+
import { Mapper, parseMapperBody } from "./mapper.js";
|
|
4
|
+
/**
|
|
5
|
+
* CESR-native compactable map primitive.
|
|
6
|
+
*
|
|
7
|
+
* Maintainer mental model:
|
|
8
|
+
* a `Compactor` is a `Mapper` plus the tree-walking utilities needed to turn
|
|
9
|
+
* nested saidive maps into their "most compact" branch form and then re-expand
|
|
10
|
+
* them into readable partial-disclosure variants. `leaves` records the saidive
|
|
11
|
+
* map nodes discovered during tracing; `partials` records staged re-expansions.
|
|
12
|
+
*/
|
|
13
|
+
export class Compactor extends Mapper {
|
|
14
|
+
/**
|
|
15
|
+
* Construct one compactable map primitive.
|
|
16
|
+
*
|
|
17
|
+
* If `compactify=true` and the input starts from semantic `mad`, the
|
|
18
|
+
* constructor eagerly runs the compact + expand lifecycle so callers
|
|
19
|
+
* immediately get both the compact current state and readable partials.
|
|
20
|
+
*/
|
|
21
|
+
constructor(init = {}) {
|
|
22
|
+
super({
|
|
23
|
+
...init,
|
|
24
|
+
saidive: init.saidive ?? true,
|
|
25
|
+
verify: init.verify ?? true,
|
|
26
|
+
});
|
|
27
|
+
/** Leaf-path index populated by `trace()`: dotted path -> saidified leaf mapper. */
|
|
28
|
+
Object.defineProperty(this, "leaves", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
configurable: true,
|
|
31
|
+
writable: true,
|
|
32
|
+
value: void 0
|
|
33
|
+
});
|
|
34
|
+
/** Partially re-expanded disclosure variants built by `expand()`. */
|
|
35
|
+
Object.defineProperty(this, "partials", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
writable: true,
|
|
39
|
+
value: void 0
|
|
40
|
+
});
|
|
41
|
+
if (!COMPACTOR_CODES.has(this.code)) {
|
|
42
|
+
throw new UnknownCodeError(`Expected map compactor group code, got ${this.code}`);
|
|
43
|
+
}
|
|
44
|
+
this.leaves = {};
|
|
45
|
+
this.partials = null;
|
|
46
|
+
if (init.mad && (init.compactify ?? false)) {
|
|
47
|
+
this.compact();
|
|
48
|
+
this.expand();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Primary SAID of the current map state, if its configured saidive label is present. */
|
|
52
|
+
get said() {
|
|
53
|
+
const label = Object.keys(this.saids)[0];
|
|
54
|
+
const value = this._mad[label];
|
|
55
|
+
return typeof value === "string" ? value : null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* True when the current map is fully compacted.
|
|
59
|
+
*
|
|
60
|
+
* `true` means the root map itself is a leaf and its own saidive value is the
|
|
61
|
+
* compact representation. `false` means there are leaves but at least one
|
|
62
|
+
* branch is still expanded. `null` means the map tree has no saidive leaves.
|
|
63
|
+
*/
|
|
64
|
+
get iscompact() {
|
|
65
|
+
const paths = Object.keys(this.leaves);
|
|
66
|
+
if (paths.length === 0) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return this.said !== null && "" in this.leaves;
|
|
70
|
+
}
|
|
71
|
+
/** Return the nested tail value located at dotted `path`, or `null` when absent. */
|
|
72
|
+
getTail(path, mad = null) {
|
|
73
|
+
let tail = mad ?? this._mad;
|
|
74
|
+
const parts = path.split(".").slice(1);
|
|
75
|
+
for (const part of parts) {
|
|
76
|
+
if (!tail || typeof tail !== "object" || Array.isArray(tail)
|
|
77
|
+
|| !(part in tail)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
tail = tail[part];
|
|
81
|
+
}
|
|
82
|
+
return tail;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Return the enclosing map and tail label for dotted `path`.
|
|
86
|
+
*
|
|
87
|
+
* Example:
|
|
88
|
+
* path `.a.address` => returns the map stored at `.a` plus tail `"address"`.
|
|
89
|
+
* path `` (top level) => returns `[null, ""]`.
|
|
90
|
+
*/
|
|
91
|
+
getMad(path, mad = null) {
|
|
92
|
+
let current = mad ?? this._mad;
|
|
93
|
+
const parts = path.split(".");
|
|
94
|
+
const tail = parts.at(-1) ?? null;
|
|
95
|
+
const parents = parts.slice(1, -1);
|
|
96
|
+
if (parts.length <= 1) {
|
|
97
|
+
return [null, tail];
|
|
98
|
+
}
|
|
99
|
+
for (const part of parents) {
|
|
100
|
+
const next = current[part];
|
|
101
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) {
|
|
102
|
+
return [null, tail];
|
|
103
|
+
}
|
|
104
|
+
current = next;
|
|
105
|
+
}
|
|
106
|
+
if (tail !== null && tail !== "" && !(tail in current)) {
|
|
107
|
+
return [null, null];
|
|
108
|
+
}
|
|
109
|
+
return [current, tail];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Walk the nested map tree and index every saidive leaf by dotted path.
|
|
113
|
+
*
|
|
114
|
+
* When `saidify=true`, each leaf map is first rebuilt as a `Mapper` with
|
|
115
|
+
* `makify=true` so its leaf SAID is computed before the path is recorded.
|
|
116
|
+
*/
|
|
117
|
+
trace(saidify = false) {
|
|
118
|
+
this.leaves = {};
|
|
119
|
+
const paths = this._trace(this._mad, [], "", saidify);
|
|
120
|
+
if (saidify && this.iscompact === false) {
|
|
121
|
+
// When nested leaves have just been saidified, the top-level map's own
|
|
122
|
+
// SAID must also be recomputed over that updated structure.
|
|
123
|
+
const top = Mapper.fromSad(this._mad, {
|
|
124
|
+
strict: this.strict,
|
|
125
|
+
saidive: true,
|
|
126
|
+
saids: this.saids,
|
|
127
|
+
kind: this.kind,
|
|
128
|
+
makify: true,
|
|
129
|
+
verify: false,
|
|
130
|
+
});
|
|
131
|
+
this._mad = top.mad;
|
|
132
|
+
this.raw = top.raw;
|
|
133
|
+
this.fields = top.fields;
|
|
134
|
+
this.code = top.code;
|
|
135
|
+
this.count = top.count;
|
|
136
|
+
this.fullSize = top.fullSize;
|
|
137
|
+
this.fullSizeB2 = top.fullSizeB2;
|
|
138
|
+
this.totalSize = top.totalSize;
|
|
139
|
+
this.totalSizeB2 = top.totalSizeB2;
|
|
140
|
+
}
|
|
141
|
+
return paths;
|
|
142
|
+
}
|
|
143
|
+
/** Apply the most-compact branch reduction recursively until the root is compact or no leaves exist. */
|
|
144
|
+
compact() {
|
|
145
|
+
while (true) {
|
|
146
|
+
const paths = this.trace(true);
|
|
147
|
+
for (const path of paths) {
|
|
148
|
+
const leafer = this.leaves[path];
|
|
149
|
+
const [mad, tail] = this.getMad(path);
|
|
150
|
+
if (mad && tail) {
|
|
151
|
+
// Replacing a nested leaf map with its SAID is the actual "compaction"
|
|
152
|
+
// step. `trace(true)` did the saidification; this step does the branch
|
|
153
|
+
// contraction.
|
|
154
|
+
mad[tail] = leafer.said;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (paths.length === 0 || this.iscompact) {
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const rebuilt = Mapper.fromSad(this._mad, {
|
|
162
|
+
strict: this.strict,
|
|
163
|
+
saidive: true,
|
|
164
|
+
saids: this.saids,
|
|
165
|
+
kind: this.kind,
|
|
166
|
+
verify: false,
|
|
167
|
+
});
|
|
168
|
+
this._mad = rebuilt.mad;
|
|
169
|
+
this.raw = rebuilt.raw;
|
|
170
|
+
this.fields = rebuilt.fields;
|
|
171
|
+
this.code = rebuilt.code;
|
|
172
|
+
this.count = rebuilt.count;
|
|
173
|
+
this.fullSize = rebuilt.fullSize;
|
|
174
|
+
this.fullSizeB2 = rebuilt.fullSizeB2;
|
|
175
|
+
this.totalSize = rebuilt.totalSize;
|
|
176
|
+
this.totalSizeB2 = rebuilt.totalSizeB2;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Build readable partial-disclosure variants by progressively re-expanding compact leaves.
|
|
180
|
+
*
|
|
181
|
+
* `greedy=true` mirrors KERIpy’s preferred order: expand deeper leaves first
|
|
182
|
+
* so each staged variant reveals as much structure as possible per step.
|
|
183
|
+
*/
|
|
184
|
+
expand(greedy = true) {
|
|
185
|
+
this.partials = {};
|
|
186
|
+
let paths = Object.keys(this.leaves);
|
|
187
|
+
if (greedy) {
|
|
188
|
+
paths = [...paths].reverse();
|
|
189
|
+
}
|
|
190
|
+
const used = [];
|
|
191
|
+
if (paths.includes("")) {
|
|
192
|
+
const top = this.leaves[""];
|
|
193
|
+
const partial = new Compactor({
|
|
194
|
+
mad: top.mad,
|
|
195
|
+
verify: false,
|
|
196
|
+
saidive: false,
|
|
197
|
+
strict: this.strict,
|
|
198
|
+
kind: this.kind,
|
|
199
|
+
});
|
|
200
|
+
partial.trace(false);
|
|
201
|
+
this.partials[""] = partial;
|
|
202
|
+
used.push("");
|
|
203
|
+
}
|
|
204
|
+
const pmad = this.mad;
|
|
205
|
+
while (true) {
|
|
206
|
+
const unused = paths.filter((path) => !used.includes(path));
|
|
207
|
+
if (unused.length === 0) {
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
let created = false;
|
|
211
|
+
for (const path of unused) {
|
|
212
|
+
const [mad, tail] = this.getMad(path, pmad);
|
|
213
|
+
if (!mad || !tail) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
// Replacing one compact SAID with the full leaf map is the inverse
|
|
217
|
+
// operation of `compact()`. Repeating this step builds a staircase of
|
|
218
|
+
// disclosure variants from compact to expanded.
|
|
219
|
+
mad[tail] = this.leaves[path].mad;
|
|
220
|
+
used.push(path);
|
|
221
|
+
created = true;
|
|
222
|
+
}
|
|
223
|
+
if (created) {
|
|
224
|
+
const partial = new Compactor({
|
|
225
|
+
mad: pmad,
|
|
226
|
+
verify: false,
|
|
227
|
+
saidive: false,
|
|
228
|
+
strict: this.strict,
|
|
229
|
+
kind: this.kind,
|
|
230
|
+
});
|
|
231
|
+
const index = partial.trace(false);
|
|
232
|
+
this.partials[index.join("|")] = partial;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
_trace(mad, paths, path, saidify) {
|
|
240
|
+
// A map is a leaf when it has one of the configured saidive labels at this
|
|
241
|
+
// level and no descendant map with its own saidive field. That is the key
|
|
242
|
+
// mental model for every compact/disclose operation in this class.
|
|
243
|
+
let isLeaf = Object.keys(this.saids).some((label) => label in mad);
|
|
244
|
+
for (const [label, value] of Object.entries(mad)) {
|
|
245
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
246
|
+
if (label in this.saids) {
|
|
247
|
+
throw new DeserializeError(`Got nested map in said field label=${label}`);
|
|
248
|
+
}
|
|
249
|
+
if (this._hasSaid(value)) {
|
|
250
|
+
isLeaf = false;
|
|
251
|
+
this._trace(value, paths, `${path}.${label}`, saidify);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (isLeaf) {
|
|
256
|
+
paths.push(path);
|
|
257
|
+
// Each leaf is normalized through plain `Mapper` so `Compactor` stays
|
|
258
|
+
// focused on tree traversal and branch replacement rather than duplicating
|
|
259
|
+
// base map serialization logic.
|
|
260
|
+
const leafer = Mapper.fromSad(mad, {
|
|
261
|
+
strict: this.strict,
|
|
262
|
+
saidive: true,
|
|
263
|
+
saids: this.saids,
|
|
264
|
+
kind: this.kind,
|
|
265
|
+
makify: true,
|
|
266
|
+
verify: false,
|
|
267
|
+
});
|
|
268
|
+
if (saidify) {
|
|
269
|
+
for (const label of Object.keys(this.saids)) {
|
|
270
|
+
if (label in mad && leafer.mad[label] !== undefined) {
|
|
271
|
+
mad[label] = leafer.mad[label];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
this.leaves[path] = leafer;
|
|
276
|
+
}
|
|
277
|
+
return paths;
|
|
278
|
+
}
|
|
279
|
+
_hasSaid(mad) {
|
|
280
|
+
// This recursive predicate is deliberately separate from `_trace()` because
|
|
281
|
+
// the leaf test is the hardest part of compactor reasoning; keeping it in
|
|
282
|
+
// one helper makes future parity changes less error-prone.
|
|
283
|
+
for (const [label, value] of Object.entries(mad)) {
|
|
284
|
+
if (label in this.saids) {
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
if (value && typeof value === "object" && !Array.isArray(value)
|
|
288
|
+
&& this._hasSaid(value)) {
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Parse one CESR-native map body/group and hydrate it as a `Compactor`.
|
|
297
|
+
*
|
|
298
|
+
* Example:
|
|
299
|
+
* a native section like `-GAB0J_dE...0J_x-GA...` becomes a `Compactor` whose
|
|
300
|
+
* `.mad` is the readable nested object and whose `.qb64` is the exact native
|
|
301
|
+
* map-group bytes used on the wire.
|
|
302
|
+
*/
|
|
4
303
|
export function parseCompactor(input, version, cold) {
|
|
5
304
|
const mapper = parseMapperBody(input, version, cold);
|
|
6
305
|
if (!COMPACTOR_CODES.has(mapper.code)) {
|
|
7
306
|
throw new UnknownCodeError(`Expected map compactor group code, got ${mapper.code}`);
|
|
8
307
|
}
|
|
9
|
-
return
|
|
308
|
+
return new Compactor({
|
|
309
|
+
...(cold === "txt" ? { raw: mapper.raw } : { qb2: input }),
|
|
310
|
+
version,
|
|
311
|
+
kind: "CESR",
|
|
312
|
+
verify: false,
|
|
313
|
+
});
|
|
10
314
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { b, b64ToInt, codeB2ToB64, codeB64ToB2, intToB64, nabSextets, sceil
|
|
1
|
+
import { b, b64ToInt, codeB2ToB64, codeB64ToB2, intToB64, nabSextets, sceil } from "../core/bytes.js";
|
|
2
2
|
import { DeserializeError, ShortageError, UnknownCodeError } from "../core/errors.js";
|
|
3
|
-
import { resolveCounterCodeNameTable, resolveCounterSizeTable
|
|
3
|
+
import { resolveCounterCodeNameTable, resolveCounterSizeTable } from "../tables/counter-version-registry.js";
|
|
4
4
|
import { COUNTER_HARDS } from "../tables/counter.tables.generated.js";
|
|
5
5
|
const COUNTER_BARDS = new Map([...COUNTER_HARDS.entries()].map(([code, hs]) => [
|
|
6
6
|
String.fromCharCode(codeB64ToB2(code)[0])
|
|
@@ -18,6 +18,7 @@ function getTables(version) {
|
|
|
18
18
|
const nameTable = resolveCounterCodeNameTable(version);
|
|
19
19
|
return { sizeTable, nameTable };
|
|
20
20
|
}
|
|
21
|
+
/** Inhale one text-domain counter token using the version-selected counter tables. */
|
|
21
22
|
function parseCounterFromTextData(input, version) {
|
|
22
23
|
const txt = String.fromCharCode(...input);
|
|
23
24
|
if (txt.length === 0) {
|
|
@@ -62,6 +63,7 @@ function parseCounterFromTextData(input, version) {
|
|
|
62
63
|
version,
|
|
63
64
|
};
|
|
64
65
|
}
|
|
66
|
+
/** Inhale one qb2 counter token into the canonical text-oriented counter shape. */
|
|
65
67
|
function parseCounterFromBinaryData(input, version) {
|
|
66
68
|
if (input.length < 2) {
|
|
67
69
|
throw new ShortageError(2, input.length);
|
|
@@ -100,6 +102,7 @@ function parseCounterFromBinaryData(input, version) {
|
|
|
100
102
|
version,
|
|
101
103
|
};
|
|
102
104
|
}
|
|
105
|
+
/** Exhale a counter code/count pair into its fully qualified versioned token. */
|
|
103
106
|
function encodeCounterFromFields(code, count, version) {
|
|
104
107
|
const { sizeTable, nameTable } = getTables(version);
|
|
105
108
|
const sizage = sizeTable.get(code);
|
|
@@ -123,6 +126,7 @@ function encodeCounterFromFields(code, count, version) {
|
|
|
123
126
|
version,
|
|
124
127
|
};
|
|
125
128
|
}
|
|
129
|
+
/** Normalize the supported constructor variants into one shared counter payload. */
|
|
126
130
|
function parseCounterInit(init) {
|
|
127
131
|
const version = init.version ?? { major: 2, minor: 0 };
|
|
128
132
|
if (init.code !== undefined) {
|
|
@@ -14,8 +14,7 @@ function toIso8601(dts) {
|
|
|
14
14
|
*/
|
|
15
15
|
export class Dater extends Matter {
|
|
16
16
|
constructor(init) {
|
|
17
|
-
|
|
18
|
-
super(matter);
|
|
17
|
+
super(init);
|
|
19
18
|
if (!DATER_CODES.has(this.code)) {
|
|
20
19
|
throw new UnknownCodeError(`Expected dater DateTime code, got ${this.code}`);
|
|
21
20
|
}
|
|
@@ -29,23 +29,19 @@ function rawifyDns(dns) {
|
|
|
29
29
|
*/
|
|
30
30
|
export class Decimer extends Matter {
|
|
31
31
|
constructor(init) {
|
|
32
|
-
|
|
32
|
+
const matterInit = (!(init instanceof Matter)
|
|
33
33
|
&& !init.raw
|
|
34
34
|
&& !init.qb64
|
|
35
35
|
&& !init.qb64b
|
|
36
36
|
&& !init.qb2
|
|
37
|
-
&& (init.dns !== undefined || init.decimal !== undefined))
|
|
38
|
-
|
|
39
|
-
super({
|
|
37
|
+
&& (init.dns !== undefined || init.decimal !== undefined))
|
|
38
|
+
? {
|
|
40
39
|
...init,
|
|
41
|
-
raw: rawifyDns(dns),
|
|
40
|
+
raw: rawifyDns(init.dns ?? `${init.decimal}`),
|
|
42
41
|
code: init.code ?? "4H",
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const matter = init instanceof Matter ? init : new Matter(init);
|
|
47
|
-
super(matter);
|
|
48
|
-
}
|
|
42
|
+
}
|
|
43
|
+
: init;
|
|
44
|
+
super(matterInit);
|
|
49
45
|
if (!DECIMAL_CODES.has(this.code)) {
|
|
50
46
|
throw new UnknownCodeError(`Expected decimal code, got ${this.code}`);
|
|
51
47
|
}
|
|
@@ -1,18 +1,134 @@
|
|
|
1
|
-
import { UnknownCodeError } from "../core/errors.js";
|
|
2
|
-
import {
|
|
1
|
+
import { DeserializeError, UnknownCodeError } from "../core/errors.js";
|
|
2
|
+
import { normalizeByteLike } from "./byte-like.js";
|
|
3
|
+
import { Cipher } from "./cipher.js";
|
|
4
|
+
import { CIPHER_X25519_ALL_QB64_CODES, CIPHER_X25519_FIXED_QB64_CODES, CIPHER_X25519_QB2_VARIABLE_CODES, CIPHER_X25519_VARIABLE_STREAM_CODES, DECRYPTER_CODES, MtrDex, } from "./codex.js";
|
|
3
5
|
import { Matter } from "./matter.js";
|
|
6
|
+
import { Salter } from "./salter.js";
|
|
7
|
+
import { boxKeyPairFromEd25519Seed, boxPublicKeyFromPrivateKey, openSealedBox } from "./sealed-box.js";
|
|
8
|
+
import { Signer } from "./signer.js";
|
|
9
|
+
import { Streamer } from "./streamer.js";
|
|
10
|
+
/** Normalize direct X25519 or derived-Ed25519 constructor forms into `Matter` input. */
|
|
11
|
+
function normalizeMatterInit(init) {
|
|
12
|
+
if (init instanceof Matter) {
|
|
13
|
+
return init;
|
|
14
|
+
}
|
|
15
|
+
const normalized = {
|
|
16
|
+
code: init.code ?? MtrDex.X25519_Private,
|
|
17
|
+
};
|
|
18
|
+
if (init.raw) {
|
|
19
|
+
normalized.raw = normalizeByteLike(init.raw);
|
|
20
|
+
return normalized;
|
|
21
|
+
}
|
|
22
|
+
if (init.qb64b) {
|
|
23
|
+
normalized.qb64b = normalizeByteLike(init.qb64b);
|
|
24
|
+
return normalized;
|
|
25
|
+
}
|
|
26
|
+
if (init.qb64) {
|
|
27
|
+
normalized.qb64b = normalizeByteLike(init.qb64);
|
|
28
|
+
return normalized;
|
|
29
|
+
}
|
|
30
|
+
if (init.qb2) {
|
|
31
|
+
normalized.qb2 = normalizeByteLike(init.qb2);
|
|
32
|
+
return normalized;
|
|
33
|
+
}
|
|
34
|
+
if (!init.seed) {
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
const signer = new Signer({ qb64b: normalizeByteLike(init.seed) });
|
|
38
|
+
if (signer.code !== MtrDex.Ed25519_Seed) {
|
|
39
|
+
throw new DeserializeError(`Unsupported signing seed derivation code = ${signer.code}.`);
|
|
40
|
+
}
|
|
41
|
+
normalized.raw = boxKeyPairFromEd25519Seed(signer.raw).privateKey;
|
|
42
|
+
return normalized;
|
|
43
|
+
}
|
|
44
|
+
function hydratePlaintext(cipher, plain, ctor, transferable) {
|
|
45
|
+
if (CIPHER_X25519_ALL_QB64_CODES.has(cipher.code)) {
|
|
46
|
+
return new ctor({ qb64b: plain, transferable });
|
|
47
|
+
}
|
|
48
|
+
if (CIPHER_X25519_QB2_VARIABLE_CODES.has(cipher.code)) {
|
|
49
|
+
return new ctor({ qb2: plain });
|
|
50
|
+
}
|
|
51
|
+
if (CIPHER_X25519_VARIABLE_STREAM_CODES.has(cipher.code)) {
|
|
52
|
+
return new ctor({ stream: plain });
|
|
53
|
+
}
|
|
54
|
+
throw new UnknownCodeError(`Unsupported cipher code = ${cipher.code}.`);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolve the default plaintext constructor implied by one cipher family.
|
|
58
|
+
*
|
|
59
|
+
* KERIpy correspondence:
|
|
60
|
+
* - fixed salt/seed families default to `Salter` / `Signer`
|
|
61
|
+
* - whole-stream families default to `Streamer`
|
|
62
|
+
* - generic qb64/qb2 variable families still require the caller to say what
|
|
63
|
+
* semantic primitive should be rehydrated from the plaintext bytes
|
|
64
|
+
*/
|
|
65
|
+
function defaultCtorForCipher(cipher) {
|
|
66
|
+
if (cipher.code === MtrDex.X25519_Cipher_Salt) {
|
|
67
|
+
return Salter;
|
|
68
|
+
}
|
|
69
|
+
if (cipher.code === MtrDex.X25519_Cipher_Seed) {
|
|
70
|
+
return Signer;
|
|
71
|
+
}
|
|
72
|
+
if (CIPHER_X25519_VARIABLE_STREAM_CODES.has(cipher.code)) {
|
|
73
|
+
return Streamer;
|
|
74
|
+
}
|
|
75
|
+
if (CIPHER_X25519_FIXED_QB64_CODES.has(cipher.code)
|
|
76
|
+
|| CIPHER_X25519_QB2_VARIABLE_CODES.has(cipher.code)
|
|
77
|
+
|| CIPHER_X25519_ALL_QB64_CODES.has(cipher.code)) {
|
|
78
|
+
throw new UnknownCodeError(`Unsupported cipher code = ${cipher.code} when ctor is missing.`);
|
|
79
|
+
}
|
|
80
|
+
throw new UnknownCodeError(`Unsupported cipher code = ${cipher.code}.`);
|
|
81
|
+
}
|
|
4
82
|
/**
|
|
5
83
|
* Private-key decryption primitive for asymmetric envelope payloads.
|
|
6
84
|
*
|
|
7
|
-
* KERIpy substance:
|
|
8
|
-
* recover
|
|
85
|
+
* KERIpy substance: `Decrypter` owns the private X25519 material used to
|
|
86
|
+
* recover CESR payloads from sealed-box ciphers, optionally deriving it from
|
|
87
|
+
* an Ed25519 signing seed.
|
|
9
88
|
*/
|
|
10
89
|
export class Decrypter extends Matter {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Construct one X25519 private-key decrypter.
|
|
92
|
+
*
|
|
93
|
+
* Default code remains the KERIpy private-box family
|
|
94
|
+
* `MtrDex.X25519_Private`.
|
|
95
|
+
*/
|
|
96
|
+
constructor(init = {}) {
|
|
97
|
+
super(normalizeMatterInit(init));
|
|
14
98
|
if (!DECRYPTER_CODES.has(this.code)) {
|
|
15
99
|
throw new UnknownCodeError(`Expected decrypter key code, got ${this.code}`);
|
|
16
100
|
}
|
|
17
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Decrypt one cipher and rehydrate the plaintext with the requested
|
|
104
|
+
* constructor.
|
|
105
|
+
*
|
|
106
|
+
* Resolution rules:
|
|
107
|
+
* - `cipher` wins when supplied
|
|
108
|
+
* - otherwise `qb64` is parsed before `qb2`
|
|
109
|
+
* - omitted `ctor` is only inferred for the KERIpy families that already
|
|
110
|
+
* name their semantic plaintext shape
|
|
111
|
+
*
|
|
112
|
+
* Output rules:
|
|
113
|
+
* - `bare=true` returns plaintext bytes directly
|
|
114
|
+
* - otherwise `transferable` is forwarded only to qb64-family primitive
|
|
115
|
+
* constructors such as `Signer`, matching the KERIpy init seam
|
|
116
|
+
*/
|
|
117
|
+
decrypt({ cipher, qb64, qb2, ctor, transferable = false, bare = false, } = {}) {
|
|
118
|
+
const hydrated = cipher
|
|
119
|
+
?? (qb64
|
|
120
|
+
? new Cipher({ qb64b: normalizeByteLike(qb64) })
|
|
121
|
+
: qb2
|
|
122
|
+
? new Cipher({ qb2: normalizeByteLike(qb2) })
|
|
123
|
+
: null);
|
|
124
|
+
if (!hydrated) {
|
|
125
|
+
throw new DeserializeError("Need one of cipher, qb64, or qb2.");
|
|
126
|
+
}
|
|
127
|
+
const plain = openSealedBox(hydrated.raw, boxPublicKeyFromPrivateKey(this.raw), this.raw);
|
|
128
|
+
if (bare) {
|
|
129
|
+
return plain;
|
|
130
|
+
}
|
|
131
|
+
const effectiveCtor = (ctor ?? defaultCtorForCipher(hydrated));
|
|
132
|
+
return hydratePlaintext(hydrated, plain, effectiveCtor, transferable);
|
|
133
|
+
}
|
|
18
134
|
}
|