usawa

Signed, immutable accounting.
Log | Files | Refs | Submodules | LICENSE

commit 4171f701be54508446298e8f862b4cc19b70d562
parent 2a03bcdc80284d549ccdaa296958ef0722cf9dd7
Author: Carlosokumu <carlosokumu254@gmail.com>
Date:   Sat, 14 Mar 2026 10:27:56 +0300

setup seed+phrase encryption command using SecretBox

Diffstat:
Mdummy/usawa/runnable/setup_wallet.py | 118++++++++++++++++++++++++-------------------------------------------------------
1 file changed, 36 insertions(+), 82 deletions(-)

diff --git a/dummy/usawa/runnable/setup_wallet.py b/dummy/usawa/runnable/setup_wallet.py @@ -1,110 +1,64 @@ import getpass import logging import os -import subprocess +from pathlib import Path from nacl.signing import SigningKey - +from nacl.secret import SecretBox +from nacl.pwhash import argon2i logg = logging.getLogger("core.setup_wallet") -GNUPG_DIR = "gnupg" -PRIVATEKEY_FILE = "privatekey.asc" +PRIVATEKEY_FILE = "privatekey.box" PUBLICKEY_FILE = "publickey.bin" +DEFAULT_WALLET_DIR = ( + Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local/share")) / "usawa" +) -def _generate_gpg_key(gpg_dir, name, email, passphrase=None): - env = {**os.environ, "GNUPGHOME": gpg_dir} - - subprocess.run( - ["gpg-agent", "--homedir", gpg_dir, "--daemon"], - capture_output=True, - env=env, - ) - - batch_input = "\n".join( - [ - "Key-Type: EdDSA", - "Key-Curve: ed25519", - "Subkey-Type: ECDH", - "Subkey-Curve: cv25519", - f"Name-Real: {name}", - f"Name-Email: {email}", - f"Passphrase: {passphrase}" if passphrase else "%no-protection", - "%commit", - "", - ] - ) - result = subprocess.run( - ["gpg", "--homedir", gpg_dir, "--batch", "--gen-key"], - input=batch_input.encode(), - capture_output=True, - env=env, +def encrypt_seed(seed: bytes, passphrase: str) -> bytes: + salt = os.urandom(argon2i.SALTBYTES) + key = argon2i.kdf( + SecretBox.KEY_SIZE, + passphrase.encode(), + salt, ) - if result.returncode != 0: - logg.error("key generation failed: %s", result.stderr.decode()) - return None + box = SecretBox(key) + encrypted = box.encrypt(seed) - list_result = subprocess.run( - ["gpg", "--homedir", gpg_dir, "--with-colons", "--fingerprint", email], - capture_output=True, - env=env, - ) - for line in list_result.stdout.decode().splitlines(): - if line.startswith("fpr"): - return line.split(":")[9] - return None + # Prepend salt so we can re-derive the key on decrypt + return salt + encrypted -def setup_wallet(): - gpg_dir = os.path.abspath(GNUPG_DIR) - os.makedirs(gpg_dir, mode=0o700, exist_ok=True) - logg.debug("gpg directory: %s", gpg_dir) +def setup_wallet(wallet_dir=None): + wallet_dir = Path(wallet_dir) if wallet_dir else DEFAULT_WALLET_DIR + wallet_dir.mkdir(parents=True, exist_ok=True) + logg.info("wallet directory: %s", wallet_dir) - env = {**os.environ, "GNUPGHOME": gpg_dir} + privatekey_path = wallet_dir / PRIVATEKEY_FILE + publickey_path = wallet_dir / PUBLICKEY_FILE - name = input("Enter your name: ") - email = input("Enter your email: ") passphrase = getpass.getpass("Enter wallet passphrase: ") - - fingerprint = _generate_gpg_key(gpg_dir, name, email, passphrase) - if not fingerprint: - logg.error("key generation failed") + passphrase_confirm = getpass.getpass("Confirm wallet passphrase: ") + if passphrase != passphrase_confirm: + logg.error("passphrases do not match") return 1 - logg.info("generated key fingerprint: %s", fingerprint) random_bytes = os.urandom(32) - result = subprocess.run( - [ - "gpg", - "--homedir", - gpg_dir, - "--armor", - "--encrypt", - "--trust-model", - "always", - "-r", - fingerprint, - ], - input=random_bytes, - capture_output=True, - env=env, - ) - if result.returncode != 0: - logg.error("encryption failed: %s", result.stderr.decode()) - return 1 - with open(PRIVATEKEY_FILE, "wb") as f: - f.write(result.stdout) - logg.info("private key material saved to: %s", PRIVATEKEY_FILE) + logg.debug("generated 32-byte seed") + + encrypted = encrypt_seed(random_bytes, passphrase) + with open(privatekey_path, "wb") as f: + f.write(encrypted) + logg.info("encrypted key material saved to: %s", privatekey_path) sk = SigningKey(random_bytes) pk = sk.verify_key - with open(PUBLICKEY_FILE, "wb") as f: + with open(publickey_path, "wb") as f: f.write(pk.encode()) - logg.info("public key saved to: %s", PUBLICKEY_FILE) + logg.info("public key saved to: %s", publickey_path) - logg.info("setup complete. add the following to your config:") - logg.info(" gpg_dir = %s", gpg_dir) - logg.info("public key (hex): %s", pk.encode().hex()) + logg.info("setup complete.") + logg.info("your 32-byte public key (hex): %s", pk.encode().hex()) return 0