@mcp-i/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +390 -0
  3. package/dist/auth/handshake.d.ts +104 -0
  4. package/dist/auth/handshake.d.ts.map +1 -0
  5. package/dist/auth/handshake.js +230 -0
  6. package/dist/auth/handshake.js.map +1 -0
  7. package/dist/auth/index.d.ts +3 -0
  8. package/dist/auth/index.d.ts.map +1 -0
  9. package/dist/auth/index.js +2 -0
  10. package/dist/auth/index.js.map +1 -0
  11. package/dist/auth/types.d.ts +31 -0
  12. package/dist/auth/types.d.ts.map +1 -0
  13. package/dist/auth/types.js +7 -0
  14. package/dist/auth/types.js.map +1 -0
  15. package/dist/delegation/audience-validator.d.ts +9 -0
  16. package/dist/delegation/audience-validator.d.ts.map +1 -0
  17. package/dist/delegation/audience-validator.js +17 -0
  18. package/dist/delegation/audience-validator.js.map +1 -0
  19. package/dist/delegation/bitstring.d.ts +37 -0
  20. package/dist/delegation/bitstring.d.ts.map +1 -0
  21. package/dist/delegation/bitstring.js +117 -0
  22. package/dist/delegation/bitstring.js.map +1 -0
  23. package/dist/delegation/cascading-revocation.d.ts +45 -0
  24. package/dist/delegation/cascading-revocation.d.ts.map +1 -0
  25. package/dist/delegation/cascading-revocation.js +148 -0
  26. package/dist/delegation/cascading-revocation.js.map +1 -0
  27. package/dist/delegation/delegation-graph.d.ts +49 -0
  28. package/dist/delegation/delegation-graph.d.ts.map +1 -0
  29. package/dist/delegation/delegation-graph.js +99 -0
  30. package/dist/delegation/delegation-graph.js.map +1 -0
  31. package/dist/delegation/did-key-resolver.d.ts +64 -0
  32. package/dist/delegation/did-key-resolver.d.ts.map +1 -0
  33. package/dist/delegation/did-key-resolver.js +154 -0
  34. package/dist/delegation/did-key-resolver.js.map +1 -0
  35. package/dist/delegation/did-web-resolver.d.ts +83 -0
  36. package/dist/delegation/did-web-resolver.d.ts.map +1 -0
  37. package/dist/delegation/did-web-resolver.js +218 -0
  38. package/dist/delegation/did-web-resolver.js.map +1 -0
  39. package/dist/delegation/index.d.ts +21 -0
  40. package/dist/delegation/index.d.ts.map +1 -0
  41. package/dist/delegation/index.js +21 -0
  42. package/dist/delegation/index.js.map +1 -0
  43. package/dist/delegation/outbound-headers.d.ts +81 -0
  44. package/dist/delegation/outbound-headers.d.ts.map +1 -0
  45. package/dist/delegation/outbound-headers.js +139 -0
  46. package/dist/delegation/outbound-headers.js.map +1 -0
  47. package/dist/delegation/outbound-proof.d.ts +43 -0
  48. package/dist/delegation/outbound-proof.d.ts.map +1 -0
  49. package/dist/delegation/outbound-proof.js +52 -0
  50. package/dist/delegation/outbound-proof.js.map +1 -0
  51. package/dist/delegation/statuslist-manager.d.ts +44 -0
  52. package/dist/delegation/statuslist-manager.d.ts.map +1 -0
  53. package/dist/delegation/statuslist-manager.js +126 -0
  54. package/dist/delegation/statuslist-manager.js.map +1 -0
  55. package/dist/delegation/storage/memory-graph-storage.d.ts +70 -0
  56. package/dist/delegation/storage/memory-graph-storage.d.ts.map +1 -0
  57. package/dist/delegation/storage/memory-graph-storage.js +145 -0
  58. package/dist/delegation/storage/memory-graph-storage.js.map +1 -0
  59. package/dist/delegation/storage/memory-statuslist-storage.d.ts +19 -0
  60. package/dist/delegation/storage/memory-statuslist-storage.d.ts.map +1 -0
  61. package/dist/delegation/storage/memory-statuslist-storage.js +33 -0
  62. package/dist/delegation/storage/memory-statuslist-storage.js.map +1 -0
  63. package/dist/delegation/utils.d.ts +49 -0
  64. package/dist/delegation/utils.d.ts.map +1 -0
  65. package/dist/delegation/utils.js +131 -0
  66. package/dist/delegation/utils.js.map +1 -0
  67. package/dist/delegation/vc-issuer.d.ts +56 -0
  68. package/dist/delegation/vc-issuer.d.ts.map +1 -0
  69. package/dist/delegation/vc-issuer.js +80 -0
  70. package/dist/delegation/vc-issuer.js.map +1 -0
  71. package/dist/delegation/vc-verifier.d.ts +112 -0
  72. package/dist/delegation/vc-verifier.d.ts.map +1 -0
  73. package/dist/delegation/vc-verifier.js +280 -0
  74. package/dist/delegation/vc-verifier.js.map +1 -0
  75. package/dist/index.d.ts +45 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +53 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/logging/index.d.ts +2 -0
  80. package/dist/logging/index.d.ts.map +1 -0
  81. package/dist/logging/index.js +2 -0
  82. package/dist/logging/index.js.map +1 -0
  83. package/dist/logging/logger.d.ts +23 -0
  84. package/dist/logging/logger.d.ts.map +1 -0
  85. package/dist/logging/logger.js +82 -0
  86. package/dist/logging/logger.js.map +1 -0
  87. package/dist/middleware/index.d.ts +7 -0
  88. package/dist/middleware/index.d.ts.map +1 -0
  89. package/dist/middleware/index.js +7 -0
  90. package/dist/middleware/index.js.map +1 -0
  91. package/dist/middleware/with-mcpi.d.ts +152 -0
  92. package/dist/middleware/with-mcpi.d.ts.map +1 -0
  93. package/dist/middleware/with-mcpi.js +472 -0
  94. package/dist/middleware/with-mcpi.js.map +1 -0
  95. package/dist/proof/errors.d.ts +49 -0
  96. package/dist/proof/errors.d.ts.map +1 -0
  97. package/dist/proof/errors.js +61 -0
  98. package/dist/proof/errors.js.map +1 -0
  99. package/dist/proof/generator.d.ts +65 -0
  100. package/dist/proof/generator.d.ts.map +1 -0
  101. package/dist/proof/generator.js +163 -0
  102. package/dist/proof/generator.js.map +1 -0
  103. package/dist/proof/index.d.ts +4 -0
  104. package/dist/proof/index.d.ts.map +1 -0
  105. package/dist/proof/index.js +4 -0
  106. package/dist/proof/index.js.map +1 -0
  107. package/dist/proof/verifier.d.ts +108 -0
  108. package/dist/proof/verifier.d.ts.map +1 -0
  109. package/dist/proof/verifier.js +299 -0
  110. package/dist/proof/verifier.js.map +1 -0
  111. package/dist/providers/base.d.ts +64 -0
  112. package/dist/providers/base.d.ts.map +1 -0
  113. package/dist/providers/base.js +19 -0
  114. package/dist/providers/base.js.map +1 -0
  115. package/dist/providers/index.d.ts +3 -0
  116. package/dist/providers/index.d.ts.map +1 -0
  117. package/dist/providers/index.js +3 -0
  118. package/dist/providers/index.js.map +1 -0
  119. package/dist/providers/memory.d.ts +33 -0
  120. package/dist/providers/memory.d.ts.map +1 -0
  121. package/dist/providers/memory.js +102 -0
  122. package/dist/providers/memory.js.map +1 -0
  123. package/dist/session/index.d.ts +2 -0
  124. package/dist/session/index.d.ts.map +1 -0
  125. package/dist/session/index.js +2 -0
  126. package/dist/session/index.js.map +1 -0
  127. package/dist/session/manager.d.ts +77 -0
  128. package/dist/session/manager.d.ts.map +1 -0
  129. package/dist/session/manager.js +251 -0
  130. package/dist/session/manager.js.map +1 -0
  131. package/dist/types/protocol.d.ts +320 -0
  132. package/dist/types/protocol.d.ts.map +1 -0
  133. package/dist/types/protocol.js +229 -0
  134. package/dist/types/protocol.js.map +1 -0
  135. package/dist/utils/base58.d.ts +31 -0
  136. package/dist/utils/base58.d.ts.map +1 -0
  137. package/dist/utils/base58.js +104 -0
  138. package/dist/utils/base58.js.map +1 -0
  139. package/dist/utils/base64.d.ts +13 -0
  140. package/dist/utils/base64.d.ts.map +1 -0
  141. package/dist/utils/base64.js +99 -0
  142. package/dist/utils/base64.js.map +1 -0
  143. package/dist/utils/crypto-service.d.ts +37 -0
  144. package/dist/utils/crypto-service.d.ts.map +1 -0
  145. package/dist/utils/crypto-service.js +153 -0
  146. package/dist/utils/crypto-service.js.map +1 -0
  147. package/dist/utils/did-helpers.d.ts +156 -0
  148. package/dist/utils/did-helpers.d.ts.map +1 -0
  149. package/dist/utils/did-helpers.js +193 -0
  150. package/dist/utils/did-helpers.js.map +1 -0
  151. package/dist/utils/ed25519-constants.d.ts +18 -0
  152. package/dist/utils/ed25519-constants.d.ts.map +1 -0
  153. package/dist/utils/ed25519-constants.js +21 -0
  154. package/dist/utils/ed25519-constants.js.map +1 -0
  155. package/dist/utils/index.d.ts +5 -0
  156. package/dist/utils/index.d.ts.map +1 -0
  157. package/dist/utils/index.js +5 -0
  158. package/dist/utils/index.js.map +1 -0
  159. package/package.json +105 -0
  160. package/src/__tests__/integration/full-flow.test.ts +362 -0
  161. package/src/__tests__/providers/base.test.ts +173 -0
  162. package/src/__tests__/providers/memory.test.ts +332 -0
  163. package/src/__tests__/utils/mock-providers.ts +319 -0
  164. package/src/__tests__/utils/node-crypto-provider.ts +93 -0
  165. package/src/auth/handshake.ts +411 -0
  166. package/src/auth/index.ts +11 -0
  167. package/src/auth/types.ts +40 -0
  168. package/src/delegation/__tests__/audience-validator.test.ts +110 -0
  169. package/src/delegation/__tests__/bitstring.test.ts +346 -0
  170. package/src/delegation/__tests__/cascading-revocation.test.ts +624 -0
  171. package/src/delegation/__tests__/delegation-graph.test.ts +623 -0
  172. package/src/delegation/__tests__/did-key-resolver.test.ts +265 -0
  173. package/src/delegation/__tests__/did-web-resolver.test.ts +467 -0
  174. package/src/delegation/__tests__/outbound-headers.test.ts +230 -0
  175. package/src/delegation/__tests__/outbound-proof.test.ts +179 -0
  176. package/src/delegation/__tests__/statuslist-manager.test.ts +515 -0
  177. package/src/delegation/__tests__/utils.test.ts +185 -0
  178. package/src/delegation/__tests__/vc-issuer.test.ts +487 -0
  179. package/src/delegation/__tests__/vc-verifier.test.ts +1029 -0
  180. package/src/delegation/audience-validator.ts +24 -0
  181. package/src/delegation/bitstring.ts +160 -0
  182. package/src/delegation/cascading-revocation.ts +224 -0
  183. package/src/delegation/delegation-graph.ts +143 -0
  184. package/src/delegation/did-key-resolver.ts +181 -0
  185. package/src/delegation/did-web-resolver.ts +270 -0
  186. package/src/delegation/index.ts +33 -0
  187. package/src/delegation/outbound-headers.ts +193 -0
  188. package/src/delegation/outbound-proof.ts +90 -0
  189. package/src/delegation/statuslist-manager.ts +219 -0
  190. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
  191. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
  192. package/src/delegation/storage/memory-graph-storage.ts +178 -0
  193. package/src/delegation/storage/memory-statuslist-storage.ts +42 -0
  194. package/src/delegation/utils.ts +189 -0
  195. package/src/delegation/vc-issuer.ts +137 -0
  196. package/src/delegation/vc-verifier.ts +440 -0
  197. package/src/index.ts +264 -0
  198. package/src/logging/__tests__/logger.test.ts +366 -0
  199. package/src/logging/index.ts +6 -0
  200. package/src/logging/logger.ts +91 -0
  201. package/src/middleware/__tests__/with-mcpi.test.ts +504 -0
  202. package/src/middleware/index.ts +16 -0
  203. package/src/middleware/with-mcpi.ts +766 -0
  204. package/src/proof/__tests__/proof-generator.test.ts +483 -0
  205. package/src/proof/__tests__/verifier.test.ts +488 -0
  206. package/src/proof/errors.ts +75 -0
  207. package/src/proof/generator.ts +255 -0
  208. package/src/proof/index.ts +22 -0
  209. package/src/proof/verifier.ts +449 -0
  210. package/src/providers/base.ts +68 -0
  211. package/src/providers/index.ts +15 -0
  212. package/src/providers/memory.ts +130 -0
  213. package/src/session/__tests__/session-manager.test.ts +342 -0
  214. package/src/session/index.ts +7 -0
  215. package/src/session/manager.ts +332 -0
  216. package/src/types/protocol.ts +596 -0
  217. package/src/utils/__tests__/base58.test.ts +281 -0
  218. package/src/utils/__tests__/base64.test.ts +239 -0
  219. package/src/utils/__tests__/crypto-service.test.ts +530 -0
  220. package/src/utils/__tests__/did-helpers.test.ts +156 -0
  221. package/src/utils/base58.ts +115 -0
  222. package/src/utils/base64.ts +116 -0
  223. package/src/utils/crypto-service.ts +209 -0
  224. package/src/utils/did-helpers.ts +210 -0
  225. package/src/utils/ed25519-constants.ts +23 -0
  226. package/src/utils/index.ts +9 -0
@@ -0,0 +1,483 @@
1
+ /**
2
+ * Proof Generator Tests β€” @mcp-i/core
3
+ *
4
+ * Ported from packages/mcp-i-core/src/proof/__tests__/proof-generator.test.ts.
5
+ * All test logic is identical β€” only import paths change.
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach } from "vitest";
9
+ import { canonicalize } from "json-canonicalize";
10
+ import {
11
+ ProofGenerator,
12
+ createProofResponse,
13
+ extractCanonicalData,
14
+ type ToolRequest,
15
+ type ToolResponse,
16
+ } from "../generator.js";
17
+ import type { ProofAgentIdentity } from "../generator.js";
18
+ import type { SessionContext } from "../../types/protocol.js";
19
+
20
+ // NodeCryptoProvider for test environment (Node.js)
21
+ import { NodeCryptoProvider } from "../../__tests__/utils/node-crypto-provider.js";
22
+
23
+ const cryptoProvider = new NodeCryptoProvider();
24
+
25
+ async function makeIdentity(): Promise<ProofAgentIdentity> {
26
+ const keyPair = await cryptoProvider.generateKeyPair();
27
+ return {
28
+ did: "did:web:example.com:agents:test-agent",
29
+ kid: "key-test-123",
30
+ privateKey: keyPair.privateKey,
31
+ publicKey: keyPair.publicKey,
32
+ };
33
+ }
34
+
35
+ function makeSession(): SessionContext {
36
+ return {
37
+ sessionId: "sess_test_123",
38
+ audience: "example.com",
39
+ nonce: "test-nonce-456",
40
+ timestamp: Math.floor(Date.now() / 1000),
41
+ createdAt: Math.floor(Date.now() / 1000),
42
+ lastActivity: Math.floor(Date.now() / 1000),
43
+ ttlMinutes: 30,
44
+ identityState: "anonymous",
45
+ };
46
+ }
47
+
48
+ describe("ProofGenerator", () => {
49
+ let proofGenerator: ProofGenerator;
50
+ let mockIdentity: ProofAgentIdentity;
51
+ let mockSession: SessionContext;
52
+
53
+ beforeEach(async () => {
54
+ mockIdentity = await makeIdentity();
55
+ mockSession = makeSession();
56
+ proofGenerator = new ProofGenerator(mockIdentity, cryptoProvider);
57
+ });
58
+
59
+ describe("Canonical Hash Generation", () => {
60
+ it("should generate consistent hashes for same request/response", async () => {
61
+ const request: ToolRequest = {
62
+ method: "test-tool",
63
+ params: { input: "hello" },
64
+ };
65
+ const response: ToolResponse = { data: { output: "world" } };
66
+
67
+ const proof1 = await proofGenerator.generateProof(
68
+ request,
69
+ response,
70
+ mockSession
71
+ );
72
+ const proof2 = await proofGenerator.generateProof(
73
+ request,
74
+ response,
75
+ mockSession
76
+ );
77
+
78
+ expect(proof1.meta.requestHash).toBe(proof2.meta.requestHash);
79
+ expect(proof1.meta.responseHash).toBe(proof2.meta.responseHash);
80
+ });
81
+
82
+ it("should generate different hashes for different requests", async () => {
83
+ const request1: ToolRequest = {
84
+ method: "test-tool",
85
+ params: { input: "hello" },
86
+ };
87
+ const request2: ToolRequest = {
88
+ method: "test-tool",
89
+ params: { input: "goodbye" },
90
+ };
91
+ const response: ToolResponse = { data: { output: "world" } };
92
+
93
+ const proof1 = await proofGenerator.generateProof(
94
+ request1,
95
+ response,
96
+ mockSession
97
+ );
98
+ const proof2 = await proofGenerator.generateProof(
99
+ request2,
100
+ response,
101
+ mockSession
102
+ );
103
+
104
+ expect(proof1.meta.requestHash).not.toBe(proof2.meta.requestHash);
105
+ expect(proof1.meta.responseHash).toBe(proof2.meta.responseHash);
106
+ });
107
+
108
+ it("should generate different hashes for different responses", async () => {
109
+ const request: ToolRequest = {
110
+ method: "test-tool",
111
+ params: { input: "hello" },
112
+ };
113
+ const response1: ToolResponse = { data: { output: "world" } };
114
+ const response2: ToolResponse = { data: { output: "universe" } };
115
+
116
+ const proof1 = await proofGenerator.generateProof(
117
+ request,
118
+ response1,
119
+ mockSession
120
+ );
121
+ const proof2 = await proofGenerator.generateProof(
122
+ request,
123
+ response2,
124
+ mockSession
125
+ );
126
+
127
+ expect(proof1.meta.requestHash).toBe(proof2.meta.requestHash);
128
+ expect(proof1.meta.responseHash).not.toBe(proof2.meta.responseHash);
129
+ });
130
+
131
+ it("should generate SHA-256 hashes with correct format", async () => {
132
+ const request: ToolRequest = {
133
+ method: "test-tool",
134
+ params: { input: "hello" },
135
+ };
136
+ const response: ToolResponse = { data: { output: "world" } };
137
+
138
+ const proof = await proofGenerator.generateProof(
139
+ request,
140
+ response,
141
+ mockSession
142
+ );
143
+
144
+ expect(proof.meta.requestHash).toMatch(/^sha256:[a-f0-9]{64}$/);
145
+ expect(proof.meta.responseHash).toMatch(/^sha256:[a-f0-9]{64}$/);
146
+ });
147
+
148
+ it("should handle requests without params", async () => {
149
+ const request: ToolRequest = { method: "simple-tool" };
150
+ const response: ToolResponse = { data: { result: "success" } };
151
+
152
+ const proof = await proofGenerator.generateProof(
153
+ request,
154
+ response,
155
+ mockSession
156
+ );
157
+
158
+ expect(proof.meta.requestHash).toMatch(/^sha256:[a-f0-9]{64}$/);
159
+ expect(proof.meta.responseHash).toMatch(/^sha256:[a-f0-9]{64}$/);
160
+ });
161
+ });
162
+
163
+ describe("Proof Metadata", () => {
164
+ it("should include all required metadata fields", async () => {
165
+ const request: ToolRequest = {
166
+ method: "test-tool",
167
+ params: { input: "hello" },
168
+ };
169
+ const response: ToolResponse = { data: { output: "world" } };
170
+
171
+ const proof = await proofGenerator.generateProof(
172
+ request,
173
+ response,
174
+ mockSession
175
+ );
176
+
177
+ expect(proof.meta.did).toBe(mockIdentity.did);
178
+ expect(proof.meta.kid).toBe(mockIdentity.kid);
179
+ expect(proof.meta.ts).toBeTypeOf("number");
180
+ expect(proof.meta.nonce).toBe(mockSession.nonce);
181
+ expect(proof.meta.audience).toBe(mockSession.audience);
182
+ expect(proof.meta.sessionId).toBe(mockSession.sessionId);
183
+ expect(proof.meta.requestHash).toBeTruthy();
184
+ expect(proof.meta.responseHash).toBeTruthy();
185
+ });
186
+
187
+ it("should include optional fields when provided", async () => {
188
+ const request: ToolRequest = {
189
+ method: "test-tool",
190
+ params: { input: "hello" },
191
+ };
192
+ const response: ToolResponse = { data: { output: "world" } };
193
+
194
+ const proof = await proofGenerator.generateProof(
195
+ request,
196
+ response,
197
+ mockSession,
198
+ {
199
+ scopeId: "orders.create",
200
+ delegationRef: "delegation-ref-123",
201
+ clientDid: "did:key:zClient",
202
+ }
203
+ );
204
+
205
+ expect(proof.meta.scopeId).toBe("orders.create");
206
+ expect(proof.meta.delegationRef).toBe("delegation-ref-123");
207
+ expect(proof.meta.clientDid).toBe("did:key:zClient");
208
+ });
209
+ });
210
+
211
+ describe("JWS Generation", () => {
212
+ it("should generate compact JWS in correct format", async () => {
213
+ const request: ToolRequest = {
214
+ method: "test-tool",
215
+ params: { input: "hello" },
216
+ };
217
+ const response: ToolResponse = { data: { output: "world" } };
218
+
219
+ const proof = await proofGenerator.generateProof(
220
+ request,
221
+ response,
222
+ mockSession
223
+ );
224
+
225
+ const jwsParts = proof.jws.split(".");
226
+ expect(jwsParts).toHaveLength(3);
227
+ expect(jwsParts[0]).toBeTruthy();
228
+ expect(jwsParts[1]).toBeTruthy();
229
+ expect(jwsParts[2]).toBeTruthy();
230
+ });
231
+
232
+ it("should use EdDSA algorithm", async () => {
233
+ const request: ToolRequest = {
234
+ method: "test-tool",
235
+ params: { input: "hello" },
236
+ };
237
+ const response: ToolResponse = { data: { output: "world" } };
238
+
239
+ const proof = await proofGenerator.generateProof(
240
+ request,
241
+ response,
242
+ mockSession
243
+ );
244
+
245
+ const [headerB64] = proof.jws.split(".");
246
+ const header = JSON.parse(
247
+ Buffer.from(headerB64, "base64url").toString()
248
+ ) as { alg: string; kid: string };
249
+
250
+ expect(header.alg).toBe("EdDSA");
251
+ expect(header.kid).toBe(mockIdentity.kid);
252
+ });
253
+
254
+ it("should encode clientDid in the JWS payload when provided", async () => {
255
+ const request: ToolRequest = {
256
+ method: "test-tool",
257
+ params: { input: "hello" },
258
+ };
259
+ const response: ToolResponse = { data: { output: "world" } };
260
+
261
+ const proof = await proofGenerator.generateProof(
262
+ request,
263
+ response,
264
+ mockSession,
265
+ { clientDid: "did:key:zClientPayload" }
266
+ );
267
+
268
+ const payload = JSON.parse(
269
+ Buffer.from(proof.jws.split(".")[1], "base64url").toString()
270
+ ) as { clientDid: string };
271
+
272
+ expect(payload.clientDid).toBe("did:key:zClientPayload");
273
+ });
274
+ });
275
+
276
+ describe("Proof Verification", () => {
277
+ it("should verify valid proof structure", async () => {
278
+ const request: ToolRequest = {
279
+ method: "test-tool",
280
+ params: { input: "hello" },
281
+ };
282
+ const response: ToolResponse = { data: { output: "world" } };
283
+
284
+ const proof = await proofGenerator.generateProof(
285
+ request,
286
+ response,
287
+ mockSession
288
+ );
289
+ const isValid = await proofGenerator.verifyProof(
290
+ proof,
291
+ request,
292
+ response
293
+ );
294
+
295
+ expect(isValid).toBe(true);
296
+ });
297
+
298
+ it("should reject proof with mismatched request", async () => {
299
+ const request1: ToolRequest = {
300
+ method: "test-tool",
301
+ params: { input: "hello" },
302
+ };
303
+ const request2: ToolRequest = {
304
+ method: "test-tool",
305
+ params: { input: "goodbye" },
306
+ };
307
+ const response: ToolResponse = { data: { output: "world" } };
308
+
309
+ const proof = await proofGenerator.generateProof(
310
+ request1,
311
+ response,
312
+ mockSession
313
+ );
314
+ const isValid = await proofGenerator.verifyProof(
315
+ proof,
316
+ request2,
317
+ response
318
+ );
319
+
320
+ expect(isValid).toBe(false);
321
+ });
322
+
323
+ it("should reject proof with mismatched response", async () => {
324
+ const request: ToolRequest = {
325
+ method: "test-tool",
326
+ params: { input: "hello" },
327
+ };
328
+ const response1: ToolResponse = { data: { output: "world" } };
329
+ const response2: ToolResponse = { data: { output: "universe" } };
330
+
331
+ const proof = await proofGenerator.generateProof(
332
+ request,
333
+ response1,
334
+ mockSession
335
+ );
336
+ const isValid = await proofGenerator.verifyProof(
337
+ proof,
338
+ request,
339
+ response2
340
+ );
341
+
342
+ expect(isValid).toBe(false);
343
+ });
344
+ });
345
+
346
+ describe("JSON Canonicalization", () => {
347
+ it("should canonicalize objects with sorted keys", () => {
348
+ const canonical = extractCanonicalData(
349
+ { method: "test", params: { b: 2, a: 1 } },
350
+ { data: { z: 26, a: 1 } }
351
+ );
352
+
353
+ expect(canonical.request).toEqual({
354
+ method: "test",
355
+ params: { b: 2, a: 1 },
356
+ });
357
+ expect(canonical.response).toEqual({ z: 26, a: 1 });
358
+ });
359
+ });
360
+ });
361
+
362
+ describe("Utility Functions", () => {
363
+ describe("createProofResponse", () => {
364
+ it("should create response with proof metadata", async () => {
365
+ const mockIdentity = await makeIdentity();
366
+ const mockSession = makeSession();
367
+ const request: ToolRequest = {
368
+ method: "test-tool",
369
+ params: { input: "hello" },
370
+ };
371
+ const data = { output: "world" };
372
+
373
+ const response = await createProofResponse(
374
+ request,
375
+ data,
376
+ mockIdentity,
377
+ mockSession,
378
+ cryptoProvider
379
+ );
380
+
381
+ expect(response.data).toEqual(data);
382
+ expect(response.meta?.proof).toBeDefined();
383
+ expect(response.meta?.proof?.meta.did).toBe(mockIdentity.did);
384
+ expect(response.meta?.proof?.jws).toBeTruthy();
385
+ });
386
+
387
+ it("should include optional proof options", async () => {
388
+ const mockIdentity = await makeIdentity();
389
+ const mockSession = makeSession();
390
+ const request: ToolRequest = {
391
+ method: "test-tool",
392
+ params: { input: "hello" },
393
+ };
394
+ const data = { output: "world" };
395
+
396
+ const response = await createProofResponse(
397
+ request,
398
+ data,
399
+ mockIdentity,
400
+ mockSession,
401
+ cryptoProvider,
402
+ { scopeId: "orders.create" }
403
+ );
404
+
405
+ expect(response.meta?.proof?.meta.scopeId).toBe("orders.create");
406
+ });
407
+ });
408
+ });
409
+
410
+ describe("RFC 8785 JCS Compliance", () => {
411
+ describe("Key Ordering", () => {
412
+ it("should sort object keys lexicographically", () => {
413
+ const obj = { z: 26, a: 1, m: 13 };
414
+ const result = canonicalize(obj);
415
+ expect(result).toBe('{"a":1,"m":13,"z":26}');
416
+ });
417
+ });
418
+
419
+ describe("Determinism", () => {
420
+ it("should produce identical output for same input", () => {
421
+ const obj = {
422
+ method: "test",
423
+ params: { nested: { z: 3, a: 1 }, array: [1, 2, 3] },
424
+ timestamp: 1234567890,
425
+ };
426
+ const result1 = canonicalize(obj);
427
+ const result2 = canonicalize(obj);
428
+ expect(result1).toBe(result2);
429
+ });
430
+
431
+ it("should produce identical output regardless of property order", () => {
432
+ const obj1 = { a: 1, b: 2, c: 3 };
433
+ const obj2 = { c: 3, a: 1, b: 2 };
434
+ const obj3 = { b: 2, c: 3, a: 1 };
435
+
436
+ expect(canonicalize(obj1)).toBe(canonicalize(obj2));
437
+ expect(canonicalize(obj2)).toBe(canonicalize(obj3));
438
+ });
439
+ });
440
+ });
441
+
442
+ describe("Cross-Package Verification β€” key ordering and Unicode", () => {
443
+ let mockIdentity: ProofAgentIdentity;
444
+ let mockSession: SessionContext;
445
+
446
+ beforeEach(async () => {
447
+ mockIdentity = await makeIdentity();
448
+ mockSession = makeSession();
449
+ });
450
+
451
+ it("should produce identical hashes for key-reordered requests", async () => {
452
+ const pg = new ProofGenerator(mockIdentity, cryptoProvider);
453
+ const response: ToolResponse = { data: { output: "world" } };
454
+
455
+ const proof1 = await pg.generateProof(
456
+ { method: "test-tool", params: { z: 26, a: 1, m: 13 } },
457
+ response,
458
+ mockSession
459
+ );
460
+ const proof2 = await pg.generateProof(
461
+ { method: "test-tool", params: { a: 1, m: 13, z: 26 } },
462
+ response,
463
+ mockSession
464
+ );
465
+
466
+ expect(proof1.meta.requestHash).toBe(proof2.meta.requestHash);
467
+ });
468
+
469
+ it("should handle Unicode and special characters consistently", async () => {
470
+ const pg = new ProofGenerator(mockIdentity, cryptoProvider);
471
+ const request: ToolRequest = {
472
+ method: "test-tool",
473
+ params: { emoji: "πŸŽ‰", text: "Hello δΈ–η•Œ", special: "\u0000\u001f" },
474
+ };
475
+ const response: ToolResponse = { data: { output: "🌍" } };
476
+
477
+ const proof1 = await pg.generateProof(request, response, mockSession);
478
+ const proof2 = await pg.generateProof(request, response, mockSession);
479
+
480
+ expect(proof1.meta.requestHash).toBe(proof2.meta.requestHash);
481
+ expect(proof1.meta.responseHash).toBe(proof2.meta.responseHash);
482
+ });
483
+ });