@agentcontextdistributionprotocol/acdp-wasm 0.8.5 → 0.14.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 CHANGED
@@ -42,8 +42,9 @@ wasm-bindgen exports (camelCase in JS/TypeScript):
42
42
  |---|---|---|
43
43
  | `verifyContentHash` | 0001 §5.7 | recompute `sha256(JCS(producer_content))` |
44
44
  | `verifySignatureEd25519` / `verifySignatureP256` | 0001 §5.8 | signature over the ASCII `"sha256:<hex>"` string |
45
+ | `verifyCtxIdBinding` | 0006 §4.1 step 7 | bind the served `ctx_id` to the one requested — see [Verifying a retrieved body](#verifying-a-retrieved-body) |
45
46
  | `verifyBodyOffline` / `verifyPublishRequestOffline` | 0002 | full `did:key` context verify (no resolution) |
46
- | `fingerprintEd25519` / `verifyReceipt` | 0010 | registry-receipt verification |
47
+ | `fingerprintEd25519` / `verifyReceipt(receiptJson, bodyJson, registryPublicKeyB64, expectedCtxId, recomputedBodyHash, producerKeyFingerprint)` | 0010 | registry-receipt verification — see [Verifying a registry receipt](#verifying-a-registry-receipt) below |
47
48
  | `verifyLineageHeadReceipt` | 0011 | lineage-head receipt |
48
49
  | `verifyLogCheckpoint` / `verifyLogInclusion` / `verifyLogConsistency` / `buildLogLeaf` / `merkleLeafHash` / `merkleNodeHash` / `merkleRootHash` | 0012 | transparency log |
49
50
  | `verifyLifecycleEvent` | 0013 | lifecycle event |
@@ -63,13 +64,53 @@ npm install @agentcontextdistributionprotocol/acdp-wasm
63
64
  ```
64
65
 
65
66
  ```js
66
- import init, { verifyContentHash, verifySignatureEd25519 }
67
+ import init, { verifyContentHash, verifySignatureEd25519, verifyCtxIdBinding }
67
68
  from "@agentcontextdistributionprotocol/acdp-wasm";
68
69
  await init();
69
70
  const verdict = JSON.parse(verifyContentHash(bodyJson, body.content_hash));
70
71
  if (verdict.valid) { /* the hash the consumer recomputed itself checks out */ }
72
+
73
+ // Bind the served ctx_id to the one requested (RFC-ACDP-0006 §4.1 step 7).
74
+ // See "Verifying a retrieved body" below for why this is a separate call.
75
+ const binding = JSON.parse(verifyCtxIdBinding(bodyJson, requestedCtxId));
76
+ if (binding.valid) { /* the ctx_id you got back is the one you asked for */ }
71
77
  ```
72
78
 
79
+ ### Verifying a retrieved body
80
+
81
+ `ctx_id` is registry-assigned and sits in the RFC-ACDP-0001 §5.7 exclusion
82
+ set, so it is stripped before `content_hash` is computed — neither the hash
83
+ recompute above nor the producer's signature covers it. Without an
84
+ explicit comparison, a registry could serve any other validly-signed body
85
+ from the same producer under the `ctx_id` URL you asked for, and every
86
+ check above would still pass. `verifyCtxIdBinding(bodyJson, expectedCtxId)`
87
+ closes that gap: `bodyJson` carries the *served* identity, `expectedCtxId`
88
+ is what you requested. Like `verifyContentHash`, a malformed *served*
89
+ `ctx_id` is a `{"valid": false, ...}` verdict, not a throw — only a
90
+ malformed `expectedCtxId` argument throws a `JsError`.
91
+
92
+ ### Verifying a registry receipt
93
+
94
+ `verifyReceipt` (RFC-ACDP-0010 §8) takes the accompanying `bodyJson` as a
95
+ **required** second argument — it binds the receipt's `lineage_id`,
96
+ `origin_registry`, and `created_at` to the served body's own fields (§8
97
+ step 3):
98
+
99
+ ```js
100
+ const verdict = JSON.parse(verifyReceipt(
101
+ receiptJson, bodyJson, registryPublicKeyB64,
102
+ expectedCtxId, recomputedBodyHash, producerKeyFingerprint,
103
+ ));
104
+ ```
105
+
106
+ A malformed `bodyJson` throws a `JsError` (host input); a body/receipt
107
+ mismatch is a `{"valid": false, ...}` verdict (verification outcome), not
108
+ a throw — same convention as `verifyContentHash` / `verifyCtxIdBinding`.
109
+ Two checks still stay the HOST's obligation, because neither needs the
110
+ body: the serving-authority binding (`receipt.registry_did` must equal
111
+ the authority you actually fetched from) and recomputing (never
112
+ trusting) the body hash you pass in.
113
+
73
114
  The package is built with `wasm-pack --target web`: an ESM module you
74
115
  initialize once with `await init()`. This is the target the crate is
75
116
  designed and CI-tested around, and it loads cleanly in browsers and in
@@ -94,10 +135,12 @@ wasm-pack build --target web --out-dir pkg --scope agentcontextdistributionproto
94
135
  Import from a browser (local, unpublished build):
95
136
 
96
137
  ```js
97
- import init, { verifyContentHash, verifySignatureEd25519 } from "./pkg/acdp_wasm.js";
138
+ import init, { verifyContentHash, verifySignatureEd25519, verifyCtxIdBinding } from "./pkg/acdp_wasm.js";
98
139
  await init();
99
140
  const verdict = JSON.parse(verifyContentHash(bodyJson, body.content_hash));
100
141
  if (verdict.valid) { /* the hash the consumer recomputed itself checks out */ }
142
+ const binding = JSON.parse(verifyCtxIdBinding(bodyJson, requestedCtxId));
143
+ if (binding.valid) { /* the ctx_id you got back is the one you asked for */ }
101
144
  ```
102
145
 
103
146
  ## Golden-vector parity
package/acdp_wasm.d.ts CHANGED
@@ -73,6 +73,18 @@ export function verifyBodyOffline(body_json: string): string;
73
73
  */
74
74
  export function verifyContentHash(body_json: string, expected_hash: string): string;
75
75
 
76
+ /**
77
+ * Verify that a body's *served* `ctx_id` matches the `ctx_id` the
78
+ * caller *expected* (RFC-ACDP-0006 §4.1 step 7, NORMATIVE). Argument
79
+ * order is `(bodyJson, expectedCtxId)`: the body's own `ctx_id` is the
80
+ * *served* identity, `expectedCtxId` is what the caller requested.
81
+ * Returns a verdict for the served side (a malformed served `ctx_id`,
82
+ * or a served/expected mismatch, is a fail verdict). Throws on
83
+ * malformed body JSON or a malformed `expectedCtxId` — that value is
84
+ * host input, mirroring `verifyContentHash`'s `expectedHash`.
85
+ */
86
+ export function verifyCtxIdBinding(body_json: string, expected_ctx_id: string): string;
87
+
76
88
  /**
77
89
  * Verify one lifecycle event offline (RFC-ACDP-0013 §5).
78
90
  * `actorDidDocJson` is `null`/`undefined` for a `did:key` actor.
@@ -110,10 +122,11 @@ export function verifyPublishRequestOffline(request_json: string): string;
110
122
 
111
123
  /**
112
124
  * Verify a registry receipt (RFC-ACDP-0010) against the consumer's own
113
- * recomputed body hash / expected ctx_id / producer key fingerprint.
114
- * Returns a verdict.
125
+ * recomputed body hash / expected ctx_id / producer key fingerprint,
126
+ * and bind it to the accompanying `body_json` (§8 step 3). Returns a
127
+ * verdict.
115
128
  */
116
- export function verifyReceipt(receipt_json: string, registry_public_key_b64: string, expected_ctx_id: string, recomputed_body_hash: string, producer_key_fingerprint: string): string;
129
+ export function verifyReceipt(receipt_json: string, body_json: string, registry_public_key_b64: string, expected_ctx_id: string, recomputed_body_hash: string, producer_key_fingerprint: string): string;
117
130
 
118
131
  /**
119
132
  * Verify an Ed25519 signature over the ASCII `"sha256:<hex>"` string.
@@ -152,13 +165,14 @@ export interface InitOutput {
152
165
  readonly resolveDidKey: (a: number, b: number, c: number) => void;
153
166
  readonly verifyBodyOffline: (a: number, b: number, c: number) => void;
154
167
  readonly verifyContentHash: (a: number, b: number, c: number, d: number, e: number) => void;
168
+ readonly verifyCtxIdBinding: (a: number, b: number, c: number, d: number, e: number) => void;
155
169
  readonly verifyLifecycleEvent: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
156
170
  readonly verifyLineageHeadReceipt: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: bigint, l: number, m: bigint) => void;
157
171
  readonly verifyLogCheckpoint: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: bigint) => void;
158
172
  readonly verifyLogConsistency: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
159
173
  readonly verifyLogInclusion: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
160
174
  readonly verifyPublishRequestOffline: (a: number, b: number, c: number) => void;
161
- readonly verifyReceipt: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => void;
175
+ readonly verifyReceipt: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number) => void;
162
176
  readonly verifySignatureEd25519: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
163
177
  readonly verifySignatureP256: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
164
178
  readonly verifyWitnessCosignature: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: bigint) => void;
package/acdp_wasm.js CHANGED
@@ -492,6 +492,48 @@ export function verifyContentHash(body_json, expected_hash) {
492
492
  }
493
493
  }
494
494
 
495
+ /**
496
+ * Verify that a body's *served* `ctx_id` matches the `ctx_id` the
497
+ * caller *expected* (RFC-ACDP-0006 §4.1 step 7, NORMATIVE). Argument
498
+ * order is `(bodyJson, expectedCtxId)`: the body's own `ctx_id` is the
499
+ * *served* identity, `expectedCtxId` is what the caller requested.
500
+ * Returns a verdict for the served side (a malformed served `ctx_id`,
501
+ * or a served/expected mismatch, is a fail verdict). Throws on
502
+ * malformed body JSON or a malformed `expectedCtxId` — that value is
503
+ * host input, mirroring `verifyContentHash`'s `expectedHash`.
504
+ * @param {string} body_json
505
+ * @param {string} expected_ctx_id
506
+ * @returns {string}
507
+ */
508
+ export function verifyCtxIdBinding(body_json, expected_ctx_id) {
509
+ let deferred4_0;
510
+ let deferred4_1;
511
+ try {
512
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
513
+ const ptr0 = passStringToWasm0(body_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
514
+ const len0 = WASM_VECTOR_LEN;
515
+ const ptr1 = passStringToWasm0(expected_ctx_id, wasm.__wbindgen_export, wasm.__wbindgen_export2);
516
+ const len1 = WASM_VECTOR_LEN;
517
+ wasm.verifyCtxIdBinding(retptr, ptr0, len0, ptr1, len1);
518
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
519
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
520
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
521
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
522
+ var ptr3 = r0;
523
+ var len3 = r1;
524
+ if (r3) {
525
+ ptr3 = 0; len3 = 0;
526
+ throw takeObject(r2);
527
+ }
528
+ deferred4_0 = ptr3;
529
+ deferred4_1 = len3;
530
+ return getStringFromWasm0(ptr3, len3);
531
+ } finally {
532
+ wasm.__wbindgen_add_to_stack_pointer(16);
533
+ wasm.__wbindgen_export3(deferred4_0, deferred4_1, 1);
534
+ }
535
+ }
536
+
495
537
  /**
496
538
  * Verify one lifecycle event offline (RFC-ACDP-0013 §5).
497
539
  * `actorDidDocJson` is `null`/`undefined` for a `did:key` actor.
@@ -730,47 +772,51 @@ export function verifyPublishRequestOffline(request_json) {
730
772
 
731
773
  /**
732
774
  * Verify a registry receipt (RFC-ACDP-0010) against the consumer's own
733
- * recomputed body hash / expected ctx_id / producer key fingerprint.
734
- * Returns a verdict.
775
+ * recomputed body hash / expected ctx_id / producer key fingerprint,
776
+ * and bind it to the accompanying `body_json` (§8 step 3). Returns a
777
+ * verdict.
735
778
  * @param {string} receipt_json
779
+ * @param {string} body_json
736
780
  * @param {string} registry_public_key_b64
737
781
  * @param {string} expected_ctx_id
738
782
  * @param {string} recomputed_body_hash
739
783
  * @param {string} producer_key_fingerprint
740
784
  * @returns {string}
741
785
  */
742
- export function verifyReceipt(receipt_json, registry_public_key_b64, expected_ctx_id, recomputed_body_hash, producer_key_fingerprint) {
743
- let deferred7_0;
744
- let deferred7_1;
786
+ export function verifyReceipt(receipt_json, body_json, registry_public_key_b64, expected_ctx_id, recomputed_body_hash, producer_key_fingerprint) {
787
+ let deferred8_0;
788
+ let deferred8_1;
745
789
  try {
746
790
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
747
791
  const ptr0 = passStringToWasm0(receipt_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
748
792
  const len0 = WASM_VECTOR_LEN;
749
- const ptr1 = passStringToWasm0(registry_public_key_b64, wasm.__wbindgen_export, wasm.__wbindgen_export2);
793
+ const ptr1 = passStringToWasm0(body_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
750
794
  const len1 = WASM_VECTOR_LEN;
751
- const ptr2 = passStringToWasm0(expected_ctx_id, wasm.__wbindgen_export, wasm.__wbindgen_export2);
795
+ const ptr2 = passStringToWasm0(registry_public_key_b64, wasm.__wbindgen_export, wasm.__wbindgen_export2);
752
796
  const len2 = WASM_VECTOR_LEN;
753
- const ptr3 = passStringToWasm0(recomputed_body_hash, wasm.__wbindgen_export, wasm.__wbindgen_export2);
797
+ const ptr3 = passStringToWasm0(expected_ctx_id, wasm.__wbindgen_export, wasm.__wbindgen_export2);
754
798
  const len3 = WASM_VECTOR_LEN;
755
- const ptr4 = passStringToWasm0(producer_key_fingerprint, wasm.__wbindgen_export, wasm.__wbindgen_export2);
799
+ const ptr4 = passStringToWasm0(recomputed_body_hash, wasm.__wbindgen_export, wasm.__wbindgen_export2);
756
800
  const len4 = WASM_VECTOR_LEN;
757
- wasm.verifyReceipt(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4);
801
+ const ptr5 = passStringToWasm0(producer_key_fingerprint, wasm.__wbindgen_export, wasm.__wbindgen_export2);
802
+ const len5 = WASM_VECTOR_LEN;
803
+ wasm.verifyReceipt(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5);
758
804
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
759
805
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
760
806
  var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
761
807
  var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
762
- var ptr6 = r0;
763
- var len6 = r1;
808
+ var ptr7 = r0;
809
+ var len7 = r1;
764
810
  if (r3) {
765
- ptr6 = 0; len6 = 0;
811
+ ptr7 = 0; len7 = 0;
766
812
  throw takeObject(r2);
767
813
  }
768
- deferred7_0 = ptr6;
769
- deferred7_1 = len6;
770
- return getStringFromWasm0(ptr6, len6);
814
+ deferred8_0 = ptr7;
815
+ deferred8_1 = len7;
816
+ return getStringFromWasm0(ptr7, len7);
771
817
  } finally {
772
818
  wasm.__wbindgen_add_to_stack_pointer(16);
773
- wasm.__wbindgen_export3(deferred7_0, deferred7_1, 1);
819
+ wasm.__wbindgen_export3(deferred8_0, deferred8_1, 1);
774
820
  }
775
821
  }
776
822
 
@@ -898,18 +944,18 @@ export function verifyWitnessCosignature(cosig_json, witness_did_doc_json, expec
898
944
  function __wbg_get_imports() {
899
945
  const import0 = {
900
946
  __proto__: null,
901
- __wbg_Error_408e67f47ca7b58b: function(arg0, arg1) {
947
+ __wbg_Error_67e7344beaa85059: function(arg0, arg1) {
902
948
  const ret = Error(getStringFromWasm0(arg0, arg1));
903
949
  return addHeapObject(ret);
904
950
  },
905
- __wbg___wbindgen_throw_bb96b2010945f0bc: function(arg0, arg1) {
951
+ __wbg___wbindgen_throw_5d9e815e6fdf150f: function(arg0, arg1) {
906
952
  throw new Error(getStringFromWasm0(arg0, arg1));
907
953
  },
908
- __wbg_getTime_63fb0332e6c4ec17: function(arg0) {
954
+ __wbg_getTime_65922ba0b59d55a7: function(arg0) {
909
955
  const ret = getObject(arg0).getTime();
910
956
  return ret;
911
957
  },
912
- __wbg_new_0_f117d868b403dc07: function() {
958
+ __wbg_new_0_35540e542ba689d2: function() {
913
959
  const ret = new Date();
914
960
  return addHeapObject(ret);
915
961
  },
package/acdp_wasm_bg.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@agentcontextdistributionprotocol/acdp-wasm",
3
3
  "type": "module",
4
4
  "description": "Agent Context Distribution Protocol — WebAssembly verification core",
5
- "version": "0.8.5",
5
+ "version": "0.14.0",
6
6
  "license": "MIT OR Apache-2.0",
7
7
  "files": [
8
8
  "acdp_wasm_bg.wasm",