UNPKG

nostr-nsec-seedphrase

Version:

A comprehensive TypeScript library for Nostr key management with BIP39 seed phrases, supporting both ESM and CommonJS. Implements NIP-01, NIP-06, NIP-19, and NIP-26 with key generation, event signing, bech32 encoding/decoding, and secure cryptographic ope

153 lines (152 loc) 4.86 kB
/** * @module crypto/events * @description Event signing and verification functions for Nostr */ import { schnorr } from '@noble/curves/secp256k1'; import { sha256 } from '@noble/hashes/sha256'; import { bytesToHex, hexToBytes } from '@noble/hashes/utils'; import { logger } from '../utils/logger.js'; import { Defaults } from '../constants.js'; /** * Calculates the event hash/ID according to the Nostr protocol * @param event - The event to hash * @returns The hex-encoded event hash */ export function getEventHash(event) { try { const serialized = JSON.stringify([ 0, event.pubkey, event.created_at, event.kind, event.tags, event.content, ]); return bytesToHex(sha256(new TextEncoder().encode(serialized))); } catch (error) { logger.error('Failed to calculate event hash:', error?.toString()); throw error; } } /** * Creates an unsigned event * @param pubkey - The public key of the event creator * @param content - The event content * @param kind - The event kind (defaults to TEXT_NOTE) * @param tags - The event tags (defaults to empty array) * @returns An unsigned event */ export function createUnsignedEvent(pubkey, content, kind = Defaults.KIND, tags = Defaults.TAGS) { return { pubkey, created_at: Defaults.CREATED_AT(), kind, tags, content, }; } /** * Signs a Nostr event using Schnorr signatures * @param event - The event to sign * @param privateKey - The hex-encoded private key to sign with * @returns The signed event * @throws {Error} If signing fails */ export async function signEvent(event, privateKey) { try { const id = getEventHash(event); const sig = bytesToHex(await schnorr.sign(hexToBytes(id), hexToBytes(privateKey))); logger.log('Event signed successfully'); return { ...event, id, sig, }; } catch (error) { logger.error('Failed to sign event:', error?.toString()); throw error; } } /** * Verifies a Nostr event signature * @param event - The event to verify * @returns Validation result */ export async function verifyEvent(event) { try { if (!event.id || !event.pubkey || !event.sig) { return { isValid: false, error: 'Missing required fields', }; } const hash = getEventHash(event); if (hash !== event.id) { return { isValid: false, error: 'Event hash mismatch', }; } logger.log('Verifying event signature'); const isValid = await schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey)); return { isValid, error: isValid ? undefined : 'Invalid signature', }; } catch (error) { logger.error('Failed to verify event:', error?.toString()); return { isValid: false, error: error instanceof Error ? error.message : 'Unknown error', }; } } /** * Signs a message with a private key using Schnorr signatures * @param message - The message to sign * @param privateKey - The hex-encoded private key to sign with * @returns The hex-encoded signature * @throws {Error} If signing fails */ export async function signMessage(message, privateKey) { try { const messageBytes = new TextEncoder().encode(message); const messageHash = sha256(messageBytes); const signature = await schnorr.sign(messageHash, hexToBytes(privateKey)); logger.log('Message signed successfully'); return bytesToHex(signature); } catch (error) { logger.error('Failed to sign message:', error?.toString()); throw error; } } /** * Verifies a message signature using Schnorr verification * @param message - The original message * @param signature - The hex-encoded signature to verify * @param publicKey - The hex-encoded public key to verify against * @returns Validation result */ export async function verifySignature(message, signature, publicKey) { try { const messageBytes = new TextEncoder().encode(message); const messageHash = sha256(messageBytes); logger.log('Verifying message signature'); const isValid = await schnorr.verify(hexToBytes(signature), messageHash, hexToBytes(publicKey)); return { isValid, error: isValid ? undefined : 'Invalid signature', }; } catch (error) { logger.error('Failed to verify signature:', error?.toString()); return { isValid: false, error: error instanceof Error ? error.message : 'Unknown error', }; } }