cesr-ts 0.4.0 → 0.5.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 +11 -2
- 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 +19 -16
- 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,8 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b, codeB2ToB64 } from "../core/bytes.js";
|
|
2
|
+
import { DeserializeError, SerializeError, UnknownCodeError } from "../core/errors.js";
|
|
3
|
+
import { CtrDexV2 } from "../tables/counter-codex.js";
|
|
2
4
|
import { AGGOR_CODES, AGGOR_LIST_CODES, AGGOR_MAP_CODES } from "../tables/counter-groups.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
+
import { MATTER_SIZES } from "../tables/matter.tables.generated.js";
|
|
6
|
+
import { DigDex } from "./codex.js";
|
|
7
|
+
import { Counter, parseCounter } from "./counter.js";
|
|
8
|
+
import { Diger } from "./diger.js";
|
|
9
|
+
import { Mapper, parseMapperBody } from "./mapper.js";
|
|
10
|
+
import { parseMatter } from "./matter.js";
|
|
5
11
|
import { parseStructor, Structor } from "./structor.js";
|
|
12
|
+
/**
|
|
13
|
+
* `Aggor` is the aggregate-list sibling to `Compactor`.
|
|
14
|
+
*
|
|
15
|
+
* Where `Compactor` contracts nested map branches to SAIDs, `Aggor` contracts a
|
|
16
|
+
* list of aggregate elements down to one commitment in slot zero (`agid`) while
|
|
17
|
+
* still supporting later selective disclosure of map elements.
|
|
18
|
+
*
|
|
19
|
+
* Boundary rule:
|
|
20
|
+
* - `Aggor` owns selective disclosure for aggregate lists
|
|
21
|
+
* - `Compactor` owns hierarchical map disclosure
|
|
22
|
+
* - `disclosure.ts` owns fixed-field blind/bound/media disclosure
|
|
23
|
+
*/
|
|
6
24
|
/** True when counter code belongs to aggregate-list group families. */
|
|
7
25
|
export function isAggorListCode(code) {
|
|
8
26
|
return AGGOR_LIST_CODES.has(code);
|
|
@@ -16,20 +34,32 @@ export function isAggorCode(code) {
|
|
|
16
34
|
return AGGOR_CODES.has(code);
|
|
17
35
|
}
|
|
18
36
|
/**
|
|
19
|
-
* Aggregate list/map
|
|
37
|
+
* Aggregate list/map primitive.
|
|
20
38
|
*
|
|
21
|
-
* KERIpy substance:
|
|
22
|
-
*
|
|
39
|
+
* KERIpy substance:
|
|
40
|
+
* - list-form `Aggor` owns aggregate-element-list (`ael`) semantics and `agid`
|
|
41
|
+
* computation/disclosure
|
|
42
|
+
* - map-form `Aggor` is preserved here only as a compatibility bridge for
|
|
43
|
+
* parser-group projections that still classify generic map groups as aggor
|
|
44
|
+
* families in the TS codebase
|
|
45
|
+
*
|
|
46
|
+
* The important tradeoff is intentional:
|
|
47
|
+
* - the list lane is the real graduated-disclosure story here
|
|
48
|
+
* - the map lane mainly keeps parser projections lossless and readable
|
|
23
49
|
*/
|
|
24
50
|
export class Aggor extends Structor {
|
|
51
|
+
/**
|
|
52
|
+
* Construct one aggregate primitive.
|
|
53
|
+
*
|
|
54
|
+
* Two semantic lanes exist:
|
|
55
|
+
* - list lane: real aggregate semantics (`ael`, `agid`, disclosure)
|
|
56
|
+
* - map lane: compatibility bridge for existing TS parser projections that
|
|
57
|
+
* still bucket generic map groups into aggregate families
|
|
58
|
+
*/
|
|
25
59
|
constructor(init) {
|
|
26
|
-
const payload =
|
|
27
|
-
?
|
|
28
|
-
:
|
|
29
|
-
? init
|
|
30
|
-
: {
|
|
31
|
-
structor: new Structor(init),
|
|
32
|
-
};
|
|
60
|
+
const payload = "structor" in init
|
|
61
|
+
? init
|
|
62
|
+
: Aggor.materializeStructor(init);
|
|
33
63
|
super(payload.structor);
|
|
34
64
|
Object.defineProperty(this, "kind", {
|
|
35
65
|
enumerable: true,
|
|
@@ -37,48 +67,362 @@ export class Aggor extends Structor {
|
|
|
37
67
|
writable: true,
|
|
38
68
|
value: void 0
|
|
39
69
|
});
|
|
70
|
+
/** Map-style compatibility projection for parser-origin map groups. */
|
|
40
71
|
Object.defineProperty(this, "mapFields", {
|
|
41
72
|
enumerable: true,
|
|
42
73
|
configurable: true,
|
|
43
74
|
writable: true,
|
|
44
75
|
value: void 0
|
|
45
76
|
});
|
|
77
|
+
Object.defineProperty(this, "strict", {
|
|
78
|
+
enumerable: true,
|
|
79
|
+
configurable: true,
|
|
80
|
+
writable: true,
|
|
81
|
+
value: void 0
|
|
82
|
+
});
|
|
83
|
+
Object.defineProperty(this, "saids", {
|
|
84
|
+
enumerable: true,
|
|
85
|
+
configurable: true,
|
|
86
|
+
writable: true,
|
|
87
|
+
value: void 0
|
|
88
|
+
});
|
|
89
|
+
/** Digest code used to compute the aggregate identifier (`agid`). */
|
|
90
|
+
Object.defineProperty(this, "digestCode", {
|
|
91
|
+
enumerable: true,
|
|
92
|
+
configurable: true,
|
|
93
|
+
writable: true,
|
|
94
|
+
value: void 0
|
|
95
|
+
});
|
|
96
|
+
Object.defineProperty(this, "wireKind", {
|
|
97
|
+
enumerable: true,
|
|
98
|
+
configurable: true,
|
|
99
|
+
writable: true,
|
|
100
|
+
value: void 0
|
|
101
|
+
});
|
|
102
|
+
Object.defineProperty(this, "_ael", {
|
|
103
|
+
enumerable: true,
|
|
104
|
+
configurable: true,
|
|
105
|
+
writable: true,
|
|
106
|
+
value: void 0
|
|
107
|
+
});
|
|
46
108
|
if (!isAggorCode(this.code)) {
|
|
47
109
|
throw new UnknownCodeError(`Expected aggregate list/map group code, got ${this.code}`);
|
|
48
110
|
}
|
|
49
111
|
this.kind = isAggorMapCode(this.code) ? "map" : "list";
|
|
50
112
|
this.mapFields = payload.mapFields;
|
|
113
|
+
this.strict = "structor" in init
|
|
114
|
+
? true
|
|
115
|
+
: (init.strict ?? true);
|
|
116
|
+
this.saids = {
|
|
117
|
+
...("structor" in init
|
|
118
|
+
? {}
|
|
119
|
+
: (init.saids ?? { d: DigDex.Blake3_256 })),
|
|
120
|
+
};
|
|
121
|
+
this.digestCode = "structor" in init
|
|
122
|
+
? DigDex.Blake3_256
|
|
123
|
+
: (init.code ?? DigDex.Blake3_256);
|
|
124
|
+
this.wireKind = "structor" in init
|
|
125
|
+
? "CESR"
|
|
126
|
+
: (init.kind ?? "CESR");
|
|
127
|
+
if (this.kind === "list") {
|
|
128
|
+
try {
|
|
129
|
+
// Parser-origin list groups may be arbitrary generic list payloads, so
|
|
130
|
+
// deserialization into semantic aggregate elements is best-effort. When
|
|
131
|
+
// that semantic view is not meaningful we still preserve the structor.
|
|
132
|
+
this._ael = Aggor.deserializeList(this.qb64g, this.strict, this.saids);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
this._ael = [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
this._ael = [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** Aggregate identifier at element zero for list-form aggregates. */
|
|
143
|
+
get agid() {
|
|
144
|
+
return this.kind === "list" && typeof this._ael[0] === "string"
|
|
145
|
+
? this._ael[0]
|
|
146
|
+
: null;
|
|
51
147
|
}
|
|
52
|
-
/**
|
|
148
|
+
/** Aggregate element list in semantic form. */
|
|
149
|
+
get ael() {
|
|
150
|
+
return this._ael.map((entry) => Aggor.clone(entry));
|
|
151
|
+
}
|
|
152
|
+
/** Tuple/list payload items for parser-origin list aggregate families. */
|
|
53
153
|
get listItems() {
|
|
54
154
|
return this.kind === "list" ? this.items : undefined;
|
|
55
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Verify that the disclosed aggregate list still hashes to the agid in slot zero.
|
|
158
|
+
*
|
|
159
|
+
* Example:
|
|
160
|
+
* a disclosure list like `[agid, {d: "...", x: 1}, "E...undisclosed"]`
|
|
161
|
+
* verifies when replacing the disclosed map with its computed SAID reproduces
|
|
162
|
+
* the agid at position zero.
|
|
163
|
+
*/
|
|
164
|
+
static verifyDisclosure(ael, kind = "CESR", code = DigDex.Blake3_256, saids = { d: DigDex.Blake3_256 }) {
|
|
165
|
+
// Verification is intentionally "rebuild and compare agid", not a more
|
|
166
|
+
// magical shortcut. Disclosure semantics are easier to trust when the test
|
|
167
|
+
// is literally "does this disclosed list still hash back to slot zero?"
|
|
168
|
+
try {
|
|
169
|
+
const aggor = new Aggor({
|
|
170
|
+
ael,
|
|
171
|
+
kind,
|
|
172
|
+
code,
|
|
173
|
+
saids,
|
|
174
|
+
verify: true,
|
|
175
|
+
});
|
|
176
|
+
return aggor.agid === (typeof ael[0] === "string" ? ael[0] : null);
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Produce a disclosure view where only `indices` are expanded back into maps.
|
|
184
|
+
*
|
|
185
|
+
* Index `0` is always the agid and stays compact; only later map elements are
|
|
186
|
+
* eligible for disclosure expansion.
|
|
187
|
+
*/
|
|
188
|
+
disclose(indices = []) {
|
|
189
|
+
if (this.kind !== "list") {
|
|
190
|
+
throw new SerializeError("Disclosure is only defined for aggregate lists.");
|
|
191
|
+
}
|
|
192
|
+
// We first normalize every element into either:
|
|
193
|
+
// - the aggregate's compact commitment string, or
|
|
194
|
+
// - a `Mapper` that knows how to compute its own compact SAID.
|
|
195
|
+
const atoms = this._ael.map((element, index) => {
|
|
196
|
+
if (index === 0) {
|
|
197
|
+
return element;
|
|
198
|
+
}
|
|
199
|
+
if (element && typeof element === "object" && !Array.isArray(element)) {
|
|
200
|
+
return Mapper.fromSad(element, {
|
|
201
|
+
strict: this.strict,
|
|
202
|
+
saidive: true,
|
|
203
|
+
saids: this.saids,
|
|
204
|
+
kind: this.wireKind,
|
|
205
|
+
makify: true,
|
|
206
|
+
verify: false,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return element;
|
|
210
|
+
});
|
|
211
|
+
const disclosure = atoms.map((atom) => atom instanceof Mapper ? (atom.said ?? "") : atom);
|
|
212
|
+
for (const index of indices) {
|
|
213
|
+
if (index > 0 && index < atoms.length && atoms[index] instanceof Mapper) {
|
|
214
|
+
// Disclosure only expands selected post-agid map elements. The agid at
|
|
215
|
+
// slot zero always remains compact because it is the commitment anchor.
|
|
216
|
+
disclosure[index] = atoms[index].mad;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return [disclosure, this.wireKind];
|
|
220
|
+
}
|
|
56
221
|
/** Hydrate from an already parsed counter-group node. */
|
|
57
222
|
static fromGroup(group, sourceDomain = "txt") {
|
|
58
|
-
|
|
223
|
+
const structor = Structor.fromGroup(group, sourceDomain);
|
|
224
|
+
if (isAggorMapCode(structor.code)) {
|
|
225
|
+
const map = parseMapperBody(b(structor.qb64g), { major: 2, minor: 0 }, "txt");
|
|
226
|
+
return new Aggor({ structor, mapFields: map.fields });
|
|
227
|
+
}
|
|
228
|
+
return new Aggor({ structor });
|
|
229
|
+
}
|
|
230
|
+
static materializeStructor(init) {
|
|
231
|
+
const version = init.version ?? { major: 2, minor: 0 };
|
|
232
|
+
const raw = init.qb2
|
|
233
|
+
? Aggor.canonicalize(init.qb2, version)
|
|
234
|
+
: init.qb64
|
|
235
|
+
? b(init.qb64)
|
|
236
|
+
: init.qb64b
|
|
237
|
+
? init.qb64b
|
|
238
|
+
: init.raw
|
|
239
|
+
? init.raw
|
|
240
|
+
: init.ael
|
|
241
|
+
? b(Aggor.serializeList(Aggor.clone(init.ael), init))
|
|
242
|
+
: null;
|
|
243
|
+
if (!raw) {
|
|
244
|
+
throw new SerializeError("Aggor requires ael or raw/qb64/qb64b/qb2 input.");
|
|
245
|
+
}
|
|
246
|
+
const structor = parseStructor(raw, version, "txt", AGGOR_CODES, "aggregate list/map");
|
|
247
|
+
const mapFields = isAggorMapCode(structor.code)
|
|
248
|
+
? new Mapper({
|
|
249
|
+
raw: b(structor.qb64g),
|
|
250
|
+
version,
|
|
251
|
+
kind: "CESR",
|
|
252
|
+
verify: false,
|
|
253
|
+
}).fields
|
|
254
|
+
: undefined;
|
|
255
|
+
if (init.verify ?? true) {
|
|
256
|
+
if (isAggorListCode(structor.code)) {
|
|
257
|
+
// Today verification proves the aggregate identifier can be recomputed.
|
|
258
|
+
// It does not yet enforce every deeper KERIpy edge case, so keep this
|
|
259
|
+
// seam explicit for future parity expansion.
|
|
260
|
+
const ael = Aggor.deserializeList(structor.qb64g, init.strict ?? true, init.saids ?? { d: DigDex.Blake3_256 });
|
|
261
|
+
Aggor.computeAgid(ael, init.kind ?? "CESR", init.code ?? DigDex.Blake3_256, init.strict ?? true, init.saids ?? { d: DigDex.Blake3_256 });
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return { structor, mapFields };
|
|
265
|
+
}
|
|
266
|
+
static canonicalize(raw, version) {
|
|
267
|
+
if (raw.length > 0 && raw[0] === "-".charCodeAt(0)) {
|
|
268
|
+
return raw;
|
|
269
|
+
}
|
|
270
|
+
const counter = parseCounter(raw, version, "bny");
|
|
271
|
+
return b(codeB2ToB64(raw, counter.fullSize + counter.count * 4));
|
|
272
|
+
}
|
|
273
|
+
static clone(value) {
|
|
274
|
+
if (Array.isArray(value)) {
|
|
275
|
+
return value.map((entry) => Aggor.clone(entry));
|
|
276
|
+
}
|
|
277
|
+
if (value && typeof value === "object") {
|
|
278
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, Aggor.clone(v)]));
|
|
279
|
+
}
|
|
280
|
+
return value;
|
|
281
|
+
}
|
|
282
|
+
static serializeList(ael, options) {
|
|
283
|
+
const strict = options.strict ?? true;
|
|
284
|
+
const saids = options.saids ?? { d: DigDex.Blake3_256 };
|
|
285
|
+
const kind = options.kind ?? "CESR";
|
|
286
|
+
const code = options.code ?? DigDex.Blake3_256;
|
|
287
|
+
const makify = options.makify ?? false;
|
|
288
|
+
const working = Aggor.clone(ael);
|
|
289
|
+
if (makify && working.length > 0) {
|
|
290
|
+
// Slot zero is always the aggregate identifier. During makify we dummy it
|
|
291
|
+
// first, normalize later map elements into saidified `Mapper`s, then
|
|
292
|
+
// compute the final agid over that compacted view.
|
|
293
|
+
const sizage = MATTER_SIZES.get(code);
|
|
294
|
+
if (!sizage?.fs) {
|
|
295
|
+
throw new SerializeError(`Unsupported aggregate digest code=${code}`);
|
|
296
|
+
}
|
|
297
|
+
working[0] = "#".repeat(sizage.fs);
|
|
298
|
+
for (let idx = 1; idx < working.length; idx++) {
|
|
299
|
+
const element = working[idx];
|
|
300
|
+
if (element && typeof element === "object" && !Array.isArray(element)) {
|
|
301
|
+
const mapper = Mapper.fromSad(element, {
|
|
302
|
+
strict,
|
|
303
|
+
saidive: true,
|
|
304
|
+
saids,
|
|
305
|
+
kind,
|
|
306
|
+
makify: true,
|
|
307
|
+
verify: false,
|
|
308
|
+
});
|
|
309
|
+
working[idx] = mapper.mad;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const agid = Aggor.computeAgid(working, kind, code, strict, saids);
|
|
313
|
+
if (ael.length > 0) {
|
|
314
|
+
ael[0] = agid;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const compacted = working.map((element, idx) => {
|
|
318
|
+
if (idx === 0) {
|
|
319
|
+
return typeof ael[0] === "string" ? ael[0] : "";
|
|
320
|
+
}
|
|
321
|
+
if (element && typeof element === "object" && !Array.isArray(element)) {
|
|
322
|
+
// Aggregate list elements compact exactly like disclosed map sections:
|
|
323
|
+
// nested map content collapses to its mapper-native representation.
|
|
324
|
+
const mapper = Mapper.fromSad(element, {
|
|
325
|
+
strict,
|
|
326
|
+
saidive: true,
|
|
327
|
+
saids,
|
|
328
|
+
kind,
|
|
329
|
+
makify: true,
|
|
330
|
+
verify: false,
|
|
331
|
+
});
|
|
332
|
+
return mapper.qb64;
|
|
333
|
+
}
|
|
334
|
+
return String(element);
|
|
335
|
+
}).join("");
|
|
336
|
+
const codeName = compacted.length / 4 < 64 ** 2
|
|
337
|
+
? CtrDexV2.GenericListGroup
|
|
338
|
+
: CtrDexV2.BigGenericListGroup;
|
|
339
|
+
return `${new Counter({ code: codeName, count: compacted.length / 4 }).qb64}${compacted}`;
|
|
340
|
+
}
|
|
341
|
+
static deserializeList(qb64, strict, saids) {
|
|
342
|
+
// Aggregate lists are walked element-by-element from the enclosed list
|
|
343
|
+
// payload. Elements may be:
|
|
344
|
+
// - compact qb64 commitments, or
|
|
345
|
+
// - nested map groups representing disclosed element bodies.
|
|
346
|
+
const raw = b(qb64);
|
|
347
|
+
const counter = parseCounter(raw, { major: 2, minor: 0 }, "txt");
|
|
348
|
+
const payload = raw.slice(counter.fullSize, counter.fullSize + counter.count * 4);
|
|
349
|
+
const out = [];
|
|
350
|
+
let offset = 0;
|
|
351
|
+
while (offset < payload.length) {
|
|
352
|
+
if (payload[offset] === "-".charCodeAt(0)) {
|
|
353
|
+
const nextCounter = parseCounter(payload.slice(offset), {
|
|
354
|
+
major: 2,
|
|
355
|
+
minor: 0,
|
|
356
|
+
}, "txt");
|
|
357
|
+
if (!isAggorMapCode(nextCounter.code)) {
|
|
358
|
+
throw new DeserializeError(`Expected aggregate element map group, got ${nextCounter.code}`);
|
|
359
|
+
}
|
|
360
|
+
const total = nextCounter.fullSize + nextCounter.count * 4;
|
|
361
|
+
const mapper = new Mapper({
|
|
362
|
+
raw: payload.slice(offset, offset + total),
|
|
363
|
+
strict,
|
|
364
|
+
saidive: true,
|
|
365
|
+
saids,
|
|
366
|
+
kind: "CESR",
|
|
367
|
+
verify: false,
|
|
368
|
+
});
|
|
369
|
+
out.push(mapper.mad);
|
|
370
|
+
offset += total;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const matter = parseMatter(payload.slice(offset), "txt");
|
|
374
|
+
out.push(matter.qb64);
|
|
375
|
+
offset += matter.fullSize;
|
|
376
|
+
}
|
|
377
|
+
return out;
|
|
378
|
+
}
|
|
379
|
+
static computeAgid(ael, kind, code, strict, saids) {
|
|
380
|
+
// `agid` is computed over the compacted aggregate view:
|
|
381
|
+
// dummy slot zero, compact every nested map element to its mapper SAID, then
|
|
382
|
+
// hash the fully enclosed list-group serialization.
|
|
383
|
+
const compacted = ael.map((element, idx) => {
|
|
384
|
+
if (idx === 0) {
|
|
385
|
+
const sizage = MATTER_SIZES.get(code);
|
|
386
|
+
if (!sizage?.fs) {
|
|
387
|
+
throw new SerializeError(`Unsupported aggregate digest code=${code}`);
|
|
388
|
+
}
|
|
389
|
+
return "#".repeat(sizage.fs);
|
|
390
|
+
}
|
|
391
|
+
if (element && typeof element === "object" && !Array.isArray(element)) {
|
|
392
|
+
const mapper = Mapper.fromSad(element, {
|
|
393
|
+
strict,
|
|
394
|
+
saidive: true,
|
|
395
|
+
saids,
|
|
396
|
+
kind,
|
|
397
|
+
makify: true,
|
|
398
|
+
verify: false,
|
|
399
|
+
});
|
|
400
|
+
return mapper.said ?? "";
|
|
401
|
+
}
|
|
402
|
+
return String(element);
|
|
403
|
+
}).join("");
|
|
404
|
+
const groupCode = compacted.length / 4 < 64 ** 2
|
|
405
|
+
? CtrDexV2.GenericListGroup
|
|
406
|
+
: CtrDexV2.BigGenericListGroup;
|
|
407
|
+
const raw = b(`${new Counter({ code: groupCode, count: compacted.length / 4 }).qb64}${compacted}`);
|
|
408
|
+
return new Diger({ code, raw: Diger.digest(raw, code) }).qb64;
|
|
59
409
|
}
|
|
60
410
|
}
|
|
61
411
|
/**
|
|
62
|
-
* Parse aggregate attachment groups as
|
|
412
|
+
* Parse aggregate attachment groups as semantic aggregate containers.
|
|
63
413
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
414
|
+
* Example:
|
|
415
|
+
* a list body `-JAE<agid><map-or-said>...` becomes an `Aggor` whose `.ael`
|
|
416
|
+
* exposes the readable element list and whose `.agid` is the commitment in slot
|
|
417
|
+
* zero. A map-group still parses for compatibility, but exposes `.mapFields`
|
|
418
|
+
* rather than aggregate-list semantics.
|
|
66
419
|
*/
|
|
67
420
|
export function parseAggor(input, version, cold) {
|
|
68
421
|
const counter = parseCounter(input, version, cold);
|
|
69
422
|
if (!isAggorCode(counter.code)) {
|
|
70
423
|
throw new UnknownCodeError(`Expected aggregate list/map group code, got ${counter.code}`);
|
|
71
424
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return new Aggor({
|
|
76
|
-
structor,
|
|
77
|
-
mapFields: map.fields,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
if (isAggorListCode(structor.code)) {
|
|
81
|
-
return new Aggor(structor);
|
|
82
|
-
}
|
|
83
|
-
throw new UnknownCodeError(`Expected aggregate list/map group code, got ${structor.code}`);
|
|
425
|
+
return new Aggor(cold === "txt"
|
|
426
|
+
? { raw: input, version, kind: "CESR", verify: false }
|
|
427
|
+
: { qb2: input, version, kind: "CESR", verify: false });
|
|
84
428
|
}
|
|
@@ -38,12 +38,11 @@ export class Bexter extends Matter {
|
|
|
38
38
|
static derawify(raw, code) {
|
|
39
39
|
const ls = getLeadSize(code);
|
|
40
40
|
const bext = encodeB64(new Uint8Array([...new Uint8Array(ls), ...raw]));
|
|
41
|
-
const ws = ls === 0
|
|
41
|
+
const ws = ls === 0 ? (bext.startsWith("A") ? 1 : 0) : (ls + 1) % 4;
|
|
42
42
|
return bext.slice(ws);
|
|
43
43
|
}
|
|
44
44
|
constructor(init) {
|
|
45
|
-
|
|
46
|
-
super(matter);
|
|
45
|
+
super(init);
|
|
47
46
|
if (!isBexterCode(this.code)) {
|
|
48
47
|
throw new UnknownCodeError(`Expected bexter strb64 code, got ${this.code}`);
|
|
49
48
|
}
|
|
@@ -10,6 +10,12 @@ export function isBlinderCode(code) {
|
|
|
10
10
|
*
|
|
11
11
|
* KERIpy substance: `Blinder` materializes blinded/bound state tuple groups
|
|
12
12
|
* used for blindable ACDC/TEL state disclosures.
|
|
13
|
+
*
|
|
14
|
+
* Maintainer note:
|
|
15
|
+
* - this class owns counted-group transport framing only
|
|
16
|
+
* - semantic blind/unblind/commit helpers live in `disclosure.ts`
|
|
17
|
+
* - the semantic fixed-field records carried by these groups are
|
|
18
|
+
* `BlindState` and `BoundState` from `structing.ts`
|
|
13
19
|
*/
|
|
14
20
|
export class Blinder extends Structor {
|
|
15
21
|
constructor(init) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { b } from "../core/bytes.js";
|
|
2
|
+
/** Normalize text or buffer-view inputs into one detached `Uint8Array`. */
|
|
3
|
+
export function normalizeByteLike(value) {
|
|
4
|
+
if (typeof value === "string") {
|
|
5
|
+
return b(value);
|
|
6
|
+
}
|
|
7
|
+
if (value instanceof Uint8Array) {
|
|
8
|
+
return Object.getPrototypeOf(value) === Uint8Array.prototype
|
|
9
|
+
? value.slice()
|
|
10
|
+
: new Uint8Array(value);
|
|
11
|
+
}
|
|
12
|
+
return new Uint8Array(value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength));
|
|
13
|
+
}
|
|
14
|
+
/** Runtime guard for byte-like primitive constructor inputs. */
|
|
15
|
+
export function isByteLike(value) {
|
|
16
|
+
return typeof value === "string"
|
|
17
|
+
|| value instanceof Uint8Array
|
|
18
|
+
|| ArrayBuffer.isView(value);
|
|
19
|
+
}
|
|
@@ -6,18 +6,32 @@ import { Matter, parseMatter } from "./matter.js";
|
|
|
6
6
|
*
|
|
7
7
|
* KERIpy substance: `Cigar` wraps detached signature material where code
|
|
8
8
|
* determines signature suite and payload holds raw signature bytes.
|
|
9
|
+
*
|
|
10
|
+
* Runtime note:
|
|
11
|
+
* - `.verfer` is contextual verifier metadata attached by signing, dispatch,
|
|
12
|
+
* or DB-rehydration code
|
|
13
|
+
* - it is not encoded inside the cigar bytes themselves
|
|
9
14
|
*/
|
|
10
15
|
export class Cigar extends Matter {
|
|
11
|
-
constructor(init) {
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
constructor(init, verfer) {
|
|
17
|
+
super(init);
|
|
18
|
+
/** Optional verifier context for the key that created this detached signature. */
|
|
19
|
+
Object.defineProperty(this, "verfer", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true,
|
|
23
|
+
value: void 0
|
|
24
|
+
});
|
|
14
25
|
if (!CIGAR_CODES.has(this.code)) {
|
|
15
26
|
throw new UnknownCodeError(`Expected non-indexed signature code, got ${this.code}`);
|
|
16
27
|
}
|
|
28
|
+
this.verfer = verfer;
|
|
17
29
|
}
|
|
30
|
+
/** Raw detached signature bytes. */
|
|
18
31
|
get sig() {
|
|
19
32
|
return this.raw;
|
|
20
33
|
}
|
|
34
|
+
/** Human-oriented generated codex member name for diagnostics and tooling. */
|
|
21
35
|
get algorithm() {
|
|
22
36
|
return matterCodexName(this.code) ?? "UnknownSig";
|
|
23
37
|
}
|
|
@@ -1,18 +1,103 @@
|
|
|
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 { CiXDex } from "./codex.js";
|
|
4
|
+
import { CIPHER_X25519_ALL_CODES, MtrDex } from "./codex.js";
|
|
5
|
+
import { Decrypter } from "./decrypter.js";
|
|
3
6
|
import { Matter } from "./matter.js";
|
|
7
|
+
/** Map the KERIpy fixed cipher families to their expected raw sealed-box sizes. */
|
|
8
|
+
function expectedFixedCipherRawSize(code) {
|
|
9
|
+
return Matter.rawSizeForCode(code);
|
|
10
|
+
}
|
|
11
|
+
const FIXED_RAW_SIZES = new Map([
|
|
12
|
+
[
|
|
13
|
+
MtrDex.X25519_Cipher_Seed,
|
|
14
|
+
expectedFixedCipherRawSize(MtrDex.X25519_Cipher_Seed),
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
MtrDex.X25519_Cipher_Salt,
|
|
18
|
+
expectedFixedCipherRawSize(MtrDex.X25519_Cipher_Salt),
|
|
19
|
+
],
|
|
20
|
+
]);
|
|
21
|
+
function inferFixedCipherCode(raw) {
|
|
22
|
+
for (const [code, size] of FIXED_RAW_SIZES.entries()) {
|
|
23
|
+
if (raw.length === size) {
|
|
24
|
+
return code;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
throw new DeserializeError(`Unsupported fixed raw size ${raw.length} for X25519 cipher material.`);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Support KERIpy's convenience rule where fixed cipher families may be
|
|
31
|
+
* inferred from raw ciphertext size when the caller omits `code`.
|
|
32
|
+
*/
|
|
33
|
+
function normalizeCipherInit(init) {
|
|
34
|
+
if (init instanceof Matter || !init.raw) {
|
|
35
|
+
return init;
|
|
36
|
+
}
|
|
37
|
+
const normalized = {
|
|
38
|
+
...init,
|
|
39
|
+
raw: init.raw.slice(),
|
|
40
|
+
};
|
|
41
|
+
if (!normalized.code) {
|
|
42
|
+
normalized.code = inferFixedCipherCode(normalized.raw);
|
|
43
|
+
}
|
|
44
|
+
return normalized;
|
|
45
|
+
}
|
|
4
46
|
/**
|
|
5
47
|
* Ciphertext primitive for encrypted secret payloads.
|
|
6
48
|
*
|
|
7
|
-
* KERIpy substance: cipher material carries encrypted
|
|
8
|
-
* while code
|
|
49
|
+
* KERIpy substance: cipher material carries sealed-box encrypted CESR payloads
|
|
50
|
+
* while the cipher code preserves how the plaintext should be rehydrated.
|
|
51
|
+
*
|
|
52
|
+
* Construction rule:
|
|
53
|
+
* - fixed salt/seed cipher families may infer `code` from raw size
|
|
54
|
+
* - variable families still require the caller or parser to provide the
|
|
55
|
+
* correct derivation code explicitly
|
|
9
56
|
*/
|
|
10
57
|
export class Cipher extends Matter {
|
|
11
58
|
constructor(init) {
|
|
12
|
-
|
|
13
|
-
super(matter);
|
|
59
|
+
super(normalizeCipherInit(init));
|
|
14
60
|
if (!CIPHER_X25519_ALL_CODES.has(this.code)) {
|
|
15
61
|
throw new UnknownCodeError(`Expected cipher code, got ${this.code}`);
|
|
16
62
|
}
|
|
17
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Recover plaintext from this cipher using either a box private key or seed.
|
|
66
|
+
*
|
|
67
|
+
* KERIpy parity:
|
|
68
|
+
* - `prikey` or `seed` instantiates a `Decrypter`
|
|
69
|
+
* - default plaintext constructor is inferred from the cipher family when
|
|
70
|
+
* possible
|
|
71
|
+
*
|
|
72
|
+
* Key-material rule:
|
|
73
|
+
* - `prikey` is already-qualified X25519 private box material
|
|
74
|
+
* - `seed` is an Ed25519 signer seed that is first converted into the
|
|
75
|
+
* corresponding X25519 private box key
|
|
76
|
+
*/
|
|
77
|
+
decrypt({ prikey, seed, ctor, transferable = false, bare = false, } = {}) {
|
|
78
|
+
return new Decrypter({
|
|
79
|
+
qb64: typeof prikey === "string" ? prikey : undefined,
|
|
80
|
+
qb64b: prikey && typeof prikey !== "string"
|
|
81
|
+
? normalizeByteLike(prikey)
|
|
82
|
+
: undefined,
|
|
83
|
+
seed,
|
|
84
|
+
}).decrypt({
|
|
85
|
+
cipher: this,
|
|
86
|
+
ctor,
|
|
87
|
+
transferable,
|
|
88
|
+
bare,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
18
91
|
}
|
|
92
|
+
Object.defineProperty(Cipher, "Codex", {
|
|
93
|
+
enumerable: true,
|
|
94
|
+
configurable: true,
|
|
95
|
+
writable: true,
|
|
96
|
+
value: CiXDex
|
|
97
|
+
});
|
|
98
|
+
Object.defineProperty(Cipher, "Codes", {
|
|
99
|
+
enumerable: true,
|
|
100
|
+
configurable: true,
|
|
101
|
+
writable: true,
|
|
102
|
+
value: Object.freeze({ ...CiXDex })
|
|
103
|
+
});
|