@attestry/sdk 0.6.0 → 0.7.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.
Files changed (49) hide show
  1. package/README.md +3 -3
  2. package/dist/annex-iv-verify/data-integrity.d.ts +57 -0
  3. package/dist/annex-iv-verify/data-integrity.d.ts.map +1 -0
  4. package/dist/annex-iv-verify/data-integrity.js +172 -0
  5. package/dist/annex-iv-verify/data-integrity.js.map +1 -0
  6. package/dist/annex-iv-verify/ed25519.d.ts +21 -0
  7. package/dist/annex-iv-verify/ed25519.d.ts.map +1 -0
  8. package/dist/annex-iv-verify/ed25519.js +67 -0
  9. package/dist/annex-iv-verify/ed25519.js.map +1 -0
  10. package/dist/annex-iv-verify/index.d.ts +4 -0
  11. package/dist/annex-iv-verify/index.d.ts.map +1 -0
  12. package/dist/annex-iv-verify/index.js +11 -0
  13. package/dist/annex-iv-verify/index.js.map +1 -0
  14. package/dist/annex-iv-verify/jwk.d.ts +27 -0
  15. package/dist/annex-iv-verify/jwk.d.ts.map +1 -0
  16. package/dist/annex-iv-verify/jwk.js +57 -0
  17. package/dist/annex-iv-verify/jwk.js.map +1 -0
  18. package/dist/annex-iv-verify/multibase.d.ts +31 -0
  19. package/dist/annex-iv-verify/multibase.d.ts.map +1 -0
  20. package/dist/annex-iv-verify/multibase.js +131 -0
  21. package/dist/annex-iv-verify/multibase.js.map +1 -0
  22. package/dist/annex-iv-verify/resolver.d.ts +28 -0
  23. package/dist/annex-iv-verify/resolver.d.ts.map +1 -0
  24. package/dist/annex-iv-verify/resolver.js +58 -0
  25. package/dist/annex-iv-verify/resolver.js.map +1 -0
  26. package/dist/annex-iv-verify/status-list.d.ts +57 -0
  27. package/dist/annex-iv-verify/status-list.d.ts.map +1 -0
  28. package/dist/annex-iv-verify/status-list.js +185 -0
  29. package/dist/annex-iv-verify/status-list.js.map +1 -0
  30. package/dist/annex-iv-verify/verify.d.ts +164 -0
  31. package/dist/annex-iv-verify/verify.d.ts.map +1 -0
  32. package/dist/annex-iv-verify/verify.js +273 -0
  33. package/dist/annex-iv-verify/verify.js.map +1 -0
  34. package/dist/client.d.ts +2 -0
  35. package/dist/client.d.ts.map +1 -1
  36. package/dist/client.js +4 -0
  37. package/dist/client.js.map +1 -1
  38. package/dist/index.d.ts +4 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +12 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/resources/annex-iv.d.ts +110 -0
  43. package/dist/resources/annex-iv.d.ts.map +1 -0
  44. package/dist/resources/annex-iv.js +146 -0
  45. package/dist/resources/annex-iv.js.map +1 -0
  46. package/dist/transport.js +1 -1
  47. package/dist/transport.js.map +1 -1
  48. package/dist/types.d.ts +1 -1
  49. package/package.json +7 -2
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Official TypeScript SDK for the [Attestry](https://attestry.ai) compliance kernel. Submit AI incidents, fetch decision records, subscribe to live decision streams, and chat with the Reggie compliance copilot from server-side TypeScript / JavaScript code.
4
4
 
5
- > **Status — v0.5.7 (preview).** Eleven resources shipped: `incidents` (create / list / update / search), `decisions` (ingest / bulk / retrieve / list / SSE stream / NDJSON export / chain verify — **decisions surface complete**, 7 methods), `chat` (send + iterator), `auditLog` (export — multi-format SIEM streaming with auto-pagination; verifyChain — org-wide audit-log hash-chain integrity verdict; 2 methods today), `regulatoryChanges` (list — read-only feed of regulatory updates filtered by framework / severity / status / date-range), `complianceCheck` (check — per-system or per-org compliance summary with active-attestations + framework coverage), `check` (run — flat per-system CI/CD compliance check with framework filter, first SDK route to pre-validate every Zod closed-spec rule synchronously), `gate` (evaluate — pass/fail CI/CD deployment gate with structured gap output + score-threshold + missing-assessment policy), `batch` (submit + get — bulk classification/assessment for up to 50 systems with per-row partial-success envelope; **first SDK resource with asymmetric auth between methods**, **first SDK route with a plan-guard 403 surface distinct from the permission-403**), `shipGate` (check — CI/CD ship-gate verdict on whether a build is gated by an in-flight approval-chain execution; 4-shape variadic response with snake_case `approvers_pending` wire field), `abacPolicies` (list / create / retrieve / update / delete — attribute-based access-control (ABAC) policy management; the SDK's FIRST 5-method CRUD cluster, and the FIRST SDK method on the HTTP `DELETE` verb). API is stable inside its surface; new resources are additive. Automatic retry on 429 is on by default.
5
+ > **Status — v0.7.0.** Twelve resources shipped — headline: **`annexIv` (W3, the offline-verifiable EU AI Act Annex IV technical-file path)**: `annexIv.generate` (first-bind-only POST minting the sealed, cryptographically bound Annex IV PDF for a signed technical file), `annexIv.downloadPdf` (the single authenticated call returning the sealed PDF bytes — served from persisted storage, never re-rendered), `annexIv.getBind` (the bind record: hash, signature, status-list ref, sidecar), plus the bundled **offline verifier** `verifyAnnexIvBindOffline` (pure Ed25519/`@noble` public-key verification of the PDF bytes against the bind — no network, no DB, no kernel import; revocation via the signed status list when supplied). The `annexIv` cluster and the offline verifier are NEW IN 0.7.0 — their first published release (npm 0.6.0 predates them entirely). The eleven pre-W3 resources: `incidents` (create / list / update / search), `decisions` (ingest / bulk / retrieve / list / SSE stream / NDJSON export / chain verify — **decisions surface complete**, 7 methods), `chat` (send + iterator), `auditLog` (export — multi-format SIEM streaming with auto-pagination; verifyChain — org-wide audit-log hash-chain integrity verdict; 2 methods today), `regulatoryChanges` (list — read-only feed of regulatory updates filtered by framework / severity / status / date-range), `complianceCheck` (check — per-system or per-org compliance summary with active-attestations + framework coverage), `check` (run — flat per-system CI/CD compliance check with framework filter, first SDK route to pre-validate every Zod closed-spec rule synchronously), `gate` (evaluate — pass/fail CI/CD deployment gate with structured gap output + score-threshold + missing-assessment policy), `batch` (submit + get — bulk classification/assessment for up to 50 systems with per-row partial-success envelope; **first SDK resource with asymmetric auth between methods**, **first SDK route with a plan-guard 403 surface distinct from the permission-403**), `shipGate` (check — CI/CD ship-gate verdict on whether a build is gated by an in-flight approval-chain execution; 4-shape variadic response with snake_case `approvers_pending` wire field), `abacPolicies` (list / create / retrieve / update / delete — attribute-based access-control (ABAC) policy management; the SDK's FIRST 5-method CRUD cluster, and the FIRST SDK method on the HTTP `DELETE` verb). API is stable inside its surface; new resources are additive. Automatic retry on 429 is on by default.
6
6
  >
7
7
  > **0.5.7 — `abacPolicies` CRUD cluster completed** (additive, no breaking changes). The `abacPolicies` resource — attribute-based access-control policy management — reaches its full 5-method surface: `list` / `create` (shipped 0.5.6) plus `retrieve` / `update` / `delete` (this release). **The SDK's FIRST 5-method CRUD cluster** — prior multi-method resources either grew an existing class over many sessions (`decisions` reached 7) or shipped a smaller surface. **FIRST SDK method on the HTTP `DELETE` verb** (`abacPolicies.delete`) and **SECOND on the HTTP `PATCH` verb** (`abacPolicies.update`; `incidents.update` is the first). **The three id-path methods** (`retrieve` / `update` / `delete`) pre-validate `id` against a strict RFC 4122 UUID regex and interpolate it into the request path RAW — mirror of `batch.get`, with **NO `encodeURIComponent` and NO `URIError` defense**: a string matching the UUID regex is ASCII hex + hyphens, URL-safe verbatim and incapable of forming a lone surrogate, so a malformed `id` is pre-rejected synchronously (`TypeError`) before any URL is built (asymmetric with `decisions.retrieve`, whose free-form id needs `encodePathSegment`). **`abacPolicies.update` is the richest method of the cluster** — a **6-arm `instanceof` catch block (the LARGEST on the SDK)**, the three-way 422 fan-out inherited from `.create` (`BodyParseError` → `Array<{path, message}>` / a defensive DEAD `ZodError` arm → `ZodIssue[]` / `AbacPolicyValidationError` → `{errors: string[]}`) PLUS HTTP 409 (name conflict) PLUS HTTP 404 (`AbacPolicyNotFoundError`, an id-embedded message). **Empty-patch pre-validation** — `.update` is a partial update with every field optional; the SDK pre-rejects an empty patch (`update(id, {})`, an all-`undefined` patch, or a patch carrying only unknown keys) synchronously with a `TypeError`, mirroring the kernel `updateAbacPolicySchema`'s `.refine()`. `.delete` returns the **deleted row** (the policy as it existed immediately before deletion — NOT `void` / NOT a `{deleted:true}` envelope); `.update` returns the **updated row** (the `after` state). All 5 methods are **dual-auth admin scope** — HTTP 401 for no/invalid/expired key, HTTP 403 for a valid key lacking `ADMIN` (both branches distinct — pin separately). `.create` / `.update` / `.delete` each write one `abac_policy.*` audit-log entry; `.list` / `.retrieve` are quiet reads. Symmetric prototype-pollution defense on input AND response sides (`Object.hasOwn` module-load snapshot).
8
8
  >
@@ -141,7 +141,7 @@ for (const change of recentCritical) {
141
141
  ```ts
142
142
  new AttestryClient({
143
143
  apiKey: "sk_live_…", // required
144
- baseUrl: "https://app.attestry.ai", // optional — defaults to prod
144
+ baseUrl: "https://attestry.ai", // optional — defaults to prod
145
145
  timeoutMs: 30_000, // optional — defaults to 30s (NOT applied to streams)
146
146
  fetch: customFetch, // optional — defaults to globalThis.fetch
147
147
  retry: { maxRetries: 3 }, // optional — see "Automatic retry" below
@@ -151,7 +151,7 @@ new AttestryClient({
151
151
  | Option | Default | Notes |
152
152
  |---|---|---|
153
153
  | `apiKey` | required | API key from the Attestry org settings page. Sent as `x-api-key`. |
154
- | `baseUrl` | `https://app.attestry.ai` | Override for self-hosted, EU residency, or local dev. Trailing slashes are stripped. |
154
+ | `baseUrl` | `https://attestry.ai` | Override for self-hosted, EU residency, or local dev. Trailing slashes are stripped. |
155
155
  | `timeoutMs` | `30_000` | Per-request timeout for JSON requests (not streams). Set `0` to disable. |
156
156
  | `fetch` | `globalThis.fetch` | Inject a custom fetch (testing, retries, observability). Must match the standard `fetch` signature. |
157
157
  | `retry` | `{maxRetries: 3, initialDelayMs: 1000, maxDelayMs: 30_000, honorRetryAfter: true}` | Automatic retry on 429. See "Automatic retry" section below. Set `{maxRetries: 0}` to disable. |
@@ -0,0 +1,57 @@
1
+ export declare const EDDSA_JCS_2022 = "eddsa-jcs-2022";
2
+ export declare const DATA_INTEGRITY_PROOF = "DataIntegrityProof";
3
+ export declare const ASSERTION_METHOD = "assertionMethod";
4
+ export interface DataIntegrityProof {
5
+ type: typeof DATA_INTEGRITY_PROOF;
6
+ cryptosuite: typeof EDDSA_JCS_2022;
7
+ created: string;
8
+ verificationMethod: string;
9
+ proofPurpose: string;
10
+ proofValue: string;
11
+ /** Mirrors the secured document's `@context` (per the cryptosuite). */
12
+ "@context"?: unknown;
13
+ }
14
+ export type JsonLdDocument = Record<string, unknown> & {
15
+ "@context": unknown;
16
+ };
17
+ export type SecuredDocument<T extends JsonLdDocument = JsonLdDocument> = T & {
18
+ proof: DataIntegrityProof;
19
+ };
20
+ export interface SignOptions {
21
+ /** Raw 32-byte Ed25519 secret key. */
22
+ privateKey: Uint8Array;
23
+ /** e.g. `https://attestry.ai/.well-known/keys#key-2026-05`. */
24
+ verificationMethod: string;
25
+ /** ISO-8601 `created`; injectable for deterministic tests. Defaults to now (seconds precision). */
26
+ created?: string;
27
+ proofPurpose?: string;
28
+ }
29
+ export interface VerifyResult {
30
+ verified: boolean;
31
+ reason?: string;
32
+ verificationMethod?: string;
33
+ }
34
+ /** Resolve a verificationMethod URL to its raw 32-byte Ed25519 public key. Return null/undefined ⇒ fail closed. */
35
+ export type PublicKeyResolver = (verificationMethod: string) => Uint8Array | null | undefined;
36
+ /** verifyData = H(JCS(proofConfig)) ‖ H(JCS(document)); proofConfig must already exclude proofValue, document must exclude proof. */
37
+ declare function createVerifyData(unsecuredDocument: JsonLdDocument, proofConfig: Record<string, unknown>): Uint8Array;
38
+ /**
39
+ * The `eddsa-jcs-2022` pre-signature hash: H(JCS(proofConfig)) ‖ H(JCS(document)).
40
+ * `proofConfig` must already exclude `proofValue`; `document` must exclude `proof`.
41
+ * Exposed so the conformance test can byte-compare against the reference cryptosuite.
42
+ */
43
+ export declare const eddsaJcsVerifyData: typeof createVerifyData;
44
+ /**
45
+ * Attach an `eddsa-jcs-2022` DataIntegrityProof to a JSON-LD document.
46
+ * Any pre-existing `proof` on the input is excluded from the signed bytes.
47
+ */
48
+ export declare function signDocument<T extends JsonLdDocument>(document: T, options: SignOptions): SecuredDocument<T>;
49
+ /**
50
+ * Verify an `eddsa-jcs-2022` secured document against a resolver-supplied public
51
+ * key. No DB, no network: the caller decides how the verificationMethod resolves
52
+ * (inline JWK, fetched controller doc, or the config key-registry). Fails CLOSED
53
+ * on every structural defect, unresolved key, or signature mismatch.
54
+ */
55
+ export declare function verifyDocument(securedDocument: unknown, resolvePublicKey: PublicKeyResolver): VerifyResult;
56
+ export {};
57
+ //# sourceMappingURL=data-integrity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-integrity.d.ts","sourceRoot":"","sources":["../../src/annex-iv-verify/data-integrity.ts"],"names":[],"mappings":"AAgCA,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAC/C,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AACzD,eAAO,MAAM,gBAAgB,oBAAoB,CAAC;AAElD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,oBAAoB,CAAC;IAClC,WAAW,EAAE,OAAO,cAAc,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC;AAC/E,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,IAAI,CAAC,GAAG;IAC3E,KAAK,EAAE,kBAAkB,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,sCAAsC;IACtC,UAAU,EAAE,UAAU,CAAC;IACvB,+DAA+D;IAC/D,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mGAAmG;IACnG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,mHAAmH;AACnH,MAAM,MAAM,iBAAiB,GAAG,CAC9B,kBAAkB,EAAE,MAAM,KACvB,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC;AAcnC,qIAAqI;AACrI,iBAAS,gBAAgB,CACvB,iBAAiB,EAAE,cAAc,EACjC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,UAAU,CAOZ;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,yBAAmB,CAAC;AA4BnD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,cAAc,EACnD,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,WAAW,GACnB,eAAe,CAAC,CAAC,CAAC,CAyBpB;AAID;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,eAAe,EAAE,OAAO,EACxB,gBAAgB,EAAE,iBAAiB,GAClC,YAAY,CA4Dd"}
@@ -0,0 +1,172 @@
1
+ // VERIFY-only faithful port of `src/lib/crypto/data-integrity.ts` — the kernel
2
+ // is the source of truth; the golden cross-vectors (`__tests__/golden-vectors.json`)
3
+ // break first on any divergence. Do NOT edit semantics independently.
4
+ //
5
+ // Copied VERBATIM, with the ONLY change being the relative-import rewrite to an
6
+ // EXPLICIT `.js` extension (the SDK is `module:"Node16"` — a bare relative
7
+ // specifier emits TS2835). Package imports (`canonicalize`) are unchanged. The
8
+ // sign-side (`signDocument`, `ed25519Sign`) is dead-but-private — only
9
+ // `verifyDocument` / `eddsaJcsVerifyData` / the types are verifier-reached.
10
+ /**
11
+ * W3C Verifiable Credential **Data Integrity** proofs — `eddsa-jcs-2022`.
12
+ *
13
+ * A conformant, dependency-light implementation of the `eddsa-jcs-2022`
14
+ * cryptosuite (W3C VC-DI-EdDSA v1.0). It is byte-compatible with
15
+ * `@digitalbazaar/eddsa-jcs-2022-cryptosuite` (pinned in the conformance test):
16
+ *
17
+ * verifyData = SHA-256( JCS(proofConfig without proofValue) )
18
+ * ‖ SHA-256( JCS(document without proof) )
19
+ * proofValue = "z" + base58btc( Ed25519.sign(verifyData) )
20
+ *
21
+ * where JCS = RFC-8785 (`canonicalize`, the same package + call the reference
22
+ * uses) and the proof's `@context` mirrors the document's (matching the
23
+ * reference's sign/verify behaviour).
24
+ *
25
+ * Pure + resolver-injected: it never reads a DB, a Vault, or env. Signing takes
26
+ * a raw private key; verification takes a public-key resolver. This is what lets
27
+ * `/verify` run **offline** — public key + credential in, valid/invalid out.
28
+ */
29
+ import canonicalize from "canonicalize";
30
+ import { ed25519Sign, ed25519Verify, sha256 } from "./ed25519.js";
31
+ import { encodeMultibaseBase58btc, decodeMultibaseBase58btc } from "./multibase.js";
32
+ export const EDDSA_JCS_2022 = "eddsa-jcs-2022";
33
+ export const DATA_INTEGRITY_PROOF = "DataIntegrityProof";
34
+ export const ASSERTION_METHOD = "assertionMethod";
35
+ // ─── Internals ───────────────────────────────────────────────────────────────
36
+ const textEncoder = new TextEncoder();
37
+ function jcsHash(value) {
38
+ const jcs = canonicalize(value);
39
+ if (typeof jcs !== "string") {
40
+ throw new Error("JCS canonicalization produced no output");
41
+ }
42
+ return sha256(textEncoder.encode(jcs));
43
+ }
44
+ /** verifyData = H(JCS(proofConfig)) ‖ H(JCS(document)); proofConfig must already exclude proofValue, document must exclude proof. */
45
+ function createVerifyData(unsecuredDocument, proofConfig) {
46
+ const proofHash = jcsHash(proofConfig);
47
+ const docHash = jcsHash(unsecuredDocument);
48
+ const out = new Uint8Array(proofHash.length + docHash.length);
49
+ out.set(proofHash, 0);
50
+ out.set(docHash, proofHash.length);
51
+ return out;
52
+ }
53
+ /**
54
+ * The `eddsa-jcs-2022` pre-signature hash: H(JCS(proofConfig)) ‖ H(JCS(document)).
55
+ * `proofConfig` must already exclude `proofValue`; `document` must exclude `proof`.
56
+ * Exposed so the conformance test can byte-compare against the reference cryptosuite.
57
+ */
58
+ export const eddsaJcsVerifyData = createVerifyData;
59
+ function toW3cDate(date) {
60
+ // VC `created` convention: second-precision UTC (drop milliseconds).
61
+ return date.toISOString().replace(/\.\d{1,}Z$/, "Z");
62
+ }
63
+ function isObject(value) {
64
+ return typeof value === "object" && value !== null && !Array.isArray(value);
65
+ }
66
+ function asContextArray(ctx) {
67
+ return Array.isArray(ctx) ? ctx : [ctx];
68
+ }
69
+ /** True iff `docCtx` begins with every entry of `proofCtx`, in order (the cryptosuite's safety check). */
70
+ function contextStartsWith(docCtx, proofCtx) {
71
+ const d = asContextArray(docCtx);
72
+ const p = asContextArray(proofCtx);
73
+ if (p.length > d.length)
74
+ return false;
75
+ for (let i = 0; i < p.length; i++) {
76
+ if (JSON.stringify(p[i]) !== JSON.stringify(d[i]))
77
+ return false;
78
+ }
79
+ return true;
80
+ }
81
+ // ─── Sign ──────────────────────────────────────────────────────────────────--
82
+ /**
83
+ * Attach an `eddsa-jcs-2022` DataIntegrityProof to a JSON-LD document.
84
+ * Any pre-existing `proof` on the input is excluded from the signed bytes.
85
+ */
86
+ export function signDocument(document, options) {
87
+ if (document["@context"] === undefined) {
88
+ throw new Error("Document must have an @context to sign");
89
+ }
90
+ // Document without any existing proof — these are the bytes we hash.
91
+ const { proof: _existingProof, ...unsecured } = document;
92
+ const proofConfig = {
93
+ "@context": unsecured["@context"],
94
+ type: DATA_INTEGRITY_PROOF,
95
+ cryptosuite: EDDSA_JCS_2022,
96
+ created: options.created ?? toW3cDate(new Date()),
97
+ verificationMethod: options.verificationMethod,
98
+ proofPurpose: options.proofPurpose ?? ASSERTION_METHOD,
99
+ };
100
+ const verifyData = createVerifyData(unsecured, proofConfig);
101
+ const signature = ed25519Sign(verifyData, options.privateKey);
102
+ const proof = {
103
+ ...proofConfig,
104
+ proofValue: encodeMultibaseBase58btc(signature),
105
+ };
106
+ return { ...unsecured, proof };
107
+ }
108
+ // ─── Verify (DB-free) ─────────────────────────────────────────────────────────
109
+ /**
110
+ * Verify an `eddsa-jcs-2022` secured document against a resolver-supplied public
111
+ * key. No DB, no network: the caller decides how the verificationMethod resolves
112
+ * (inline JWK, fetched controller doc, or the config key-registry). Fails CLOSED
113
+ * on every structural defect, unresolved key, or signature mismatch.
114
+ */
115
+ export function verifyDocument(securedDocument, resolvePublicKey) {
116
+ if (!isObject(securedDocument)) {
117
+ return { verified: false, reason: "Secured document is not an object" };
118
+ }
119
+ const proof = securedDocument.proof;
120
+ if (!isObject(proof)) {
121
+ return { verified: false, reason: "Missing or malformed proof" };
122
+ }
123
+ if (proof.type !== DATA_INTEGRITY_PROOF) {
124
+ return { verified: false, reason: `Unsupported proof type: ${String(proof.type)}` };
125
+ }
126
+ if (proof.cryptosuite !== EDDSA_JCS_2022) {
127
+ return { verified: false, reason: `Unsupported cryptosuite: ${String(proof.cryptosuite)}` };
128
+ }
129
+ if (proof.proofPurpose !== ASSERTION_METHOD) {
130
+ return { verified: false, reason: `Unsupported proofPurpose: ${String(proof.proofPurpose)}` };
131
+ }
132
+ if (typeof proof.verificationMethod !== "string") {
133
+ return { verified: false, reason: "Missing verificationMethod" };
134
+ }
135
+ if (typeof proof.proofValue !== "string" || proof.proofValue.length > 120) {
136
+ // A valid Ed25519 proofValue is ~89 chars; bound it before the O(n²) base58
137
+ // decode so an oversized string can't burn CPU (DoS) on the public route.
138
+ return { verified: false, reason: "Missing or oversized proofValue", verificationMethod: proof.verificationMethod };
139
+ }
140
+ const verificationMethod = proof.verificationMethod;
141
+ const publicKey = resolvePublicKey(verificationMethod);
142
+ if (!publicKey) {
143
+ return { verified: false, reason: `Unresolved verificationMethod: ${verificationMethod}`, verificationMethod };
144
+ }
145
+ let signature;
146
+ try {
147
+ signature = decodeMultibaseBase58btc(proof.proofValue);
148
+ }
149
+ catch {
150
+ return { verified: false, reason: "Invalid proofValue encoding", verificationMethod };
151
+ }
152
+ const { proof: _p, ...unsecured } = securedDocument;
153
+ const { proofValue: _pv, ...proofConfig } = proof;
154
+ // Mirror the reference: a proof.@context must be a prefix of the document's,
155
+ // and the document is hashed under the proof's @context.
156
+ if (proofConfig["@context"] !== undefined) {
157
+ if (!contextStartsWith(unsecured["@context"], proofConfig["@context"])) {
158
+ return {
159
+ verified: false,
160
+ reason: "Document @context does not start with proof @context",
161
+ verificationMethod,
162
+ };
163
+ }
164
+ unsecured["@context"] = proofConfig["@context"];
165
+ }
166
+ const verifyData = createVerifyData(unsecured, proofConfig);
167
+ const ok = ed25519Verify(signature, verifyData, publicKey);
168
+ return ok
169
+ ? { verified: true, verificationMethod }
170
+ : { verified: false, reason: "Signature verification failed", verificationMethod };
171
+ }
172
+ //# sourceMappingURL=data-integrity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-integrity.js","sourceRoot":"","sources":["../../src/annex-iv-verify/data-integrity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export declare const ED25519_PUBLIC_KEY_LENGTH = 32;
2
+ export declare const ED25519_SECRET_KEY_LENGTH = 32;
3
+ export declare const ED25519_SIGNATURE_LENGTH = 64;
4
+ /** Generate a fresh 32-byte Ed25519 secret key (CSPRNG). */
5
+ export declare function generateEd25519SecretKey(): Uint8Array;
6
+ /** Derive the 32-byte public key from a 32-byte secret key. */
7
+ export declare function ed25519GetPublicKey(secretKey: Uint8Array): Uint8Array;
8
+ /** Deterministically sign `message`, returning the 64-byte signature. */
9
+ export declare function ed25519Sign(message: Uint8Array, secretKey: Uint8Array): Uint8Array;
10
+ /**
11
+ * Verify a 64-byte Ed25519 signature over `message` against `publicKey`.
12
+ *
13
+ * Returns a boolean and NEVER throws: noble raises on malformed inputs
14
+ * (wrong-length signature/key, non-canonical encodings, …). For a verifier,
15
+ * every such failure is a plain "invalid" — surfacing it as an exception would
16
+ * be a fail-OPEN footgun, so we trap it and return false.
17
+ */
18
+ export declare function ed25519Verify(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): boolean;
19
+ /** SHA-256 over `data` (used by the eddsa-jcs-2022 hashing step + status list). */
20
+ export declare function sha256(data: Uint8Array): Uint8Array;
21
+ //# sourceMappingURL=ed25519.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ed25519.d.ts","sourceRoot":"","sources":["../../src/annex-iv-verify/ed25519.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAI3C,4DAA4D;AAC5D,wBAAgB,wBAAwB,IAAI,UAAU,CAErD;AAED,+DAA+D;AAC/D,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,UAAU,GAAG,UAAU,CAErE;AAID,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,UAAU,CAElF;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,UAAU,EACrB,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,UAAU,GACpB,OAAO,CAMT;AAID,mFAAmF;AACnF,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAEnD"}
@@ -0,0 +1,67 @@
1
+ // VERIFY-only faithful port of `src/lib/crypto/ed25519.ts` — the kernel is the
2
+ // source of truth; the golden cross-vectors (`__tests__/golden-vectors.json`)
3
+ // break first on any divergence. Do NOT edit semantics independently.
4
+ //
5
+ // Copied VERBATIM (the sign-side `ed25519Sign` / `generateEd25519SecretKey` /
6
+ // `ed25519GetPublicKey` carried here are dead-but-private — the only verifier-
7
+ // reachable exports are `ed25519Verify` + `sha256`; tree-shaking drops the rest).
8
+ // Package imports (`@noble/*`) are unchanged; there are no `@/lib` imports to
9
+ // rewrite under the SDK's `module:"Node16"` resolution.
10
+ /**
11
+ * Ed25519 primitives — a thin, portable wrapper over `@noble/ed25519` v3.
12
+ *
13
+ * `@noble/ed25519` v3 ships with its SHA-512 hash slot UNSET; we wire it once
14
+ * here (synchronously, from `@noble/hashes`) so the sync sign/verify/derive API
15
+ * works in every runtime — Node server routes, tests, and a future standalone
16
+ * verifier — with zero per-call setup.
17
+ *
18
+ * This module is deliberately free of any DB / Vault / env dependency. It is
19
+ * the cryptographic floor the DB-free offline verifier and the JWKS / controller
20
+ * routes stand on (W2.5a). Asymmetric, public-key verifiable — no shared secret.
21
+ */
22
+ import * as ed from "@noble/ed25519";
23
+ import { sha512, sha256 as nobleSha256 } from "@noble/hashes/sha2.js";
24
+ // ─── One-time hash wiring (required by @noble/ed25519 v3) ────────────────────
25
+ // Populating the sha512 slot enables the synchronous API. Assigning a property
26
+ // on the (mutable) `hashes` object is idempotent; importing this module anywhere
27
+ // in the crypto stack guarantees the primitives are usable.
28
+ ed.hashes.sha512 = sha512;
29
+ export const ED25519_PUBLIC_KEY_LENGTH = 32;
30
+ export const ED25519_SECRET_KEY_LENGTH = 32;
31
+ export const ED25519_SIGNATURE_LENGTH = 64;
32
+ // ─── Key generation / derivation ─────────────────────────────────────────────
33
+ /** Generate a fresh 32-byte Ed25519 secret key (CSPRNG). */
34
+ export function generateEd25519SecretKey() {
35
+ return ed.utils.randomSecretKey();
36
+ }
37
+ /** Derive the 32-byte public key from a 32-byte secret key. */
38
+ export function ed25519GetPublicKey(secretKey) {
39
+ return ed.getPublicKey(secretKey);
40
+ }
41
+ // ─── Sign / verify ───────────────────────────────────────────────────────────
42
+ /** Deterministically sign `message`, returning the 64-byte signature. */
43
+ export function ed25519Sign(message, secretKey) {
44
+ return ed.sign(message, secretKey);
45
+ }
46
+ /**
47
+ * Verify a 64-byte Ed25519 signature over `message` against `publicKey`.
48
+ *
49
+ * Returns a boolean and NEVER throws: noble raises on malformed inputs
50
+ * (wrong-length signature/key, non-canonical encodings, …). For a verifier,
51
+ * every such failure is a plain "invalid" — surfacing it as an exception would
52
+ * be a fail-OPEN footgun, so we trap it and return false.
53
+ */
54
+ export function ed25519Verify(signature, message, publicKey) {
55
+ try {
56
+ return ed.verify(signature, message, publicKey);
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ // ─── Hashing ───────────────────────────────────────────────────────────────--
63
+ /** SHA-256 over `data` (used by the eddsa-jcs-2022 hashing step + status list). */
64
+ export function sha256(data) {
65
+ return nobleSha256(data);
66
+ }
67
+ //# sourceMappingURL=ed25519.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ed25519.js","sourceRoot":"","sources":["../../src/annex-iv-verify/ed25519.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,8EAA8E;AAC9E,sEAAsE;AACtE,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,kFAAkF;AAClF,8EAA8E;AAC9E,wDAAwD;AACxD;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEtE,gFAAgF;AAChF,+EAA+E;AAC/E,iFAAiF;AACjF,4DAA4D;AAC5D,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;AAE1B,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAC5C,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAC5C,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAE3C,gFAAgF;AAEhF,4DAA4D;AAC5D,MAAM,UAAU,wBAAwB;IACtC,OAAO,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC;AACpC,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,mBAAmB,CAAC,SAAqB;IACvD,OAAO,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;AACpC,CAAC;AAED,gFAAgF;AAEhF,yEAAyE;AACzE,MAAM,UAAU,WAAW,CAAC,OAAmB,EAAE,SAAqB;IACpE,OAAO,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,SAAqB,EACrB,OAAmB,EACnB,SAAqB;IAErB,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,mFAAmF;AACnF,MAAM,UAAU,MAAM,CAAC,IAAgB;IACrC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { verifyAnnexIvBindOffline, type VerifyAnnexIvBindOfflineInput, type VerifyAnnexIvBindResult, type AnnexIvBindPayload, } from "./verify.js";
2
+ export { makeJwksResolver, type Ed25519PublicJwk, } from "./resolver.js";
3
+ export type { PublicKeyResolver } from "./data-integrity.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/annex-iv-verify/index.ts"],"names":[],"mappings":"AASA,OAAO,EACL,wBAAwB,EACxB,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,11 @@
1
+ // ─── The bundled OFFLINE Annex IV bind verifier (work-item C) ───────────────
2
+ //
3
+ // A DB-free, network-free, pure verifier — a faithful VERIFY-only port of the
4
+ // kernel's `verifyAnnexIvBind` (the kernel is the source of truth; the golden
5
+ // cross-vectors break first on any divergence). The caller supplies key material
6
+ // (a `resolvePublicKey` or a `jwks`); the SDK never reads a DB or the network.
7
+ //
8
+ // Barrel imports take the explicit `.js` extension (the SDK is `module:"Node16"`).
9
+ export { verifyAnnexIvBindOffline, } from "./verify.js";
10
+ export { makeJwksResolver, } from "./resolver.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/annex-iv-verify/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,iFAAiF;AACjF,+EAA+E;AAC/E,EAAE;AACF,mFAAmF;AAEnF,OAAO,EACL,wBAAwB,GAIzB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,GAEjB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Ed25519 JWK (RFC 8037 / OKP) helpers + base64url codec.
3
+ *
4
+ * The JWK representation is the dual-use publication surface advertised at
5
+ * `/.well-known/keys` (consumed by the P3 Consumer API + attestry-atlassian),
6
+ * alongside the Multikey representation the off-the-shelf eddsa-jcs-2022 verifier
7
+ * resolves through the controller document. Same key, two encodings.
8
+ */
9
+ /** Encode bytes as unpadded base64url. */
10
+ export declare function bytesToBase64url(bytes: Uint8Array): string;
11
+ /** Decode unpadded (or padded) base64url back to bytes. Fails closed on garbage. */
12
+ export declare function base64urlToBytes(value: string): Uint8Array;
13
+ export interface Ed25519PublicJwk {
14
+ kty: "OKP";
15
+ crv: "Ed25519";
16
+ /** base64url of the raw 32-byte public key. */
17
+ x: string;
18
+ /** Key id — unique, never reused, matches the credential's verificationMethod fragment. */
19
+ kid: string;
20
+ use?: "sig";
21
+ alg?: "EdDSA";
22
+ }
23
+ /** Build a public Ed25519 JWK from a raw 32-byte public key + kid. */
24
+ export declare function ed25519PublicKeyToJwk(publicKey: Uint8Array, kid: string): Ed25519PublicJwk;
25
+ /** Extract the raw 32-byte public key from an Ed25519 OKP JWK. Fails closed. */
26
+ export declare function jwkToEd25519PublicKey(jwk: Partial<Ed25519PublicJwk> | null | undefined): Uint8Array;
27
+ //# sourceMappingURL=jwk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwk.d.ts","sourceRoot":"","sources":["../../src/annex-iv-verify/jwk.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AAIH,0CAA0C;AAC1C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAE1D;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAK1D;AAID,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,KAAK,CAAC;IACX,GAAG,EAAE,SAAS,CAAC;IACf,+CAA+C;IAC/C,CAAC,EAAE,MAAM,CAAC;IACV,2FAA2F;IAC3F,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAY1F;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,CAanG"}
@@ -0,0 +1,57 @@
1
+ // VERIFY-only faithful port of `src/lib/crypto/jwk.ts` — the kernel is the
2
+ // source of truth; the golden cross-vectors (`__tests__/golden-vectors.json`)
3
+ // break first on any divergence. Do NOT edit semantics independently.
4
+ //
5
+ // Copied VERBATIM. Uses Node `Buffer` (the SDK is a Node package,
6
+ // engines.node>=18) — REQUIRED for byte-identity; do NOT web-ify. No `@/lib`
7
+ // imports to rewrite.
8
+ /**
9
+ * Ed25519 JWK (RFC 8037 / OKP) helpers + base64url codec.
10
+ *
11
+ * The JWK representation is the dual-use publication surface advertised at
12
+ * `/.well-known/keys` (consumed by the P3 Consumer API + attestry-atlassian),
13
+ * alongside the Multikey representation the off-the-shelf eddsa-jcs-2022 verifier
14
+ * resolves through the controller document. Same key, two encodings.
15
+ */
16
+ // ─── base64url (unpadded) ────────────────────────────────────────────────────
17
+ /** Encode bytes as unpadded base64url. */
18
+ export function bytesToBase64url(bytes) {
19
+ return Buffer.from(bytes).toString("base64url");
20
+ }
21
+ /** Decode unpadded (or padded) base64url back to bytes. Fails closed on garbage. */
22
+ export function base64urlToBytes(value) {
23
+ if (!/^[A-Za-z0-9_-]*={0,2}$/.test(value)) {
24
+ throw new Error("Invalid base64url string");
25
+ }
26
+ return new Uint8Array(Buffer.from(value, "base64url"));
27
+ }
28
+ /** Build a public Ed25519 JWK from a raw 32-byte public key + kid. */
29
+ export function ed25519PublicKeyToJwk(publicKey, kid) {
30
+ if (publicKey.length !== 32) {
31
+ throw new Error(`Ed25519 public key must be 32 bytes, got ${publicKey.length}`);
32
+ }
33
+ return {
34
+ kty: "OKP",
35
+ crv: "Ed25519",
36
+ x: bytesToBase64url(publicKey),
37
+ kid,
38
+ use: "sig",
39
+ alg: "EdDSA",
40
+ };
41
+ }
42
+ /** Extract the raw 32-byte public key from an Ed25519 OKP JWK. Fails closed. */
43
+ export function jwkToEd25519PublicKey(jwk) {
44
+ if (!jwk || jwk.kty !== "OKP" || jwk.crv !== "Ed25519" || typeof jwk.x !== "string") {
45
+ throw new Error("Not an Ed25519 OKP JWK");
46
+ }
47
+ // A 32-byte key is ~43 base64url chars; bound before decoding caller-supplied `x`.
48
+ if (jwk.x.length > 100) {
49
+ throw new Error("Ed25519 JWK 'x' is too long");
50
+ }
51
+ const key = base64urlToBytes(jwk.x);
52
+ if (key.length !== 32) {
53
+ throw new Error(`Decoded Ed25519 public key must be 32 bytes, got ${key.length}`);
54
+ }
55
+ return key;
56
+ }
57
+ //# sourceMappingURL=jwk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwk.js","sourceRoot":"","sources":["../../src/annex-iv-verify/jwk.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,8EAA8E;AAC9E,sEAAsE;AACtE,EAAE;AACF,kEAAkE;AAClE,6EAA6E;AAC7E,sBAAsB;AACtB;;;;;;;GAOG;AAEH,gFAAgF;AAEhF,0CAA0C;AAC1C,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAClD,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC;AACzD,CAAC;AAeD,sEAAsE;AACtE,MAAM,UAAU,qBAAqB,CAAC,SAAqB,EAAE,GAAW;IACtE,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,4CAA4C,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,OAAO;QACL,GAAG,EAAE,KAAK;QACV,GAAG,EAAE,SAAS;QACd,CAAC,EAAE,gBAAgB,CAAC,SAAS,CAAC;QAC9B,GAAG;QACH,GAAG,EAAE,KAAK;QACV,GAAG,EAAE,OAAO;KACb,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,qBAAqB,CAAC,GAAiD;IACrF,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QACpF,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,mFAAmF;IACnF,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oDAAoD,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Multibase / multicodec encodings used by the W3C VC Data Integrity stack.
3
+ *
4
+ * Two distinct encodings live here, both base58btc with the multibase `z`
5
+ * prefix but with different payloads — keeping them straight matters:
6
+ *
7
+ * - **proofValue** (eddsa-jcs-2022): `z` + base58btc(rawSignatureBytes). No
8
+ * multicodec prefix. This is exactly what `@digitalbazaar/data-integrity`
9
+ * emits/consumes.
10
+ * - **publicKeyMultibase** (Multikey): `z` + base58btc(0xed01 ‖ rawPublicKey).
11
+ * The `0xed01` multicodec header is what makes it render as `z6Mk…` and is
12
+ * what `@digitalbazaar/ed25519-multikey` requires to resolve the key.
13
+ *
14
+ * Implemented dependency-free (no Buffer, no external base58 pkg) so the same
15
+ * code can power a standalone offline verifier later. Cross-checked against
16
+ * `base58-universal` + `@digitalbazaar/ed25519-multikey` in the conformance test.
17
+ */
18
+ /** Encode raw bytes as base58btc (Bitcoin alphabet), preserving leading zeros. */
19
+ export declare function base58btcEncode(bytes: Uint8Array): string;
20
+ /** Decode a base58btc string back to raw bytes, preserving leading-`1` zeros. */
21
+ export declare function base58btcDecode(str: string): Uint8Array;
22
+ export declare const MULTIBASE_BASE58BTC_PREFIX = "z";
23
+ /** `z` + base58btc(bytes) — multibase base58btc, the proofValue encoding. */
24
+ export declare function encodeMultibaseBase58btc(bytes: Uint8Array): string;
25
+ /** Decode a multibase base58btc (`z`-prefixed) string. Fails closed otherwise. */
26
+ export declare function decodeMultibaseBase58btc(value: string): Uint8Array;
27
+ /** Encode a raw 32-byte Ed25519 public key as `z6Mk…` publicKeyMultibase. */
28
+ export declare function encodeEd25519PublicKeyMultibase(publicKey: Uint8Array): string;
29
+ /** Decode a `z6Mk…` publicKeyMultibase back to the raw 32-byte public key. */
30
+ export declare function decodeEd25519PublicKeyMultibase(value: string): Uint8Array;
31
+ //# sourceMappingURL=multibase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multibase.d.ts","sourceRoot":"","sources":["../../src/annex-iv-verify/multibase.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;GAgBG;AAcH,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CA4BzD;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAgCvD;AAID,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,6EAA6E;AAC7E,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAElE;AAED,kFAAkF;AAClF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAOlE;AAOD,6EAA6E;AAC7E,wBAAgB,+BAA+B,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAQ7E;AAED,8EAA8E;AAC9E,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAUzE"}