Подойдет для интерграции в шоп/etc. Полностью оффлайн.
Python:
# pip install pycryptodome base58 ecdsa
import hashlib
from Crypto.Hash import RIPEMD160
from binascii import hexlify
from hashlib import sha256
from os import urandom
from random import randrange
from time import time
import base58
from ecdsa import SECP256k1, SigningKey
class BitcoinWallet:
def __init__(self, ver: str = '3') -> None:
self.prefix = b'\x80'
self.sufix = b'\x01'
self.addr_ver = ver
self._seed_gen()
def checksum(self, what: str) -> bytes:
return sha256(sha256(what).digest()).digest()[:4]
def _seed_gen(self) -> None:
self.digest = hashlib.sha256(
str(
str(urandom(32).hex()) +
str(randrange(2 ** 256)) +
str(int(time() * 1000000))
).encode()
).digest()
self.hex = hexlify(self.digest).decode()
wif_dig = self.prefix + self.digest
if self.addr_ver == '1':
self.wif = base58.b58encode(
wif_dig + self.checksum(wif_dig)
).decode('utf-8')
else:
self.wif = base58.b58encode(
wif_dig+self.sufix+self.checksum(wif_dig+self.sufix)
).decode('utf-8')
def hash160(self, v: str) -> bytes:
r = RIPEMD160.new()
r.update(hashlib.sha256(v).digest())
return r
def _generate_compressed_pubkey(self) -> str:
ecdsa_digest = SigningKey.from_string(
self.digest, curve=SECP256k1
).get_verifying_key().to_string()
x_coord = ecdsa_digest[:int(len(ecdsa_digest) / 2)]
y_coord = ecdsa_digest[int(len(ecdsa_digest) / 2):]
if int(hexlify(y_coord), 16) % 2 == 0:
p = b'\x02' + x_coord
else:
p = b'\x03' + x_coord
self.pubkeyc = str(hexlify(p).decode('utf-8'))
return p
def _generate_address(self) -> str:
p = self._generate_compressed_pubkey()
redeem_script = self.hash160(
b'\x00\x14' + self.hash160(p).digest()
).digest()
m = b'\x05' + redeem_script
c = self.checksum(m)
return base58.b58encode(m + c).decode('utf-8')
def new(self) -> tuple:
return (
self._generate_address(), f'p2wpkh-p2sh:{self.wif}'
)