If anyone needs it, here's some python that will do the trick.
```
import hashlib
# Base58 Bitcoin Alphabet
B58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
# Bech32 character set
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
def convertbits(data, frombits, tobits, pad=True):
"""General power-of-2 base conversion. Groups 5-bit values back to 8-bit."""
acc = 0
bits = 0
ret = []
maxv = (1 << tobits) - 1
max_acc = (1 << (frombits + tobits - 1)) - 1
for value in data:
if value < 0 or (value >> frombits):
return None
acc = ((acc << frombits) | value) & max_acc
bits += frombits
while bits >= tobits:
bits -= tobits
ret.append((acc >> bits) & maxv)
if pad:
if bits:
ret.append((acc << (tobits - bits)) & maxv)
elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
return None
return ret
def bech32_decode_nsec(nsec_str):
"""Correctly decodes an nsec string into its original 32-byte private key."""
if not nsec_str.startswith("nsec1"):
raise ValueError("Invalid prefix. Your key must start with 'nsec1'")
# Strip the prefix 'nsec1'
data_part = nsec_str[5:]
# Extract 5-bit values from string mapping
five_bit_values = []
for char in data_part:
if char not in CHARSET:
raise ValueError(f"Invalid character in bech32 string: {char}")
five_bit_values.append(CHARSET.index(char))
# Slice off the final 6 characters (the Bech32 checksum)
data_payload = five_bit_values[:-6]
# Regroup the 5-bit payload chunks into standard 8-bit bytes
eight_bit_bytes = convertbits(data_payload, 5, 8, pad=False)
if eight_bit_bytes is None or len(eight_bit_bytes) != 32:
raise ValueError("Decoding error: Key data did not result in exactly 32 bytes.")
return bytes(eight_bit_bytes)
def base58_encode(raw_bytes):
"""Encodes raw bytes into a standard Bitcoin Base58 string."""
int_val = int.from_bytes(raw_bytes, byteorder="big")
result = ""
while int_val > 0:
int_val, mod = divmod(int_val, 58)
result = B58_ALPHABET[mod] + result
for byte in raw_bytes:
if byte == 0:
result = "1" + result
else:
break
return result
def nsec_to_wif(nsec_string):
# Step 1 & 2: Decode Bech32 properly to get the true 32 raw bytes
privkey_bytes = bech32_decode_nsec(nsec_string)
# Step 3: Prefix 0x80 (Mainnet) and Suffix 0x01 (Compressed marker)
wif_payload = b"\x80" + privkey_bytes + b"\x01"
# Step 4 & 5: Compute double SHA256 checksum
first_sha = hashlib.sha256(wif_payload).digest()
second_sha = hashlib.sha256(first_sha).digest()
checksum = second_sha[:4]
# Step 6 & 7: Append checksum and convert to Base58
final_bytes = wif_payload + checksum
wif_string = base58_encode(final_bytes)
return wif_string
# --- Example Test ---
if __name__ == "__main__":
# Test using a burner/mock nsec key
test_nsec = "nsec..."
try:
wif = nsec_to_wif(test_nsec)
print(f"Success! Your valid WIF Key is:\n{wif}")
except Exception as e:
print(f"Error: {e}")
```
Login to reply