commit 56041b244d5870ac2c16fd21b233bb37a4484e4a Author: Logen <79722764+btcforplebs@users.noreply.github.com> Date: Mon Sep 8 17:51:35 2025 -0400 Initial commit: basic keygen tool diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7519eaa --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +__pycache__/ +venv/ +*.pyc +*.pyo +*.pyd + +# OS generated files +.DS_Store + diff --git a/README.md b/README.md new file mode 100644 index 0000000..bfb31d8 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# README.md +# nostr-keygen + +A tiny command‑line utility written in Python that generates an Nostr **npub** (public key) and **nsec** (private key) pair from a single file that you drop into the terminal. + +## How it works + +1. **Entropy** – The contents of the file you provide are read in binary mode. +2. **Hash** – The data is hashed with SHA‑256 to produce a 32‑byte seed. +3. **Key generation** – The seed is fed to the secp256k1 curve to create an ECDSA private key. +4. **Bech32 encoding** – The private key is encoded as `nsec`; the compressed public key is encoded as `npub`. + +The utility is intentionally lightweight; it has no external configuration and works on any platform with Python 3.8+. + +## Installation + +```bash +# Clone the repo +git clone https://github.com/yourname/nostr-keygen.git +cd nostr-keygen + +# Create a virtualenv and install deps +python3 -m venv venv +source venv/bin/activate +pip install -e . # installs the program and its deps +``` + +After that you can run it with: + +```bash +# Replace file.txt with the path to any file you want to use as entropy +nostr-keygen file.txt +``` + +## Using drag‑and‑drop in the terminal + +On macOS (and most X11 terminals) you can simply drag a file into the terminal prompt. The terminal translates that to the file’s full path. For example: + +``` +$ nostr-keygen +``` + +This will invoke the program using the path of the dropped file. + +## License + +MIT diff --git a/main.py b/main.py new file mode 100644 index 0000000..c02a80b --- /dev/null +++ b/main.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +"""Generate a fresh Nostr key (npub/nsec) using a file as entropy source. + +Usage: + nostr-keygen + +The file is read in binary mode and its bytes are hashed with SHA‑256 to +produce the 32‑byte seed which is then used to generate a secp256k1 +private key. The private key is hex‑encoded as an nsec, and the +corresponding public key is converted to a Bech32 npub. The example +uses the official Nostr prefix "nsec"/ +""" + +import argparse +import hashlib +import os +import sys + +from ecdsa import SigningKey, SECP256k1 +from bech32 import bech32_encode, convertbits + +# Constants for Nostr bech32 encoding +NSEC_PREFIX = "nsec" +NPUB_PREFIX = "npub" + +# convertbits helper adapted from bech32 library; using provided function for clarity + +def _to_bech32(data: bytes, hrp: str) -> str: + """Encode raw bytes into a Bech32 string with the given human‑readable part.""" + # Convert 8‑bit bytes to 5‑bit groups + five_bits = convertbits(list(data), 8, 5, True) + if five_bits is None: + raise ValueError("Error converting data to 5‑bit groups") + return bech32_encode(hrp, five_bits) + + +def _entropy_to_pri_key(entropy: bytes) -> SigningKey: + """Return an ECDSA SECP256k1 private key derived from entropy.""" + # Use SHA‑256 of the provided entropy for deterministic key generation + seed = hashlib.sha256(entropy).digest() + return SigningKey.from_string(seed, curve=SECP256k1) + + +def generate_key_from_file(file_path: str) -> (str, str): + """Return (nsec, npub) for the key derived from the file content.""" + if not os.path.isfile(file_path): + raise FileNotFoundError(f"File not found: {file_path}") + with open(file_path, "rb") as f: + data = f.read() + + sk = _entropy_to_pri_key(data) + vk = sk.get_verifying_key() + # Private key bytes + private_bytes = sk.to_string() + # Public key bytes, compressed (33 bytes) + public_bytes = vk.to_string("compressed") + nsec = _to_bech32(private_bytes, NSEC_PREFIX) + npub = _to_bech32(public_bytes, NPUB_PREFIX) + return nsec, npub + + + +def main(): + parser = argparse.ArgumentParser(description="Generate Nostr key pair from file entropy") + parser.add_argument("file", help="Path to file used as entropy source") + args = parser.parse_args() + + try: + nsec, npub = generate_key_from_file(args.file) + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + + print("NSEc:", nsec) + print("NPop:", npub) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..881af33 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,12 @@ +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "nostr-keygen" +version = "0.1.0" +description = "Terminal tool to generate nostr npub/nsec from file entropy" +authors = [{name = "Your Name", email = "you@example.com"}] +readme = "README.md" +requires-python = ">=3.8" +dependencies = ["ecdsa", "bech32"]