Last active
February 21, 2023 19:57
-
-
Save odudex/9e848a91d23e967309bd1719910021e6 to your computer and use it in GitHub Desktop.
Uses Embit and qrcode modules to generate ascii compact seed QR codes from nostr keys.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Uses Embit and qrcode modules to convert hex and bech32 keys to BIP39 seed words and vice-versa. | |
Also generates ascii compact seed QR codes and public keys. | |
Install Embit: | |
pip install embit | |
Exemple: Words as input: | |
python nostr_c_seed_qr.py picture body actor coil end satoshi fish mom distance proof thank play fantasy friend dinner clump boring ozone review cart virtual toss foot infant | |
Exemple: Hex key as input: | |
python nostr_c_seed_qr.py a4431c0a96a4997ed5ec763fb58b7f532530b9cf916219f3d2e2118f47cb56bb | |
Exemple: Bech32 key as input: | |
python nostr_c_seed_qr.py nsec153p3cz5k5jvha40vwclmtzml2vjnpww0j93pnu7juggc737t26ascxcmgr | |
""" | |
import sys | |
from io import StringIO | |
from embit import bip39, bech32, ec | |
from embit.wordlists.bip39 import WORDLIST | |
from qrcode import QRCode | |
def _compact_seed_qr(): | |
# Krux code snippet | |
words = mnemonic.split(" ") | |
checksum_bits = 8 if len(words) == 24 else 4 | |
indexes = [WORDLIST.index(word) for word in words] | |
bitstring = "".join([f"{bin(index)[2:]:0>11}" for index in indexes])[ | |
:-checksum_bits | |
] | |
qr_data = int(bitstring, 2).to_bytes((len(bitstring) + 7) // 8, "big") | |
# Prints ascii QR code | |
qr_code = QRCode() | |
qr_code.add_data(qr_data) | |
qr_string = StringIO() | |
qr_code.print_ascii(out=qr_string, invert=True) | |
print("Compact Seed QR:") | |
print(qr_string.getvalue()) | |
def _seed_numbers(): | |
seed_numbers = [] | |
words = mnemonic.split(" ") | |
for word in words: | |
seed_numbers.append(WORDLIST.index(word) + 1) | |
print("BIP39 Seed Numbers: " + str(seed_numbers)) | |
def _public_keys(): | |
print("Public Data:") | |
pub_key = ec.PrivateKey(bip39.mnemonic_to_bytes(mnemonic, ignore_checksum=True)).get_public_key().serialize()[1:] | |
print("Hex Public key: " + pub_key.hex()) | |
converted_bits = bech32.convertbits(pub_key, 8, 5) | |
print( | |
"Bech32 Public key: " | |
+ bech32.bech32_encode(bech32.Encoding.BECH32, "npub", converted_bits) | |
) | |
def _print_common(): | |
_seed_numbers() | |
_compact_seed_qr() | |
_public_keys() | |
print("Private Data:") | |
if len(sys.argv) == 2: | |
input_data = sys.argv[1] | |
if len(input_data) == 64: # bytes input | |
try: | |
entropy_bytes = bytes.fromhex(input_data) | |
except IOError: | |
print("Invalid string, must be a string of bytes") | |
sys.exit() | |
mnemonic = bip39.mnemonic_from_bytes(entropy_bytes) | |
print("Seed words: " + str(mnemonic)) | |
converted_bits = bech32.convertbits(bytearray.fromhex(input_data), 8, 5) | |
print( | |
"Bech32 Private Key: " | |
+ bech32.bech32_encode(bech32.Encoding.BECH32, "nsec", converted_bits) | |
) | |
_print_common() | |
elif len(input_data) == 63 and input_data.startswith("nsec"): # bech32 input | |
spec, hrp, data = bech32.bech32_decode(input_data) | |
decoded = bech32.convertbits(data, 5, 8, False) | |
print("Hex Private Key: " + bytes(decoded).hex()) | |
mnemonic = bip39.mnemonic_from_bytes(bytes(decoded)) | |
print("Seed words: " + str(mnemonic)) | |
_print_common() | |
else: | |
print("Invalid keys") | |
else: | |
if len(sys.argv) == 25: | |
mnemonic = " ".join(sys.argv[1:]) | |
entropy = bip39.mnemonic_to_bytes(mnemonic, ignore_checksum=True) | |
print("Hex Private Key: " + str(entropy.hex())) | |
converted_bits = bech32.convertbits(entropy, 8, 5) | |
print( | |
"Bech32 Private key: " | |
+ bech32.bech32_encode(bech32.Encoding.BECH32, "nsec", converted_bits) | |
) | |
_print_common() | |
else: | |
print("Inform a 64 bytes private key or a 24 BIP39 words seed") | |
print(str(len(sys.argv) - 1) + " words were given") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment