UNPKG

semnet-snap-protocol

Version:

TypeScript reference implementation of the SNAP Protocol v1.1 - Agent Internet Edition

193 lines 5.31 kB
import nacl from 'tweetnacl'; const { sign, verify, box, randomBytes } = nacl; import { nanoid } from 'nanoid'; /** * Generate a new agent identity with Ed25519 keypair */ export function generateAgentIdentity() { const keypair = sign.keyPair(); const uuid = generateUUID(); return { identity: { id: `snap:agent:${uuid}`, publicKey: encodeBase64(keypair.publicKey) }, privateKey: keypair.secretKey, publicKey: keypair.publicKey }; } /** * Generate a UUID v4 */ export function generateUUID() { const bytes = randomBytes(16); // Set version (4) and variant bits bytes[6] = (bytes[6] & 0x0f) | 0x40; bytes[8] = (bytes[8] & 0x3f) | 0x80; // Format as UUID string const hex = Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join(''); return [ hex.slice(0, 8), hex.slice(8, 12), hex.slice(12, 16), hex.slice(16, 20), hex.slice(20, 32) ].join('-'); } /** * Generate a unique message ID */ export function generateMessageId() { return `msg_${nanoid()}`; } /** * Generate a unique context ID */ export function generateContextId() { return `ctx_${nanoid()}`; } /** * Sign a message with Ed25519 private key */ export function signMessage(message, privateKey) { const messageBytes = new TextEncoder().encode(message); const signature = sign.detached(messageBytes, privateKey); return encodeBase64(signature); } /** * Verify a message signature with Ed25519 public key */ export function verifySignature(message, signature, publicKey) { try { const messageBytes = new TextEncoder().encode(message); const signatureBytes = decodeBase64(signature); const publicKeyBytes = decodeBase64(publicKey); return sign.detached.verify(messageBytes, signatureBytes, publicKeyBytes); } catch { return false; } } /** * Validate agent ID format */ export function validateAgentId(id) { const regex = /^snap:agent:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; return regex.test(id); } /** * Extract UUID from agent ID */ export function extractUUID(agentId) { const match = agentId.match(/^snap:agent:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/); return match ? match[1] : null; } /** * Encode bytes to base64 */ export function encodeBase64(bytes) { return Buffer.from(bytes).toString('base64'); } /** * Decode base64 to bytes */ export function decodeBase64(base64) { return new Uint8Array(Buffer.from(base64, 'base64')); } /** * Hash content using SHA-256 */ export async function hashContent(content) { const encoder = new TextEncoder(); const data = encoder.encode(content); const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = new Uint8Array(hashBuffer); return encodeBase64(hashArray); } /** * Generate a secure random string */ export function generateSecureRandom(length = 32) { const bytes = randomBytes(length); return encodeBase64(bytes).slice(0, length); } /** * Create a canonical string representation of an object for signing */ export function canonicalizeObject(obj) { // Sort keys recursively and stringify const sortedObj = sortKeysRecursive(obj); return JSON.stringify(sortedObj); } function sortKeysRecursive(obj) { if (obj === null || typeof obj !== 'object') { return obj; } if (Array.isArray(obj)) { return obj.map(sortKeysRecursive); } const sorted = {}; const keys = Object.keys(obj).sort(); for (const key of keys) { sorted[key] = sortKeysRecursive(obj[key]); } return sorted; } /** * Agent identity utilities */ export class AgentIdentity { identity; privateKey; publicKey; constructor(identity, privateKey, publicKey) { this.identity = identity; this.privateKey = privateKey; this.publicKey = publicKey; } /** * Sign a message with this agent's private key */ sign(message) { return signMessage(message, this.privateKey); } /** * Sign an object by creating canonical representation */ signObject(obj) { const canonical = canonicalizeObject(obj); return this.sign(canonical); } /** * Export public identity (safe to share) */ exportPublic() { return { ...this.identity, publicKey: encodeBase64(this.publicKey) }; } /** * Export private key (keep secure!) */ exportPrivateKey() { return encodeBase64(this.privateKey); } /** * Import agent identity from private key */ static fromPrivateKey(identity, privateKeyBase64) { const privateKey = decodeBase64(privateKeyBase64); // Extract public key from private key (Ed25519 property) const publicKey = privateKey.slice(32); return new AgentIdentity(identity, privateKey, publicKey); } /** * Generate new agent identity */ static generate() { const { identity, privateKey, publicKey } = generateAgentIdentity(); return new AgentIdentity(identity, privateKey, publicKey); } } //# sourceMappingURL=identity.js.map