@agentcontextdistributionprotocol/acdp-wasm 0.8.4 → 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 +46 -3
- package/acdp_wasm.d.ts +18 -4
- package/acdp_wasm.js +67 -21
- package/acdp_wasm_bg.wasm +0 -0
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
744
|
-
let
|
|
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(
|
|
793
|
+
const ptr1 = passStringToWasm0(body_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
750
794
|
const len1 = WASM_VECTOR_LEN;
|
|
751
|
-
const ptr2 = passStringToWasm0(
|
|
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(
|
|
797
|
+
const ptr3 = passStringToWasm0(expected_ctx_id, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
754
798
|
const len3 = WASM_VECTOR_LEN;
|
|
755
|
-
const ptr4 = passStringToWasm0(
|
|
799
|
+
const ptr4 = passStringToWasm0(recomputed_body_hash, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
756
800
|
const len4 = WASM_VECTOR_LEN;
|
|
757
|
-
|
|
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
|
|
763
|
-
var
|
|
808
|
+
var ptr7 = r0;
|
|
809
|
+
var len7 = r1;
|
|
764
810
|
if (r3) {
|
|
765
|
-
|
|
811
|
+
ptr7 = 0; len7 = 0;
|
|
766
812
|
throw takeObject(r2);
|
|
767
813
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
return getStringFromWasm0(
|
|
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(
|
|
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
|
-
|
|
947
|
+
__wbg_Error_67e7344beaa85059: function(arg0, arg1) {
|
|
902
948
|
const ret = Error(getStringFromWasm0(arg0, arg1));
|
|
903
949
|
return addHeapObject(ret);
|
|
904
950
|
},
|
|
905
|
-
|
|
951
|
+
__wbg___wbindgen_throw_5d9e815e6fdf150f: function(arg0, arg1) {
|
|
906
952
|
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
907
953
|
},
|
|
908
|
-
|
|
954
|
+
__wbg_getTime_65922ba0b59d55a7: function(arg0) {
|
|
909
955
|
const ret = getObject(arg0).getTime();
|
|
910
956
|
return ret;
|
|
911
957
|
},
|
|
912
|
-
|
|
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.
|
|
5
|
+
"version": "0.14.0",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
|
7
7
|
"files": [
|
|
8
8
|
"acdp_wasm_bg.wasm",
|