You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
4.2 KiB

import 'package:nostr_tools/nostr_tools.dart';
/// Represents a Nostr keypair (private and public keys).
class NostrKeyPair {
/// Private key in hex format (32 bytes, 64 hex characters).
final String privateKey;
/// Public key in hex format (32 bytes, 64 hex characters).
final String publicKey;
/// Key API instance for key operations.
static final _keyApi = KeyApi();
/// NIP-19 API instance for bech32 encoding/decoding.
static final _nip19 = Nip19();
/// Creates a [NostrKeyPair] with the provided keys.
///
/// [privateKey] - Private key in hex format.
/// [publicKey] - Public key in hex format.
NostrKeyPair({
required this.privateKey,
required this.publicKey,
});
/// Generates a new Nostr keypair using nostr_tools.
///
/// Returns a new [NostrKeyPair] with random private and public keys.
factory NostrKeyPair.generate() {
final privateKey = _keyApi.generatePrivateKey();
final publicKey = _keyApi.getPublicKey(privateKey);
return NostrKeyPair(
privateKey: privateKey,
publicKey: publicKey,
);
}
/// Creates a [NostrKeyPair] from nsec (private key in bech32 format).
///
/// [nsec] - Private key in nsec format (e.g., 'nsec1...').
///
/// Returns a [NostrKeyPair] with the decoded private key and derived public key.
///
/// Throws [FormatException] if nsec is invalid.
factory NostrKeyPair.fromNsec(String nsec) {
try {
final decoded = _nip19.decode(nsec);
if (decoded['type'] != 'nsec') {
throw FormatException('Invalid nsec format: expected "nsec" type');
}
final privateKey = decoded['data'] as String;
final publicKey = _keyApi.getPublicKey(privateKey);
return NostrKeyPair(
privateKey: privateKey,
publicKey: publicKey,
);
} catch (e) {
throw FormatException('Failed to parse nsec: $e');
}
}
/// Creates a [NostrKeyPair] from npub (public key in bech32 format).
///
/// Note: This creates a keypair with only the public key. Private key operations won't work.
///
/// [npub] - Public key in npub format (e.g., 'npub1...').
///
/// Returns a [NostrKeyPair] with the decoded public key and empty private key.
///
/// Throws [FormatException] if npub is invalid.
factory NostrKeyPair.fromNpub(String npub) {
try {
final decoded = _nip19.decode(npub);
if (decoded['type'] != 'npub') {
throw FormatException('Invalid npub format: expected "npub" type');
}
final publicKey = decoded['data'] as String;
// No private key available when importing from npub
return NostrKeyPair(
privateKey: '', // Empty private key - can't sign events
publicKey: publicKey,
);
} catch (e) {
throw FormatException('Failed to parse npub: $e');
}
}
/// Creates a [NostrKeyPair] from a hex private key.
///
/// [hexPrivateKey] - Private key in hex format (64 hex characters).
///
/// Returns a [NostrKeyPair] with the provided private key and derived public key.
factory NostrKeyPair.fromHexPrivateKey(String hexPrivateKey) {
if (hexPrivateKey.length != 64) {
throw FormatException('Invalid hex private key: expected 64 hex characters');
}
final publicKey = _keyApi.getPublicKey(hexPrivateKey);
return NostrKeyPair(
privateKey: hexPrivateKey,
publicKey: publicKey,
);
}
/// Creates a [NostrKeyPair] from a JSON map.
factory NostrKeyPair.fromJson(Map<String, dynamic> json) {
return NostrKeyPair(
privateKey: json['privateKey'] as String,
publicKey: json['publicKey'] as String,
);
}
/// Converts the [NostrKeyPair] to a JSON map.
Map<String, dynamic> toJson() {
return {
'privateKey': privateKey,
'publicKey': publicKey,
};
}
/// Encodes the private key to nsec format.
String toNsec() {
if (privateKey.isEmpty) {
throw StateError('Cannot encode empty private key to nsec');
}
return _nip19.nsecEncode(privateKey);
}
/// Encodes the public key to npub format.
String toNpub() {
return _nip19.npubEncode(publicKey);
}
@override
String toString() {
return 'NostrKeyPair(publicKey: $publicKey)';
}
}

Powered by TurnKey Linux.