#!/usr/bin/env python3 """ Generate Ed25519 keypair for node with stable printable outputs. Primary purpose: provide a portable alternative to OpenSSL-based generation. If 'cryptography' is unavailable, gracefully degrade with exit code 0 but no output, so caller can fallback. Outputs JSON to stdout on success: { "private_key_pem": "...", "public_key_pem": "...", "public_key_hex": "....", "node_id": "node-...", } Exit codes: 0 - success OR graceful degrade (no output) when cryptography not available 1 - unexpected error Note: We intentionally avoid printing anything besides the JSON on success. """ import sys import json try: from cryptography.hazmat.primitives.asymmetric import ed25519 from cryptography.hazmat.primitives import serialization from cryptography.hazmat.backends import default_backend except Exception: # cryptography not available - graceful degradation: no output, caller will fallback sys.exit(0) def main(): try: # Generate Ed25519 keypair private_key = ed25519.Ed25519PrivateKey.generate() public_key = private_key.public_key() private_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ).decode("utf-8") public_pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo, ).decode("utf-8") # Extract raw 32-byte public key public_der = public_key.public_bytes( encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) # The last 32 bytes are the raw key for Ed25519 public_key_hex = public_der[-32:].hex() node_id = f"node-{public_key_hex[:16]}" print(json.dumps({ "private_key_pem": private_pem, "public_key_pem": public_pem, "public_key_hex": public_key_hex, "node_id": node_id, })) return 0 except Exception: # Do not spam stdout; caller will fallback to OpenSSL path return 1 if __name__ == "__main__": sys.exit(main())