@weave_protocol/domere 1.0.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 (104) hide show
  1. package/PLANNING.md +231 -0
  2. package/README.md +50 -0
  3. package/dist/anchoring/ethereum.d.ts +135 -0
  4. package/dist/anchoring/ethereum.d.ts.map +1 -0
  5. package/dist/anchoring/ethereum.js +474 -0
  6. package/dist/anchoring/ethereum.js.map +1 -0
  7. package/dist/anchoring/index.d.ts +93 -0
  8. package/dist/anchoring/index.d.ts.map +1 -0
  9. package/dist/anchoring/index.js +184 -0
  10. package/dist/anchoring/index.js.map +1 -0
  11. package/dist/anchoring/merkle.d.ts +91 -0
  12. package/dist/anchoring/merkle.d.ts.map +1 -0
  13. package/dist/anchoring/merkle.js +203 -0
  14. package/dist/anchoring/merkle.js.map +1 -0
  15. package/dist/anchoring/solana.d.ts +85 -0
  16. package/dist/anchoring/solana.d.ts.map +1 -0
  17. package/dist/anchoring/solana.js +301 -0
  18. package/dist/anchoring/solana.js.map +1 -0
  19. package/dist/constants.d.ts +130 -0
  20. package/dist/constants.d.ts.map +1 -0
  21. package/dist/constants.js +536 -0
  22. package/dist/constants.js.map +1 -0
  23. package/dist/index.d.ts +13 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +37 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/language/code-analyzer.d.ts +80 -0
  28. package/dist/language/code-analyzer.d.ts.map +1 -0
  29. package/dist/language/code-analyzer.js +489 -0
  30. package/dist/language/code-analyzer.js.map +1 -0
  31. package/dist/language/detector.d.ts +53 -0
  32. package/dist/language/detector.d.ts.map +1 -0
  33. package/dist/language/detector.js +248 -0
  34. package/dist/language/detector.js.map +1 -0
  35. package/dist/language/index.d.ts +61 -0
  36. package/dist/language/index.d.ts.map +1 -0
  37. package/dist/language/index.js +109 -0
  38. package/dist/language/index.js.map +1 -0
  39. package/dist/language/nl-analyzer.d.ts +59 -0
  40. package/dist/language/nl-analyzer.d.ts.map +1 -0
  41. package/dist/language/nl-analyzer.js +350 -0
  42. package/dist/language/nl-analyzer.js.map +1 -0
  43. package/dist/language/semantic.d.ts +48 -0
  44. package/dist/language/semantic.d.ts.map +1 -0
  45. package/dist/language/semantic.js +329 -0
  46. package/dist/language/semantic.js.map +1 -0
  47. package/dist/storage/index.d.ts +6 -0
  48. package/dist/storage/index.d.ts.map +1 -0
  49. package/dist/storage/index.js +6 -0
  50. package/dist/storage/index.js.map +1 -0
  51. package/dist/storage/memory.d.ts +48 -0
  52. package/dist/storage/memory.d.ts.map +1 -0
  53. package/dist/storage/memory.js +211 -0
  54. package/dist/storage/memory.js.map +1 -0
  55. package/dist/thread/drift.d.ts +43 -0
  56. package/dist/thread/drift.d.ts.map +1 -0
  57. package/dist/thread/drift.js +248 -0
  58. package/dist/thread/drift.js.map +1 -0
  59. package/dist/thread/index.d.ts +9 -0
  60. package/dist/thread/index.d.ts.map +1 -0
  61. package/dist/thread/index.js +9 -0
  62. package/dist/thread/index.js.map +1 -0
  63. package/dist/thread/intent.d.ts +68 -0
  64. package/dist/thread/intent.d.ts.map +1 -0
  65. package/dist/thread/intent.js +333 -0
  66. package/dist/thread/intent.js.map +1 -0
  67. package/dist/thread/manager.d.ts +85 -0
  68. package/dist/thread/manager.d.ts.map +1 -0
  69. package/dist/thread/manager.js +305 -0
  70. package/dist/thread/manager.js.map +1 -0
  71. package/dist/thread/weave.d.ts +61 -0
  72. package/dist/thread/weave.d.ts.map +1 -0
  73. package/dist/thread/weave.js +158 -0
  74. package/dist/thread/weave.js.map +1 -0
  75. package/dist/tools/index.d.ts +18 -0
  76. package/dist/tools/index.d.ts.map +1 -0
  77. package/dist/tools/index.js +102 -0
  78. package/dist/tools/index.js.map +1 -0
  79. package/dist/types.d.ts +466 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +48 -0
  82. package/dist/types.js.map +1 -0
  83. package/package.json +24 -0
  84. package/src/anchoring/ethereum.ts +568 -0
  85. package/src/anchoring/index.ts +236 -0
  86. package/src/anchoring/merkle.ts +256 -0
  87. package/src/anchoring/solana.ts +370 -0
  88. package/src/constants.ts +566 -0
  89. package/src/index.ts +43 -0
  90. package/src/language/code-analyzer.ts +564 -0
  91. package/src/language/detector.ts +297 -0
  92. package/src/language/index.ts +129 -0
  93. package/src/language/nl-analyzer.ts +411 -0
  94. package/src/language/semantic.ts +385 -0
  95. package/src/storage/index.ts +6 -0
  96. package/src/storage/memory.ts +271 -0
  97. package/src/thread/drift.ts +319 -0
  98. package/src/thread/index.ts +9 -0
  99. package/src/thread/intent.ts +409 -0
  100. package/src/thread/manager.ts +414 -0
  101. package/src/thread/weave.ts +205 -0
  102. package/src/tools/index.ts +107 -0
  103. package/src/types.ts +736 -0
  104. package/tsconfig.json +19 -0
@@ -0,0 +1,414 @@
1
+ /**
2
+ * Dōmere - The Judge Protocol
3
+ * Thread Manager
4
+ */
5
+
6
+ import * as crypto from 'crypto';
7
+ import type {
8
+ Thread,
9
+ ThreadOrigin,
10
+ ThreadIntent,
11
+ ThreadHop,
12
+ ThreadStatus,
13
+ IDomereStorage,
14
+ AgentInfo,
15
+ HopAction,
16
+ DriftAnalysis,
17
+ LanguageAnalysis,
18
+ SecurityScanResult,
19
+ } from '../types.js';
20
+ import { ThreadError } from '../types.js';
21
+ import { LanguageAnalyzerService } from '../language/index.js';
22
+ import { IntentAnalyzer } from './intent.js';
23
+ import { DriftDetector } from './drift.js';
24
+ import { WeaveSignature } from './weave.js';
25
+
26
+ // ============================================================================
27
+ // Thread Manager
28
+ // ============================================================================
29
+
30
+ export class ThreadManager {
31
+ private storage: IDomereStorage;
32
+ private languageAnalyzer: LanguageAnalyzerService;
33
+ private intentAnalyzer: IntentAnalyzer;
34
+ private driftDetector: DriftDetector;
35
+ private weaveSignature: WeaveSignature;
36
+
37
+ constructor(storage: IDomereStorage) {
38
+ this.storage = storage;
39
+ this.languageAnalyzer = new LanguageAnalyzerService();
40
+ this.intentAnalyzer = new IntentAnalyzer();
41
+ this.driftDetector = new DriftDetector();
42
+ this.weaveSignature = new WeaveSignature();
43
+ }
44
+
45
+ /**
46
+ * Create a new thread
47
+ */
48
+ async createThread(config: {
49
+ origin: Omit<ThreadOrigin, 'timestamp'>;
50
+ intent: string;
51
+ constraints?: string[];
52
+ metadata?: Record<string, unknown>;
53
+ }): Promise<Thread> {
54
+ const now = new Date();
55
+ const threadId = this.generateThreadId();
56
+
57
+ // Analyze the intent
58
+ const intentAnalysis = this.intentAnalyzer.analyze(config.intent);
59
+ const languageAnalysis = this.languageAnalyzer.analyze(config.intent);
60
+
61
+ const intent: ThreadIntent = {
62
+ raw: config.intent,
63
+ hash: this.hashContent(config.intent),
64
+ normalized: intentAnalysis.normalized,
65
+ classification: languageAnalysis.semantic?.intent_classification || 'unknown',
66
+ constraints: config.constraints || [],
67
+ entities: languageAnalysis.semantic?.entities || [],
68
+ actions_implied: languageAnalysis.semantic?.actions_implied || [],
69
+ language_analysis: languageAnalysis,
70
+ };
71
+
72
+ const origin: ThreadOrigin = {
73
+ ...config.origin,
74
+ timestamp: now,
75
+ };
76
+
77
+ // Create initial weave signature
78
+ const initialSignature = this.weaveSignature.createInitial({
79
+ threadId,
80
+ origin,
81
+ intent,
82
+ });
83
+
84
+ const thread: Thread = {
85
+ id: threadId,
86
+ origin,
87
+ intent,
88
+ hops: [],
89
+ weave_signature: initialSignature,
90
+ status: 'active',
91
+ created_at: now,
92
+ updated_at: now,
93
+ metadata: config.metadata || {},
94
+ };
95
+
96
+ await this.storage.saveThread(thread);
97
+
98
+ return thread;
99
+ }
100
+
101
+ /**
102
+ * Add a hop to a thread
103
+ */
104
+ async addHop(config: {
105
+ thread_id: string;
106
+ agent: AgentInfo;
107
+ received_intent: string;
108
+ actions: HopAction[];
109
+ security_scan?: SecurityScanResult;
110
+ sandbox_result?: { sandbox_id: string; result_id: string; status: string; summary: string };
111
+ }): Promise<ThreadHop> {
112
+ const thread = await this.storage.getThread(config.thread_id);
113
+ if (!thread) {
114
+ throw new ThreadError('Thread not found', { thread_id: config.thread_id });
115
+ }
116
+
117
+ if (thread.status !== 'active') {
118
+ throw new ThreadError('Thread is not active', {
119
+ thread_id: config.thread_id,
120
+ status: thread.status
121
+ });
122
+ }
123
+
124
+ const now = new Date();
125
+ const sequence = thread.hops.length + 1;
126
+ const hopId = this.generateHopId(config.thread_id, sequence);
127
+
128
+ // Analyze received intent
129
+ const languageAnalysis = this.languageAnalyzer.analyze(config.received_intent);
130
+
131
+ // Calculate previous intent for drift detection
132
+ const previousIntent = sequence === 1
133
+ ? thread.intent.raw
134
+ : thread.hops[thread.hops.length - 1].received_intent;
135
+
136
+ // Detect drift
137
+ const driftAnalysis = this.driftDetector.analyze({
138
+ original_intent: thread.intent.raw,
139
+ previous_intent: previousIntent,
140
+ current_intent: config.received_intent,
141
+ constraints: thread.intent.constraints,
142
+ hop_number: sequence,
143
+ });
144
+
145
+ // Calculate cumulative hash
146
+ const previousHash = sequence === 1
147
+ ? thread.weave_signature
148
+ : thread.hops[thread.hops.length - 1].cumulative_hash;
149
+
150
+ const hopData = {
151
+ hopId,
152
+ agent: config.agent,
153
+ received_intent: config.received_intent,
154
+ actions: config.actions,
155
+ timestamp: now,
156
+ };
157
+
158
+ const hopSignature = this.weaveSignature.signHop(hopData, previousHash);
159
+ const cumulativeHash = this.weaveSignature.computeCumulativeHash(previousHash, hopSignature);
160
+
161
+ const hop: ThreadHop = {
162
+ sequence,
163
+ hop_id: hopId,
164
+ agent: config.agent,
165
+ received_intent: config.received_intent,
166
+ received_intent_hash: this.hashContent(config.received_intent),
167
+ intent_preserved: driftAnalysis.verdict === 'aligned' || driftAnalysis.verdict === 'minor_drift',
168
+ intent_drift: driftAnalysis,
169
+ actions: config.actions,
170
+ language_analysis: languageAnalysis,
171
+ security_scan: config.security_scan,
172
+ sandbox_result: config.sandbox_result ? {
173
+ sandbox_id: config.sandbox_result.sandbox_id,
174
+ result_id: config.sandbox_result.result_id,
175
+ status: config.sandbox_result.status as 'safe' | 'review' | 'blocked',
176
+ summary: config.sandbox_result.summary,
177
+ } : undefined,
178
+ hop_signature: hopSignature,
179
+ cumulative_hash: cumulativeHash,
180
+ started_at: now,
181
+ completed_at: now,
182
+ duration_ms: 0,
183
+ status: 'success',
184
+ };
185
+
186
+ // Update thread
187
+ thread.hops.push(hop);
188
+ thread.weave_signature = cumulativeHash;
189
+ thread.updated_at = now;
190
+
191
+ // Check for violations
192
+ if (driftAnalysis.verdict === 'violated') {
193
+ thread.status = 'violated';
194
+ }
195
+
196
+ // Update merkle root
197
+ thread.merkle_root = this.computeMerkleRoot(thread.hops);
198
+
199
+ await this.storage.updateThread(thread);
200
+ await this.storage.addHop(config.thread_id, hop);
201
+
202
+ return hop;
203
+ }
204
+
205
+ /**
206
+ * Close a thread
207
+ */
208
+ async closeThread(threadId: string, outcome: 'success' | 'failure' | 'abandoned'): Promise<Thread> {
209
+ const thread = await this.storage.getThread(threadId);
210
+ if (!thread) {
211
+ throw new ThreadError('Thread not found', { thread_id: threadId });
212
+ }
213
+
214
+ const now = new Date();
215
+
216
+ thread.status = outcome === 'success' ? 'complete' :
217
+ outcome === 'failure' ? 'violated' : 'abandoned';
218
+ thread.closed_at = now;
219
+ thread.updated_at = now;
220
+
221
+ // Final merkle root
222
+ thread.merkle_root = this.computeMerkleRoot(thread.hops);
223
+
224
+ await this.storage.updateThread(thread);
225
+
226
+ return thread;
227
+ }
228
+
229
+ /**
230
+ * Get a thread
231
+ */
232
+ async getThread(threadId: string): Promise<Thread | null> {
233
+ return this.storage.getThread(threadId);
234
+ }
235
+
236
+ /**
237
+ * List threads
238
+ */
239
+ async listThreads(filters?: {
240
+ status?: ThreadStatus;
241
+ origin_type?: ThreadOrigin['type'];
242
+ origin_identity?: string;
243
+ since?: Date;
244
+ until?: Date;
245
+ limit?: number;
246
+ }): Promise<Thread[]> {
247
+ return this.storage.listThreads(filters);
248
+ }
249
+
250
+ /**
251
+ * Verify thread integrity
252
+ */
253
+ async verifyThread(threadId: string): Promise<{
254
+ valid: boolean;
255
+ errors: string[];
256
+ verified_hops: number;
257
+ total_hops: number;
258
+ }> {
259
+ const thread = await this.storage.getThread(threadId);
260
+ if (!thread) {
261
+ return { valid: false, errors: ['Thread not found'], verified_hops: 0, total_hops: 0 };
262
+ }
263
+
264
+ const errors: string[] = [];
265
+ let verifiedHops = 0;
266
+
267
+ // Verify initial signature
268
+ const expectedInitial = this.weaveSignature.createInitial({
269
+ threadId: thread.id,
270
+ origin: thread.origin,
271
+ intent: thread.intent,
272
+ });
273
+
274
+ let previousHash = expectedInitial;
275
+
276
+ // Verify each hop
277
+ for (let i = 0; i < thread.hops.length; i++) {
278
+ const hop = thread.hops[i];
279
+
280
+ // Verify sequence
281
+ if (hop.sequence !== i + 1) {
282
+ errors.push(`Hop ${i + 1} has incorrect sequence: ${hop.sequence}`);
283
+ }
284
+
285
+ // Verify hop signature
286
+ const hopData = {
287
+ hopId: hop.hop_id,
288
+ agent: hop.agent,
289
+ received_intent: hop.received_intent,
290
+ actions: hop.actions,
291
+ timestamp: hop.started_at,
292
+ };
293
+
294
+ const expectedSignature = this.weaveSignature.signHop(hopData, previousHash);
295
+ if (hop.hop_signature !== expectedSignature) {
296
+ errors.push(`Hop ${i + 1} has invalid signature`);
297
+ } else {
298
+ verifiedHops++;
299
+ }
300
+
301
+ // Verify cumulative hash
302
+ const expectedCumulative = this.weaveSignature.computeCumulativeHash(previousHash, hop.hop_signature);
303
+ if (hop.cumulative_hash !== expectedCumulative) {
304
+ errors.push(`Hop ${i + 1} has invalid cumulative hash`);
305
+ }
306
+
307
+ previousHash = hop.cumulative_hash;
308
+ }
309
+
310
+ // Verify final weave signature
311
+ if (thread.hops.length > 0) {
312
+ const lastHop = thread.hops[thread.hops.length - 1];
313
+ if (thread.weave_signature !== lastHop.cumulative_hash) {
314
+ errors.push('Thread weave signature does not match last hop');
315
+ }
316
+ }
317
+
318
+ // Verify merkle root
319
+ const expectedMerkle = this.computeMerkleRoot(thread.hops);
320
+ if (thread.merkle_root && thread.merkle_root !== expectedMerkle) {
321
+ errors.push('Thread merkle root is invalid');
322
+ }
323
+
324
+ return {
325
+ valid: errors.length === 0,
326
+ errors,
327
+ verified_hops: verifiedHops,
328
+ total_hops: thread.hops.length,
329
+ };
330
+ }
331
+
332
+ /**
333
+ * Get thread summary
334
+ */
335
+ async getThreadSummary(threadId: string): Promise<{
336
+ id: string;
337
+ status: ThreadStatus;
338
+ origin: string;
339
+ intent_summary: string;
340
+ hop_count: number;
341
+ total_drift: number;
342
+ has_violations: boolean;
343
+ duration_ms: number;
344
+ merkle_root?: string;
345
+ } | null> {
346
+ const thread = await this.storage.getThread(threadId);
347
+ if (!thread) return null;
348
+
349
+ const totalDrift = thread.hops.reduce(
350
+ (sum, hop) => sum + (hop.intent_drift?.hop_drift || 0),
351
+ 0
352
+ );
353
+
354
+ const hasViolations = thread.hops.some(
355
+ hop => hop.intent_drift?.verdict === 'violated' || hop.status !== 'success'
356
+ );
357
+
358
+ const durationMs = thread.closed_at
359
+ ? thread.closed_at.getTime() - thread.created_at.getTime()
360
+ : Date.now() - thread.created_at.getTime();
361
+
362
+ return {
363
+ id: thread.id,
364
+ status: thread.status,
365
+ origin: `${thread.origin.type}:${thread.origin.identity}`,
366
+ intent_summary: thread.intent.raw.slice(0, 100),
367
+ hop_count: thread.hops.length,
368
+ total_drift: totalDrift,
369
+ has_violations: hasViolations,
370
+ duration_ms: durationMs,
371
+ merkle_root: thread.merkle_root,
372
+ };
373
+ }
374
+
375
+ // ============================================================================
376
+ // Private Methods
377
+ // ============================================================================
378
+
379
+ private generateThreadId(): string {
380
+ return `thr_${crypto.randomBytes(12).toString('hex')}`;
381
+ }
382
+
383
+ private generateHopId(threadId: string, sequence: number): string {
384
+ return `hop_${crypto.randomBytes(8).toString('hex')}_${sequence}`;
385
+ }
386
+
387
+ private hashContent(content: string): string {
388
+ return crypto.createHash('sha256').update(content).digest('hex');
389
+ }
390
+
391
+ private computeMerkleRoot(hops: ThreadHop[]): string {
392
+ if (hops.length === 0) {
393
+ return this.hashContent('empty');
394
+ }
395
+
396
+ // Get leaf hashes
397
+ let hashes = hops.map(hop => hop.hop_signature);
398
+
399
+ // Build tree
400
+ while (hashes.length > 1) {
401
+ const newLevel: string[] = [];
402
+ for (let i = 0; i < hashes.length; i += 2) {
403
+ if (i + 1 < hashes.length) {
404
+ newLevel.push(this.hashContent(hashes[i] + hashes[i + 1]));
405
+ } else {
406
+ newLevel.push(hashes[i]); // Odd one out
407
+ }
408
+ }
409
+ hashes = newLevel;
410
+ }
411
+
412
+ return hashes[0];
413
+ }
414
+ }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Dōmere - The Judge Protocol
3
+ * Weave Signature - Cryptographic thread verification
4
+ */
5
+
6
+ import * as crypto from 'crypto';
7
+ import type { ThreadOrigin, ThreadIntent, AgentInfo, HopAction } from '../types.js';
8
+
9
+ // ============================================================================
10
+ // Weave Signature
11
+ // ============================================================================
12
+
13
+ export class WeaveSignature {
14
+ private algorithm: string = 'sha256';
15
+
16
+ /**
17
+ * Create initial thread signature
18
+ */
19
+ createInitial(data: {
20
+ threadId: string;
21
+ origin: ThreadOrigin;
22
+ intent: ThreadIntent;
23
+ }): string {
24
+ const canonical = this.canonicalize({
25
+ type: 'thread_init',
26
+ thread_id: data.threadId,
27
+ origin: {
28
+ type: data.origin.type,
29
+ identity: data.origin.identity,
30
+ timestamp: data.origin.timestamp.toISOString(),
31
+ },
32
+ intent: {
33
+ hash: data.intent.hash,
34
+ classification: data.intent.classification,
35
+ constraints: data.intent.constraints,
36
+ },
37
+ });
38
+
39
+ return this.hash(canonical);
40
+ }
41
+
42
+ /**
43
+ * Sign a hop
44
+ */
45
+ signHop(data: {
46
+ hopId: string;
47
+ agent: AgentInfo;
48
+ received_intent: string;
49
+ actions: HopAction[];
50
+ timestamp: Date;
51
+ }, previousHash: string): string {
52
+ const canonical = this.canonicalize({
53
+ type: 'hop',
54
+ hop_id: data.hopId,
55
+ previous_hash: previousHash,
56
+ agent: {
57
+ id: data.agent.id,
58
+ type: data.agent.type,
59
+ },
60
+ received_intent_hash: this.hash(data.received_intent),
61
+ actions_hash: this.hashActions(data.actions),
62
+ timestamp: data.timestamp.toISOString(),
63
+ });
64
+
65
+ return this.hash(canonical);
66
+ }
67
+
68
+ /**
69
+ * Compute cumulative hash
70
+ */
71
+ computeCumulativeHash(previousHash: string, currentSignature: string): string {
72
+ return this.hash(`${previousHash}:${currentSignature}`);
73
+ }
74
+
75
+ /**
76
+ * Verify a signature chain
77
+ */
78
+ verifyChain(signatures: string[]): boolean {
79
+ if (signatures.length < 2) return true;
80
+ const unique = new Set(signatures);
81
+ return unique.size === signatures.length;
82
+ }
83
+
84
+ /**
85
+ * Generate Merkle root from hop signatures
86
+ */
87
+ generateMerkleRoot(signatures: string[]): string {
88
+ if (signatures.length === 0) {
89
+ return this.hash('empty');
90
+ }
91
+
92
+ let hashes = [...signatures];
93
+
94
+ while (hashes.length > 1) {
95
+ const newLevel: string[] = [];
96
+ for (let i = 0; i < hashes.length; i += 2) {
97
+ if (i + 1 < hashes.length) {
98
+ newLevel.push(this.hash(hashes[i] + hashes[i + 1]));
99
+ } else {
100
+ newLevel.push(hashes[i]);
101
+ }
102
+ }
103
+ hashes = newLevel;
104
+ }
105
+
106
+ return hashes[0];
107
+ }
108
+
109
+ /**
110
+ * Generate Merkle proof for a specific leaf
111
+ */
112
+ generateMerkleProof(signatures: string[], leafIndex: number): string[] {
113
+ if (leafIndex < 0 || leafIndex >= signatures.length) {
114
+ return [];
115
+ }
116
+
117
+ const proof: string[] = [];
118
+ let hashes = [...signatures];
119
+ let index = leafIndex;
120
+
121
+ while (hashes.length > 1) {
122
+ const newLevel: string[] = [];
123
+
124
+ for (let i = 0; i < hashes.length; i += 2) {
125
+ if (i + 1 < hashes.length) {
126
+ if (i === index || i + 1 === index) {
127
+ const siblingIndex = i === index ? i + 1 : i;
128
+ proof.push(hashes[siblingIndex]);
129
+ }
130
+ newLevel.push(this.hash(hashes[i] + hashes[i + 1]));
131
+ } else {
132
+ newLevel.push(hashes[i]);
133
+ }
134
+ }
135
+
136
+ index = Math.floor(index / 2);
137
+ hashes = newLevel;
138
+ }
139
+
140
+ return proof;
141
+ }
142
+
143
+ /**
144
+ * Verify Merkle proof
145
+ */
146
+ verifyMerkleProof(
147
+ leaf: string,
148
+ proof: string[],
149
+ root: string,
150
+ leafIndex: number
151
+ ): boolean {
152
+ let hash = leaf;
153
+ let index = leafIndex;
154
+
155
+ for (const sibling of proof) {
156
+ if (index % 2 === 0) {
157
+ hash = this.hash(hash + sibling);
158
+ } else {
159
+ hash = this.hash(sibling + hash);
160
+ }
161
+ index = Math.floor(index / 2);
162
+ }
163
+
164
+ return hash === root;
165
+ }
166
+
167
+ /**
168
+ * Create a thread summary hash for anchoring
169
+ */
170
+ createAnchorHash(data: {
171
+ threadId: string;
172
+ merkleRoot: string;
173
+ hopCount: number;
174
+ intentHash: string;
175
+ compliant: boolean;
176
+ closedAt: Date;
177
+ }): string {
178
+ const canonical = this.canonicalize({
179
+ type: 'anchor',
180
+ thread_id: data.threadId,
181
+ merkle_root: data.merkleRoot,
182
+ hop_count: data.hopCount,
183
+ intent_hash: data.intentHash,
184
+ compliant: data.compliant,
185
+ closed_at: data.closedAt.toISOString(),
186
+ });
187
+
188
+ return this.hash(canonical);
189
+ }
190
+
191
+ private hash(data: string): string {
192
+ return crypto.createHash(this.algorithm).update(data).digest('hex');
193
+ }
194
+
195
+ private canonicalize(obj: unknown): string {
196
+ return JSON.stringify(obj, Object.keys(obj as object).sort());
197
+ }
198
+
199
+ private hashActions(actions: HopAction[]): string {
200
+ const actionStrings = actions.map(a =>
201
+ `${a.type}:${a.target || ''}:${a.description}`
202
+ );
203
+ return this.hash(actionStrings.join('|'));
204
+ }
205
+ }