@highway1/core 0.1.39 → 0.1.41

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.
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Endorsement System
3
+ *
4
+ * Allows agents to endorse each other, building a web of trust
5
+ */
6
+
7
+ import type { Level } from 'level';
8
+ import { createLogger } from '../utils/logger.js';
9
+
10
+ const logger = createLogger('endorsement');
11
+
12
+ /**
13
+ * Endorsement Record
14
+ */
15
+ export interface Endorsement {
16
+ from: string; // Endorser DID
17
+ to: string; // Endorsed agent DID
18
+ score: number; // 0-1
19
+ reason: string;
20
+ timestamp: number;
21
+ signature: string; // Signed by endorser
22
+ }
23
+
24
+ /**
25
+ * Sign function type
26
+ */
27
+ export type SignFunction = (data: Uint8Array) => Promise<Uint8Array>;
28
+
29
+ /**
30
+ * Verify function type
31
+ */
32
+ export type VerifyFunction = (signature: Uint8Array, data: Uint8Array, publicKey: Uint8Array) => Promise<boolean>;
33
+
34
+ /**
35
+ * Endorsement Manager
36
+ */
37
+ export class EndorsementManager {
38
+ constructor(
39
+ private db: Level<string, Endorsement>,
40
+ private getPublicKey: (did: string) => Promise<Uint8Array>
41
+ ) {}
42
+
43
+ /**
44
+ * Create an endorsement
45
+ */
46
+ async endorse(
47
+ fromDid: string,
48
+ toDid: string,
49
+ score: number,
50
+ reason: string,
51
+ signFn: SignFunction
52
+ ): Promise<Endorsement> {
53
+ if (score < 0 || score > 1) {
54
+ throw new Error('Score must be between 0 and 1');
55
+ }
56
+
57
+ const endorsement: Omit<Endorsement, 'signature'> = {
58
+ from: fromDid,
59
+ to: toDid,
60
+ score,
61
+ reason,
62
+ timestamp: Date.now(),
63
+ };
64
+
65
+ // Sign the endorsement
66
+ const data = new TextEncoder().encode(JSON.stringify(endorsement));
67
+ const signatureBytes = await signFn(data);
68
+ const signature = Buffer.from(signatureBytes).toString('hex');
69
+
70
+ const signedEndorsement: Endorsement = {
71
+ ...endorsement,
72
+ signature,
73
+ };
74
+
75
+ logger.info('Created endorsement', { from: fromDid, to: toDid, score });
76
+ return signedEndorsement;
77
+ }
78
+
79
+ /**
80
+ * Verify endorsement signature
81
+ */
82
+ async verify(endorsement: Endorsement, verifyFn: VerifyFunction): Promise<boolean> {
83
+ try {
84
+ const { signature, ...endorsementWithoutSig } = endorsement;
85
+ const data = new TextEncoder().encode(JSON.stringify(endorsementWithoutSig));
86
+ const signatureBytes = Buffer.from(signature, 'hex');
87
+ const publicKey = await this.getPublicKey(endorsement.from);
88
+
89
+ return await verifyFn(signatureBytes, data, publicKey);
90
+ } catch (error) {
91
+ logger.error('Failed to verify endorsement', { error });
92
+ return false;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Publish endorsement to local database
98
+ */
99
+ async publish(endorsement: Endorsement): Promise<void> {
100
+ const key = `endorsement:${endorsement.to}:${endorsement.from}`;
101
+ await this.db.put(key, endorsement);
102
+ logger.info('Published endorsement', { from: endorsement.from, to: endorsement.to });
103
+ }
104
+
105
+ /**
106
+ * Get all endorsements for an agent
107
+ */
108
+ async getEndorsements(agentDid: string): Promise<Endorsement[]> {
109
+ const endorsements: Endorsement[] = [];
110
+ const prefix = `endorsement:${agentDid}:`;
111
+
112
+ try {
113
+ for await (const [_, value] of this.db.iterator({
114
+ gte: prefix,
115
+ lte: prefix + '\xff',
116
+ })) {
117
+ endorsements.push(value);
118
+ }
119
+ } catch (error) {
120
+ logger.error('Failed to get endorsements', { agentDid, error });
121
+ }
122
+
123
+ return endorsements;
124
+ }
125
+
126
+ /**
127
+ * Get endorsements given by an agent
128
+ */
129
+ async getEndorsementsBy(fromDid: string): Promise<Endorsement[]> {
130
+ const endorsements: Endorsement[] = [];
131
+
132
+ try {
133
+ for await (const [_, value] of this.db.iterator()) {
134
+ if (value.from === fromDid) {
135
+ endorsements.push(value);
136
+ }
137
+ }
138
+ } catch (error) {
139
+ logger.error('Failed to get endorsements by agent', { fromDid, error });
140
+ }
141
+
142
+ return endorsements;
143
+ }
144
+
145
+ /**
146
+ * Calculate average endorsement score
147
+ */
148
+ async getAverageScore(agentDid: string): Promise<number> {
149
+ const endorsements = await this.getEndorsements(agentDid);
150
+
151
+ if (endorsements.length === 0) {
152
+ return 0;
153
+ }
154
+
155
+ const totalScore = endorsements.reduce((sum, e) => sum + e.score, 0);
156
+ return totalScore / endorsements.length;
157
+ }
158
+
159
+ /**
160
+ * Delete an endorsement
161
+ */
162
+ async deleteEndorsement(fromDid: string, toDid: string): Promise<void> {
163
+ const key = `endorsement:${toDid}:${fromDid}`;
164
+ await this.db.del(key);
165
+ logger.info('Deleted endorsement', { from: fromDid, to: toDid });
166
+ }
167
+ }
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Trust System - Main Export
3
+ *
4
+ * Combines all trust components into a unified interface
5
+ */
6
+
7
+ export * from './trust-score.js';
8
+ export * from './interaction-history.js';
9
+ export * from './endorsement.js';
10
+ export * from './sybil-defense.js';
11
+
12
+ import { Level } from 'level';
13
+ import { TrustMetrics } from './trust-score.js';
14
+ import type { TrustScore, Interaction } from './trust-score.js';
15
+ import { InteractionHistory } from './interaction-history.js';
16
+ import { EndorsementManager } from './endorsement.js';
17
+ import type { Endorsement, SignFunction, VerifyFunction } from './endorsement.js';
18
+ import { SybilDefense } from './sybil-defense.js';
19
+ import { createLogger } from '../utils/logger.js';
20
+
21
+ const logger = createLogger('trust-system');
22
+
23
+ /**
24
+ * Trust System Configuration
25
+ */
26
+ export interface TrustSystemConfig {
27
+ dbPath: string;
28
+ getPublicKey: (did: string) => Promise<Uint8Array>;
29
+ }
30
+
31
+ /**
32
+ * Unified Trust System
33
+ */
34
+ export class TrustSystem {
35
+ private metrics: TrustMetrics;
36
+ private history: InteractionHistory;
37
+ private endorsements: EndorsementManager;
38
+ private sybilDefense: SybilDefense;
39
+ private trustCache = new Map<string, { score: TrustScore; timestamp: number }>();
40
+ private readonly CACHE_TTL = 5 * 60 * 1000; // 5 minutes
41
+
42
+ constructor(config: TrustSystemConfig) {
43
+ this.metrics = new TrustMetrics();
44
+ this.history = new InteractionHistory(`${config.dbPath}/interactions`);
45
+
46
+ const endorsementDb = new Level<string, Endorsement>(`${config.dbPath}/endorsements`, {
47
+ valueEncoding: 'json',
48
+ });
49
+ this.endorsements = new EndorsementManager(endorsementDb, config.getPublicKey);
50
+ this.sybilDefense = new SybilDefense();
51
+ }
52
+
53
+ /**
54
+ * Initialize the trust system
55
+ */
56
+ async start(): Promise<void> {
57
+ await this.history.open();
58
+ logger.info('Trust system started');
59
+ }
60
+
61
+ /**
62
+ * Shutdown the trust system
63
+ */
64
+ async stop(): Promise<void> {
65
+ await this.history.close();
66
+ logger.info('Trust system stopped');
67
+ }
68
+
69
+ /**
70
+ * Record an interaction
71
+ */
72
+ async recordInteraction(interaction: Interaction): Promise<void> {
73
+ await this.history.record(interaction);
74
+ this.sybilDefense.recordRequest(interaction.agentDid);
75
+
76
+ // Invalidate cache
77
+ this.trustCache.delete(interaction.agentDid);
78
+ }
79
+
80
+ /**
81
+ * Get trust score for an agent
82
+ */
83
+ async getTrustScore(agentDid: string): Promise<TrustScore> {
84
+ // Check cache
85
+ const cached = this.trustCache.get(agentDid);
86
+ if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
87
+ return cached.score;
88
+ }
89
+
90
+ // Calculate fresh score
91
+ const stats = await this.history.getStats(agentDid);
92
+ const endorsementList = await this.endorsements.getEndorsements(agentDid);
93
+ const uptime = 1.0; // TODO: Implement uptime tracking
94
+
95
+ const score = this.metrics.calculateScore(stats, endorsementList.length, uptime);
96
+
97
+ // Cache result
98
+ this.trustCache.set(agentDid, { score, timestamp: Date.now() });
99
+
100
+ return score;
101
+ }
102
+
103
+ /**
104
+ * Create an endorsement
105
+ */
106
+ async endorse(
107
+ fromDid: string,
108
+ toDid: string,
109
+ score: number,
110
+ reason: string,
111
+ signFn: SignFunction
112
+ ): Promise<Endorsement> {
113
+ const endorsement = await this.endorsements.endorse(fromDid, toDid, score, reason, signFn);
114
+ await this.endorsements.publish(endorsement);
115
+
116
+ // Invalidate cache
117
+ this.trustCache.delete(toDid);
118
+
119
+ return endorsement;
120
+ }
121
+
122
+ /**
123
+ * Get endorsements for an agent
124
+ */
125
+ async getEndorsements(agentDid: string): Promise<Endorsement[]> {
126
+ return this.endorsements.getEndorsements(agentDid);
127
+ }
128
+
129
+ /**
130
+ * Verify an endorsement
131
+ */
132
+ async verifyEndorsement(endorsement: Endorsement, verifyFn: VerifyFunction): Promise<boolean> {
133
+ return this.endorsements.verify(endorsement, verifyFn);
134
+ }
135
+
136
+ /**
137
+ * Check if agent should be rate limited
138
+ */
139
+ isRateLimited(agentDid: string): boolean {
140
+ return this.sybilDefense.isRateLimited(agentDid);
141
+ }
142
+
143
+ /**
144
+ * Generate Sybil defense challenge
145
+ */
146
+ generateChallenge(did: string, difficulty?: number) {
147
+ return this.sybilDefense.generateChallenge(did, difficulty);
148
+ }
149
+
150
+ /**
151
+ * Verify Sybil defense challenge
152
+ */
153
+ verifyChallenge(solution: any): boolean {
154
+ return this.sybilDefense.verifyChallenge(solution);
155
+ }
156
+
157
+ /**
158
+ * Get peer trust level
159
+ */
160
+ getPeerTrustLevel(peerId: string) {
161
+ return this.sybilDefense.getPeerTrustLevel(peerId);
162
+ }
163
+
164
+ /**
165
+ * Record peer seen
166
+ */
167
+ recordPeerSeen(peerId: string): void {
168
+ this.sybilDefense.recordPeerSeen(peerId);
169
+ }
170
+
171
+ /**
172
+ * Get interaction history
173
+ */
174
+ async getHistory(agentDid: string, limit?: number): Promise<Interaction[]> {
175
+ return this.history.getHistory(agentDid, limit);
176
+ }
177
+
178
+ /**
179
+ * Clean up old data
180
+ */
181
+ async cleanup(): Promise<void> {
182
+ await this.history.cleanup();
183
+ this.sybilDefense.cleanup();
184
+ this.trustCache.clear();
185
+ logger.info('Trust system cleanup completed');
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Create a trust system instance
191
+ */
192
+ export function createTrustSystem(config: TrustSystemConfig): TrustSystem {
193
+ return new TrustSystem(config);
194
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Interaction History Tracker
3
+ *
4
+ * Records and queries agent interaction history for trust scoring
5
+ */
6
+
7
+ import { Level } from 'level';
8
+ import type { Interaction, InteractionStats } from './trust-score.js';
9
+ import { createLogger } from '../utils/logger.js';
10
+
11
+ const logger = createLogger('interaction-history');
12
+
13
+ /**
14
+ * Interaction History Manager
15
+ */
16
+ export class InteractionHistory {
17
+ private db: Level<string, Interaction>;
18
+
19
+ constructor(dbPath: string) {
20
+ this.db = new Level(dbPath, { valueEncoding: 'json' });
21
+ }
22
+
23
+ /**
24
+ * Open database connection
25
+ */
26
+ async open(): Promise<void> {
27
+ await this.db.open();
28
+ logger.info('Interaction history database opened', { path: this.db.location });
29
+ }
30
+
31
+ /**
32
+ * Close database connection
33
+ */
34
+ async close(): Promise<void> {
35
+ await this.db.close();
36
+ logger.info('Interaction history database closed');
37
+ }
38
+
39
+ /**
40
+ * Record an interaction
41
+ */
42
+ async record(interaction: Interaction): Promise<void> {
43
+ const key = `interaction:${interaction.agentDid}:${interaction.timestamp}`;
44
+ await this.db.put(key, interaction);
45
+ logger.debug('Recorded interaction', { agentDid: interaction.agentDid, type: interaction.type });
46
+ }
47
+
48
+ /**
49
+ * Get interaction history for an agent
50
+ */
51
+ async getHistory(agentDid: string, limit = 100): Promise<Interaction[]> {
52
+ const interactions: Interaction[] = [];
53
+ const prefix = `interaction:${agentDid}:`;
54
+
55
+ try {
56
+ for await (const [_, value] of this.db.iterator({
57
+ gte: prefix,
58
+ lte: prefix + '\xff',
59
+ limit,
60
+ reverse: true, // Most recent first
61
+ })) {
62
+ interactions.push(value);
63
+ }
64
+ } catch (error) {
65
+ logger.error('Failed to get interaction history', { agentDid, error });
66
+ }
67
+
68
+ return interactions;
69
+ }
70
+
71
+ /**
72
+ * Get interaction statistics for an agent
73
+ */
74
+ async getStats(agentDid: string): Promise<InteractionStats> {
75
+ const history = await this.getHistory(agentDid, 1000); // Last 1000 interactions
76
+
77
+ if (history.length === 0) {
78
+ return {
79
+ totalInteractions: 0,
80
+ successRate: 0,
81
+ avgResponseTime: 0,
82
+ lastInteraction: 0,
83
+ };
84
+ }
85
+
86
+ const successCount = history.filter(i => i.success).length;
87
+ const totalResponseTime = history.reduce((sum, i) => sum + i.responseTime, 0);
88
+
89
+ return {
90
+ totalInteractions: history.length,
91
+ successRate: successCount / history.length,
92
+ avgResponseTime: totalResponseTime / history.length,
93
+ lastInteraction: history[0].timestamp,
94
+ };
95
+ }
96
+
97
+ /**
98
+ * Get all agents with interaction history
99
+ */
100
+ async getAllAgents(): Promise<string[]> {
101
+ const agents = new Set<string>();
102
+
103
+ try {
104
+ for await (const [key] of this.db.iterator()) {
105
+ const match = key.match(/^interaction:([^:]+):/);
106
+ if (match) {
107
+ agents.add(match[1]);
108
+ }
109
+ }
110
+ } catch (error) {
111
+ logger.error('Failed to get all agents', { error });
112
+ }
113
+
114
+ return Array.from(agents);
115
+ }
116
+
117
+ /**
118
+ * Delete all interactions for an agent
119
+ */
120
+ async deleteAgent(agentDid: string): Promise<void> {
121
+ const prefix = `interaction:${agentDid}:`;
122
+ const keysToDelete: string[] = [];
123
+
124
+ for await (const [key] of this.db.iterator({
125
+ gte: prefix,
126
+ lte: prefix + '\xff',
127
+ })) {
128
+ keysToDelete.push(key);
129
+ }
130
+
131
+ await this.db.batch(keysToDelete.map(key => ({ type: 'del', key })));
132
+ logger.info('Deleted interaction history', { agentDid, count: keysToDelete.length });
133
+ }
134
+
135
+ /**
136
+ * Clean up old interactions (older than 90 days)
137
+ */
138
+ async cleanup(maxAge = 90 * 24 * 60 * 60 * 1000): Promise<number> {
139
+ const cutoff = Date.now() - maxAge;
140
+ const keysToDelete: string[] = [];
141
+
142
+ for await (const [key, value] of this.db.iterator()) {
143
+ if (value.timestamp < cutoff) {
144
+ keysToDelete.push(key);
145
+ }
146
+ }
147
+
148
+ if (keysToDelete.length > 0) {
149
+ await this.db.batch(keysToDelete.map(key => ({ type: 'del', key })));
150
+ logger.info('Cleaned up old interactions', { count: keysToDelete.length });
151
+ }
152
+
153
+ return keysToDelete.length;
154
+ }
155
+ }