/** * Nsec signer (direct private key, NIP-49 encrypted) */ import { decryptPrivateKey } from '../security/key-management.js'; import { getPublicKey, finalizeEvent } from 'nostr-tools'; import type { NostrEvent } from '../../types/nostr.js'; /** * Convert hex string to Uint8Array */ function hexToBytes(hex: string): Uint8Array { if (hex.length !== 64) { throw new Error('Invalid hex string: must be 64 characters (32 bytes)'); } const bytes = new Uint8Array(32); for (let i = 0; i < 32; i++) { const hexByte = hex.slice(i * 2, i * 2 + 2); bytes[i] = parseInt(hexByte, 16); } return bytes; } /** * Sign event with nsec (private key) * Uses proper secp256k1 cryptography via nostr-tools finalizeEvent */ export async function signEventWithNsec( event: Omit, ncryptsec: string, password: string ): Promise { // Decrypt private key - NEVER log the nsec, password, or ncryptsec const nsec = await decryptPrivateKey(ncryptsec, password); // Convert hex string to Uint8Array for finalizeEvent const privkey = hexToBytes(nsec); // Use nostr-tools finalizeEvent to properly sign the event // This computes the event ID (SHA256) and secp256k1 signature return finalizeEvent(event, privkey); } /** * Get public key from private key (hex string) * Uses proper secp256k1 cryptography via nostr-tools */ export async function getPublicKeyFromNsec(nsec: string): Promise { // Convert hex string to Uint8Array // nsec is a 64-character hex string representing 32 bytes if (nsec.length !== 64) { throw new Error('Invalid nsec: must be 64 hex characters (32 bytes)'); } // Convert hex string to bytes const bytes = new Uint8Array(32); for (let i = 0; i < 32; i++) { const hexByte = nsec.slice(i * 2, i * 2 + 2); bytes[i] = parseInt(hexByte, 16); } // Use nostr-tools to get the proper public key return getPublicKey(bytes); }