NAME
Net::Nostr::Key - Secp256k1 keypair management for Nostr
SYNOPSIS
use Net::Nostr::Key;
# Generate a new keypair
my $key = Net::Nostr::Key->new;
say $key->pubkey_npub; # npub1...
say $key->privkey_nsec; # nsec1...
say $key->pubkey_hex; # 64-char hex (x-only, BIP-340)
say $key->privkey_hex; # 64-char hex
# Save and load from file
$key->save_privkey('my_key.pem');
my $key = Net::Nostr::Key->new(privkey => 'my_key.pem');
# Create and sign an event
my $event = $key->create_event(kind => 1, content => 'hello', tags => []);
# Load from DER data
my $key = Net::Nostr::Key->new(privkey => \$der_bytes);
my $key = Net::Nostr::Key->new(pubkey => \$der_bytes);
# Derive from mnemonic seed phrase (NIP-06)
my $mnemonic = Net::Nostr::Key->generate_mnemonic;
my $key = Net::Nostr::Key->from_mnemonic($mnemonic);
my $key = Net::Nostr::Key->from_mnemonic($mnemonic, account => 1);
DESCRIPTION
Manages secp256k1 keypairs for the Nostr protocol. Supports key generation, import/export in multiple formats (hex, raw, DER, PEM, NIP-19 bech32), file-based key storage, BIP-340 Schnorr signatures, and NIP-06 key derivation from BIP-39 mnemonic seed phrases.
CLASS METHODS
from_mnemonic
my $key = Net::Nostr::Key->from_mnemonic($mnemonic);
my $key = Net::Nostr::Key->from_mnemonic($mnemonic, account => 1);
Derives a secp256k1 keypair from a BIP-39 mnemonic seed phrase using the NIP-06 derivation path m/44'/1237'/<account>'/0/0. The account defaults to 0.
my $mnemonic = 'leader monkey parrot ring guide accident before fence cannon height naive bean';
my $key = Net::Nostr::Key->from_mnemonic($mnemonic);
say $key->privkey_hex; # 7f7ff03d...
say $key->pubkey_npub; # npub1zut...
A basic client can use the default account 0 to derive a single key. For more advanced use-cases, increment account to generate practically infinite keys from the same mnemonic:
my $key0 = Net::Nostr::Key->from_mnemonic($mnemonic);
my $key1 = Net::Nostr::Key->from_mnemonic($mnemonic, account => 1);
Croaks if the mnemonic is invalid.
generate_mnemonic
my $mnemonic = Net::Nostr::Key->generate_mnemonic;
my $mnemonic = Net::Nostr::Key->generate_mnemonic(bits => 256);
Generates a new BIP-39 mnemonic seed phrase. The bits parameter controls the entropy size: 128 (default) produces 12 words, 256 produces 24 words.
my $mnemonic = Net::Nostr::Key->generate_mnemonic;
my $key = Net::Nostr::Key->from_mnemonic($mnemonic);
say $key->pubkey_npub;
CONSTRUCTOR
new
my $key = Net::Nostr::Key->new;
my $key = Net::Nostr::Key->new(privkey => \$der_bytes);
my $key = Net::Nostr::Key->new(pubkey => \$der_bytes);
my $key = Net::Nostr::Key->new(privkey => 'my_key.pem');
Without arguments, generates a new secp256k1 keypair. Pass privkey or pubkey as a scalar reference to key data (DER or PEM), or as a filename string to load from a file (PEM or DER format). privkey and pubkey are mutually exclusive. When only a public key is loaded, signing operations will fail. Croaks on unknown arguments or if both privkey and pubkey are provided.
# Save a key to a file and load it back
$key->save_privkey('my_key.pem');
my $key = Net::Nostr::Key->new(privkey => 'my_key.pem');
METHODS
schnorr_sign
my $sig = $key->schnorr_sign($message); # 64 raw bytes
Signs the given message using BIP-340 Schnorr signatures. Returns the raw 64-byte signature. Requires a private key to be loaded.
my $key = Net::Nostr::Key->new;
my $sig = $key->schnorr_sign('hello');
say length($sig); # 64
privkey_loaded
my $bool = $key->privkey_loaded;
Returns true if a private key is loaded (i.e. signing is possible).
pubkey_loaded
my $bool = $key->pubkey_loaded;
Returns true if any key material is loaded (public or private).
my $key = Net::Nostr::Key->new(pubkey => \$der);
say $key->pubkey_loaded; # 1
say $key->privkey_loaded; # 0
pubkey_hex
my $hex = $key->pubkey_hex; # 64-char lowercase hex
Returns the x-only public key as a 64-character hex string, suitable for use as a Nostr pubkey (BIP-340 format).
privkey_hex
my $hex = $key->privkey_hex; # 64-char lowercase hex
Returns the private key as a 64-character hex string.
pubkey_npub
my $npub = $key->pubkey_npub; # 'npub1...'
Returns the public key as a NIP-19 bech32-encoded npub string.
my $key = Net::Nostr::Key->new;
say $key->pubkey_npub; # npub1...
privkey_nsec
my $nsec = $key->privkey_nsec; # 'nsec1...'
Returns the private key as a NIP-19 bech32-encoded nsec string.
my $key = Net::Nostr::Key->new;
say $key->privkey_nsec; # nsec1...
pubkey_raw
my $raw = $key->pubkey_raw; # 65 bytes (04 || x || y)
Returns the uncompressed public key as raw bytes (65 bytes with 04 prefix).
privkey_raw
my $raw = $key->privkey_raw; # 32 bytes
Returns the private key as 32 raw bytes.
pubkey_der
my $der = $key->pubkey_der;
Returns the public key in DER-encoded format. Can be passed to a new Key constructor:
my $key2 = Net::Nostr::Key->new(pubkey => \$key->pubkey_der);
privkey_der
my $der = $key->privkey_der;
Returns the private key in DER-encoded format.
my $key2 = Net::Nostr::Key->new(privkey => \$key->privkey_der);
pubkey_pem
my $pem = $key->pubkey_pem;
Returns the public key in PEM-encoded format (Base64 with header/footer).
say $key->pubkey_pem;
# -----BEGIN PUBLIC KEY-----
# ...
# -----END PUBLIC KEY-----
privkey_pem
my $pem = $key->privkey_pem;
Returns the private key in PEM-encoded format.
save_privkey
$key->save_privkey('my_key.pem');
Saves the private key to the given file path in PEM format with file mode 0600 (owner read/write only). Croaks if no private key is loaded.
my $key = Net::Nostr::Key->new;
$key->save_privkey('my_key.pem');
# Load it back later
my $same_key = Net::Nostr::Key->new(privkey => 'my_key.pem');
save_pubkey
$key->save_pubkey('my_pubkey.pem');
Saves the public key to the given file path in PEM format.
my $key = Net::Nostr::Key->new;
$key->save_pubkey('my_pubkey.pem');
my $pub_only = Net::Nostr::Key->new(pubkey => 'my_pubkey.pem');
sign_event
my $sig_hex = $key->sign_event($event);
Verifies that $event->pubkey matches this key and that the stored ID matches the event body, then signs with BIP-340 Schnorr and sets the event's sig field. Croaks if the pubkey does not match or the ID has been tampered with. Any existing signature is unconditionally replaced. Returns the signature as a 128-character hex string.
my $event = Net::Nostr::Event->new(
pubkey => $key->pubkey_hex, kind => 1,
content => 'hello', tags => [],
);
$key->sign_event($event);
say $event->sig; # 128-char hex
create_event
my $event = $key->create_event(kind => 1, content => 'hello', tags => []);
Convenience method that creates a new Net::Nostr::Event with the key's public key, signs it, and returns the signed event.
my $event = $key->create_event(
kind => 1,
content => 'hello world',
tags => [['t', 'nostr']],
);
say $event->id; # set
say $event->sig; # set
constructor_keys
my @keys = Net::Nostr::Key->constructor_keys; # ('privkey', 'pubkey')
Returns the list of valid constructor argument names. Used internally by Net::Nostr to extract key-related arguments.