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,6 +1,11 @@
|
|
|
1
|
-
import { b, b64ToInt, codeB2ToB64, codeB64ToB2, concatBytes, decodeB64, encodeB64, intToB64, nabSextets, sceil, } from "../core/bytes.js";
|
|
1
|
+
import { b, b64ToInt, bytesEqual, codeB2ToB64, codeB64ToB2, concatBytes, decodeB64, encodeB64, intToB64, nabSextets, sceil, } from "../core/bytes.js";
|
|
2
2
|
import { DeserializeError, ShortageError, UnknownCodeError } from "../core/errors.js";
|
|
3
|
-
import { MATTER_HARDS, MATTER_SIZES } from "../tables/matter.tables.generated.js";
|
|
3
|
+
import { MATTER_CODE_NAMES, MATTER_HARDS, MATTER_SIZES } from "../tables/matter.tables.generated.js";
|
|
4
|
+
import { DIGEST_CODES, NON_TRANSFERABLE_CODES, PREFIX_CODES } from "./codex.js";
|
|
5
|
+
const SMALL_VAR_SELECTORS = ["4", "5", "6"];
|
|
6
|
+
const LARGE_VAR_SELECTORS = ["7", "8", "9"];
|
|
7
|
+
const MATTER_PAD = "_";
|
|
8
|
+
const MATTER_CODE_NAMES_BY_CODE = MATTER_CODE_NAMES;
|
|
4
9
|
const MATTER_BARDS = new Map([...MATTER_HARDS.entries()].map(([code, hs]) => [
|
|
5
10
|
String.fromCharCode(codeB64ToB2(code)[0]),
|
|
6
11
|
hs,
|
|
@@ -14,6 +19,54 @@ function isMatterData(value) {
|
|
|
14
19
|
&& "fullSize" in value
|
|
15
20
|
&& "fullSizeB2" in value;
|
|
16
21
|
}
|
|
22
|
+
function rawSizeForCode(code) {
|
|
23
|
+
const sizage = sizageForCode(code);
|
|
24
|
+
if (sizage.fs === null) {
|
|
25
|
+
throw new DeserializeError(`Non-fixed raw size for code ${code}.`);
|
|
26
|
+
}
|
|
27
|
+
const cs = sizage.hs + sizage.ss;
|
|
28
|
+
return Math.floor(((sizage.fs - cs) * 3) / 4) - sizage.ls;
|
|
29
|
+
}
|
|
30
|
+
function sizageForCode(code) {
|
|
31
|
+
const sizage = MATTER_SIZES.get(code);
|
|
32
|
+
if (!sizage) {
|
|
33
|
+
throw new UnknownCodeError(`Unknown matter code ${code}`);
|
|
34
|
+
}
|
|
35
|
+
return sizage;
|
|
36
|
+
}
|
|
37
|
+
function matterNameForCode(code) {
|
|
38
|
+
const name = MATTER_CODE_NAMES_BY_CODE[code];
|
|
39
|
+
if (!name) {
|
|
40
|
+
throw new UnknownCodeError(`Unknown matter code ${code}`);
|
|
41
|
+
}
|
|
42
|
+
return name;
|
|
43
|
+
}
|
|
44
|
+
function normalizeVariableMatterCode(code, raw) {
|
|
45
|
+
const sizage = MATTER_SIZES.get(code);
|
|
46
|
+
if (!sizage || sizage.fs !== null) {
|
|
47
|
+
return code;
|
|
48
|
+
}
|
|
49
|
+
const selector = code[0];
|
|
50
|
+
const leadSize = (3 - (raw.length % 3)) % 3;
|
|
51
|
+
const size = (raw.length + leadSize) / 3;
|
|
52
|
+
if (SMALL_VAR_SELECTORS.includes(selector)) {
|
|
53
|
+
if (size <= (64 ** 2) - 1) {
|
|
54
|
+
return `${SMALL_VAR_SELECTORS[leadSize]}${code.slice(1, 2)}`;
|
|
55
|
+
}
|
|
56
|
+
if (size <= (64 ** 4) - 1) {
|
|
57
|
+
return `${LARGE_VAR_SELECTORS[leadSize]}AA${code.slice(1, 2)}`;
|
|
58
|
+
}
|
|
59
|
+
throw new DeserializeError(`Unsupported variable raw size for ${code}: ${raw.length}.`);
|
|
60
|
+
}
|
|
61
|
+
if (LARGE_VAR_SELECTORS.includes(selector)) {
|
|
62
|
+
if (size <= (64 ** 4) - 1) {
|
|
63
|
+
return `${LARGE_VAR_SELECTORS[leadSize]}${code.slice(1, 4)}`;
|
|
64
|
+
}
|
|
65
|
+
throw new DeserializeError(`Unsupported variable raw size for large ${code}: ${raw.length}.`);
|
|
66
|
+
}
|
|
67
|
+
throw new DeserializeError(`Unsupported variable raw-size family for ${code}.`);
|
|
68
|
+
}
|
|
69
|
+
/** Resolve the effective matter code from the text-domain hard-selector prefix. */
|
|
17
70
|
function parseMatterCodeFromText(txt) {
|
|
18
71
|
const hs = MATTER_HARDS.get(txt[0]);
|
|
19
72
|
if (!hs) {
|
|
@@ -32,6 +85,7 @@ function parseMatterCodeFromText(txt) {
|
|
|
32
85
|
}
|
|
33
86
|
return { code, hs: sizage.hs };
|
|
34
87
|
}
|
|
88
|
+
/** Inhale one text-domain CESR primitive into normalized matter data fields. */
|
|
35
89
|
function parseMatterFromTextData(input) {
|
|
36
90
|
const txt = String.fromCharCode(...input);
|
|
37
91
|
if (txt.length === 0) {
|
|
@@ -57,6 +111,7 @@ function parseMatterFromTextData(input) {
|
|
|
57
111
|
fullSizeB2: sceil((fullSize * 3) / 4),
|
|
58
112
|
};
|
|
59
113
|
}
|
|
114
|
+
/** Inhale one qb2 CESR primitive into the canonical text-oriented matter shape. */
|
|
60
115
|
function parseMatterFromBinaryData(input) {
|
|
61
116
|
if (input.length === 0) {
|
|
62
117
|
throw new ShortageError(1, 0);
|
|
@@ -112,7 +167,9 @@ function parseMatterFromBinaryData(input) {
|
|
|
112
167
|
fullSizeB2: bfs,
|
|
113
168
|
};
|
|
114
169
|
}
|
|
170
|
+
/** Exhale raw bytes plus code into fully qualified CESR matter encodings. */
|
|
115
171
|
function encodeMatterFromRaw(code, raw) {
|
|
172
|
+
code = normalizeVariableMatterCode(code, raw);
|
|
116
173
|
const sizage = MATTER_SIZES.get(code);
|
|
117
174
|
if (!sizage) {
|
|
118
175
|
throw new UnknownCodeError(`Unknown matter code ${code}`);
|
|
@@ -146,6 +203,7 @@ function encodeMatterFromRaw(code, raw) {
|
|
|
146
203
|
fullSizeB2: sceil((fullSize * 3) / 4),
|
|
147
204
|
};
|
|
148
205
|
}
|
|
206
|
+
/** Normalize the supported constructor variants into one shared matter payload. */
|
|
149
207
|
function parseMatterInit(init) {
|
|
150
208
|
if (init.raw && init.code) {
|
|
151
209
|
return encodeMatterFromRaw(init.code, init.raw);
|
|
@@ -165,7 +223,8 @@ function parseMatterInit(init) {
|
|
|
165
223
|
* Base CESR primitive carrying qualified matter material.
|
|
166
224
|
*
|
|
167
225
|
* KERIpy substance: `Matter` is the foundational primitive abstraction that
|
|
168
|
-
* handles exfil/infil between raw bytes and qualified CESR encodings
|
|
226
|
+
* handles exfil/infil between raw bytes and qualified CESR encodings and owns
|
|
227
|
+
* the base derivation-code semantic projections shared by semantic subclasses.
|
|
169
228
|
*/
|
|
170
229
|
export class Matter {
|
|
171
230
|
constructor(init) {
|
|
@@ -222,6 +281,36 @@ export class Matter {
|
|
|
222
281
|
get code() {
|
|
223
282
|
return this._code;
|
|
224
283
|
}
|
|
284
|
+
/** KERIpy parity alias: codex member name for this derivation code. */
|
|
285
|
+
get name() {
|
|
286
|
+
return matterNameForCode(this._code);
|
|
287
|
+
}
|
|
288
|
+
/** KERIpy parity alias: hard code portion of the qualified text code. */
|
|
289
|
+
get hard() {
|
|
290
|
+
return this._code;
|
|
291
|
+
}
|
|
292
|
+
/** Soft code portion exclusive of any prepad xtra characters. */
|
|
293
|
+
get soft() {
|
|
294
|
+
const sizage = sizageForCode(this._code);
|
|
295
|
+
if (sizage.ss === 0) {
|
|
296
|
+
return "";
|
|
297
|
+
}
|
|
298
|
+
return this._qb64.slice(sizage.hs + sizage.xs, sizage.hs + sizage.ss);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* KERIpy parity size projection.
|
|
302
|
+
*
|
|
303
|
+
* This follows KERIpy's generic `Matter.size` rule: decode the soft sextets
|
|
304
|
+
* when present, otherwise return `null`.
|
|
305
|
+
*/
|
|
306
|
+
get size() {
|
|
307
|
+
return this.soft ? b64ToInt(this.soft) : null;
|
|
308
|
+
}
|
|
309
|
+
/** Hard + padded-soft view of the full text code. */
|
|
310
|
+
get both() {
|
|
311
|
+
const sizage = sizageForCode(this._code);
|
|
312
|
+
return `${this._code}${MATTER_PAD.repeat(sizage.xs)}${this.soft}`;
|
|
313
|
+
}
|
|
225
314
|
get raw() {
|
|
226
315
|
return this._raw;
|
|
227
316
|
}
|
|
@@ -240,12 +329,53 @@ export class Matter {
|
|
|
240
329
|
get fullSizeB2() {
|
|
241
330
|
return this._fullSizeB2;
|
|
242
331
|
}
|
|
332
|
+
/** Generic KERIpy derivation-code transferability rule. */
|
|
333
|
+
get transferable() {
|
|
334
|
+
return !NON_TRANSFERABLE_CODES.has(this._code);
|
|
335
|
+
}
|
|
336
|
+
/** Generic KERIpy digest-family semantic projection. */
|
|
337
|
+
get digestive() {
|
|
338
|
+
return DIGEST_CODES.has(this._code);
|
|
339
|
+
}
|
|
340
|
+
/** Generic KERIpy identifier-prefix semantic projection. */
|
|
341
|
+
get prefixive() {
|
|
342
|
+
return PREFIX_CODES.has(this._code);
|
|
343
|
+
}
|
|
344
|
+
/** True when the code family carries fixed-size soft text metadata. */
|
|
345
|
+
get special() {
|
|
346
|
+
const sizage = sizageForCode(this._code);
|
|
347
|
+
return sizage.fs !== null && sizage.ss > 0;
|
|
348
|
+
}
|
|
349
|
+
/** True when both qb64 and qb2 are 24-bit aligned and round-trip exactly. */
|
|
350
|
+
get composable() {
|
|
351
|
+
const qb2 = this.qb2;
|
|
352
|
+
return this.qb64b.length % 4 === 0
|
|
353
|
+
&& qb2.length % 3 === 0
|
|
354
|
+
&& encodeB64(qb2) === this.qb64
|
|
355
|
+
&& bytesEqual(decodeB64(this.qb64), qb2);
|
|
356
|
+
}
|
|
243
357
|
equals(other) {
|
|
244
358
|
return this._qb64 === other.qb64;
|
|
245
359
|
}
|
|
246
360
|
toString() {
|
|
247
361
|
return this._qb64;
|
|
248
362
|
}
|
|
363
|
+
/** KERIpy parity helper: fixed raw size for one code. */
|
|
364
|
+
static rawSizeForCode(code) {
|
|
365
|
+
return rawSizeForCode(code);
|
|
366
|
+
}
|
|
367
|
+
/** KERIpy parity helper: fixed full qb64 size for one code. */
|
|
368
|
+
static fullSizeForCode(code) {
|
|
369
|
+
const sizage = sizageForCode(code);
|
|
370
|
+
if (sizage.fs === null) {
|
|
371
|
+
throw new DeserializeError(`Non-fixed full size for code ${code}.`);
|
|
372
|
+
}
|
|
373
|
+
return sizage.fs;
|
|
374
|
+
}
|
|
375
|
+
/** KERIpy parity helper: lead-byte size for one code. */
|
|
376
|
+
static leadSizeForCode(code) {
|
|
377
|
+
return sizageForCode(code).ls;
|
|
378
|
+
}
|
|
249
379
|
}
|
|
250
380
|
/** Parse matter from text-domain CESR bytes. */
|
|
251
381
|
export function parseMatterFromText(input) {
|
|
@@ -10,6 +10,12 @@ export function isMediarCode(code) {
|
|
|
10
10
|
*
|
|
11
11
|
* KERIpy substance: `Mediar` materializes media metadata/value tuple groups
|
|
12
12
|
* used in blinded media attachments and related CESR payload envelopes.
|
|
13
|
+
*
|
|
14
|
+
* Maintainer note:
|
|
15
|
+
* - this class owns counted-group transport framing only
|
|
16
|
+
* - semantic disclosure helpers live in `disclosure.ts`
|
|
17
|
+
* - the semantic fixed-field record carried by these groups is `TypeMedia`
|
|
18
|
+
* from `structing.ts`
|
|
13
19
|
*/
|
|
14
20
|
export class Mediar extends Structor {
|
|
15
21
|
constructor(init) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UnknownCodeError } from "../core/errors.js";
|
|
2
2
|
import { NONCE_CODES, NonceDex } from "./codex.js";
|
|
3
3
|
import { Diger } from "./diger.js";
|
|
4
|
-
import {
|
|
4
|
+
import { parseMatter } from "./matter.js";
|
|
5
5
|
/**
|
|
6
6
|
* Nonce primitive for UUID/salt-or-digest nonce representations.
|
|
7
7
|
*
|
|
@@ -10,8 +10,7 @@ import { Matter, parseMatter } from "./matter.js";
|
|
|
10
10
|
*/
|
|
11
11
|
export class Noncer extends Diger {
|
|
12
12
|
constructor(init) {
|
|
13
|
-
|
|
14
|
-
super(matter, { strict: false });
|
|
13
|
+
super(init, { strict: false });
|
|
15
14
|
if (!NONCE_CODES.has(this.code)) {
|
|
16
15
|
throw new UnknownCodeError(`Expected nonce code, got ${this.code}`);
|
|
17
16
|
}
|
|
@@ -9,8 +9,7 @@ import { Matter, parseMatter } from "./matter.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export class NumberPrimitive extends Matter {
|
|
11
11
|
constructor(init) {
|
|
12
|
-
|
|
13
|
-
super(matter);
|
|
12
|
+
super(init);
|
|
14
13
|
if (!NUMBER_CODES.has(this.code)) {
|
|
15
14
|
throw new UnknownCodeError(`Expected number code, got ${this.code}`);
|
|
16
15
|
}
|
|
@@ -1,11 +1,109 @@
|
|
|
1
|
-
import { t } from "../core/bytes.js";
|
|
2
|
-
import { UnknownCodeError } from "../core/errors.js";
|
|
1
|
+
import { b, t } from "../core/bytes.js";
|
|
2
|
+
import { DeserializeError, UnknownCodeError } from "../core/errors.js";
|
|
3
3
|
import { Bexter } from "./bexter.js";
|
|
4
|
-
import { BEXTER_CODES, TEXTER_CODES } from "./codex.js";
|
|
4
|
+
import { BEXTER_CODES, MtrDex, TEXTER_CODES } from "./codex.js";
|
|
5
5
|
import { Matter, parseMatter } from "./matter.js";
|
|
6
6
|
function isPatherCode(code) {
|
|
7
7
|
return BEXTER_CODES.has(code) || TEXTER_CODES.has(code);
|
|
8
8
|
}
|
|
9
|
+
function normalizeParts(path) {
|
|
10
|
+
if (typeof path !== "string") {
|
|
11
|
+
return [...path];
|
|
12
|
+
}
|
|
13
|
+
if (path.includes("/")) {
|
|
14
|
+
return path.split("/");
|
|
15
|
+
}
|
|
16
|
+
return path.split("-");
|
|
17
|
+
}
|
|
18
|
+
const RE_PATH_PART = /^[A-Za-z0-9_]*$/;
|
|
19
|
+
function strB64CodeForText(bext) {
|
|
20
|
+
const ts = bext.length % 4;
|
|
21
|
+
const ls = (3 - ts) % 3;
|
|
22
|
+
switch (ls) {
|
|
23
|
+
case 0:
|
|
24
|
+
return MtrDex.StrB64_L0;
|
|
25
|
+
case 1:
|
|
26
|
+
return MtrDex.StrB64_L1;
|
|
27
|
+
case 2:
|
|
28
|
+
return MtrDex.StrB64_L2;
|
|
29
|
+
default:
|
|
30
|
+
throw new DeserializeError(`Unsupported StrB64 leader size=${ls}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function bytesCodeForRaw(raw) {
|
|
34
|
+
const ls = (3 - (raw.length % 3)) % 3;
|
|
35
|
+
switch (ls) {
|
|
36
|
+
case 0:
|
|
37
|
+
return MtrDex.Bytes_L0;
|
|
38
|
+
case 1:
|
|
39
|
+
return MtrDex.Bytes_L1;
|
|
40
|
+
case 2:
|
|
41
|
+
return MtrDex.Bytes_L2;
|
|
42
|
+
default:
|
|
43
|
+
throw new DeserializeError(`Unsupported bytes leader size=${ls}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Build a Pather from semantic route/path text.
|
|
48
|
+
*
|
|
49
|
+
* This mirrors the KERIpy `Pather(path=..., relative=..., pathive=...)`
|
|
50
|
+
* constructor path:
|
|
51
|
+
* - "pathive" base64-safe segments use compact StrB64 encoding with `-`
|
|
52
|
+
* separators
|
|
53
|
+
* - non-pathive routes fall back to byte/text encoding when they contain
|
|
54
|
+
* characters like `/`
|
|
55
|
+
* - relative routes keep the first segment as-is, while absolute paths are
|
|
56
|
+
* forced to start with an empty root segment
|
|
57
|
+
*
|
|
58
|
+
* Examples:
|
|
59
|
+
* - `makePather("ksn", { relative: true, pathive: false }).qb64 === "4AABAksn"`
|
|
60
|
+
* - `makePather("reply", { relative: true, pathive: false }).qb64 === "6AACAAAreply"`
|
|
61
|
+
* - `makePather("credential/issue", { relative: true, pathive: false }).qb64 === "4AAEcredential-issue"`
|
|
62
|
+
*/
|
|
63
|
+
export function makePather(path, opts = {}) {
|
|
64
|
+
const relative = opts.relative ?? false;
|
|
65
|
+
const pathive = opts.pathive ?? true;
|
|
66
|
+
const parts = normalizeParts(path);
|
|
67
|
+
let bextable = true;
|
|
68
|
+
for (const part of parts) {
|
|
69
|
+
if (!RE_PATH_PART.test(part)) {
|
|
70
|
+
if (pathive) {
|
|
71
|
+
throw new DeserializeError(`Invalid pathive path part=${part}`);
|
|
72
|
+
}
|
|
73
|
+
bextable = false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!relative) {
|
|
77
|
+
if (parts.length > 0 && parts[0] !== "") {
|
|
78
|
+
parts.unshift("");
|
|
79
|
+
}
|
|
80
|
+
else if (parts.length === 0) {
|
|
81
|
+
parts.push("", "");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (bextable) {
|
|
85
|
+
let bext = parts.join("-");
|
|
86
|
+
if (bext.includes("--")) {
|
|
87
|
+
throw new DeserializeError(`Non-unitary path separators for path=${bext}`);
|
|
88
|
+
}
|
|
89
|
+
const ws = (4 - (bext.length % 4)) % 4;
|
|
90
|
+
if (bext.startsWith("A") && (ws === 0 || ws === 1)) {
|
|
91
|
+
// KERIpy reserves `--` as an escape prefix when the compact path would
|
|
92
|
+
// otherwise start with an ambiguous leading `A`.
|
|
93
|
+
bext = `--${bext}`;
|
|
94
|
+
}
|
|
95
|
+
return new Pather({
|
|
96
|
+
raw: Bexter.rawify(bext),
|
|
97
|
+
code: strB64CodeForText(bext),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const text = parts.join("/");
|
|
101
|
+
if (text.includes("//")) {
|
|
102
|
+
throw new DeserializeError(`Non-unitary path separators for path=${text}`);
|
|
103
|
+
}
|
|
104
|
+
const raw = b(text);
|
|
105
|
+
return new Pather({ raw, code: bytesCodeForRaw(raw) });
|
|
106
|
+
}
|
|
9
107
|
/**
|
|
10
108
|
* CESR path primitive for SAD traversal routes.
|
|
11
109
|
*
|
|
@@ -14,8 +112,7 @@ function isPatherCode(code) {
|
|
|
14
112
|
*/
|
|
15
113
|
export class Pather extends Matter {
|
|
16
114
|
constructor(init) {
|
|
17
|
-
|
|
18
|
-
super(matter);
|
|
115
|
+
super(init);
|
|
19
116
|
if (!isPatherCode(this.code)) {
|
|
20
117
|
throw new UnknownCodeError(`Expected pather-compatible code, got ${this.code}`);
|
|
21
118
|
}
|
|
@@ -10,8 +10,7 @@ import { Matter, parseMatter } from "./matter.js";
|
|
|
10
10
|
*/
|
|
11
11
|
export class Prefixer extends Matter {
|
|
12
12
|
constructor(init) {
|
|
13
|
-
|
|
14
|
-
super(matter);
|
|
13
|
+
super(init);
|
|
15
14
|
if (!PREFIX_CODES.has(this.code)) {
|
|
16
15
|
throw new UnknownCodeError(`Expected prefix code, got ${this.code}`);
|
|
17
16
|
}
|
|
@@ -7,3 +7,17 @@ export function isCounterGroupLike(entry) {
|
|
|
7
7
|
return typeof entry === "object" && entry !== null && !Array.isArray(entry)
|
|
8
8
|
&& "items" in entry && "count" in entry && "code" in entry;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Runtime guard for one rehydratable qualified primitive in a parsed group graph.
|
|
12
|
+
*
|
|
13
|
+
* This intentionally means "real CESR primitive with `qb64b`" rather than
|
|
14
|
+
* "any parser primitive union member", so tuples, nested counter groups, and
|
|
15
|
+
* `UnknownPrimitive` placeholders are all excluded.
|
|
16
|
+
*/
|
|
17
|
+
export function isQualifiedPrimitive(entry) {
|
|
18
|
+
return typeof entry === "object"
|
|
19
|
+
&& entry !== null
|
|
20
|
+
&& !Array.isArray(entry)
|
|
21
|
+
&& !isCounterGroupLike(entry)
|
|
22
|
+
&& "qb64b" in entry;
|
|
23
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MATTER_CODE_NAMES } from "../tables/matter.tables.generated.js";
|
|
2
2
|
import { parseMatterFromText } from "./matter.js";
|
|
3
|
+
/** Parse one text-domain primitive token and include its generated code name. */
|
|
3
4
|
export function parsePrimitiveFromText(input) {
|
|
4
5
|
const matter = parseMatterFromText(input);
|
|
5
6
|
const name = MATTER_CODE_NAMES[matter.code]
|
|
@@ -12,6 +13,7 @@ export function parsePrimitiveFromText(input) {
|
|
|
12
13
|
fullSize: matter.fullSize,
|
|
13
14
|
};
|
|
14
15
|
}
|
|
16
|
+
/** Return all known generated matter codes sorted for deterministic scans. */
|
|
15
17
|
export function supportedPrimitiveCodes() {
|
|
16
18
|
return Object.keys(MATTER_CODE_NAMES).sort();
|
|
17
19
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { UnknownCodeError } from "../core/errors.js";
|
|
1
|
+
import { SerializeError, UnknownCodeError } from "../core/errors.js";
|
|
2
|
+
import { dumps, sizeify } from "../serder/serder.js";
|
|
3
|
+
import { smell } from "../serder/smell.js";
|
|
4
|
+
import { MATTER_SIZES } from "../tables/matter.tables.generated.js";
|
|
2
5
|
import { DIGEST_CODES } from "./codex.js";
|
|
6
|
+
import { Diger } from "./diger.js";
|
|
3
7
|
import { Matter, parseMatter } from "./matter.js";
|
|
4
8
|
/**
|
|
5
9
|
* Self-addressing identifier digest primitive.
|
|
@@ -9,8 +13,7 @@ import { Matter, parseMatter } from "./matter.js";
|
|
|
9
13
|
*/
|
|
10
14
|
export class Saider extends Matter {
|
|
11
15
|
constructor(init) {
|
|
12
|
-
|
|
13
|
-
super(matter);
|
|
16
|
+
super(init);
|
|
14
17
|
if (!DIGEST_CODES.has(this.code)) {
|
|
15
18
|
throw new UnknownCodeError(`Expected said digest code, got ${this.code}`);
|
|
16
19
|
}
|
|
@@ -21,6 +24,80 @@ export class Saider extends Matter {
|
|
|
21
24
|
get digest() {
|
|
22
25
|
return this.raw;
|
|
23
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Derive one SAID from a SAD, inject it at `label`, and return the updated SAD.
|
|
29
|
+
*
|
|
30
|
+
* KERIpy places `saidify` on `Saider`, not `Serder`: the responsibility here
|
|
31
|
+
* is digest derivation for one saidive field, while event-specific policies
|
|
32
|
+
* such as mirrored `i == d` handling belong in higher layers.
|
|
33
|
+
*/
|
|
34
|
+
static saidify(sad, { code = "E", kind, label = "d", ignore, digest = Diger.digest, }) {
|
|
35
|
+
const working = { ...sad };
|
|
36
|
+
if (ignore) {
|
|
37
|
+
for (const field of ignore) {
|
|
38
|
+
delete working[field];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const { sad: saidified, saiders } = Saider.saidifyFields(working, {
|
|
42
|
+
kind,
|
|
43
|
+
saids: { [label]: code },
|
|
44
|
+
digest,
|
|
45
|
+
});
|
|
46
|
+
const saider = saiders[label];
|
|
47
|
+
if (!saider) {
|
|
48
|
+
throw new SerializeError(`Expected digestive SAID result for ${label}`);
|
|
49
|
+
}
|
|
50
|
+
return { saider, sad: saidified };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Compute all digestive saidive fields from the same sized-dummied SAD bytes.
|
|
54
|
+
*
|
|
55
|
+
* This mirrors the KERIpy `makify/_compute` model for top-level saidive
|
|
56
|
+
* fields: resolve effective field codes first, dummy only digestive fields,
|
|
57
|
+
* size the version string once, hash once, then fill all digestive fields
|
|
58
|
+
* from that same raw serialization.
|
|
59
|
+
*/
|
|
60
|
+
static saidifyFields(sad, { kind, saids, digest = Diger.digest, }) {
|
|
61
|
+
const working = { ...sad };
|
|
62
|
+
const actualKind = kind ?? inferKind(working);
|
|
63
|
+
for (const [label, code] of Object.entries(saids)) {
|
|
64
|
+
if (!(label in working)) {
|
|
65
|
+
throw new SerializeError(`Missing SAID field labeled ${label}`);
|
|
66
|
+
}
|
|
67
|
+
if (!DIGEST_CODES.has(code)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const sizage = MATTER_SIZES.get(code);
|
|
71
|
+
if (!sizage || sizage.fs === null) {
|
|
72
|
+
throw new SerializeError(`Unsupported fixed-size SAID code ${code}`);
|
|
73
|
+
}
|
|
74
|
+
working[label] = "#".repeat(sizage.fs);
|
|
75
|
+
}
|
|
76
|
+
if ("v" in working) {
|
|
77
|
+
sizeify(working, actualKind);
|
|
78
|
+
}
|
|
79
|
+
const digestRaw = dumps(working, actualKind);
|
|
80
|
+
const saiders = {};
|
|
81
|
+
for (const [label, code] of Object.entries(saids)) {
|
|
82
|
+
if (!DIGEST_CODES.has(code)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const saider = new Saider({
|
|
86
|
+
code,
|
|
87
|
+
raw: digest(digestRaw, code),
|
|
88
|
+
});
|
|
89
|
+
working[label] = saider.qb64;
|
|
90
|
+
saiders[label] = saider;
|
|
91
|
+
}
|
|
92
|
+
const raw = dumps(working, actualKind);
|
|
93
|
+
return { sad: working, raw, saiders };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function inferKind(sad) {
|
|
97
|
+
if (typeof sad.v !== "string") {
|
|
98
|
+
return "JSON";
|
|
99
|
+
}
|
|
100
|
+
return smell(new TextEncoder().encode(sad.v)).smellage.kind;
|
|
24
101
|
}
|
|
25
102
|
/** Parse and hydrate `Saider` from txt/qb2 bytes. */
|
|
26
103
|
export function parseSaider(input, cold) {
|
|
@@ -1,22 +1,116 @@
|
|
|
1
|
+
import { argon2id } from "@noble/hashes/argon2";
|
|
1
2
|
import { UnknownCodeError } from "../core/errors.js";
|
|
3
|
+
import { Tiers } from "../core/vocabulary.js";
|
|
4
|
+
import { MtrDex } from "./codex.js";
|
|
2
5
|
import { SALTER_CODES } from "./codex.js";
|
|
3
6
|
import { Matter } from "./matter.js";
|
|
7
|
+
import { Signer } from "./signer.js";
|
|
8
|
+
/** Encode one KERI salty-derivation path string into bytes for Argon2id input. */
|
|
9
|
+
function pathToBytes(path) {
|
|
10
|
+
return new TextEncoder().encode(path);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Map KERI tier/temp policy to Argon2id work factors.
|
|
14
|
+
*
|
|
15
|
+
* `temp=true` keeps the KERIpy testing rule: intentionally cheap stretching
|
|
16
|
+
* for test-only paths, never for normal persisted key derivation.
|
|
17
|
+
*/
|
|
18
|
+
function tierParams(tier, temp) {
|
|
19
|
+
if (temp) {
|
|
20
|
+
return { t: 1, m: 8 };
|
|
21
|
+
}
|
|
22
|
+
if (tier === Tiers.low)
|
|
23
|
+
return { t: 2, m: 65536 };
|
|
24
|
+
if (tier === Tiers.med)
|
|
25
|
+
return { t: 3, m: 262144 };
|
|
26
|
+
if (tier === Tiers.high)
|
|
27
|
+
return { t: 4, m: 1048576 };
|
|
28
|
+
throw new Error(`Unsupported security tier=${tier}`);
|
|
29
|
+
}
|
|
4
30
|
/**
|
|
5
31
|
* Salt primitive for deterministic secret/signer derivation workflows.
|
|
6
32
|
*
|
|
7
33
|
* KERIpy substance: Salter stores random or fixed salt bytes and is used as
|
|
8
34
|
* input to deterministic signer/seed generation paths.
|
|
35
|
+
*
|
|
36
|
+
* Maintainer model:
|
|
37
|
+
* - `tier` is the default stretch policy carried with the salt instance
|
|
38
|
+
* - individual `stretch()` / `signer()` calls may still override it
|
|
9
39
|
*/
|
|
10
40
|
export class Salter extends Matter {
|
|
11
41
|
constructor(init) {
|
|
12
|
-
|
|
13
|
-
|
|
42
|
+
super(init);
|
|
43
|
+
Object.defineProperty(this, "tier", {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
value: void 0
|
|
48
|
+
});
|
|
14
49
|
if (!SALTER_CODES.has(this.code)) {
|
|
15
50
|
throw new UnknownCodeError(`Expected salt code, got ${this.code}`);
|
|
16
51
|
}
|
|
52
|
+
this.tier = init instanceof Salter
|
|
53
|
+
? init.tier
|
|
54
|
+
: init.tier ?? Tiers.low;
|
|
17
55
|
}
|
|
18
56
|
/** Raw salt bytes used by key-derivation consumers. */
|
|
19
57
|
get salt() {
|
|
20
58
|
return this.raw;
|
|
21
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Derive deterministic secret bytes from this salt and one derivation path.
|
|
62
|
+
*
|
|
63
|
+
* KERIpy correspondence:
|
|
64
|
+
* - mirrors `Salter.stretch(...)` using Argon2id and tier/temp policy
|
|
65
|
+
*
|
|
66
|
+
* Path rule:
|
|
67
|
+
* - callers supply the fully formed KERI salty path string
|
|
68
|
+
* - `Salter` does not impose `pidx/ridx/kidx` structure itself; that remains
|
|
69
|
+
* a higher-layer manager/creator responsibility
|
|
70
|
+
*/
|
|
71
|
+
stretch({ size = 32, path = "", tier = this.tier, temp = false, } = {}) {
|
|
72
|
+
const params = tierParams(tier, temp);
|
|
73
|
+
return argon2id(pathToBytes(path), this.raw, {
|
|
74
|
+
p: 1,
|
|
75
|
+
t: params.t,
|
|
76
|
+
m: params.m,
|
|
77
|
+
dkLen: size,
|
|
78
|
+
version: 0x13,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Derive one deterministic executable signer from this salt and one path.
|
|
83
|
+
*
|
|
84
|
+
* The signer suite controls seed width; `Salter` only owns the deterministic
|
|
85
|
+
* seed derivation.
|
|
86
|
+
*/
|
|
87
|
+
signer({ code = MtrDex.Ed25519_Seed, transferable = true, path = "", tier, temp = false, } = {}) {
|
|
88
|
+
return new Signer({
|
|
89
|
+
code,
|
|
90
|
+
raw: this.stretch({
|
|
91
|
+
size: Signer.seedSizeForCode(code),
|
|
92
|
+
path,
|
|
93
|
+
tier,
|
|
94
|
+
temp,
|
|
95
|
+
}),
|
|
96
|
+
transferable,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Derive an ordered signer list from one path prefix plus hex suffix range.
|
|
101
|
+
*
|
|
102
|
+
* KERIpy correspondence:
|
|
103
|
+
* - successive signers append lowercase-hex offsets to the supplied path
|
|
104
|
+
* prefix
|
|
105
|
+
*/
|
|
106
|
+
signers({ count = 1, start = 0, path = "", code = MtrDex.Ed25519_Seed, codes, transferable = true, tier, temp = false, } = {}) {
|
|
107
|
+
const effectiveCodes = codes ?? Array.from({ length: count }, () => code);
|
|
108
|
+
return effectiveCodes.map((suite, offset) => this.signer({
|
|
109
|
+
code: suite,
|
|
110
|
+
transferable,
|
|
111
|
+
path: `${path}${(start + offset).toString(16)}`,
|
|
112
|
+
tier,
|
|
113
|
+
temp,
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
22
116
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import sodium from "libsodium-wrappers";
|
|
2
|
+
await sodium.ready;
|
|
3
|
+
/**
|
|
4
|
+
* Internal libsodium-backed sealed-box seam for KERIpy cipher parity.
|
|
5
|
+
*
|
|
6
|
+
* Boundary rule:
|
|
7
|
+
* - CESR primitives own sealed-box behavior
|
|
8
|
+
* - higher layers consume `Cipher`/`Encrypter`/`Decrypter`, not sodium calls
|
|
9
|
+
* - this module returns only raw key/plaintext/cipher bytes; derivation codes
|
|
10
|
+
* and primitive hydration stay outside at the CESR primitive layer
|
|
11
|
+
*/
|
|
12
|
+
/** Derive X25519 public key material from one Ed25519 verifier key. */
|
|
13
|
+
export function boxPublicKeyFromEd25519Verfer(verferRaw) {
|
|
14
|
+
return new Uint8Array(sodium.crypto_sign_ed25519_pk_to_curve25519(verferRaw));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Derive the X25519 box keypair corresponding to one Ed25519 signing seed.
|
|
18
|
+
*
|
|
19
|
+
* KERIpy parity:
|
|
20
|
+
* - derive the Ed25519 signing keypair first
|
|
21
|
+
* - then convert both sides to the associated X25519 box keys
|
|
22
|
+
*/
|
|
23
|
+
export function boxKeyPairFromEd25519Seed(seedRaw) {
|
|
24
|
+
const keyPair = sodium.crypto_sign_seed_keypair(seedRaw);
|
|
25
|
+
return {
|
|
26
|
+
publicKey: new Uint8Array(sodium.crypto_sign_ed25519_pk_to_curve25519(keyPair.publicKey)),
|
|
27
|
+
privateKey: new Uint8Array(sodium.crypto_sign_ed25519_sk_to_curve25519(keyPair.privateKey)),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Recover the X25519 public key corresponding to one raw X25519 private key. */
|
|
31
|
+
export function boxPublicKeyFromPrivateKey(privateKey) {
|
|
32
|
+
return new Uint8Array(sodium.crypto_scalarmult_base(privateKey));
|
|
33
|
+
}
|
|
34
|
+
/** Encrypt one plaintext using libsodium's X25519 sealed-box primitive. */
|
|
35
|
+
export function sealBox(plaintext, publicKey) {
|
|
36
|
+
return new Uint8Array(sodium.crypto_box_seal(plaintext, publicKey));
|
|
37
|
+
}
|
|
38
|
+
/** Open one libsodium X25519 sealed-box ciphertext back to raw plaintext bytes. */
|
|
39
|
+
export function openSealedBox(cipher, publicKey, privateKey) {
|
|
40
|
+
return new Uint8Array(sodium.crypto_box_seal_open(cipher, publicKey, privateKey));
|
|
41
|
+
}
|
|
@@ -9,8 +9,7 @@ import { Matter, parseMatter } from "./matter.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export class Seqner extends Matter {
|
|
11
11
|
constructor(init) {
|
|
12
|
-
|
|
13
|
-
super(matter);
|
|
12
|
+
super(init);
|
|
14
13
|
if (!SEQNER_CODES.has(this.code)) {
|
|
15
14
|
throw new UnknownCodeError(`Expected seqner Salt_128 code, got ${this.code}`);
|
|
16
15
|
}
|