@real-life/trust-protocol 0.1.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/README.md +99 -0
- package/dist/core.d.ts +32 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +312 -0
- package/dist/core.js.map +1 -0
- package/dist/crypto.d.ts +32 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +114 -0
- package/dist/crypto.js.map +1 -0
- package/dist/delivery.d.ts +51 -0
- package/dist/delivery.d.ts.map +1 -0
- package/dist/delivery.js +170 -0
- package/dist/delivery.js.map +1 -0
- package/dist/encounter.d.ts +63 -0
- package/dist/encounter.d.ts.map +1 -0
- package/dist/encounter.js +56 -0
- package/dist/encounter.js.map +1 -0
- package/dist/identity.d.ts +25 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +87 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/probe/continuity.d.ts +99 -0
- package/dist/probe/continuity.d.ts.map +1 -0
- package/dist/probe/continuity.js +303 -0
- package/dist/probe/continuity.js.map +1 -0
- package/dist/probe/deps.d.ts +61 -0
- package/dist/probe/deps.d.ts.map +1 -0
- package/dist/probe/deps.js +54 -0
- package/dist/probe/deps.js.map +1 -0
- package/dist/probe/introduce.d.ts +70 -0
- package/dist/probe/introduce.d.ts.map +1 -0
- package/dist/probe/introduce.js +295 -0
- package/dist/probe/introduce.js.map +1 -0
- package/dist/probe/membership.d.ts +90 -0
- package/dist/probe/membership.d.ts.map +1 -0
- package/dist/probe/membership.js +450 -0
- package/dist/probe/membership.js.map +1 -0
- package/dist/probe/trust.d.ts +116 -0
- package/dist/probe/trust.d.ts.map +1 -0
- package/dist/probe/trust.js +345 -0
- package/dist/probe/trust.js.map +1 -0
- package/dist/probe.d.ts +8 -0
- package/dist/probe.d.ts.map +1 -0
- package/dist/probe.js +41 -0
- package/dist/probe.js.map +1 -0
- package/dist/schemas.d.ts +2 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +51 -0
- package/dist/schemas.js.map +1 -0
- package/dist/unicode15.d.ts +8 -0
- package/dist/unicode15.d.ts.map +1 -0
- package/dist/unicode15.js +55 -0
- package/dist/unicode15.js.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# @real-life/trust-protocol
|
|
2
|
+
|
|
3
|
+
**The Real Life Trust Protocol (RLTP), as running code.** Trust rooted in
|
|
4
|
+
encounters between people: two humans meet, recognize each other, and record
|
|
5
|
+
that recognition as verifiable credentials. Cryptography proves freshness and
|
|
6
|
+
authorship; only a human can witness a human.
|
|
7
|
+
|
|
8
|
+
This package is the **executable form of the specification** — it lives beside
|
|
9
|
+
the schemas and the test vectors it must reproduce byte-for-byte. Published by
|
|
10
|
+
the [Real Life Organisation](https://real-life.org) under CC BY 4.0.
|
|
11
|
+
|
|
12
|
+
- Specification, schemas and vectors: <https://rltp.real-life.org>
|
|
13
|
+
- Zero dependencies. WebCrypto only (Ed25519, X25519, HKDF, AES-256-GCM).
|
|
14
|
+
- Works in browsers, Node ≥ 20, Deno, Bun. No DOM, no storage, no network:
|
|
15
|
+
the library computes and verifies, the host decides where bytes live.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm i @real-life/trust-protocol
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## The modules mirror the specification
|
|
24
|
+
|
|
25
|
+
Each module answers to one document, so a reader of the spec knows where to
|
|
26
|
+
look in the code:
|
|
27
|
+
|
|
28
|
+
| Module | Specification | What it carries |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `core` | across all layers | The canonical form: JCS serialization, multibase encodings, digest equality over *decoded* bytes, whole-second timestamps, calendar validity — and the JSON-Schema subset validator the conformance runner uses. |
|
|
31
|
+
| `crypto` | — (primitives) | Hashes, HKDF, key pairs, did:key and multikey renderings, ECDH, and the eddsa-jcs-2022 Data Integrity proof every layer signs with. Answers *how*, never *what*. |
|
|
32
|
+
| `identity` | Identity Layer | One root seed, every context derived — community anchor, pair anchor per relationship, member anchor per group. Contexts never link without their holder's deliberate act. |
|
|
33
|
+
| `encounter` | Encounter Layer | The ceremony under fresh-always pair anchors: challenges, contact cards, the enactment binding both sides compute independently, encounter credentials. |
|
|
34
|
+
| `delivery` | Delivery Contract | The sealed envelope, and the receive chain in its declared order — size bound *before* decryption, envelope form, decryption, parse and digest over the canonical form, completed-effect cache. |
|
|
35
|
+
|
|
36
|
+
Everything is re-exported from the package root; the table is a map, not an
|
|
37
|
+
import instruction.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { labeledContext, signCard, seal, sameDigest } from '@real-life/trust-protocol'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Two entry points
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { … } from '@real-life/trust-protocol' // wire-normative core
|
|
47
|
+
import { introduce, trust, continuity, membership }
|
|
48
|
+
from '@real-life/trust-protocol/probe' // draft — will change
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The **`/probe` subpath is deliberate.** Its modules exercise the converged
|
|
52
|
+
*semantics* of their layers, but their transport shapes carry `@probe` and
|
|
53
|
+
are **not wire-normative**: mediated introductions over a rendezvous drop,
|
|
54
|
+
the explicit trust act with the blinded star, §6a continuity (chains
|
|
55
|
+
instead of duplicates), and group membership (founding, VIC invite,
|
|
56
|
+
admission, vouching). Experiment with them; do not treat their wire forms
|
|
57
|
+
as an interoperability target. A subpath import is a decision someone has
|
|
58
|
+
to make — nothing behind it can be reached by accident.
|
|
59
|
+
|
|
60
|
+
**The redelivery contract of probe receivers:** a receiver's inbound
|
|
61
|
+
effect is complete the moment it returns `handled: true` without `error` —
|
|
62
|
+
that delivery is cached and answers `duplicate-known` forever after.
|
|
63
|
+
Outbound work a receiver triggers (star refreshes, continuity mappings)
|
|
64
|
+
is built per recipient and never discards partial results; what failed is
|
|
65
|
+
named in `outboundError` / `outbound.failures`, and **redelivering the
|
|
66
|
+
inbound document is not the retry path** — re-invoking the producing call
|
|
67
|
+
(e.g. `trust.starRefreshAll`) is, and it is the host application's job.
|
|
68
|
+
|
|
69
|
+
## Versions
|
|
70
|
+
|
|
71
|
+
This package uses its own semver; the specification uses castings. Each
|
|
72
|
+
release states, per module, whose **wire forms** it implements — and what
|
|
73
|
+
it deliberately does not:
|
|
74
|
+
|
|
75
|
+
| Module (0.1.x) | Casting | Implemented | Not in this package |
|
|
76
|
+
|---|---|---|---|
|
|
77
|
+
| `identity` | Identity 0.50 | context derivation under the closed label registry (§6.1, unchanged since 0.13) with the ordered persona pipeline (§6.2, Unicode 15.0 pinned) | recovery derivation (§5.3), service identities (§7), carrier relationship (§7a), the label register and its state |
|
|
78
|
+
| `encounter` | Encounter 0.29 — wire `0.25` (`rltp-card/0.25`, `encounter-scan@0.25`) | challenges, both card profiles, the enactment binding, encounter credentials | the ceremony state machine, acceptance rules, ack deadlines |
|
|
79
|
+
| `delivery` | Delivery 0.64 | the sealed envelope (§5) and the generic receive stages 1–4 | the type-specific stages, residual bookkeeping, transport adapters |
|
|
80
|
+
| `core`, `crypto` | cross-layer | canonical form, digest equality, timestamps, validator; primitives + `eddsa-jcs-2022` proof | — |
|
|
81
|
+
| `/probe` | Network Visibility · Membership Tasks + Access | introductions, trust act + blinded star, §6a continuity, group membership — semantics of the running castings, transport shapes `@probe` | any wire-form stability whatsoever |
|
|
82
|
+
|
|
83
|
+
Persona-name validation is **pinned to Unicode 15.0** as Identity §6.2
|
|
84
|
+
requires: the repertoire ships with the package (`unicode15.ts`, ~5 kB of
|
|
85
|
+
ranges) and no platform Unicode data is consulted — the same name derives
|
|
86
|
+
the same anchor on every runtime, whatever ICU it carries.
|
|
87
|
+
|
|
88
|
+
## The contract: the vectors
|
|
89
|
+
|
|
90
|
+
A version that does not reproduce `vectors/` byte-for-byte is not a valid
|
|
91
|
+
version — the conformance runner checks every cryptographic claim, and every
|
|
92
|
+
negative case must fail at its declared stage. If you implement RLTP in
|
|
93
|
+
another language, those same vectors are how you check yourself; you do not
|
|
94
|
+
need this package to do it.
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — specification and
|
|
99
|
+
reference implementation alike.
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type Json = string | number | boolean | null | Json[] | {
|
|
2
|
+
[k: string]: Json;
|
|
3
|
+
};
|
|
4
|
+
/** RFC 8785 subset for the ASCII I-JSON forms this stack ships. */
|
|
5
|
+
export declare const jcs: (o: unknown) => string;
|
|
6
|
+
export declare const B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
7
|
+
export declare function base58(bytes: Uint8Array): string;
|
|
8
|
+
export declare function fromBase58(s: string): Uint8Array | null;
|
|
9
|
+
export declare const b64uOf: (bytes: Uint8Array) => string;
|
|
10
|
+
export declare const fromB64u: (s: string) => Uint8Array;
|
|
11
|
+
export declare const toU: (v: unknown) => string | null;
|
|
12
|
+
export declare const sameDigest: (a: unknown, b: unknown) => boolean;
|
|
13
|
+
/** Whole-second ISO rendering — the timestamp form every artifact carries. */
|
|
14
|
+
export declare const iso: (ms: number) => string;
|
|
15
|
+
export declare const tsec: (v: string | number) => number;
|
|
16
|
+
export declare const calOK: (t: unknown) => boolean;
|
|
17
|
+
export type Schema = boolean | {
|
|
18
|
+
[k: string]: any;
|
|
19
|
+
};
|
|
20
|
+
export type SchemaMap = Record<string, Schema>;
|
|
21
|
+
export interface Validator {
|
|
22
|
+
validate: (data: unknown, schema: Schema, root: Schema, path?: string) => string[];
|
|
23
|
+
resolveRef: (ref: string, root: Schema) => {
|
|
24
|
+
node: Schema;
|
|
25
|
+
root: Schema;
|
|
26
|
+
};
|
|
27
|
+
SCHEMAS: SchemaMap;
|
|
28
|
+
BYID: SchemaMap;
|
|
29
|
+
}
|
|
30
|
+
/** Builds a validator bound to one schema map ({ filename → parsed schema }). */
|
|
31
|
+
export declare function makeValidator(SCHEMAS: SchemaMap): Validator;
|
|
32
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,EAAE,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAA;AAEpF,mEAAmE;AACnE,eAAO,MAAM,GAAG,GAAI,GAAG,OAAO,KAAG,MA0ChC,CAAA;AAGD,eAAO,MAAM,GAAG,+DAA+D,CAAA;AAC/E,wBAAgB,MAAM,CAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAOjD;AACD,wBAAgB,UAAU,CAAE,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAWxD;AACD,eAAO,MAAM,MAAM,GAAI,OAAO,UAAU,KAAG,MAO1C,CAAA;AACD,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,KAAG,UAMpC,CAAA;AAMD,eAAO,MAAM,GAAG,GAAI,GAAG,OAAO,KAAG,MAAM,GAAG,IAgBzC,CAAA;AACD,eAAO,MAAM,UAAU,GAAI,GAAG,OAAO,EAAE,GAAG,OAAO,KAAG,OAAqE,CAAA;AAEzH,8EAA8E;AAC9E,eAAO,MAAM,GAAG,GAAI,IAAI,MAAM,KAAG,MAA8D,CAAA;AAI/F,eAAO,MAAM,IAAI,GAAI,GAAG,MAAM,GAAG,MAAM,KAAG,MAA+E,CAAA;AAGzH,eAAO,MAAM,KAAK,GAAI,GAAG,OAAO,KAAG,OAKlC,CAAA;AAKD,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAA;AACnD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAC9C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,EAAE,CAAA;IAClF,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACzE,OAAO,EAAE,SAAS,CAAA;IAClB,IAAI,EAAE,SAAS,CAAA;CAChB;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAE,OAAO,EAAE,SAAS,GAAG,SAAS,CAiF5D"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
// core — the form layer: the canonical rules every RLTP artifact obeys.
|
|
2
|
+
//
|
|
3
|
+
// One implementation of the canonical form (JCS subset, multibase
|
|
4
|
+
// encodings, digest equality over DECODED bytes, timestamp
|
|
5
|
+
// normalization) and the JSON-Schema subset validator. The conformance
|
|
6
|
+
// runner, the reference engine and every simulator delegate here.
|
|
7
|
+
//
|
|
8
|
+
// Predicates exist ONCE — that is the point. Weakening a rule here fails
|
|
9
|
+
// the conformance runner's self-tests rather than silently changing what
|
|
10
|
+
// some user interface accepts.
|
|
11
|
+
//
|
|
12
|
+
// Dependency-free and environment-free: no node:*, no DOM, no WebCrypto.
|
|
13
|
+
// Everything here is synchronous and pure.
|
|
14
|
+
/** RFC 8785 subset for the ASCII I-JSON forms this stack ships. */
|
|
15
|
+
export const jcs = (o) => {
|
|
16
|
+
if (o === undefined)
|
|
17
|
+
throw new Error('jcs: undefined is not serializable');
|
|
18
|
+
// RFC 8785 operates on Unicode strings — a lone surrogate is not one,
|
|
19
|
+
// and a conformant implementation MUST error rather than canonicalize
|
|
20
|
+
// it (review 3, B-1: divergent digests between implementations)
|
|
21
|
+
if (typeof o === 'string' && !o.isWellFormed())
|
|
22
|
+
throw new Error('jcs: lone surrogate');
|
|
23
|
+
if (typeof o === 'number' && !Number.isFinite(o))
|
|
24
|
+
throw new Error('jcs: non-finite number');
|
|
25
|
+
if (Array.isArray(o)) {
|
|
26
|
+
// a sparse array is not a JSON value: map() skips holes and join()
|
|
27
|
+
// erases them, so [empty] and [] would COLLIDE on one digest
|
|
28
|
+
// (review 4, B-3) — reject instead of silently canonicalizing
|
|
29
|
+
for (let i = 0; i < o.length; i++)
|
|
30
|
+
if (!(i in o))
|
|
31
|
+
throw new Error('jcs: sparse array');
|
|
32
|
+
// non-index own properties (arr.x = 1) and symbol keys would be
|
|
33
|
+
// silently DROPPED and collide with the bare array (review 6, B-2)
|
|
34
|
+
if (Object.getOwnPropertyNames(o).length !== o.length + 1 /* 'length' itself */ || Object.getOwnPropertySymbols(o).length > 0)
|
|
35
|
+
throw new Error('jcs: array with extra own properties');
|
|
36
|
+
return '[' + o.map(jcs).join(',') + ']';
|
|
37
|
+
}
|
|
38
|
+
if (o && typeof o === 'object') {
|
|
39
|
+
// only PLAIN objects are JSON values: a Date, Map or class instance
|
|
40
|
+
// would serialize by its enumerable keys alone and collide with {}
|
|
41
|
+
// (review 5, B-3) — reject at the edge of the digest domain
|
|
42
|
+
const proto = Object.getPrototypeOf(o);
|
|
43
|
+
if (proto !== null && proto !== Object.prototype)
|
|
44
|
+
throw new Error('jcs: not a plain JSON object');
|
|
45
|
+
// symbol-keyed own properties would be silently dropped — the object
|
|
46
|
+
// would collide with its symbol-free twin (review 6, B-2)
|
|
47
|
+
if (Object.getOwnPropertySymbols(o).length > 0)
|
|
48
|
+
throw new Error('jcs: object with symbol keys');
|
|
49
|
+
// non-enumerable own properties are invisible to Object.keys and
|
|
50
|
+
// would collide with the bare twin (review 7, B-4)
|
|
51
|
+
if (Object.getOwnPropertyNames(o).length !== Object.keys(o).length)
|
|
52
|
+
throw new Error('jcs: object with non-enumerable own properties');
|
|
53
|
+
const rec = o;
|
|
54
|
+
return '{' + Object.keys(rec).sort().map((k) => {
|
|
55
|
+
if (rec[k] === undefined)
|
|
56
|
+
throw new Error('jcs: undefined property ' + k);
|
|
57
|
+
if (!k.isWellFormed())
|
|
58
|
+
throw new Error('jcs: lone surrogate in key');
|
|
59
|
+
return JSON.stringify(k) + ':' + jcs(rec[k]);
|
|
60
|
+
}).join(',') + '}';
|
|
61
|
+
}
|
|
62
|
+
const s = JSON.stringify(o);
|
|
63
|
+
// M-4 (review 1): symbols and functions stringify to undefined — the
|
|
64
|
+
// invariant "jcs returns a string" is enforced at the API edge, not
|
|
65
|
+
// silently violated downstream in a digest.
|
|
66
|
+
if (typeof s !== 'string')
|
|
67
|
+
throw new Error('jcs: value is not JSON-representable');
|
|
68
|
+
return s;
|
|
69
|
+
};
|
|
70
|
+
// ── multibase encodings ─────────────────────────────────────────────────
|
|
71
|
+
export const B58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
72
|
+
export function base58(bytes) {
|
|
73
|
+
let n = 0n;
|
|
74
|
+
for (const b of bytes)
|
|
75
|
+
n = n * 256n + BigInt(b);
|
|
76
|
+
let out = '';
|
|
77
|
+
while (n > 0n) {
|
|
78
|
+
out = B58[Number(n % 58n)] + out;
|
|
79
|
+
n /= 58n;
|
|
80
|
+
}
|
|
81
|
+
for (const b of bytes) {
|
|
82
|
+
if (b === 0)
|
|
83
|
+
out = '1' + out;
|
|
84
|
+
else
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
export function fromBase58(s) {
|
|
90
|
+
let n = 0n;
|
|
91
|
+
for (const c of s) {
|
|
92
|
+
const i = B58.indexOf(c);
|
|
93
|
+
if (i < 0)
|
|
94
|
+
return null;
|
|
95
|
+
n = n * 58n + BigInt(i);
|
|
96
|
+
}
|
|
97
|
+
const out = [];
|
|
98
|
+
while (n > 0n) {
|
|
99
|
+
out.unshift(Number(n % 256n));
|
|
100
|
+
n /= 256n;
|
|
101
|
+
}
|
|
102
|
+
for (const c of s) {
|
|
103
|
+
if (c === '1')
|
|
104
|
+
out.unshift(0);
|
|
105
|
+
else
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
return new Uint8Array(out);
|
|
109
|
+
}
|
|
110
|
+
export const b64uOf = (bytes) => {
|
|
111
|
+
let s = '';
|
|
112
|
+
for (const b of bytes)
|
|
113
|
+
s += String.fromCharCode(b);
|
|
114
|
+
const btoaFn = typeof btoa === 'function'
|
|
115
|
+
? btoa
|
|
116
|
+
: (x) => globalThis.Buffer.from(x, 'binary').toString('base64');
|
|
117
|
+
return btoaFn(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
118
|
+
};
|
|
119
|
+
export const fromB64u = (s) => {
|
|
120
|
+
const atobFn = typeof atob === 'function'
|
|
121
|
+
? atob
|
|
122
|
+
: (x) => globalThis.Buffer.from(x, 'base64').toString('binary');
|
|
123
|
+
const bin = atobFn(s.replace(/-/g, '+').replace(/_/g, '/'));
|
|
124
|
+
return Uint8Array.from(bin, (c) => c.charCodeAt(0));
|
|
125
|
+
};
|
|
126
|
+
// ── digest equality over decoded multihash bytes (Encounter 2.3) ────────
|
|
127
|
+
// toU: strict multibase bridge — prefix, sha2-256 multihash header and
|
|
128
|
+
// length, AND canonical-form round-trip; returns the canonical u rendering
|
|
129
|
+
// or null. A u input is checked for header/length too.
|
|
130
|
+
export const toU = (v) => {
|
|
131
|
+
if (typeof v !== 'string' || v.length < 2)
|
|
132
|
+
return null;
|
|
133
|
+
let bytes;
|
|
134
|
+
if (v[0] === 'u') {
|
|
135
|
+
try {
|
|
136
|
+
bytes = fromB64u(v.slice(1));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
// canonical base64url only — padding or non-zero trailing bits make a
|
|
142
|
+
// DIFFERENT string decode to the same bytes, and equality is decided
|
|
143
|
+
// over bytes; without this check 16 spellings of one digest verify
|
|
144
|
+
// (B-1, review 1; the shipped reject vectors demand exactly this).
|
|
145
|
+
if (bytes && 'u' + b64uOf(bytes) !== v)
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
else if (v[0] === 'z') {
|
|
149
|
+
bytes = fromBase58(v.slice(1));
|
|
150
|
+
if (bytes && 'z' + base58(bytes) !== v)
|
|
151
|
+
return null; // canonical base58btc only
|
|
152
|
+
}
|
|
153
|
+
else
|
|
154
|
+
return null;
|
|
155
|
+
if (!bytes || bytes.length !== 34 || bytes[0] !== 0x12 || bytes[1] !== 0x20)
|
|
156
|
+
return null;
|
|
157
|
+
return 'u' + b64uOf(bytes);
|
|
158
|
+
};
|
|
159
|
+
export const sameDigest = (a, b) => { const na = toU(a); return na !== null && na === toU(b); };
|
|
160
|
+
/** Whole-second ISO rendering — the timestamp form every artifact carries. */
|
|
161
|
+
export const iso = (ms) => new Date(ms).toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
162
|
+
// ── timestamps (Encounter 2.3) ──────────────────────────────────────────
|
|
163
|
+
// tsec: whole-second truncation of EVERY comparison operand (incl. now).
|
|
164
|
+
export const tsec = (v) => Math.floor((typeof v === 'number' ? v : Date.parse(v)) / 1000) * 1000;
|
|
165
|
+
// calOK: calendar-valid round-trip AND the ≤3-fractional-digit cap —
|
|
166
|
+
// Date.parse silently normalizes impossible dates, so demand the round-trip.
|
|
167
|
+
export const calOK = (t) => {
|
|
168
|
+
if (typeof t !== 'string')
|
|
169
|
+
return false;
|
|
170
|
+
if (!/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]{1,3})?Z$/.test(t))
|
|
171
|
+
return false;
|
|
172
|
+
const d = new Date(t);
|
|
173
|
+
return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 19) === t.slice(0, 19);
|
|
174
|
+
};
|
|
175
|
+
/** Builds a validator bound to one schema map ({ filename → parsed schema }). */
|
|
176
|
+
export function makeValidator(SCHEMAS) {
|
|
177
|
+
const BYID = {};
|
|
178
|
+
for (const s of Object.values(SCHEMAS))
|
|
179
|
+
if (typeof s === 'object' && s.$id)
|
|
180
|
+
BYID[s.$id] = s;
|
|
181
|
+
const walk = (node, parts) => { let n = node; for (const p of parts)
|
|
182
|
+
n = n[p]; return n; };
|
|
183
|
+
const resolveRef = (ref, root) => {
|
|
184
|
+
if (ref.startsWith('#'))
|
|
185
|
+
return { node: walk(root, ref.slice(2).split('/')), root };
|
|
186
|
+
const [base, frag] = ref.split('#');
|
|
187
|
+
const target = SCHEMAS[base] || BYID[base];
|
|
188
|
+
if (!target)
|
|
189
|
+
throw new Error('unresolvable $ref ' + ref);
|
|
190
|
+
if (!frag)
|
|
191
|
+
return { node: target, root: target };
|
|
192
|
+
return { node: walk(target, frag.slice(1).split('/')), root: target };
|
|
193
|
+
};
|
|
194
|
+
function validate(data, schema, root, path = '$') {
|
|
195
|
+
const errs = [];
|
|
196
|
+
const E = (m) => errs.push(`${path}: ${m}`);
|
|
197
|
+
if (schema === false) {
|
|
198
|
+
E('schema false');
|
|
199
|
+
return errs;
|
|
200
|
+
}
|
|
201
|
+
if (schema === true || schema == null)
|
|
202
|
+
return errs;
|
|
203
|
+
if (schema.$ref) {
|
|
204
|
+
const { node, root: r } = resolveRef(schema.$ref, root);
|
|
205
|
+
return validate(data, node, r, path);
|
|
206
|
+
}
|
|
207
|
+
const anyData = data;
|
|
208
|
+
if (schema.const !== undefined && jcs(data) !== jcs(schema.const))
|
|
209
|
+
E('const mismatch');
|
|
210
|
+
if (schema.enum && !schema.enum.some((v) => jcs(v) === jcs(data)))
|
|
211
|
+
E('enum mismatch');
|
|
212
|
+
if (schema.type) {
|
|
213
|
+
const t = Array.isArray(data) ? 'array' : data === null ? 'null' : typeof data;
|
|
214
|
+
const want = [].concat(schema.type);
|
|
215
|
+
const okT = want.some((w) => w === t || (w === 'integer' && t === 'number' && Number.isInteger(data)));
|
|
216
|
+
if (!okT) {
|
|
217
|
+
E(`type ${t} != ${schema.type}`);
|
|
218
|
+
return errs;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (typeof data === 'string') {
|
|
222
|
+
if (schema.pattern && !new RegExp(schema.pattern).test(data))
|
|
223
|
+
E('pattern');
|
|
224
|
+
// JSON Schema misst Stringlänge in CODEPUNKTEN, nicht UTF-16-
|
|
225
|
+
// Einheiten (Review 4, M-2: 101 Emoji sind 101 Zeichen, nicht 202)
|
|
226
|
+
const cpLen = (schema.minLength != null || schema.maxLength != null) ? [...data].length : 0;
|
|
227
|
+
if (schema.minLength != null && cpLen < schema.minLength)
|
|
228
|
+
E('minLength');
|
|
229
|
+
if (schema.maxLength != null && cpLen > schema.maxLength)
|
|
230
|
+
E('maxLength');
|
|
231
|
+
}
|
|
232
|
+
if (Array.isArray(data)) {
|
|
233
|
+
if (schema.minItems != null && data.length < schema.minItems)
|
|
234
|
+
E('minItems');
|
|
235
|
+
if (schema.maxItems != null && data.length > schema.maxItems)
|
|
236
|
+
E('maxItems');
|
|
237
|
+
if (schema.uniqueItems && new Set(data.map(jcs)).size !== data.length)
|
|
238
|
+
E('uniqueItems');
|
|
239
|
+
if (schema.prefixItems) {
|
|
240
|
+
schema.prefixItems.forEach((ps, i) => { if (i < data.length)
|
|
241
|
+
errs.push(...validate(data[i], ps, root, `${path}[${i}]`)); });
|
|
242
|
+
if (schema.items === false && data.length > schema.prefixItems.length)
|
|
243
|
+
E('items false beyond prefixItems');
|
|
244
|
+
}
|
|
245
|
+
else if (schema.items !== undefined && schema.items !== true) {
|
|
246
|
+
data.forEach((d, i) => errs.push(...validate(d, schema.items, root, `${path}[${i}]`)));
|
|
247
|
+
}
|
|
248
|
+
if (schema.contains && !data.some((d) => validate(d, schema.contains, root, path).length === 0))
|
|
249
|
+
E('contains unmatched');
|
|
250
|
+
}
|
|
251
|
+
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
252
|
+
const keys = Object.keys(anyData);
|
|
253
|
+
if (schema.minProperties != null && keys.length < schema.minProperties)
|
|
254
|
+
E('minProperties');
|
|
255
|
+
if (schema.maxProperties != null && keys.length > schema.maxProperties)
|
|
256
|
+
E('maxProperties');
|
|
257
|
+
for (const r of schema.required || [])
|
|
258
|
+
if (!Object.hasOwn(anyData, r))
|
|
259
|
+
E(`missing required ${r}`);
|
|
260
|
+
for (const [k, deps] of Object.entries(schema.dependentRequired || {})) {
|
|
261
|
+
if (Object.hasOwn(anyData, k))
|
|
262
|
+
for (const d of deps)
|
|
263
|
+
if (!Object.hasOwn(anyData, d))
|
|
264
|
+
E(`dependentRequired ${k}→${d}`);
|
|
265
|
+
}
|
|
266
|
+
if (schema.propertyNames)
|
|
267
|
+
for (const k of keys)
|
|
268
|
+
errs.push(...validate(k, schema.propertyNames, root, `${path}.<name:${k}>`));
|
|
269
|
+
for (const k of keys) {
|
|
270
|
+
if (schema.properties && Object.hasOwn(schema.properties, k))
|
|
271
|
+
errs.push(...validate(anyData[k], schema.properties[k], root, `${path}.${k}`));
|
|
272
|
+
else if (schema.additionalProperties === false)
|
|
273
|
+
E(`additionalProperty ${k}`);
|
|
274
|
+
else if (schema.additionalProperties && typeof schema.additionalProperties === 'object')
|
|
275
|
+
errs.push(...validate(anyData[k], schema.additionalProperties, root, `${path}.${k}`));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (typeof data === 'number') {
|
|
279
|
+
if (schema.minimum != null && data < schema.minimum)
|
|
280
|
+
E('minimum');
|
|
281
|
+
if (schema.maximum != null && data > schema.maximum)
|
|
282
|
+
E('maximum');
|
|
283
|
+
if (schema.exclusiveMinimum != null && data <= schema.exclusiveMinimum)
|
|
284
|
+
E('exclusiveMinimum');
|
|
285
|
+
if (schema.exclusiveMaximum != null && data >= schema.exclusiveMaximum)
|
|
286
|
+
E('exclusiveMaximum');
|
|
287
|
+
if (schema.multipleOf != null && (data / schema.multipleOf) % 1 !== 0)
|
|
288
|
+
E('multipleOf');
|
|
289
|
+
}
|
|
290
|
+
if (schema.anyOf && !schema.anyOf.some((s2) => validate(data, s2, root, path).length === 0))
|
|
291
|
+
E('anyOf unmatched');
|
|
292
|
+
if (schema.oneOf) {
|
|
293
|
+
const n = schema.oneOf.filter((s2) => validate(data, s2, root, path).length === 0).length;
|
|
294
|
+
if (n !== 1)
|
|
295
|
+
E(`oneOf matched ${n}`);
|
|
296
|
+
}
|
|
297
|
+
if (schema.not !== undefined && validate(data, schema.not, root, path).length === 0)
|
|
298
|
+
E('not matched');
|
|
299
|
+
if (schema.if !== undefined) {
|
|
300
|
+
const hit = validate(data, schema.if, root, path).length === 0;
|
|
301
|
+
if (hit && schema.then !== undefined)
|
|
302
|
+
errs.push(...validate(data, schema.then, root, path));
|
|
303
|
+
if (!hit && schema.else !== undefined)
|
|
304
|
+
errs.push(...validate(data, schema.else, root, path));
|
|
305
|
+
}
|
|
306
|
+
for (const sub of (schema.allOf || []))
|
|
307
|
+
errs.push(...validate(data, sub, root, path));
|
|
308
|
+
return errs;
|
|
309
|
+
}
|
|
310
|
+
return { validate, resolveRef, SCHEMAS, BYID };
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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","sourcesContent":["// core — the form layer: the canonical rules every RLTP artifact obeys.\n//\n// One implementation of the canonical form (JCS subset, multibase\n// encodings, digest equality over DECODED bytes, timestamp\n// normalization) and the JSON-Schema subset validator. The conformance\n// runner, the reference engine and every simulator delegate here.\n//\n// Predicates exist ONCE — that is the point. Weakening a rule here fails\n// the conformance runner's self-tests rather than silently changing what\n// some user interface accepts.\n//\n// Dependency-free and environment-free: no node:*, no DOM, no WebCrypto.\n// Everything here is synchronous and pure.\n\n// ── JCS (RFC 8785 subset for the ASCII I-JSON forms this stack ships) ──\nexport type Json = string | number | boolean | null | Json[] | { [k: string]: Json }\n\n/** RFC 8785 subset for the ASCII I-JSON forms this stack ships. */\nexport const jcs = (o: unknown): string => {\n if (o === undefined) throw new Error('jcs: undefined is not serializable')\n // RFC 8785 operates on Unicode strings — a lone surrogate is not one,\n // and a conformant implementation MUST error rather than canonicalize\n // it (review 3, B-1: divergent digests between implementations)\n if (typeof o === 'string' && !(o as unknown as { isWellFormed(): boolean }).isWellFormed()) throw new Error('jcs: lone surrogate')\n if (typeof o === 'number' && !Number.isFinite(o)) throw new Error('jcs: non-finite number')\n if (Array.isArray(o)) {\n // a sparse array is not a JSON value: map() skips holes and join()\n // erases them, so [empty] and [] would COLLIDE on one digest\n // (review 4, B-3) — reject instead of silently canonicalizing\n for (let i = 0; i < o.length; i++) if (!(i in o)) throw new Error('jcs: sparse array')\n // non-index own properties (arr.x = 1) and symbol keys would be\n // silently DROPPED and collide with the bare array (review 6, B-2)\n if (Object.getOwnPropertyNames(o).length !== o.length + 1 /* 'length' itself */ || Object.getOwnPropertySymbols(o).length > 0) throw new Error('jcs: array with extra own properties')\n return '[' + o.map(jcs).join(',') + ']'\n }\n if (o && typeof o === 'object') {\n // only PLAIN objects are JSON values: a Date, Map or class instance\n // would serialize by its enumerable keys alone and collide with {}\n // (review 5, B-3) — reject at the edge of the digest domain\n const proto = Object.getPrototypeOf(o)\n if (proto !== null && proto !== Object.prototype) throw new Error('jcs: not a plain JSON object')\n // symbol-keyed own properties would be silently dropped — the object\n // would collide with its symbol-free twin (review 6, B-2)\n if (Object.getOwnPropertySymbols(o).length > 0) throw new Error('jcs: object with symbol keys')\n // non-enumerable own properties are invisible to Object.keys and\n // would collide with the bare twin (review 7, B-4)\n if (Object.getOwnPropertyNames(o).length !== Object.keys(o).length) throw new Error('jcs: object with non-enumerable own properties')\n const rec = o as Record<string, unknown>\n return '{' + Object.keys(rec).sort().map((k) => {\n if (rec[k] === undefined) throw new Error('jcs: undefined property ' + k)\n if (!(k as unknown as { isWellFormed(): boolean }).isWellFormed()) throw new Error('jcs: lone surrogate in key')\n return JSON.stringify(k) + ':' + jcs(rec[k])\n }).join(',') + '}'\n }\n const s = JSON.stringify(o)\n // M-4 (review 1): symbols and functions stringify to undefined — the\n // invariant \"jcs returns a string\" is enforced at the API edge, not\n // silently violated downstream in a digest.\n if (typeof s !== 'string') throw new Error('jcs: value is not JSON-representable')\n return s\n}\n\n// ── multibase encodings ─────────────────────────────────────────────────\nexport const B58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'\nexport function base58 (bytes: Uint8Array): string {\n let n = 0n\n for (const b of bytes) n = n * 256n + BigInt(b)\n let out = ''\n while (n > 0n) { out = B58[Number(n % 58n)] + out; n /= 58n }\n for (const b of bytes) { if (b === 0) out = '1' + out; else break }\n return out\n}\nexport function fromBase58 (s: string): Uint8Array | null {\n let n = 0n\n for (const c of s) {\n const i = B58.indexOf(c)\n if (i < 0) return null\n n = n * 58n + BigInt(i)\n }\n const out: number[] = []\n while (n > 0n) { out.unshift(Number(n % 256n)); n /= 256n }\n for (const c of s) { if (c === '1') out.unshift(0); else break }\n return new Uint8Array(out)\n}\nexport const b64uOf = (bytes: Uint8Array): string => {\n let s = ''\n for (const b of bytes) s += String.fromCharCode(b)\n const btoaFn: (x: string) => string = typeof btoa === 'function'\n ? btoa\n : (x) => (globalThis as any).Buffer.from(x, 'binary').toString('base64')\n return btoaFn(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\nexport const fromB64u = (s: string): Uint8Array => {\n const atobFn: (x: string) => string = typeof atob === 'function'\n ? atob\n : (x) => (globalThis as any).Buffer.from(x, 'base64').toString('binary')\n const bin = atobFn(s.replace(/-/g, '+').replace(/_/g, '/'))\n return Uint8Array.from(bin, (c) => c.charCodeAt(0))\n}\n\n// ── digest equality over decoded multihash bytes (Encounter 2.3) ────────\n// toU: strict multibase bridge — prefix, sha2-256 multihash header and\n// length, AND canonical-form round-trip; returns the canonical u rendering\n// or null. A u input is checked for header/length too.\nexport const toU = (v: unknown): string | null => {\n if (typeof v !== 'string' || v.length < 2) return null\n let bytes: Uint8Array | null\n if (v[0] === 'u') {\n try { bytes = fromB64u(v.slice(1)) } catch { return null }\n // canonical base64url only — padding or non-zero trailing bits make a\n // DIFFERENT string decode to the same bytes, and equality is decided\n // over bytes; without this check 16 spellings of one digest verify\n // (B-1, review 1; the shipped reject vectors demand exactly this).\n if (bytes && 'u' + b64uOf(bytes) !== v) return null\n } else if (v[0] === 'z') {\n bytes = fromBase58(v.slice(1))\n if (bytes && 'z' + base58(bytes) !== v) return null // canonical base58btc only\n } else return null\n if (!bytes || bytes.length !== 34 || bytes[0] !== 0x12 || bytes[1] !== 0x20) return null\n return 'u' + b64uOf(bytes)\n}\nexport const sameDigest = (a: unknown, b: unknown): boolean => { const na = toU(a); return na !== null && na === toU(b) }\n\n/** Whole-second ISO rendering — the timestamp form every artifact carries. */\nexport const iso = (ms: number): string => new Date(ms).toISOString().replace(/\\.\\d{3}Z$/, 'Z')\n\n// ── timestamps (Encounter 2.3) ──────────────────────────────────────────\n// tsec: whole-second truncation of EVERY comparison operand (incl. now).\nexport const tsec = (v: string | number): number => Math.floor((typeof v === 'number' ? v : Date.parse(v)) / 1000) * 1000\n// calOK: calendar-valid round-trip AND the ≤3-fractional-digit cap —\n// Date.parse silently normalizes impossible dates, so demand the round-trip.\nexport const calOK = (t: unknown): boolean => {\n if (typeof t !== 'string') return false\n if (!/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,3})?Z$/.test(t)) return false\n const d = new Date(t)\n return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 19) === t.slice(0, 19)\n}\n\n// ── THE JSON-Schema subset validator (exactly the keywords we ship) ─────\n// makeValidator(schemaMap): schemaMap is { filename → parsed schema }.\n// Returns { validate, resolveRef, SCHEMAS, BYID } bound to that map.\nexport type Schema = boolean | { [k: string]: any }\nexport type SchemaMap = Record<string, Schema>\nexport interface Validator {\n validate: (data: unknown, schema: Schema, root: Schema, path?: string) => string[]\n resolveRef: (ref: string, root: Schema) => { node: Schema, root: Schema }\n SCHEMAS: SchemaMap\n BYID: SchemaMap\n}\n\n/** Builds a validator bound to one schema map ({ filename → parsed schema }). */\nexport function makeValidator (SCHEMAS: SchemaMap): Validator {\n const BYID: SchemaMap = {}\n for (const s of Object.values(SCHEMAS)) if (typeof s === 'object' && s.$id) BYID[s.$id] = s\n const walk = (node: any, parts: string[]): any => { let n = node; for (const p of parts) n = n[p]; return n }\n const resolveRef = (ref: string, root: Schema) => {\n if (ref.startsWith('#')) return { node: walk(root, ref.slice(2).split('/')), root }\n const [base, frag] = ref.split('#')\n const target = SCHEMAS[base!] || BYID[base!]\n if (!target) throw new Error('unresolvable $ref ' + ref)\n if (!frag) return { node: target, root: target }\n return { node: walk(target, frag.slice(1).split('/')), root: target }\n }\n function validate (data: unknown, schema: Schema, root: Schema, path = '$'): string[] {\n const errs: string[] = []\n const E = (m: string) => errs.push(`${path}: ${m}`)\n if (schema === false) { E('schema false'); return errs }\n if (schema === true || schema == null) return errs\n if (schema.$ref) { const { node, root: r } = resolveRef(schema.$ref, root); return validate(data, node, r, path) }\n const anyData = data as any\n if (schema.const !== undefined && jcs(data) !== jcs(schema.const)) E('const mismatch')\n if (schema.enum && !schema.enum.some((v: unknown) => jcs(v) === jcs(data))) E('enum mismatch')\n if (schema.type) {\n const t = Array.isArray(data) ? 'array' : data === null ? 'null' : typeof data\n const want: string[] = ([] as string[]).concat(schema.type)\n const okT = want.some((w) => w === t || (w === 'integer' && t === 'number' && Number.isInteger(data)))\n if (!okT) { E(`type ${t} != ${schema.type}`); return errs }\n }\n if (typeof data === 'string') {\n if (schema.pattern && !new RegExp(schema.pattern).test(data)) E('pattern')\n // JSON Schema misst Stringlänge in CODEPUNKTEN, nicht UTF-16-\n // Einheiten (Review 4, M-2: 101 Emoji sind 101 Zeichen, nicht 202)\n const cpLen = (schema.minLength != null || schema.maxLength != null) ? [...data].length : 0\n if (schema.minLength != null && cpLen < schema.minLength) E('minLength')\n if (schema.maxLength != null && cpLen > schema.maxLength) E('maxLength')\n }\n if (Array.isArray(data)) {\n if (schema.minItems != null && data.length < schema.minItems) E('minItems')\n if (schema.maxItems != null && data.length > schema.maxItems) E('maxItems')\n if (schema.uniqueItems && new Set(data.map(jcs)).size !== data.length) E('uniqueItems')\n if (schema.prefixItems) {\n schema.prefixItems.forEach((ps: Schema, i: number) => { if (i < data.length) errs.push(...validate(data[i], ps, root, `${path}[${i}]`)) })\n if (schema.items === false && data.length > schema.prefixItems.length) E('items false beyond prefixItems')\n } else if (schema.items !== undefined && schema.items !== true) {\n data.forEach((d: unknown, i: number) => errs.push(...validate(d, schema.items, root, `${path}[${i}]`)))\n }\n if (schema.contains && !data.some((d: unknown) => validate(d, schema.contains, root, path).length === 0)) E('contains unmatched')\n }\n if (data && typeof data === 'object' && !Array.isArray(data)) {\n const keys = Object.keys(anyData)\n if (schema.minProperties != null && keys.length < schema.minProperties) E('minProperties')\n if (schema.maxProperties != null && keys.length > schema.maxProperties) E('maxProperties')\n for (const r of schema.required || []) if (!Object.hasOwn(anyData, r)) E(`missing required ${r}`)\n for (const [k, deps] of Object.entries(schema.dependentRequired || {} as Record<string, string[]>)) {\n if (Object.hasOwn(anyData, k)) for (const d of deps as string[]) if (!Object.hasOwn(anyData, d)) E(`dependentRequired ${k}→${d}`)\n }\n if (schema.propertyNames) for (const k of keys) errs.push(...validate(k, schema.propertyNames, root, `${path}.<name:${k}>`))\n for (const k of keys) {\n if (schema.properties && Object.hasOwn(schema.properties, k)) errs.push(...validate(anyData[k], schema.properties[k], root, `${path}.${k}`))\n else if (schema.additionalProperties === false) E(`additionalProperty ${k}`)\n else if (schema.additionalProperties && typeof schema.additionalProperties === 'object') errs.push(...validate(anyData[k], schema.additionalProperties, root, `${path}.${k}`))\n }\n }\n if (typeof data === 'number') {\n if (schema.minimum != null && data < schema.minimum) E('minimum')\n if (schema.maximum != null && data > schema.maximum) E('maximum')\n if (schema.exclusiveMinimum != null && data <= schema.exclusiveMinimum) E('exclusiveMinimum')\n if (schema.exclusiveMaximum != null && data >= schema.exclusiveMaximum) E('exclusiveMaximum')\n if (schema.multipleOf != null && (data / schema.multipleOf) % 1 !== 0) E('multipleOf')\n }\n if (schema.anyOf && !schema.anyOf.some((s2: Schema) => validate(data, s2, root, path).length === 0)) E('anyOf unmatched')\n if (schema.oneOf) { const n = schema.oneOf.filter((s2: Schema) => validate(data, s2, root, path).length === 0).length; if (n !== 1) E(`oneOf matched ${n}`) }\n if (schema.not !== undefined && validate(data, schema.not, root, path).length === 0) E('not matched')\n if (schema.if !== undefined) {\n const hit = validate(data, schema.if, root, path).length === 0\n if (hit && schema.then !== undefined) errs.push(...validate(data, schema.then, root, path))\n if (!hit && schema.else !== undefined) errs.push(...validate(data, schema.else, root, path))\n }\n for (const sub of (schema.allOf || []) as Schema[]) errs.push(...validate(data, sub, root, path))\n return errs\n }\n return { validate, resolveRef, SCHEMAS, BYID }\n}\n"]}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { base58, fromBase58, b64uOf, fromB64u } from './core.js';
|
|
2
|
+
export { b64uOf, fromB64u, base58, fromBase58 };
|
|
3
|
+
export declare const cat: (...bs: Uint8Array[]) => Uint8Array;
|
|
4
|
+
export declare const rand: (n: number) => Uint8Array;
|
|
5
|
+
export declare const sha: (bytes: Uint8Array) => Promise<Uint8Array>;
|
|
6
|
+
export declare const hkdf: (ikm: Uint8Array, info: string, len?: number) => Promise<Uint8Array>;
|
|
7
|
+
export declare const digestBytes: (bytes: Uint8Array) => Promise<string>;
|
|
8
|
+
export declare const digestDoc: (obj: unknown) => Promise<string>;
|
|
9
|
+
/** A key pair as this library carries it: the private CryptoKey plus the raw public bytes. */
|
|
10
|
+
export interface KeyPair {
|
|
11
|
+
priv: CryptoKey;
|
|
12
|
+
pubRaw: Uint8Array;
|
|
13
|
+
}
|
|
14
|
+
export declare function edFromSeed(seed: Uint8Array): Promise<KeyPair>;
|
|
15
|
+
export declare function xFromSeed(seed: Uint8Array): Promise<KeyPair>;
|
|
16
|
+
export declare const anchorOfEd: (pubRaw: Uint8Array) => string;
|
|
17
|
+
export declare const mkOfX: (pubRaw: Uint8Array) => string;
|
|
18
|
+
export declare const edRawOfAnchor: (did: unknown) => Uint8Array | null;
|
|
19
|
+
export declare const xRawOfMk: (mk: unknown) => Uint8Array | null;
|
|
20
|
+
export declare const ecdh: (xPriv: CryptoKey, theirPubRaw: Uint8Array) => Promise<Uint8Array>;
|
|
21
|
+
/** What a signer must offer: its anchor and its Ed25519 key. A full identity Context satisfies this. */
|
|
22
|
+
export interface Signer {
|
|
23
|
+
anchor: string;
|
|
24
|
+
ed: {
|
|
25
|
+
priv: CryptoKey;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export declare function diSign<T extends Record<string, any>>(ctx: Signer, doc: T, created: string): Promise<T & {
|
|
29
|
+
proof: Record<string, any>;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function diVerify(doc: any, expectedAnchor?: string): Promise<boolean>;
|
|
32
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAcA,OAAO,EAAO,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAS,MAAM,WAAW,CAAA;AAC5E,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;AAM/C,eAAO,MAAM,GAAG,GAAI,GAAG,IAAI,UAAU,EAAE,KAAG,UAIzC,CAAA;AACD,eAAO,MAAM,IAAI,GAAI,GAAG,MAAM,KAAG,UAAkE,CAAA;AAGnG,eAAO,MAAM,GAAG,GAAU,OAAO,UAAU,KAAG,OAAO,CAAC,UAAU,CAAqD,CAAA;AACrH,eAAO,MAAM,IAAI,GAAU,KAAK,UAAU,EAAE,MAAM,MAAM,EAAE,YAAQ,KAAG,OAAO,CAAC,UAAU,CAGtF,CAAA;AAED,eAAO,MAAM,WAAW,GAAU,OAAO,UAAU,KAAG,OAAO,CAAC,MAAM,CAAuE,CAAA;AAE3I,eAAO,MAAM,SAAS,GAAU,KAAK,OAAO,KAAG,OAAO,CAAC,MAAM,CAAqC,CAAA;AAMlG,8FAA8F;AAC9F,MAAM,WAAW,OAAO;IAAG,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE;AAEhE,wBAAsB,UAAU,CAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAGpE;AACD,wBAAsB,SAAS,CAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAGnE;AACD,eAAO,MAAM,UAAU,GAAI,QAAQ,UAAU,KAAG,MAA0E,CAAA;AAC1H,eAAO,MAAM,KAAK,GAAI,QAAQ,UAAU,KAAG,MAAkE,CAAA;AAC7G,eAAO,MAAM,aAAa,GAAI,KAAK,OAAO,KAAG,UAAU,GAAG,IAIzD,CAAA;AACD,eAAO,MAAM,QAAQ,GAAI,IAAI,OAAO,KAAG,UAAU,GAAG,IAInD,CAAA;AACD,eAAO,MAAM,IAAI,GAAU,OAAO,SAAS,EAAE,aAAa,UAAU,KAAG,OAAO,CAAC,UAAU,CAGxF,CAAA;AAMD,wGAAwG;AACxG,MAAM,WAAW,MAAM;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAA;CAAE;AAEnE,wBAAsB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAG,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC,CAM9I;AACD,wBAAsB,QAAQ,CAAE,GAAG,EAAE,GAAG,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAyBnF"}
|