11import { generateMnemonic , validateMnemonic , mnemonicToEntropy } from "bip39" ;
22import * as secp256k1 from "@noble/secp256k1" ;
3+ import { schnorr } from "@noble/curves/secp256k1" ;
34import { bytesToHex , hexToBytes } from "@noble/hashes/utils" ;
45import { sha256 } from "@noble/hashes/sha256" ;
56import { hmac } from "@noble/hashes/hmac" ;
@@ -124,7 +125,9 @@ export function seedPhraseToKeyPair(seedPhrase: string): KeyPair {
124125 const entropy = getEntropyFromSeedPhrase ( seedPhrase ) ;
125126 // Hash the entropy to generate a proper private key
126127 const privateKeyBytes = sha256 ( entropy ) ;
128+ entropy . fill ( 0 ) ; // zero sensitive material
127129 const privateKeyHex = bytesToHex ( privateKeyBytes ) ;
130+ privateKeyBytes . fill ( 0 ) ; // zero sensitive material
128131
129132 // Derive the public key
130133 const publicKeyBytes = secp256k1 . getPublicKey ( privateKeyHex , true ) ; // Force compressed format
@@ -180,11 +183,13 @@ export function fromHex(privateKeyHex: string): KeyPair {
180183 // Validate the private key
181184 const privateKeyBytes = hexToBytes ( privateKeyHex ) ;
182185 if ( ! secp256k1 . utils . isValidPrivateKey ( privateKeyBytes ) ) {
186+ privateKeyBytes . fill ( 0 ) ; // zero sensitive material
183187 throw new Error ( "Invalid private key" ) ;
184188 }
185189
186190 // Derive the public key
187191 const publicKeyBytes = secp256k1 . getPublicKey ( privateKeyBytes , true ) ; // Force compressed format
192+ privateKeyBytes . fill ( 0 ) ; // zero sensitive material
188193 const publicKey = bytesToHex ( publicKeyBytes ) ;
189194
190195 // Generate the nsec and npub formats
@@ -216,6 +221,7 @@ export function getPublicKey(privateKey: string): string {
216221 try {
217222 const privateKeyBytes = hexToBytes ( privateKey ) ;
218223 const publicKeyBytes = secp256k1 . getPublicKey ( privateKeyBytes , true ) ; // Force compressed format
224+ privateKeyBytes . fill ( 0 ) ; // zero sensitive material
219225 return bytesToHex ( publicKeyBytes ) ;
220226 } catch ( error ) {
221227 logger . error ( "Failed to get public key:" , error ?. toString ( ) ) ;
@@ -358,12 +364,11 @@ export async function signEvent(
358364) : Promise < string > {
359365 try {
360366 const eventHash = getEventHash ( event ) ;
361- const signature = await secp256k1 . sign (
362- hexToBytes ( eventHash ) ,
363- hexToBytes ( privateKey ) ,
364- ) ;
367+ const privateKeyBytes = hexToBytes ( privateKey ) ;
368+ const signature = schnorr . sign ( eventHash , privateKeyBytes ) ;
369+ privateKeyBytes . fill ( 0 ) ; // zero sensitive material
365370 logger . log ( "Event signed successfully" ) ;
366- return bytesToHex ( signature . toCompactRawBytes ( ) ) ;
371+ return bytesToHex ( signature ) ;
367372 } catch ( error ) {
368373 logger . error ( "Failed to sign event:" , error ?. toString ( ) ) ;
369374 throw error ;
@@ -392,9 +397,9 @@ export async function verifyEvent(event: NostrEvent): Promise<boolean> {
392397 }
393398
394399 logger . log ( "Verifying event signature" ) ;
395- return await secp256k1 . verify (
400+ return schnorr . verify (
396401 hexToBytes ( event . sig ) ,
397- hexToBytes ( hash ) ,
402+ hash ,
398403 hexToBytes ( event . pubkey ) ,
399404 ) ;
400405 } catch ( error ) {
@@ -527,6 +532,7 @@ export function privateKeyToNpub(privateKey: string): string {
527532 try {
528533 const privateKeyBytes = hexToBytes ( privateKey ) ;
529534 const publicKey = secp256k1 . getPublicKey ( privateKeyBytes , true ) ;
535+ privateKeyBytes . fill ( 0 ) ; // zero sensitive material
530536 return nip19 . npubEncode ( bytesToHex ( publicKey ) ) ;
531537 } catch ( error ) {
532538 logger . error ( "Failed to encode npub:" , error ?. toString ( ) ) ;
@@ -632,9 +638,12 @@ export async function signMessage(
632638 try {
633639 const messageBytes = new TextEncoder ( ) . encode ( message ) ;
634640 const messageHash = sha256 ( messageBytes ) ;
635- const signature = await secp256k1 . sign ( messageHash , hexToBytes ( privateKey ) ) ;
641+ const messageHashHex = bytesToHex ( messageHash ) ;
642+ const privateKeyBytes = hexToBytes ( privateKey ) ;
643+ const signature = schnorr . sign ( messageHashHex , privateKeyBytes ) ;
644+ privateKeyBytes . fill ( 0 ) ; // zero sensitive material
636645 logger . log ( "Message signed successfully" ) ;
637- return bytesToHex ( signature . toCompactRawBytes ( ) ) ;
646+ return bytesToHex ( signature ) ;
638647 } catch ( error ) {
639648 logger . error ( "Failed to sign message:" , error ?. toString ( ) ) ;
640649 throw error ;
@@ -659,10 +668,11 @@ export async function verifySignature(
659668 try {
660669 const messageBytes = new TextEncoder ( ) . encode ( message ) ;
661670 const messageHash = sha256 ( messageBytes ) ;
671+ const messageHashHex = bytesToHex ( messageHash ) ;
662672 logger . log ( "Verifying message signature" ) ;
663- return await secp256k1 . verify (
673+ return schnorr . verify (
664674 hexToBytes ( signature ) ,
665- messageHash ,
675+ messageHashHex ,
666676 hexToBytes ( publicKey ) ,
667677 ) ;
668678 } catch ( error ) {
0 commit comments