@agentcontextdistributionprotocol/acdp 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +243 -8
- package/package.json +5 -5
package/index.d.ts
CHANGED
|
@@ -19,6 +19,25 @@ export interface ResolvedDidKey {
|
|
|
19
19
|
*/
|
|
20
20
|
publicKeyB64: string
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* [`ResolvedDidKey`] plus the RFC-ACDP-0010 §9 lifecycle signal for
|
|
24
|
+
* registry receipt keys.
|
|
25
|
+
*/
|
|
26
|
+
export interface ResolvedReceiptKey {
|
|
27
|
+
/** Verification-method id (full DID URL with `#fragment`). */
|
|
28
|
+
keyId: string
|
|
29
|
+
/** `ed25519` or `ecdsa-p256`. */
|
|
30
|
+
algorithm: string
|
|
31
|
+
/** Standard base64 of the raw key bytes (see [`ResolvedDidKey`]). */
|
|
32
|
+
publicKeyB64: string
|
|
33
|
+
/**
|
|
34
|
+
* `true` when the key is retained in `verificationMethod` but no
|
|
35
|
+
* longer referenced by `assertionMethod` — a retired receipt key.
|
|
36
|
+
* Verify the receipt, but report it with the distinguishable
|
|
37
|
+
* *historically authorized* status (RFC-ACDP-0010 §9).
|
|
38
|
+
*/
|
|
39
|
+
historical: boolean
|
|
40
|
+
}
|
|
22
41
|
/**
|
|
23
42
|
* Options for `buildPublishRequest`. Field names map directly to the
|
|
24
43
|
* PublishRequest wire schema (camelCase on the JS side).
|
|
@@ -80,6 +99,25 @@ export interface PublishOpts {
|
|
|
80
99
|
* only — rejected on first-version publishes.
|
|
81
100
|
*/
|
|
82
101
|
expectedLineageId?: string
|
|
102
|
+
/**
|
|
103
|
+
* Explicit `acdp_version` string for the emitted request.
|
|
104
|
+
*
|
|
105
|
+
* **SDK default (since 0.2): `acdp_version` is emitted explicitly,
|
|
106
|
+
* set to the library's current ACDP protocol version
|
|
107
|
+
* (`acdp::ACDP_VERSION` — `"0.2.0"` as of this release).** Per
|
|
108
|
+
* RFC-ACDP-0001 §6 consumers treat an absent field as `"0.1.0"`,
|
|
109
|
+
* but the omitted and explicit forms are *different JCS preimages*
|
|
110
|
+
* and therefore hash differently — pick one form per lineage and
|
|
111
|
+
* never switch mid-lineage.
|
|
112
|
+
*/
|
|
113
|
+
acdpVersion?: string
|
|
114
|
+
/**
|
|
115
|
+
* When `true`, omit `acdp_version` entirely (the 0.1.x SDK default
|
|
116
|
+
* form). Use this only to reproduce hashes signed under the
|
|
117
|
+
* omitted form (e.g. the sig-001 golden vector); takes precedence
|
|
118
|
+
* over `acdpVersion`.
|
|
119
|
+
*/
|
|
120
|
+
omitAcdpVersion?: boolean
|
|
83
121
|
}
|
|
84
122
|
/**
|
|
85
123
|
* Options for `buildSupersedeRequest`. Any field omitted is carried
|
|
@@ -103,6 +141,18 @@ export interface SupersedeOpts {
|
|
|
103
141
|
dataPeriod?: string
|
|
104
142
|
/** Self-verifying `lin:sha256:<hex>` lineage id (v2+). */
|
|
105
143
|
expectedLineageId?: string
|
|
144
|
+
/**
|
|
145
|
+
* Explicit `acdp_version` string. **By default (since 0.2) the
|
|
146
|
+
* library's current ACDP protocol version (`acdp::ACDP_VERSION` —
|
|
147
|
+
* `"0.2.0"` as of this release) is emitted explicitly** — see
|
|
148
|
+
* `PublishOpts.acdpVersion`. Do not switch the form mid-lineage.
|
|
149
|
+
*/
|
|
150
|
+
acdpVersion?: string
|
|
151
|
+
/**
|
|
152
|
+
* When `true`, omit `acdp_version` entirely (the 0.1.x form);
|
|
153
|
+
* takes precedence over `acdpVersion`.
|
|
154
|
+
*/
|
|
155
|
+
omitAcdpVersion?: boolean
|
|
106
156
|
}
|
|
107
157
|
/** Stateless did:web string helpers. All methods are static. */
|
|
108
158
|
export declare class AcdpDid {
|
|
@@ -162,6 +212,26 @@ export declare class AcdpDidDocument {
|
|
|
162
212
|
* is the full DID URL from the signature's `key_id`.
|
|
163
213
|
*/
|
|
164
214
|
keyForAlgorithm(requestedKeyId: string, requestedAlg: string): ResolvedDidKey
|
|
215
|
+
/**
|
|
216
|
+
* Resolve a **registry receipt** signing key, applying the
|
|
217
|
+
* RFC-ACDP-0010 §9 lifecycle instead of the `assertionMethod` gate:
|
|
218
|
+
* retired receipt keys MUST remain in `verificationMethod`
|
|
219
|
+
* indefinitely and MUST still verify historical receipts even after
|
|
220
|
+
* rotation removes them from `assertionMethod`. A key absent from
|
|
221
|
+
* `verificationMethod` entirely still fails
|
|
222
|
+
* (`.code === "key_not_found"`) — full removal is the registry's
|
|
223
|
+
* compromise-revocation signal.
|
|
224
|
+
*
|
|
225
|
+
* `historical` on the result is `true` when the key is no longer in
|
|
226
|
+
* `assertionMethod`: verify the receipt, but report it with the
|
|
227
|
+
* distinguishable *historically authorized* status. The
|
|
228
|
+
* algorithm-downgrade defense (RFC-ACDP-0008 §3.9) and key decoding
|
|
229
|
+
* are enforced identically to `keyForAlgorithm`.
|
|
230
|
+
*
|
|
231
|
+
* Use `keyForAlgorithm` for producer keys and auth challenges —
|
|
232
|
+
* publish-time authorization still requires `assertionMethod`.
|
|
233
|
+
*/
|
|
234
|
+
receiptKeyForAlgorithm(requestedKeyId: string, requestedAlg: string): ResolvedReceiptKey
|
|
165
235
|
}
|
|
166
236
|
/** RFC 8785 canonicalization utilities. All methods are static. */
|
|
167
237
|
export declare class AcdpCanonicalizer {
|
|
@@ -189,7 +259,8 @@ export declare class AcdpCanonicalizer {
|
|
|
189
259
|
static contentHash(jsonStr: string): string
|
|
190
260
|
}
|
|
191
261
|
/**
|
|
192
|
-
* An ACDP producer: an Ed25519 signing key and its
|
|
262
|
+
* An ACDP producer: an Ed25519 signing key and its DID identity
|
|
263
|
+
* (`did:web`, or `did:key` via the `*DidKey` factories — ACDP 0.2).
|
|
193
264
|
*
|
|
194
265
|
* All methods return wire-ready JSON strings the caller sends via its
|
|
195
266
|
* own HTTP client. No HTTP calls are made inside this class.
|
|
@@ -197,11 +268,38 @@ export declare class AcdpCanonicalizer {
|
|
|
197
268
|
export declare class AcdpProducer {
|
|
198
269
|
/** Generate a producer with a fresh random Ed25519 key (OsRng). */
|
|
199
270
|
static generate(agentDid: string, keyId: string): AcdpProducer
|
|
271
|
+
/**
|
|
272
|
+
* Generate a producer whose identity **is** its fresh Ed25519 key
|
|
273
|
+
* (`did:key`, ACDP 0.2). The `agentDid` and `keyId` are derived
|
|
274
|
+
* from the public key — no domain, no DID-document hosting.
|
|
275
|
+
* Consumers verify did:key contexts offline
|
|
276
|
+
* (`AcdpVerifier.verifyBodyOffline`), with no dependency on the
|
|
277
|
+
* producer's infrastructure remaining online.
|
|
278
|
+
*
|
|
279
|
+
* Tradeoff: did:key cannot rotate — a new key is a new identity,
|
|
280
|
+
* and `supersedes` requires the same `agent_id`, so lineage
|
|
281
|
+
* continuity ends with the key. Use `did:web` for long-lived
|
|
282
|
+
* organizational anchors; use did:key for ephemeral or
|
|
283
|
+
* archival-critical producers.
|
|
284
|
+
*/
|
|
285
|
+
static generateDidKey(): AcdpProducer
|
|
286
|
+
/**
|
|
287
|
+
* Construct a `did:key` producer from a 32-byte Ed25519 seed.
|
|
288
|
+
*
|
|
289
|
+
* Deterministic — the same seed always derives the same
|
|
290
|
+
* `agentDid` / `keyId`. The seed is the private key — protect it
|
|
291
|
+
* as such. See [`AcdpProducer::generate_did_key`] for the did:key
|
|
292
|
+
* rotation tradeoff.
|
|
293
|
+
*/
|
|
294
|
+
static fromSeedDidKey(seed: Buffer): AcdpProducer
|
|
200
295
|
/** Construct from a 32-byte Ed25519 seed (deterministic). */
|
|
201
296
|
static fromSeed(seed: Buffer, agentDid: string, keyId: string): AcdpProducer
|
|
202
|
-
/** The producer's DID (`did:web:…`). */
|
|
297
|
+
/** The producer's DID (`did:web:…` or `did:key:…`). */
|
|
203
298
|
get agentDid(): string
|
|
204
|
-
/**
|
|
299
|
+
/**
|
|
300
|
+
* The producer's signing-key DID URL (`did:web:…#key-1`, or the
|
|
301
|
+
* `did:key:z…#z…` self-fragment form).
|
|
302
|
+
*/
|
|
205
303
|
get keyId(): string
|
|
206
304
|
/**
|
|
207
305
|
* Raw Ed25519 public key as standard base64 (44 chars with padding).
|
|
@@ -216,12 +314,25 @@ export declare class AcdpProducer {
|
|
|
216
314
|
/**
|
|
217
315
|
* Build and sign a first-version PublishRequest. Returns the
|
|
218
316
|
* wire JSON string.
|
|
317
|
+
*
|
|
318
|
+
* **By default (since 0.2) `acdp_version` is emitted explicitly,
|
|
319
|
+
* set to the library's current ACDP protocol version
|
|
320
|
+
* (`acdp::ACDP_VERSION` — `"0.2.0"` as of this release).** Pass
|
|
321
|
+
* `omitAcdpVersion: true` to reproduce the 0.1.x omitted form (a
|
|
322
|
+
* distinct JCS preimage, so a distinct `content_hash`), or
|
|
323
|
+
* `acdpVersion` to pin another string.
|
|
219
324
|
*/
|
|
220
325
|
buildPublishRequest(opts: PublishOpts): string
|
|
221
326
|
/**
|
|
222
327
|
* Build and sign a supersession PublishRequest from a previous
|
|
223
328
|
* version's `Body` JSON. Version is propagated automatically
|
|
224
329
|
* (`previous.version + 1`) and `lineage_id` is carried forward.
|
|
330
|
+
*
|
|
331
|
+
* **By default (since 0.2) `acdp_version` is emitted explicitly,
|
|
332
|
+
* set to the library's current ACDP protocol version
|
|
333
|
+
* (`acdp::ACDP_VERSION` — `"0.2.0"` as of this release)** — see
|
|
334
|
+
* `buildPublishRequest`. Do not switch between the omitted and
|
|
335
|
+
* explicit forms mid-lineage.
|
|
225
336
|
*/
|
|
226
337
|
buildSupersedeRequest(previousBodyJson: string, opts: SupersedeOpts): string
|
|
227
338
|
/**
|
|
@@ -247,14 +358,30 @@ export declare class AcdpProducer {
|
|
|
247
358
|
export declare class AcdpP256Producer {
|
|
248
359
|
/** Generate a producer with a fresh random P-256 key (OsRng). */
|
|
249
360
|
static generate(agentDid: string, keyId: string): AcdpP256Producer
|
|
361
|
+
/**
|
|
362
|
+
* Generate a producer whose identity **is** its fresh P-256 key
|
|
363
|
+
* (`did:key`, ACDP 0.2). See [`AcdpProducer::generate_did_key`]
|
|
364
|
+
* for the did:key rotation tradeoff.
|
|
365
|
+
*/
|
|
366
|
+
static generateDidKey(): AcdpP256Producer
|
|
367
|
+
/**
|
|
368
|
+
* Construct a `did:key` producer from a 32-byte P-256 private
|
|
369
|
+
* scalar (big-endian). Deterministic — the same seed always
|
|
370
|
+
* derives the same `agentDid` / `keyId`. Throws if the bytes are
|
|
371
|
+
* not exactly 32 or are not a valid scalar.
|
|
372
|
+
*/
|
|
373
|
+
static fromSeedDidKey(seed: Buffer): AcdpP256Producer
|
|
250
374
|
/**
|
|
251
375
|
* Construct from a 32-byte P-256 private scalar (deterministic).
|
|
252
376
|
* Throws if the bytes are not exactly 32 or are not a valid scalar.
|
|
253
377
|
*/
|
|
254
378
|
static fromSeed(seed: Buffer, agentDid: string, keyId: string): AcdpP256Producer
|
|
255
|
-
/** The producer's DID (`did:web:…`). */
|
|
379
|
+
/** The producer's DID (`did:web:…` or `did:key:…`). */
|
|
256
380
|
get agentDid(): string
|
|
257
|
-
/**
|
|
381
|
+
/**
|
|
382
|
+
* The producer's signing-key DID URL (`did:web:…#key-1`, or the
|
|
383
|
+
* `did:key:z…#z…` self-fragment form).
|
|
384
|
+
*/
|
|
258
385
|
get keyId(): string
|
|
259
386
|
/**
|
|
260
387
|
* SEC1-uncompressed public key (`0x04 || x || y`, 65 bytes) as
|
|
@@ -289,14 +416,19 @@ export declare class AcdpP256Producer {
|
|
|
289
416
|
seedBytes(): Buffer
|
|
290
417
|
/**
|
|
291
418
|
* Build and sign a first-version PublishRequest. Returns the wire
|
|
292
|
-
* JSON string. Same surface as [`AcdpProducer::build_publish_request`]
|
|
293
|
-
*
|
|
419
|
+
* JSON string. Same surface as [`AcdpProducer::build_publish_request`]
|
|
420
|
+
* — including the explicit `acdp_version` default (the library's
|
|
421
|
+
* current ACDP protocol version, `"0.2.0"` as of this release) and
|
|
422
|
+
* the `acdpVersion` / `omitAcdpVersion` controls; only the
|
|
423
|
+
* signature algorithm differs.
|
|
294
424
|
*/
|
|
295
425
|
buildPublishRequest(opts: PublishOpts): string
|
|
296
426
|
/**
|
|
297
427
|
* Build and sign a supersession PublishRequest from a previous
|
|
298
428
|
* version's `Body` JSON. Same semantics as
|
|
299
|
-
* [`AcdpProducer::build_supersede_request`]
|
|
429
|
+
* [`AcdpProducer::build_supersede_request`], including the
|
|
430
|
+
* explicit `acdp_version` default (the library's current ACDP
|
|
431
|
+
* protocol version, `"0.2.0"` as of this release).
|
|
300
432
|
*/
|
|
301
433
|
buildSupersedeRequest(previousBodyJson: string, opts: SupersedeOpts): string
|
|
302
434
|
/**
|
|
@@ -399,4 +531,107 @@ export declare class AcdpVerifier {
|
|
|
399
531
|
* Returns `true` on success; throws on failure.
|
|
400
532
|
*/
|
|
401
533
|
static verifySignatureP256(pubKeySec1B64: string, sigB64: string, contentHash: string): boolean
|
|
534
|
+
/**
|
|
535
|
+
* Full offline verification of a retrieved `Body` from a `did:key`
|
|
536
|
+
* producer (ACDP 0.2) — structural validation, `content_hash`
|
|
537
|
+
* recomputation, key_id/agent_id binding, and signature check, all
|
|
538
|
+
* with no network.
|
|
539
|
+
*
|
|
540
|
+
* * `bodyJson` — the `body` object from a `FullContext` retrieval
|
|
541
|
+
* (the registry-assigned fields must be present).
|
|
542
|
+
*
|
|
543
|
+
* Throws for `did:web` bodies — those need DID-document
|
|
544
|
+
* resolution, which stays in JS land (resolve via `AcdpDid.webToUrl`
|
|
545
|
+
* + `fetch`, then use `verifySignature`).
|
|
546
|
+
*
|
|
547
|
+
* Returns `true` on success; throws on any failure.
|
|
548
|
+
*/
|
|
549
|
+
static verifyBodyOffline(bodyJson: string): boolean
|
|
550
|
+
/**
|
|
551
|
+
* Offline verification of a `PublishRequest` from a `did:key`
|
|
552
|
+
* producer (ACDP 0.2): recomputes the `content_hash` over the
|
|
553
|
+
* request's producer-controlled fields, then verifies the
|
|
554
|
+
* signature against the key embedded in the `did:key` itself.
|
|
555
|
+
*
|
|
556
|
+
* * `requestJson` — the full PublishRequest wire JSON (e.g. the
|
|
557
|
+
* string `buildPublishRequest` returned).
|
|
558
|
+
*
|
|
559
|
+
* Throws for non-`did:key` requests — `did:web` verification needs
|
|
560
|
+
* DID resolution, which stays in JS land by design.
|
|
561
|
+
*
|
|
562
|
+
* Returns `true` on success; throws on any failure.
|
|
563
|
+
*/
|
|
564
|
+
static verifyPublishRequestOffline(requestJson: string): boolean
|
|
565
|
+
/**
|
|
566
|
+
* Diagnose a `content_hash` mismatch (ACDP 0.2 divergence
|
|
567
|
+
* tooling). Probes the known cross-implementation divergence
|
|
568
|
+
* patterns — `acdp_version` omitted vs explicit, null-vs-absent
|
|
569
|
+
* optionals, sub-millisecond timestamps — and returns a
|
|
570
|
+
* human-readable report naming the matching pattern (or the
|
|
571
|
+
* recomputed hash and preimage when none matches).
|
|
572
|
+
*
|
|
573
|
+
* Never use this to *accept* a body; it is producer/SDK-author
|
|
574
|
+
* tooling for chasing "the hash that won't reproduce".
|
|
575
|
+
*/
|
|
576
|
+
static explainHashMismatch(bodyJson: string, expectedHash: string): string
|
|
577
|
+
/**
|
|
578
|
+
* The exact JCS canonical preimage hashed for `content_hash`,
|
|
579
|
+
* returned as a UTF-8 string. When two SDKs disagree on a hash,
|
|
580
|
+
* diffing their canonical preimages localizes the divergence in a
|
|
581
|
+
* way two opaque digests never can.
|
|
582
|
+
*/
|
|
583
|
+
static canonicalPreimage(bodyJson: string): string
|
|
584
|
+
/**
|
|
585
|
+
* SHA-256 fingerprint (`"sha256:<64-hex>"`) of a raw Ed25519
|
|
586
|
+
* public key, as carried in a registry receipt's
|
|
587
|
+
* `key_fingerprint` (ACDP 0.2).
|
|
588
|
+
*
|
|
589
|
+
* * `publicKeyB64` — standard base64 of the 32-byte raw key (the
|
|
590
|
+
* same shape as `AcdpProducer.publicKeyB64` /
|
|
591
|
+
* `ResolvedDidKey.publicKeyB64`).
|
|
592
|
+
*/
|
|
593
|
+
static fingerprintEd25519B64(publicKeyB64: string): string
|
|
594
|
+
/**
|
|
595
|
+
* Verify a registry receipt (ACDP 0.2, RFC-ACDP-0010): the
|
|
596
|
+
* canonical `created_at` byte-form check, the offline cross-checks
|
|
597
|
+
* (`ctx_id`, recomputed body hash, producer key fingerprint,
|
|
598
|
+
* ms-truncated `created_at`, `registry_did`/`origin_registry`
|
|
599
|
+
* consistency), then the Ed25519 signature check against the
|
|
600
|
+
* registry's receipt key — with the signature preimage hashed over
|
|
601
|
+
* the **raw wire JSON** of the receipt as received (minus
|
|
602
|
+
* `signature`), never a re-serialization of the parsed struct.
|
|
603
|
+
*
|
|
604
|
+
* Resolving `registry_did` to that key is the caller's job — DID
|
|
605
|
+
* resolution stays in JS land by design (resolve the registry's
|
|
606
|
+
* DID document via `AcdpDid.webToUrl` + `fetch`, extract the key
|
|
607
|
+
* with `AcdpDidDocument.keyForAlgorithm`).
|
|
608
|
+
*
|
|
609
|
+
* **Two checks remain the HOST's obligation** — this binding makes
|
|
610
|
+
* no HTTP calls and never sees the accompanying body:
|
|
611
|
+
*
|
|
612
|
+
* 1. **Serving-authority binding** — `receipt.registry_did` MUST
|
|
613
|
+
* equal `"did:web:" + <authority>` where `<authority>` is the
|
|
614
|
+
* authority the response was *actually fetched from*, not
|
|
615
|
+
* whatever the receipt claims.
|
|
616
|
+
* 2. **Body bindings** — the receipt's `lineage_id`,
|
|
617
|
+
* `origin_registry`, and `created_at` MUST equal the
|
|
618
|
+
* accompanying body's fields, and the `recomputedBodyHash`
|
|
619
|
+
* argument MUST be independently recomputed from that body
|
|
620
|
+
* (run `AcdpVerifier.verifyContentHash` first) — never the
|
|
621
|
+
* body's echoed `content_hash` field.
|
|
622
|
+
*
|
|
623
|
+
* * `receiptJson` — the `registry_receipt` object from a
|
|
624
|
+
* `FullContext` retrieval.
|
|
625
|
+
* * `registryPublicKeyB64` — standard base64 of the registry's
|
|
626
|
+
* 32-byte raw Ed25519 receipt key.
|
|
627
|
+
* * `expectedCtxId` — the ctx_id the caller actually requested.
|
|
628
|
+
* * `recomputedBodyHash` — the *independently recomputed* body
|
|
629
|
+
* hash, never the body's echoed `content_hash` field.
|
|
630
|
+
* * `producerKeyFingerprint` — fingerprint of the resolved
|
|
631
|
+
* producer key (see `fingerprintEd25519B64`).
|
|
632
|
+
*
|
|
633
|
+
* Returns `true` on success; throws with the failing check's
|
|
634
|
+
* message otherwise.
|
|
635
|
+
*/
|
|
636
|
+
static verifyReceipt(receiptJson: string, registryPublicKeyB64: string, expectedCtxId: string, recomputedBodyHash: string, producerKeyFingerprint: string): boolean
|
|
402
637
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentcontextdistributionprotocol/acdp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Agent Context Distribution Protocol — Node.js SDK",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
"registry": "https://registry.npmjs.org/"
|
|
48
48
|
},
|
|
49
49
|
"optionalDependencies": {
|
|
50
|
-
"@agentcontextdistributionprotocol/acdp-darwin-x64": "0.
|
|
51
|
-
"@agentcontextdistributionprotocol/acdp-darwin-arm64": "0.
|
|
52
|
-
"@agentcontextdistributionprotocol/acdp-linux-x64-gnu": "0.
|
|
53
|
-
"@agentcontextdistributionprotocol/acdp-linux-arm64-gnu": "0.
|
|
50
|
+
"@agentcontextdistributionprotocol/acdp-darwin-x64": "0.5.0",
|
|
51
|
+
"@agentcontextdistributionprotocol/acdp-darwin-arm64": "0.5.0",
|
|
52
|
+
"@agentcontextdistributionprotocol/acdp-linux-x64-gnu": "0.5.0",
|
|
53
|
+
"@agentcontextdistributionprotocol/acdp-linux-arm64-gnu": "0.5.0"
|
|
54
54
|
}
|
|
55
55
|
}
|