From e83fe4026770f267e73ce15a2eb47e4427ace2a9 Mon Sep 17 00:00:00 2001 From: mohanson Date: Fri, 6 Dec 2024 20:16:27 +0800 Subject: [PATCH] Refactoring project name --- README.md | 16 ++- btc/ecdsa.py | 51 -------- example/addr.py | 18 +-- example/message.py | 8 +- example/regtest.py | 24 ++-- example/taproot.py | 92 +++++++------- example/transfer.py | 20 ++-- pyproject.toml | 11 +- test/test_base58.py | 18 +-- test/test_bech32.py | 14 +-- test/test_core.py | 106 ++++++++-------- test/test_ripemd160.py | 4 +- test/test_rpc.py | 18 +-- test/test_schnorr.py | 12 +- test/test_wallet.py | 34 +++--- {btc => yabtc}/__init__.py | 0 {btc => yabtc}/base58.py | 0 {btc => yabtc}/bech32.py | 0 {btc => yabtc}/config.py | 0 {btc => yabtc}/core.py | 162 ++++++++++++------------- {btc => yabtc}/denomination.py | 0 yabtc/ecdsa.py | 52 ++++++++ {btc => yabtc}/opcode.py | 0 {btc => yabtc}/ripemd160.py | 0 {btc => yabtc}/rpc.py | 12 +- {btc => yabtc}/schnorr.py | 24 ++-- {btc => yabtc}/secp256k1.py | 0 {btc => yabtc}/wallet.py | 213 ++++++++++++++++----------------- 28 files changed, 456 insertions(+), 453 deletions(-) delete mode 100644 btc/ecdsa.py rename {btc => yabtc}/__init__.py (100%) rename {btc => yabtc}/base58.py (100%) rename {btc => yabtc}/bech32.py (100%) rename {btc => yabtc}/config.py (100%) rename {btc => yabtc}/core.py (86%) rename {btc => yabtc}/denomination.py (100%) create mode 100644 yabtc/ecdsa.py rename {btc => yabtc}/opcode.py (100%) rename {btc => yabtc}/ripemd160.py (100%) rename {btc => yabtc}/rpc.py (96%) rename {btc => yabtc}/schnorr.py (55%) rename {btc => yabtc}/secp256k1.py (100%) rename {btc => yabtc}/wallet.py (57%) diff --git a/README.md b/README.md index f693039..fdb8e35 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,26 @@ -# Python SDK for BTC +# Yabtc: Bitcoin Library For Humans -Python BTC is an experimental project that aims to provide human-friendly interfaces for common BTC operations. Note that Python BTC is not a complete SDK, but only implements the BTC functions that I am interested in. +Yabtc is a project that aims to provide human-friendly interfaces for common btc operations. Using yabtc, you can easily and happily complete everything you want to do on btc. Features: -- No third-party dependencies. All code is visible. -- Incredibly simple. +- No third-party dependencies, everything is visible. +- Incredibly simple, even a cat knows how to use it. ## Installation ```sh -$ git clone https://github.com/mohanson/pybtc -$ cd pybtc +$ pip install yabtc +# or +$ git clone https://github.com/mohanson/yabtc +$ cd yabtc $ python -m pip install --editable . ``` ## Usage +By default, yabtc is configured on the develop. To switch networks, use `yabtc.config.current = yabtc.config.mainnet`. + **example/addr.py** Calculate the address from a private key. diff --git a/btc/ecdsa.py b/btc/ecdsa.py deleted file mode 100644 index 1b9a368..0000000 --- a/btc/ecdsa.py +++ /dev/null @@ -1,51 +0,0 @@ -import btc.secp256k1 -import itertools -import random -import typing - - -def sign(prikey: btc.secp256k1.Fr, m: btc.secp256k1.Fr) -> typing.Tuple[btc.secp256k1.Fr, btc.secp256k1.Fr, int]: - # https://www.secg.org/sec1-v2.pdf - # 4.1.3 Signing Operation - for _ in itertools.repeat(0): - k = btc.secp256k1.Fr(random.randint(0, btc.secp256k1.N - 1)) - R = btc.secp256k1.G * k - r = btc.secp256k1.Fr(R.x.x) - if r.x == 0: - continue - s = (m + prikey * r) / k - if s.x == 0: - continue - v = 0 - if R.y.x & 1 == 1: - v |= 1 - if R.x.x >= btc.secp256k1.N: - v |= 2 - return r, s, v - - -def verify(pubkey: btc.secp256k1.Pt, m: btc.secp256k1.Fr, r: btc.secp256k1.Fr, s: btc.secp256k1.Fr) -> bool: - # https://www.secg.org/sec1-v2.pdf - # 4.1.4 Verifying Operation - u1 = m / s - u2 = r / s - x = btc.secp256k1.G * u1 + pubkey * u2 - assert x != btc.secp256k1.I - v = btc.secp256k1.Fr(x.x.x) - return v == r - - -def pubkey(m: btc.secp256k1.Fr, r: btc.secp256k1.Fr, s: btc.secp256k1.Fr, v: int) -> btc.secp256k1.Pt: - # https://www.secg.org/sec1-v2.pdf - # 4.1.6 Public Key Recovery Operation - assert v in [0, 1, 2, 3] - if v & 2 == 0: - x = btc.secp256k1.Fq(r.x) - else: - x = btc.secp256k1.Fq(r.x + btc.secp256k1.N) - y_y = x * x * x + btc.secp256k1.A * x + btc.secp256k1.B - y = y_y ** ((btc.secp256k1.P + 1) // 4) - if v & 1 != y.x & 1: - y = -y - R = btc.secp256k1.Pt(x, y) - return (R * s - btc.secp256k1.G * m) / r diff --git a/example/addr.py b/example/addr.py index 8504b11..d6918a2 100644 --- a/example/addr.py +++ b/example/addr.py @@ -1,5 +1,5 @@ import argparse -import btc +import yabtc # Calculate the address from a private key. @@ -9,16 +9,16 @@ args = parser.parse_args() if args.net == 'develop': - btc.config.current = btc.config.develop + yabtc.config.current = yabtc.config.develop if args.net == 'mainnet': - btc.config.current = btc.config.mainnet + yabtc.config.current = yabtc.config.mainnet if args.net == 'testnet': - btc.config.current = btc.config.testnet + yabtc.config.current = yabtc.config.testnet -prikey = btc.core.PriKey(int(args.prikey, 0)) +prikey = yabtc.core.PriKey(int(args.prikey, 0)) pubkey = prikey.pubkey() -print('p2pkh ', btc.core.address_p2pkh(pubkey)) -print('p2sh-p2wpkh', btc.core.address_p2sh_p2wpkh(pubkey)) -print('p2wpkh ', btc.core.address_p2wpkh(pubkey)) -print('p2tr ', btc.core.address_p2tr(pubkey, bytearray())) +print('p2pkh ', yabtc.core.address_p2pkh(pubkey)) +print('p2sh-p2wpkh', yabtc.core.address_p2sh_p2wpkh(pubkey)) +print('p2wpkh ', yabtc.core.address_p2wpkh(pubkey)) +print('p2tr ', yabtc.core.address_p2tr(pubkey, bytearray())) diff --git a/example/message.py b/example/message.py index 3ca9959..1e08110 100644 --- a/example/message.py +++ b/example/message.py @@ -1,5 +1,5 @@ import argparse -import btc +import yabtc # Sign a message with the private key and verify it. @@ -9,11 +9,11 @@ parser.add_argument('--sig', type=str, default='', help='the signature of the message encoded in base 64') args = parser.parse_args() -prikey = btc.core.PriKey(int(args.prikey, 0)) +prikey = yabtc.core.PriKey(int(args.prikey, 0)) pubkey = prikey.pubkey() if args.sig == '': - print(btc.core.Message(args.msg).sign(prikey)) + print(yabtc.core.Message(args.msg).sign(prikey)) if args.sig != '': - print(btc.core.Message(args.msg).pubkey(args.sig) == pubkey) + print(yabtc.core.Message(args.msg).pubkey(args.sig) == pubkey) diff --git a/example/regtest.py b/example/regtest.py index 3069655..1713d72 100644 --- a/example/regtest.py +++ b/example/regtest.py @@ -1,9 +1,9 @@ -import btc +import yabtc -pub1 = btc.core.PriKey(1).pubkey() -pub2 = btc.core.PriKey(2).pubkey() +pub1 = yabtc.core.PriKey(1).pubkey() +pub2 = yabtc.core.PriKey(2).pubkey() -btc.rpc.call('createwallet', ['main', True, True, None, None, None, True]) +yabtc.rpc.call('createwallet', ['main', True, True, None, None, None, True]) for d in [ f'pkh({pub1.sec().hex()})', f'pkh({pub2.sec().hex()})', @@ -16,14 +16,14 @@ f'tr({pub1.sec().hex()})', f'tr({pub2.sec().hex()})', ]: - d = btc.rpc.get_descriptor_info(d)['descriptor'] - btc.rpc.import_descriptors([{ + d = yabtc.rpc.get_descriptor_info(d)['descriptor'] + yabtc.rpc.import_descriptors([{ 'desc': d, 'timestamp': 0, }]) -btc.rpc.generate_to_address(10, btc.core.address_p2pkh(pub1)) -btc.rpc.generate_to_address(10, btc.core.address_p2sh_p2ms(2, [pub1, pub2])) -btc.rpc.generate_to_address(10, btc.core.address_p2sh_p2wpkh(pub1)) -btc.rpc.generate_to_address(10, btc.core.address_p2wpkh(pub1)) -btc.rpc.generate_to_address(10, btc.core.address_p2tr(pub1, bytearray())) -btc.rpc.generate_to_address(99, btc.core.address_p2pkh(pub1)) +yabtc.rpc.generate_to_address(10, yabtc.core.address_p2pkh(pub1)) +yabtc.rpc.generate_to_address(10, yabtc.core.address_p2sh_p2ms(2, [pub1, pub2])) +yabtc.rpc.generate_to_address(10, yabtc.core.address_p2sh_p2wpkh(pub1)) +yabtc.rpc.generate_to_address(10, yabtc.core.address_p2wpkh(pub1)) +yabtc.rpc.generate_to_address(10, yabtc.core.address_p2tr(pub1, bytearray())) +yabtc.rpc.generate_to_address(99, yabtc.core.address_p2pkh(pub1)) diff --git a/example/taproot.py b/example/taproot.py index 45bc944..46d0861 100644 --- a/example/taproot.py +++ b/example/taproot.py @@ -1,47 +1,47 @@ -import btc +import yabtc # This example shows how to create a P2TR script with two unlock conditions: p2pk and p2ms. # Here created two scripts, one of which is a p2pk script, which requires that it can only be unlocked by private key 2, # and the other is an 2-of-2 multisig script. -mast = btc.core.TapNode( - btc.core.TapLeaf(btc.core.script([ - btc.opcode.op_pushdata(btc.core.PriKey(2).pubkey().sec()[1:]), - btc.opcode.op_checksig, +mast = yabtc.core.TapNode( + yabtc.core.TapLeaf(yabtc.core.script([ + yabtc.opcode.op_pushdata(yabtc.core.PriKey(2).pubkey().sec()[1:]), + yabtc.opcode.op_checksig, ])), - btc.core.TapLeaf(btc.core.script([ - btc.opcode.op_pushdata(btc.core.PriKey(3).pubkey().sec()[1:]), - btc.opcode.op_checksig, - btc.opcode.op_pushdata(btc.core.PriKey(4).pubkey().sec()[1:]), - btc.opcode.op_checksigadd, - btc.opcode.op_n(2), - btc.opcode.op_equal, + yabtc.core.TapLeaf(yabtc.core.script([ + yabtc.opcode.op_pushdata(yabtc.core.PriKey(3).pubkey().sec()[1:]), + yabtc.opcode.op_checksig, + yabtc.opcode.op_pushdata(yabtc.core.PriKey(4).pubkey().sec()[1:]), + yabtc.opcode.op_checksigadd, + yabtc.opcode.op_n(2), + yabtc.opcode.op_equal, ])) ) class Tp2trp2pk: - def __init__(self, pubkey: btc.core.PubKey): + def __init__(self, pubkey: yabtc.core.PubKey): self.pubkey = pubkey - self.addr = btc.core.address_p2tr(pubkey, mast.hash) - self.script = btc.core.script_pubkey_p2tr(self.addr) - output_pubkey_byte = bytearray([0x02]) + btc.bech32.decode(btc.config.current.prefix.bech32, 1, self.addr) - output_pubkey = btc.core.PubKey.sec_decode(output_pubkey_byte) + self.addr = yabtc.core.address_p2tr(pubkey, mast.hash) + self.script = yabtc.core.script_pubkey_p2tr(self.addr) + output_pubkey_byte = bytearray([0x02]) + yabtc.bech32.decode(yabtc.config.current.prefix.bech32, 1, self.addr) + output_pubkey = yabtc.core.PubKey.sec_decode(output_pubkey_byte) # Control byte with leaf version and parity bit. if output_pubkey.y & 1: self.prefix = 0xc1 else: self.prefix = 0xc0 - def sign(self, tx: btc.core.Transaction): + def sign(self, tx: yabtc.core.Transaction): for i, e in enumerate(tx.vin): - m = tx.digest_segwit_v1(i, btc.core.sighash_all, mast.l.script) - s = btc.core.PriKey(2).sign_schnorr(m) + bytearray([btc.core.sighash_all]) + m = tx.digest_segwit_v1(i, yabtc.core.sighash_all, mast.l.script) + s = yabtc.core.PriKey(2).sign_schnorr(m) + bytearray([yabtc.core.sighash_all]) e.witness[0] = s - def txin(self, op: btc.core.OutPoint): - return btc.core.TxIn(op, bytearray(), 0xffffffff, [ + def txin(self, op: yabtc.core.OutPoint): + return yabtc.core.TxIn(op, bytearray(), 0xffffffff, [ bytearray(65), mast.l.script, bytearray([self.prefix]) + self.pubkey.sec()[1:] + mast.r.hash, @@ -49,26 +49,26 @@ def txin(self, op: btc.core.OutPoint): class Tp2trp2ms: - def __init__(self, pubkey: btc.core.PubKey): + def __init__(self, pubkey: yabtc.core.PubKey): self.pubkey = pubkey - self.addr = btc.core.address_p2tr(pubkey, mast.hash) - self.script = btc.core.script_pubkey_p2tr(self.addr) - output_pubkey_byte = bytearray([0x02]) + btc.bech32.decode(btc.config.current.prefix.bech32, 1, self.addr) - output_pubkey = btc.core.PubKey.sec_decode(output_pubkey_byte) + self.addr = yabtc.core.address_p2tr(pubkey, mast.hash) + self.script = yabtc.core.script_pubkey_p2tr(self.addr) + output_pubkey_byte = bytearray([0x02]) + yabtc.bech32.decode(yabtc.config.current.prefix.bech32, 1, self.addr) + output_pubkey = yabtc.core.PubKey.sec_decode(output_pubkey_byte) # Control byte with leaf version and parity bit. if output_pubkey.y & 1: self.prefix = 0xc1 else: self.prefix = 0xc0 - def sign(self, tx: btc.core.Transaction): + def sign(self, tx: yabtc.core.Transaction): for i, e in enumerate(tx.vin): - m = tx.digest_segwit_v1(i, btc.core.sighash_all, mast.r.script) - e.witness[0] = btc.core.PriKey(4).sign_schnorr(m) + bytearray([btc.core.sighash_all]) - e.witness[1] = btc.core.PriKey(3).sign_schnorr(m) + bytearray([btc.core.sighash_all]) + m = tx.digest_segwit_v1(i, yabtc.core.sighash_all, mast.r.script) + e.witness[0] = yabtc.core.PriKey(4).sign_schnorr(m) + bytearray([yabtc.core.sighash_all]) + e.witness[1] = yabtc.core.PriKey(3).sign_schnorr(m) + bytearray([yabtc.core.sighash_all]) - def txin(self, op: btc.core.OutPoint): - return btc.core.TxIn(op, bytearray(), 0xffffffff, [ + def txin(self, op: yabtc.core.OutPoint): + return yabtc.core.TxIn(op, bytearray(), 0xffffffff, [ bytearray(65), bytearray(65), mast.r.script, @@ -76,36 +76,36 @@ def txin(self, op: btc.core.OutPoint): ]) -mate = btc.wallet.Wallet(btc.wallet.Tp2pkh(1)) -btc.rpc.generate_to_address(10, mate.addr) +mate = yabtc.wallet.Wallet(yabtc.wallet.Tp2pkh(1)) +yabtc.rpc.generate_to_address(10, mate.addr) -user_p2tr = btc.wallet.Wallet(btc.wallet.Tp2tr(1, mast.hash)) -btc.rpc.import_descriptors([{ - 'desc': btc.rpc.get_descriptor_info(f'addr({user_p2tr.addr})')['descriptor'], +user_p2tr = yabtc.wallet.Wallet(yabtc.wallet.Tp2tr(1, mast.hash)) +yabtc.rpc.import_descriptors([{ + 'desc': yabtc.rpc.get_descriptor_info(f'addr({user_p2tr.addr})')['descriptor'], 'timestamp': 'now', }]) # Spending by key path. -mate.transfer(user_p2tr.script, 1 * btc.denomination.bitcoin) -assert user_p2tr.balance() == btc.denomination.bitcoin +mate.transfer(user_p2tr.script, 1 * yabtc.denomination.bitcoin) +assert user_p2tr.balance() == yabtc.denomination.bitcoin print('main: spending by key path') user_p2tr.transfer_all(mate.script) assert user_p2tr.balance() == 0 print('main: spending by key path done') # Spending by script path: pay to public key. -mate.transfer(user_p2tr.script, 1 * btc.denomination.bitcoin) -assert user_p2tr.balance() == btc.denomination.bitcoin -user_p2pk = btc.wallet.Wallet(Tp2trp2pk(user_p2tr.signer.pubkey)) +mate.transfer(user_p2tr.script, 1 * yabtc.denomination.bitcoin) +assert user_p2tr.balance() == yabtc.denomination.bitcoin +user_p2pk = yabtc.wallet.Wallet(Tp2trp2pk(user_p2tr.signer.pubkey)) print('main: spending by script path p2pk') user_p2pk.transfer_all(mate.script) assert user_p2tr.balance() == 0 print('main: spending by script path p2pk done') # Spending by script path: pay to 2-of-2 multisig script. -mate.transfer(user_p2tr.script, 1 * btc.denomination.bitcoin) -assert user_p2tr.balance() == btc.denomination.bitcoin -user_p2ms = btc.wallet.Wallet(Tp2trp2ms(user_p2tr.signer.pubkey)) +mate.transfer(user_p2tr.script, 1 * yabtc.denomination.bitcoin) +assert user_p2tr.balance() == yabtc.denomination.bitcoin +user_p2ms = yabtc.wallet.Wallet(Tp2trp2ms(user_p2tr.signer.pubkey)) print('main: spending by script path p2ms') user_p2ms.transfer_all(mate.script) assert user_p2tr.balance() == 0 diff --git a/example/transfer.py b/example/transfer.py index 9aeb1f4..041753d 100644 --- a/example/transfer.py +++ b/example/transfer.py @@ -1,5 +1,5 @@ import argparse -import btc +import yabtc # Transfer bitcoin to another account. @@ -12,22 +12,22 @@ args = parser.parse_args() if args.net == 'develop': - btc.config.current = btc.config.develop + yabtc.config.current = yabtc.config.develop if args.net == 'mainnet': - btc.config.current = btc.config.mainnet + yabtc.config.current = yabtc.config.mainnet if args.net == 'testnet': - btc.config.current = btc.config.testnet + yabtc.config.current = yabtc.config.testnet -accept_script = btc.core.script_pubkey(args.to) -accept_value = int(args.value * btc.denomination.bitcoin) +accept_script = yabtc.core.script_pubkey(args.to) +accept_value = int(args.value * yabtc.denomination.bitcoin) prikey = int(args.prikey, 0) if args.script_type == 'p2pkh': - wallet = btc.wallet.Wallet(btc.wallet.Tp2pkh(prikey)) + wallet = yabtc.wallet.Wallet(yabtc.wallet.Tp2pkh(prikey)) if args.script_type == 'p2sh-p2wpkh': - wallet = btc.wallet.Wallet(btc.wallet.Tp2shp2wpkh(prikey)) + wallet = yabtc.wallet.Wallet(yabtc.wallet.Tp2shp2wpkh(prikey)) if args.script_type == 'p2wpkh': - wallet = btc.wallet.Wallet(btc.wallet.Tp2wpkh(prikey)) + wallet = yabtc.wallet.Wallet(yabtc.wallet.Tp2wpkh(prikey)) if args.script_type == 'p2tr': - wallet = btc.wallet.Wallet(btc.wallet.Tp2tr(prikey, bytearray())) + wallet = yabtc.wallet.Wallet(yabtc.wallet.Tp2tr(prikey, bytearray())) txid = wallet.transfer(accept_script, accept_value) print(f'0x{txid.hex()}') diff --git a/pyproject.toml b/pyproject.toml index fc97aa8..d79daa2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,18 +3,15 @@ requires = ["hatchling"] build-backend = "hatchling.build" [project] -name = "pybtc" -version = "1.1.1" +name = "yabtc" +version = "1.2.0" authors = [ { name="Mohanson", email="mohanson@outlook.com" }, ] -description = "Python SDK for BTC" +description = "Yabtc: bitcoin library for humans" readme = "README.md" license = { file = "LICENSE" } dependencies = ["requests"] [project.urls] -homepage = "https://github.com/mohanson/pybtc" - -[tool.hatch.build.targets.wheel] -packages = ["btc"] +homepage = "https://github.com/mohanson/yabtc" diff --git a/test/test_base58.py b/test/test_base58.py index b42b6d3..5e0f518 100644 --- a/test/test_base58.py +++ b/test/test_base58.py @@ -1,22 +1,22 @@ -import btc import random +import yabtc def test_base58_encode(): - assert btc.base58.encode(bytearray.fromhex('00')) == '1' - assert btc.base58.encode(bytearray.fromhex('626262')) == 'a3gV' - assert btc.base58.encode(bytearray.fromhex('636363')) == 'aPEr' + assert yabtc.base58.encode(bytearray.fromhex('00')) == '1' + assert yabtc.base58.encode(bytearray.fromhex('626262')) == 'a3gV' + assert yabtc.base58.encode(bytearray.fromhex('636363')) == 'aPEr' def test_base58_decode(): - assert btc.base58.decode('1') == bytearray.fromhex('00') - assert btc.base58.decode('a3gV') == bytearray.fromhex('626262') - assert btc.base58.decode('aPEr') == bytearray.fromhex('636363') + assert yabtc.base58.decode('1') == bytearray.fromhex('00') + assert yabtc.base58.decode('a3gV') == bytearray.fromhex('626262') + assert yabtc.base58.decode('aPEr') == bytearray.fromhex('636363') def test_base58_random(): for _ in range(256): b = bytearray(random.randbytes(random.randint(0, 256))) - s = btc.base58.encode(b) - f = btc.base58.decode(s) + s = yabtc.base58.encode(b) + f = yabtc.base58.decode(s) assert b == f diff --git a/test/test_bech32.py b/test/test_bech32.py index b7d48b6..458881a 100644 --- a/test/test_bech32.py +++ b/test/test_bech32.py @@ -1,5 +1,5 @@ -import btc import pytest +import yabtc def test_bech32(): @@ -13,8 +13,8 @@ def test_bech32(): 'split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w', '?1ezyfcl', ]: - hrp, data = btc.bech32.bech32_decode(0, s) - assert btc.bech32.bech32_encode(hrp, 0, data) == s.lower() + hrp, data = yabtc.bech32.bech32_decode(0, s) + assert yabtc.bech32.bech32_encode(hrp, 0, data) == s.lower() for s in [ '\x20' + '1nwldj5', '\x7F' + '1axkwrx', @@ -30,7 +30,7 @@ def test_bech32(): '1qzzfhee', ]: with pytest.raises(AssertionError): - btc.bech32.bech32_decode(0, s) + yabtc.bech32.bech32_decode(0, s) def test_bech32m(): @@ -44,8 +44,8 @@ def test_bech32m(): 'split1checkupstagehandshakeupstreamerranterredcaperredlc445v', '?1v759aa', ]: - hrp, data = btc.bech32.bech32_decode(1, s) - assert btc.bech32.bech32_encode(hrp, 1, data) == s.lower() + hrp, data = yabtc.bech32.bech32_decode(1, s) + assert yabtc.bech32.bech32_encode(hrp, 1, data) == s.lower() for s in [ '\x20' + '1xj0phk', '\x7F' + '1g6xzxy', @@ -63,4 +63,4 @@ def test_bech32m(): '1p2gdwpf', ]: with pytest.raises(AssertionError): - btc.bech32.bech32_decode(1, s) + yabtc.bech32.bech32_decode(1, s) diff --git a/test/test_core.py b/test/test_core.py index 1a80811..a374042 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1,78 +1,78 @@ -import btc import random import string +import yabtc def test_address_p2pkh(): - btc.config.current = btc.config.mainnet - prikey = btc.core.PriKey(1) + yabtc.config.current = yabtc.config.mainnet + prikey = yabtc.core.PriKey(1) pubkey = prikey.pubkey() - addr = btc.core.address_p2pkh(pubkey) + addr = yabtc.core.address_p2pkh(pubkey) assert addr == '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH' - btc.config.current = btc.config.testnet - addr = btc.core.address_p2pkh(pubkey) + yabtc.config.current = yabtc.config.testnet + addr = yabtc.core.address_p2pkh(pubkey) assert addr == 'mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r' def test_address_p2sh(): # https://en.bitcoin.it/wiki/Pay_to_script_hash # https://mempool.space/tx/40eee3ae1760e3a8532263678cdf64569e6ad06abc133af64f735e52562bccc8 - btc.config.current = btc.config.mainnet + yabtc.config.current = yabtc.config.mainnet pubkey = bytearray() pubkey.append(0x04) pubkey.extend(bytearray.fromhex('2f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a5878')) pubkey.extend(bytearray.fromhex('8505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf')) - redeem = btc.core.script([ - btc.opcode.op_1, - btc.opcode.op_pushdata(pubkey), - btc.opcode.op_1, - btc.opcode.op_checkmultisig, + redeem = yabtc.core.script([ + yabtc.opcode.op_1, + yabtc.opcode.op_pushdata(pubkey), + yabtc.opcode.op_1, + yabtc.opcode.op_checkmultisig, ]) - addr = btc.core.address_p2sh(redeem) + addr = yabtc.core.address_p2sh(redeem) assert addr == '3P14159f73E4gFr7JterCCQh9QjiTjiZrG' def test_address_p2sh_p2ms(): - btc.config.current = btc.config.develop - keys = [btc.core.PubKey.sec_decode(bytearray.fromhex(e)) for e in [ + yabtc.config.current = yabtc.config.develop + keys = [yabtc.core.PubKey.sec_decode(bytearray.fromhex(e)) for e in [ '03150176a55b6d77eec5740c1f87f434cf416d5bbde1704bd816288a4466afb7bb', '02c3b2d3baf90e559346895b43253407fbb345c146910837b61f301f4c9a7edfe5', '02c6e3e94f7ff77457da9e76cf0779ca7c1e8575db064a2ea55400e6a9d8190225', ]] - addr = btc.core.address_p2sh_p2ms(2, keys) + addr = yabtc.core.address_p2sh_p2ms(2, keys) assert addr == '2MyxShnGQ5NifGb8CHYrtmzosRySxZ9pZo5' def test_address_p2sh_p2wpkh(): - btc.config.current = btc.config.mainnet - prikey = btc.core.PriKey(1) + yabtc.config.current = yabtc.config.mainnet + prikey = yabtc.core.PriKey(1) pubkey = prikey.pubkey() - addr = btc.core.address_p2sh_p2wpkh(pubkey) + addr = yabtc.core.address_p2sh_p2wpkh(pubkey) assert addr == '3JvL6Ymt8MVWiCNHC7oWU6nLeHNJKLZGLN' - btc.config.current = btc.config.testnet - addr = btc.core.address_p2sh_p2wpkh(pubkey) + yabtc.config.current = yabtc.config.testnet + addr = yabtc.core.address_p2sh_p2wpkh(pubkey) assert addr == '2NAUYAHhujozruyzpsFRP63mbrdaU5wnEpN' def test_address_p2tr(): - btc.config.current = btc.config.mainnet - prikey = btc.core.PriKey(1) + yabtc.config.current = yabtc.config.mainnet + prikey = yabtc.core.PriKey(1) pubkey = prikey.pubkey() - addr = btc.core.address_p2tr(pubkey, bytearray()) + addr = yabtc.core.address_p2tr(pubkey, bytearray()) assert addr == 'bc1pmfr3p9j00pfxjh0zmgp99y8zftmd3s5pmedqhyptwy6lm87hf5sspknck9' - btc.config.current = btc.config.testnet - addr = btc.core.address_p2tr(pubkey, bytearray()) + yabtc.config.current = yabtc.config.testnet + addr = yabtc.core.address_p2tr(pubkey, bytearray()) assert addr == 'tb1pmfr3p9j00pfxjh0zmgp99y8zftmd3s5pmedqhyptwy6lm87hf5ssk79hv2' def test_address_p2wpkh(): - btc.config.current = btc.config.mainnet - prikey = btc.core.PriKey(1) + yabtc.config.current = yabtc.config.mainnet + prikey = yabtc.core.PriKey(1) pubkey = prikey.pubkey() - addr = btc.core.address_p2wpkh(pubkey) + addr = yabtc.core.address_p2wpkh(pubkey) assert addr == 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4' - btc.config.current = btc.config.testnet - addr = btc.core.address_p2wpkh(pubkey) + yabtc.config.current = yabtc.config.testnet + addr = yabtc.core.address_p2wpkh(pubkey) assert addr == 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx' @@ -86,57 +86,59 @@ def test_compact_size(): [0xb4da564e2857, bytearray([0xff, 0x57, 0x28, 0x4e, 0x56, 0xda, 0xb4, 0x00, 0x00])], [0x4bf583a17d59c158, bytearray([0xff, 0x58, 0xc1, 0x59, 0x7d, 0xa1, 0x83, 0xf5, 0x4b])], ]: - assert btc.core.compact_size_encode(n) == b - assert btc.core.compact_size_decode(b) == n + assert yabtc.core.compact_size_encode(n) == b + assert yabtc.core.compact_size_decode(b) == n def test_der(): for _ in range(256): - r0 = btc.secp256k1.Fr(random.randint(0, btc.secp256k1.N - 1)) - s0 = btc.secp256k1.Fr(random.randint(0, btc.secp256k1.N - 1)) - r1, s1 = btc.core.der_decode(btc.core.der_encode(r0, s0)) + r0 = yabtc.secp256k1.Fr(random.randint(0, yabtc.secp256k1.N - 1)) + s0 = yabtc.secp256k1.Fr(random.randint(0, yabtc.secp256k1.N - 1)) + r1, s1 = yabtc.core.der_decode(yabtc.core.der_encode(r0, s0)) assert r0 == r1 assert s0 == s1 def test_difficulty_target(): - assert btc.core.difficulty_target(0x1b0404cb) == 0x00000000000404CB000000000000000000000000000000000000000000000000 - assert btc.core.difficulty_target(0x1d00ffff) == 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + assert yabtc.core.difficulty_target( + 0x1b0404cb) == 0x00000000000404CB000000000000000000000000000000000000000000000000 + assert yabtc.core.difficulty_target( + 0x1d00ffff) == 0x00000000FFFF0000000000000000000000000000000000000000000000000000 def test_hash160(): - hash = btc.core.hash160(bytearray([0, 1, 2, 3])) + hash = yabtc.core.hash160(bytearray([0, 1, 2, 3])) assert hash.hex() == '3c3fa3d4adcaf8f52d5b1843975e122548269937' def test_message(): for _ in range(4): - prikey = btc.core.PriKey(random.randint(0, btc.secp256k1.N)) + prikey = yabtc.core.PriKey(random.randint(0, yabtc.secp256k1.N)) pubkey = prikey.pubkey() - msg = btc.core.Message(''.join(random.choice(string.ascii_letters) for _ in range(random.randint(0, 1024)))) + msg = yabtc.core.Message(''.join(random.choice(string.ascii_letters) for _ in range(random.randint(0, 1024)))) sig = msg.sign(prikey) assert msg.pubkey(sig) == pubkey def test_prikey(): - prikey = btc.core.PriKey(1) + prikey = yabtc.core.PriKey(1) pubkey = prikey.pubkey() assert pubkey.x == 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 assert pubkey.y == 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 def test_prikey_wif(): - btc.config.current = btc.config.mainnet - prikey = btc.core.PriKey(1) + yabtc.config.current = yabtc.config.mainnet + prikey = yabtc.core.PriKey(1) assert prikey.wif() == 'KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn' - assert prikey == btc.core.PriKey.wif_decode(prikey.wif()) - btc.config.current = btc.config.testnet + assert prikey == yabtc.core.PriKey.wif_decode(prikey.wif()) + yabtc.config.current = yabtc.config.testnet assert prikey.wif() == 'cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87JcbXMTcA' - assert prikey == btc.core.PriKey.wif_decode(prikey.wif()) + assert prikey == yabtc.core.PriKey.wif_decode(prikey.wif()) def test_pubkey_sec(): - pubkey = btc.core.PubKey( + pubkey = yabtc.core.PubKey( 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 ) @@ -144,14 +146,14 @@ def test_pubkey_sec(): def test_pubkey_sec_read(): - pubkey = btc.core.PubKey.sec_decode(bytes.fromhex(''.join([ + pubkey = yabtc.core.PubKey.sec_decode(bytes.fromhex(''.join([ '04', '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8' ]))) assert pubkey.x == 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 assert pubkey.y == 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 - pubkey = btc.core.PubKey.sec_decode(bytes.fromhex(''.join([ + pubkey = yabtc.core.PubKey.sec_decode(bytes.fromhex(''.join([ '02', '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', ]))) @@ -177,7 +179,7 @@ def test_transaction(): 0xb0, 0xd2, 0xfa, 0x2b, 0x42, 0xa4, 0x51, 0x82, 0xfc, 0x83, 0xe8, 0x17, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, ]) - tx = btc.core.Transaction.serialize_decode(data) + tx = yabtc.core.Transaction.serialize_decode(data) assert tx.serialize() == data assert tx.version == 1 assert len(tx.vin) == 1 @@ -190,4 +192,4 @@ def test_transaction(): def test_witness(): for _ in range(256): wits = [random.randbytes(random.randint(0, 256)) for _ in range(random.randint(0, 256))] - assert btc.core.witness_decode(btc.core.witness_encode(wits)) == wits + assert yabtc.core.witness_decode(yabtc.core.witness_encode(wits)) == wits diff --git a/test/test_ripemd160.py b/test/test_ripemd160.py index d738cae..0f79a02 100644 --- a/test/test_ripemd160.py +++ b/test/test_ripemd160.py @@ -1,4 +1,4 @@ -import btc +import yabtc def test_ripemd160(): @@ -14,4 +14,4 @@ def test_ripemd160(): (b'1234567890' * 8, '9b752e45573d4b39f4dbd3323cab82bf63326bfb'), (b'a' * 1000, 'aa69deee9a8922e92f8105e007f76110f381e9cf') ]: - assert btc.ripemd160.ripemd160(msg).digest().hex() == out + assert yabtc.ripemd160.ripemd160(msg).digest().hex() == out diff --git a/test/test_rpc.py b/test/test_rpc.py index 73cfdf6..e387e7c 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -1,21 +1,21 @@ -import btc +import yabtc def test_generate_to_address(): - btc.config.current = btc.config.develop - prikey = btc.core.PriKey(1) + yabtc.config.current = yabtc.config.develop + prikey = yabtc.core.PriKey(1) pubkey = prikey.pubkey() - addr = btc.core.address_p2wpkh(pubkey) - hash = btc.rpc.generate_to_address(4, addr) + addr = yabtc.core.address_p2wpkh(pubkey) + hash = yabtc.rpc.generate_to_address(4, addr) assert len(hash) == 4 def test_get_best_block_hash(): - btc.config.current = btc.config.develop - hash = btc.rpc.get_best_block_hash() + yabtc.config.current = yabtc.config.develop + hash = yabtc.rpc.get_best_block_hash() assert len(hash) == 64 def test_get_block_count(): - btc.config.current = btc.config.develop - assert btc.rpc.get_block_count() != 0 + yabtc.config.current = yabtc.config.develop + assert yabtc.rpc.get_block_count() != 0 diff --git a/test/test_schnorr.py b/test/test_schnorr.py index 0bfb256..59e7ef9 100644 --- a/test/test_schnorr.py +++ b/test/test_schnorr.py @@ -1,11 +1,11 @@ -import btc import random +import yabtc def test_schnorr(): for _ in range(4): - prikey = btc.secp256k1.Fr(random.randint(0, btc.secp256k1.N)) - pubkey = btc.secp256k1.G * prikey - m = btc.secp256k1.Fr(random.randint(0, btc.secp256k1.N)) - r, s = btc.schnorr.sign(prikey, m) - assert btc.schnorr.verify(pubkey, m, r, s) + prikey = yabtc.secp256k1.Fr(random.randint(0, yabtc.secp256k1.N)) + pubkey = yabtc.secp256k1.G * prikey + m = yabtc.secp256k1.Fr(random.randint(0, yabtc.secp256k1.N)) + r, s = yabtc.schnorr.sign(prikey, m) + assert yabtc.schnorr.verify(pubkey, m, r, s) diff --git a/test/test_wallet.py b/test/test_wallet.py index 3b01526..ab1a2ad 100644 --- a/test/test_wallet.py +++ b/test/test_wallet.py @@ -1,36 +1,36 @@ -import btc import itertools +import yabtc def test_wallet_transfer(): - btc.config.current = btc.config.develop + yabtc.config.current = yabtc.config.develop user_list = [ - btc.wallet.Wallet(btc.wallet.Tp2pkh(1)), - btc.wallet.Wallet(btc.wallet.Tp2shp2ms([btc.core.PriKey(e).pubkey() for e in [1, 2]], [1, 2])), - btc.wallet.Wallet(btc.wallet.Tp2shp2wpkh(1)), - btc.wallet.Wallet(btc.wallet.Tp2wpkh(1)), - btc.wallet.Wallet(btc.wallet.Tp2tr(1, bytearray())), + yabtc.wallet.Wallet(yabtc.wallet.Tp2pkh(1)), + yabtc.wallet.Wallet(yabtc.wallet.Tp2shp2ms([yabtc.core.PriKey(e).pubkey() for e in [1, 2]], [1, 2])), + yabtc.wallet.Wallet(yabtc.wallet.Tp2shp2wpkh(1)), + yabtc.wallet.Wallet(yabtc.wallet.Tp2wpkh(1)), + yabtc.wallet.Wallet(yabtc.wallet.Tp2tr(1, bytearray())), ] mate_list = [ - btc.wallet.Wallet(btc.wallet.Tp2pkh(2)), - btc.wallet.Wallet(btc.wallet.Tp2shp2ms([btc.core.PriKey(e).pubkey() for e in [2, 1]], [2, 1])), - btc.wallet.Wallet(btc.wallet.Tp2shp2wpkh(2)), - btc.wallet.Wallet(btc.wallet.Tp2wpkh(2)), - btc.wallet.Wallet(btc.wallet.Tp2tr(2, bytearray())), + yabtc.wallet.Wallet(yabtc.wallet.Tp2pkh(2)), + yabtc.wallet.Wallet(yabtc.wallet.Tp2shp2ms([yabtc.core.PriKey(e).pubkey() for e in [2, 1]], [2, 1])), + yabtc.wallet.Wallet(yabtc.wallet.Tp2shp2wpkh(2)), + yabtc.wallet.Wallet(yabtc.wallet.Tp2wpkh(2)), + yabtc.wallet.Wallet(yabtc.wallet.Tp2tr(2, bytearray())), ] for user, mate in itertools.product(user_list, mate_list): - value = btc.denomination.bitcoin + value = yabtc.denomination.bitcoin value_old = mate.balance() txid = user.transfer(mate.script, value) - btc.rpc.wait(txid[::-1].hex()) + yabtc.rpc.wait(txid[::-1].hex()) value_new = mate.balance() assert value_new - value_old == value value_old = value_new txid = user.transfer(mate.script, value) - btc.rpc.wait(txid[::-1].hex()) + yabtc.rpc.wait(txid[::-1].hex()) value_new = mate.balance() assert value_new - value_old == value - btc.rpc.generate_to_address(6, user.addr) + yabtc.rpc.generate_to_address(6, user.addr) txid = mate.transfer_all(user.script) - btc.rpc.wait(txid[::-1].hex()) + yabtc.rpc.wait(txid[::-1].hex()) assert mate.balance() == 0 diff --git a/btc/__init__.py b/yabtc/__init__.py similarity index 100% rename from btc/__init__.py rename to yabtc/__init__.py diff --git a/btc/base58.py b/yabtc/base58.py similarity index 100% rename from btc/base58.py rename to yabtc/base58.py diff --git a/btc/bech32.py b/yabtc/bech32.py similarity index 100% rename from btc/bech32.py rename to yabtc/bech32.py diff --git a/btc/config.py b/yabtc/config.py similarity index 100% rename from btc/config.py rename to yabtc/config.py diff --git a/btc/core.py b/yabtc/core.py similarity index 86% rename from btc/core.py rename to yabtc/core.py index 7ab89f0..7e6c1c6 100644 --- a/btc/core.py +++ b/yabtc/core.py @@ -1,20 +1,20 @@ import base64 -import btc.base58 -import btc.bech32 -import btc.config -import btc.denomination -import btc.ecdsa -import btc.opcode -import btc.ripemd160 -import btc.rpc -import btc.schnorr -import btc.secp256k1 import hashlib import itertools import math import io import json import typing +import yabtc.base58 +import yabtc.bech32 +import yabtc.config +import yabtc.denomination +import yabtc.ecdsa +import yabtc.opcode +import yabtc.ripemd160 +import yabtc.rpc +import yabtc.schnorr +import yabtc.secp256k1 sighash_default = 0x00 sighash_all = 0x01 @@ -24,7 +24,7 @@ def hash160(data: bytearray) -> bytearray: - return bytearray(btc.ripemd160.ripemd160(hashlib.sha256(data).digest()).digest()) + return bytearray(yabtc.ripemd160.ripemd160(hashlib.sha256(data).digest()).digest()) def hash256(data: bytearray) -> bytearray: @@ -32,7 +32,7 @@ def hash256(data: bytearray) -> bytearray: def hashtag(name: str, data: bytearray) -> bytearray: - return btc.schnorr.hash(name, data) + return yabtc.schnorr.hash(name, data) class PriKey: @@ -51,18 +51,18 @@ def json(self) -> typing.Dict: } def pubkey(self): - pubkey = btc.secp256k1.G * btc.secp256k1.Fr(self.n) + pubkey = yabtc.secp256k1.G * yabtc.secp256k1.Fr(self.n) return PubKey(pubkey.x.x, pubkey.y.x) - def sign_ecdsa(self, data: bytearray) -> typing.Tuple[btc.secp256k1.Fr, btc.secp256k1.Fr, int]: + def sign_ecdsa(self, data: bytearray) -> typing.Tuple[yabtc.secp256k1.Fr, yabtc.secp256k1.Fr, int]: assert len(data) == 32 - m = btc.secp256k1.Fr(int.from_bytes(data)) + m = yabtc.secp256k1.Fr(int.from_bytes(data)) for _ in itertools.repeat(0): - r, s, v = btc.ecdsa.sign(btc.secp256k1.Fr(self.n), m) + r, s, v = yabtc.ecdsa.sign(yabtc.secp256k1.Fr(self.n), m) # We require that the S value inside ECDSA signatures is at most the curve order divided by 2 (essentially # restricting this value to its lower half range). # See: https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki - if s.x * 2 >= btc.secp256k1.N: + if s.x * 2 >= yabtc.secp256k1.N: s = -s v ^= 1 return r, s, v @@ -74,24 +74,24 @@ def sign_ecdsa_der(self, data: bytearray) -> bytearray: def sign_schnorr(self, data: bytearray) -> bytearray: assert len(data) == 32 - m = btc.secp256k1.Fr(int.from_bytes(data)) - r, s = btc.schnorr.sign(btc.secp256k1.Fr(self.n), m) + m = yabtc.secp256k1.Fr(int.from_bytes(data)) + r, s = yabtc.schnorr.sign(yabtc.secp256k1.Fr(self.n), m) return bytearray(r.x.x.to_bytes(32) + s.x.to_bytes(32)) def wif(self) -> str: # See https://en.bitcoin.it/wiki/Wallet_import_format data = bytearray() - data.append(btc.config.current.prefix.wif) + data.append(yabtc.config.current.prefix.wif) data.extend(self.n.to_bytes(32)) data.append(0x01) checksum = hash256(data)[:4] data.extend(checksum) - return btc.base58.encode(data) + return yabtc.base58.encode(data) @classmethod def wif_decode(cls, data: str) -> typing.Self: - data = btc.base58.decode(data) - assert data[0] == btc.config.current.prefix.wif + data = yabtc.base58.decode(data) + assert data[0] == yabtc.config.current.prefix.wif assert hash256(data[:-4])[:4] == data[-4:] return PriKey(int.from_bytes(data[1:33])) @@ -99,7 +99,7 @@ def wif_decode(cls, data: str) -> typing.Self: class PubKey: def __init__(self, x: int, y: int) -> None: # The public key must be on the curve. - _ = btc.secp256k1.Pt(btc.secp256k1.Fq(x), btc.secp256k1.Fq(y)) + _ = yabtc.secp256k1.Pt(yabtc.secp256k1.Fq(x), yabtc.secp256k1.Fq(y)) self.x = x self.y = y @@ -118,11 +118,11 @@ def json(self) -> typing.Dict: 'y': f'0x{self.y:064x}' } - def pt(self) -> btc.secp256k1.Pt: - return btc.secp256k1.Pt(btc.secp256k1.Fq(self.x), btc.secp256k1.Fq(self.y)) + def pt(self) -> yabtc.secp256k1.Pt: + return yabtc.secp256k1.Pt(yabtc.secp256k1.Fq(self.x), yabtc.secp256k1.Fq(self.y)) @classmethod - def pt_decode(cls, data: btc.secp256k1.Pt) -> typing.Self: + def pt_decode(cls, data: yabtc.secp256k1.Pt) -> typing.Self: return PubKey(data.x.x, data.y.x) def sec(self) -> bytearray: @@ -142,10 +142,10 @@ def sec_decode(cls, data: bytearray) -> typing.Self: if p == 0x04: y = int.from_bytes(data[33:65]) else: - y_x_y = x * x * x + btc.secp256k1.A.x * x + btc.secp256k1.B.x - y = pow(y_x_y, (btc.secp256k1.P + 1) // 4, btc.secp256k1.P) + y_x_y = x * x * x + yabtc.secp256k1.A.x * x + yabtc.secp256k1.B.x + y = pow(y_x_y, (yabtc.secp256k1.P + 1) // 4, yabtc.secp256k1.P) if y & 1 != p - 2: - y = -y % btc.secp256k1.P + y = -y % yabtc.secp256k1.P return PubKey(x, y) # Bitcoin address prefix: https://en.bitcoin.it/wiki/List_of_address_prefixes @@ -154,27 +154,27 @@ def sec_decode(cls, data: bytearray) -> typing.Self: def address_p2pkh(pubkey: PubKey) -> str: # Legacy pubkey_hash = hash160(pubkey.sec()) - data = bytearray([btc.config.current.prefix.p2pkh]) + pubkey_hash + data = bytearray([yabtc.config.current.prefix.p2pkh]) + pubkey_hash chk4 = hash256(data)[:4] - return btc.base58.encode(data + chk4) + return yabtc.base58.encode(data + chk4) def address_p2sh(redeem: bytearray) -> str: # Pay to Script Hash. # See: https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki redeem_hash = hash160(redeem) - data = bytearray([btc.config.current.prefix.p2sh]) + redeem_hash + data = bytearray([yabtc.config.current.prefix.p2sh]) + redeem_hash chk4 = hash256(data)[:4] - return btc.base58.encode(data + chk4) + return yabtc.base58.encode(data + chk4) def address_p2sh_p2ms(n: int, pubkey: typing.List[PubKey]) -> str: redeem_script = [] - redeem_script.append(btc.opcode.op_n(n)) + redeem_script.append(yabtc.opcode.op_n(n)) for e in pubkey: - redeem_script.append(btc.opcode.op_pushdata(e.sec())) - redeem_script.append(btc.opcode.op_n(len(pubkey))) - redeem_script.append(btc.opcode.op_checkmultisig) + redeem_script.append(yabtc.opcode.op_pushdata(e.sec())) + redeem_script.append(yabtc.opcode.op_n(len(pubkey))) + redeem_script.append(yabtc.opcode.op_checkmultisig) redeem_script = script(redeem_script) return address_p2sh(redeem_script) @@ -183,7 +183,7 @@ def address_p2sh_p2wpkh(pubkey: PubKey) -> str: # Nested Segwit. # See https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki pubkey_hash = hash160(pubkey.sec()) - redeem_script = script([btc.opcode.op_0, btc.opcode.op_pushdata(pubkey_hash)]) + redeem_script = script([yabtc.opcode.op_0, yabtc.opcode.op_pushdata(pubkey_hash)]) return address_p2sh(redeem_script) @@ -191,7 +191,7 @@ def address_p2wpkh(pubkey: PubKey) -> str: # Native SegWit. # See https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki pubkey_hash = hash160(pubkey.sec()) - return btc.bech32.encode(btc.config.current.prefix.bech32, 0, pubkey_hash) + return yabtc.bech32.encode(yabtc.config.current.prefix.bech32, 0, pubkey_hash) def address_p2tr(pubkey: PubKey, root: bytearray) -> str: @@ -204,10 +204,10 @@ def address_p2tr(pubkey: PubKey, root: bytearray) -> str: # There is no script path if root is empty. assert len(root) in [0x00, 0x20] adjust_prikey_byte = hashtag('TapTweak', bytearray(origin_pubkey.x.x.to_bytes(32)) + root) - adjust_prikey = btc.secp256k1.Fr(int.from_bytes(adjust_prikey_byte)) - adjust_pubkey = btc.secp256k1.G * adjust_prikey + adjust_prikey = yabtc.secp256k1.Fr(int.from_bytes(adjust_prikey_byte)) + adjust_pubkey = yabtc.secp256k1.G * adjust_prikey output_pubkey = origin_pubkey + adjust_pubkey - return btc.bech32.encode(btc.config.current.prefix.bech32, 1, bytearray(output_pubkey.x.x.to_bytes(32))) + return yabtc.bech32.encode(yabtc.config.current.prefix.bech32, 1, bytearray(output_pubkey.x.x.to_bytes(32))) def compact_size_encode(n: int) -> bytearray: @@ -316,9 +316,9 @@ def json(self) -> typing.Dict: } def load(self): - rpcret = btc.rpc.get_tx_out(self.txid[::-1].hex(), self.vout) + rpcret = yabtc.rpc.get_tx_out(self.txid[::-1].hex(), self.vout) script_pubkey = bytearray.fromhex(rpcret['scriptPubKey']['hex']) - amount = rpcret['value'] * btc.denomination.bitcoin + amount = rpcret['value'] * yabtc.denomination.bitcoin amount = int(amount.to_integral_exact()) return TxOut(amount, script_pubkey) @@ -692,56 +692,56 @@ def weight(self) -> int: def script_pubkey_p2pkh(addr: str) -> bytearray: - data = btc.base58.decode(addr) - assert data[0] == btc.config.current.prefix.p2pkh + data = yabtc.base58.decode(addr) + assert data[0] == yabtc.config.current.prefix.p2pkh hash = data[0x01:0x15] - assert btc.core.hash256(data[0x00:0x15])[:4] == data[0x15:0x19] + assert yabtc.core.hash256(data[0x00:0x15])[:4] == data[0x15:0x19] return script([ - btc.opcode.op_dup, - btc.opcode.op_hash160, - btc.opcode.op_pushdata(hash), - btc.opcode.op_equalverify, - btc.opcode.op_checksig, + yabtc.opcode.op_dup, + yabtc.opcode.op_hash160, + yabtc.opcode.op_pushdata(hash), + yabtc.opcode.op_equalverify, + yabtc.opcode.op_checksig, ]) def script_pubkey_p2sh(addr: str) -> bytearray: - data = btc.base58.decode(addr) - assert data[0] == btc.config.current.prefix.p2sh + data = yabtc.base58.decode(addr) + assert data[0] == yabtc.config.current.prefix.p2sh hash = data[0x01:0x15] - assert btc.core.hash256(data[0x00:0x15])[:4] == data[0x15:0x19] + assert yabtc.core.hash256(data[0x00:0x15])[:4] == data[0x15:0x19] return script([ - btc.opcode.op_hash160, - btc.opcode.op_pushdata(hash), - btc.opcode.op_equal, + yabtc.opcode.op_hash160, + yabtc.opcode.op_pushdata(hash), + yabtc.opcode.op_equal, ]) def script_pubkey_p2wpkh(addr: str) -> bytearray: - hash = btc.bech32.decode(btc.config.current.prefix.bech32, 0, addr) + hash = yabtc.bech32.decode(yabtc.config.current.prefix.bech32, 0, addr) return script([ - btc.opcode.op_0, - btc.opcode.op_pushdata(hash), + yabtc.opcode.op_0, + yabtc.opcode.op_pushdata(hash), ]) def script_pubkey_p2tr(addr: str) -> bytearray: - pubx = btc.bech32.decode(btc.config.current.prefix.bech32, 1, addr) + pubx = yabtc.bech32.decode(yabtc.config.current.prefix.bech32, 1, addr) return script([ - btc.opcode.op_1, - btc.opcode.op_pushdata(pubx), + yabtc.opcode.op_1, + yabtc.opcode.op_pushdata(pubx), ]) def script_pubkey(addr: str) -> bytearray: - if addr.startswith(btc.config.current.prefix.bech32): - if addr[len(btc.config.current.prefix.bech32) + 1] == 'q': + if addr.startswith(yabtc.config.current.prefix.bech32): + if addr[len(yabtc.config.current.prefix.bech32) + 1] == 'q': return script_pubkey_p2wpkh(addr) - if addr[len(btc.config.current.prefix.bech32) + 1] == 'p': + if addr[len(yabtc.config.current.prefix.bech32) + 1] == 'p': return script_pubkey_p2tr(addr) - if btc.base58.decode(addr)[0] == btc.config.current.prefix.p2pkh: + if yabtc.base58.decode(addr)[0] == yabtc.config.current.prefix.p2pkh: return script_pubkey_p2pkh(addr) - if btc.base58.decode(addr)[0] == btc.config.current.prefix.p2sh: + if yabtc.base58.decode(addr)[0] == yabtc.config.current.prefix.p2sh: return script_pubkey_p2sh(addr) raise Exception @@ -756,7 +756,7 @@ def script(i: typing.List[int | bytearray]) -> bytearray: return r -def der_encode(r: btc.secp256k1.Fr, s: btc.secp256k1.Fr) -> bytearray: +def der_encode(r: yabtc.secp256k1.Fr, s: yabtc.secp256k1.Fr) -> bytearray: # DER encoding: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#der-encoding body = bytearray() body.append(0x02) @@ -775,17 +775,17 @@ def der_encode(r: btc.secp256k1.Fr, s: btc.secp256k1.Fr) -> bytearray: return head + body -def der_decode(sign: bytearray) -> typing.Tuple[btc.secp256k1.Fr, btc.secp256k1.Fr]: +def der_decode(sign: bytearray) -> typing.Tuple[yabtc.secp256k1.Fr, yabtc.secp256k1.Fr]: assert sign[0] == 0x30 assert sign[1] == len(sign) - 2 assert sign[2] == 0x02 rlen = sign[3] - r = btc.secp256k1.Fr(int.from_bytes(sign[4:4+rlen])) + r = yabtc.secp256k1.Fr(int.from_bytes(sign[4:4+rlen])) f = 4 + rlen assert sign[f] == 0x02 slen = sign[f+1] f = f + 2 - s = btc.secp256k1.Fr(int.from_bytes(sign[f:f+slen])) + s = yabtc.secp256k1.Fr(int.from_bytes(sign[f:f+slen])) return r, s @@ -816,11 +816,11 @@ def __init__(self, data: str) -> None: def hash(self) -> bytearray: b = bytearray() # Text used to signify that a signed message follows and to prevent inadvertently signing a transaction. - b.extend(btc.core.compact_size_encode(24)) + b.extend(yabtc.core.compact_size_encode(24)) b.extend(bytearray('Bitcoin Signed Message:\n'.encode())) - b.extend(btc.core.compact_size_encode(len(self.data))) + b.extend(yabtc.core.compact_size_encode(len(self.data))) b.extend(bytearray(self.data.encode())) - return btc.core.hash256(b) + return yabtc.core.hash256(b) def sign(self, prikey: PriKey) -> str: r, s, v = prikey.sign_ecdsa(self.hash()) @@ -834,13 +834,13 @@ def sign(self, prikey: PriKey) -> str: return base64.b64encode(sig).decode() def pubkey(self, sig: str) -> PubKey: - m = btc.secp256k1.Fr(int.from_bytes(self.hash())) + m = yabtc.secp256k1.Fr(int.from_bytes(self.hash())) sig = base64.b64decode(sig) assert sig[0] >= 27 v = (sig[0] - 27) & 3 - r = btc.secp256k1.Fr(int.from_bytes(sig[0x01:0x21])) - s = btc.secp256k1.Fr(int.from_bytes(sig[0x21:0x41])) - return PubKey.pt_decode(btc.ecdsa.pubkey(m, r, s, v)) + r = yabtc.secp256k1.Fr(int.from_bytes(sig[0x01:0x21])) + s = yabtc.secp256k1.Fr(int.from_bytes(sig[0x21:0x41])) + return PubKey.pt_decode(yabtc.ecdsa.pubkey(m, r, s, v)) class TapLeaf: diff --git a/btc/denomination.py b/yabtc/denomination.py similarity index 100% rename from btc/denomination.py rename to yabtc/denomination.py diff --git a/yabtc/ecdsa.py b/yabtc/ecdsa.py new file mode 100644 index 0000000..b811dc4 --- /dev/null +++ b/yabtc/ecdsa.py @@ -0,0 +1,52 @@ +import itertools +import random +import typing +import yabtc.secp256k1 + + + +def sign(prikey: yabtc.secp256k1.Fr, m: yabtc.secp256k1.Fr) -> typing.Tuple[yabtc.secp256k1.Fr, yabtc.secp256k1.Fr, int]: + # https://www.secg.org/sec1-v2.pdf + # 4.1.3 Signing Operation + for _ in itertools.repeat(0): + k = yabtc.secp256k1.Fr(random.randint(0, yabtc.secp256k1.N - 1)) + R = yabtc.secp256k1.G * k + r = yabtc.secp256k1.Fr(R.x.x) + if r.x == 0: + continue + s = (m + prikey * r) / k + if s.x == 0: + continue + v = 0 + if R.y.x & 1 == 1: + v |= 1 + if R.x.x >= yabtc.secp256k1.N: + v |= 2 + return r, s, v + + +def verify(pubkey: yabtc.secp256k1.Pt, m: yabtc.secp256k1.Fr, r: yabtc.secp256k1.Fr, s: yabtc.secp256k1.Fr) -> bool: + # https://www.secg.org/sec1-v2.pdf + # 4.1.4 Verifying Operation + u1 = m / s + u2 = r / s + x = yabtc.secp256k1.G * u1 + pubkey * u2 + assert x != yabtc.secp256k1.I + v = yabtc.secp256k1.Fr(x.x.x) + return v == r + + +def pubkey(m: yabtc.secp256k1.Fr, r: yabtc.secp256k1.Fr, s: yabtc.secp256k1.Fr, v: int) -> yabtc.secp256k1.Pt: + # https://www.secg.org/sec1-v2.pdf + # 4.1.6 Public Key Recovery Operation + assert v in [0, 1, 2, 3] + if v & 2 == 0: + x = yabtc.secp256k1.Fq(r.x) + else: + x = yabtc.secp256k1.Fq(r.x + yabtc.secp256k1.N) + y_y = x * x * x + yabtc.secp256k1.A * x + yabtc.secp256k1.B + y = y_y ** ((yabtc.secp256k1.P + 1) // 4) + if v & 1 != y.x & 1: + y = -y + R = yabtc.secp256k1.Pt(x, y) + return (R * s - yabtc.secp256k1.G * m) / r diff --git a/btc/opcode.py b/yabtc/opcode.py similarity index 100% rename from btc/opcode.py rename to yabtc/opcode.py diff --git a/btc/ripemd160.py b/yabtc/ripemd160.py similarity index 100% rename from btc/ripemd160.py rename to yabtc/ripemd160.py diff --git a/btc/rpc.py b/yabtc/rpc.py similarity index 96% rename from btc/rpc.py rename to yabtc/rpc.py index ea4fd35..d2e762a 100644 --- a/btc/rpc.py +++ b/yabtc/rpc.py @@ -1,23 +1,23 @@ -import btc.config import decimal import itertools import random import requests import time import typing +import yabtc.config # Doc: https://developer.bitcoin.org/reference/rpc/ def call(method: str, params: typing.List[typing.Any]) -> typing.Any: - r = requests.post(btc.config.current.rpc.addr, json={ + r = requests.post(yabtc.config.current.rpc.addr, json={ 'id': random.randint(0x00000000, 0xffffffff), 'jsonrpc': '2.0', 'method': method, 'params': params, }, auth=( - btc.config.current.rpc.username, - btc.config.current.rpc.password, + yabtc.config.current.rpc.username, + yabtc.config.current.rpc.password, )).json(parse_float=decimal.Decimal) if 'error' in r and r['error']: raise Exception(r['error']) @@ -25,7 +25,7 @@ def call(method: str, params: typing.List[typing.Any]) -> typing.Any: def wait(txid: str): - if btc.config.current == btc.config.develop: + if yabtc.config.current == yabtc.config.develop: return for _ in itertools.repeat(0): r = get_raw_transaction(txid) @@ -353,7 +353,7 @@ def derive_addresses(): def estimates_mart_fee(conf_target: int) -> typing.Dict: # A mock is required on RegTest to allow this RPC to return meaningful data. # See: https://github.com/bitcoin/bitcoin/issues/11500 - if btc.config.current == btc.config.develop: + if yabtc.config.current == yabtc.config.develop: return {'feerate': decimal.Decimal('0.00001'), 'blocks': conf_target} return call('estimatesmartfee', [conf_target, 'ECONOMICAL']) diff --git a/btc/schnorr.py b/yabtc/schnorr.py similarity index 55% rename from btc/schnorr.py rename to yabtc/schnorr.py index 91f76f4..c57906f 100644 --- a/btc/schnorr.py +++ b/yabtc/schnorr.py @@ -1,21 +1,21 @@ -import btc.secp256k1 import hashlib import random import typing +import yabtc.secp256k1 # Schnorr Signatures for secp256k1. # See: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki -def prikey_implicit(prikey: btc.secp256k1.Fr) -> btc.secp256k1.Fr: - pubkey = btc.secp256k1.G * prikey +def prikey_implicit(prikey: yabtc.secp256k1.Fr) -> yabtc.secp256k1.Fr: + pubkey = yabtc.secp256k1.G * prikey if pubkey == pubkey_implicit(pubkey): return +prikey else: return -prikey -def pubkey_implicit(pubkey: btc.secp256k1.Pt) -> btc.secp256k1.Pt: +def pubkey_implicit(pubkey: yabtc.secp256k1.Pt) -> yabtc.secp256k1.Pt: if pubkey.y.x & 1: return -pubkey else: @@ -28,21 +28,21 @@ def hash(name: str, data: bytearray) -> bytearray: return out -def sign(prikey: btc.secp256k1.Fr, m: btc.secp256k1.Fr) -> typing.Tuple[btc.secp256k1.Pt, btc.secp256k1.Fr]: +def sign(prikey: yabtc.secp256k1.Fr, m: yabtc.secp256k1.Fr) -> typing.Tuple[yabtc.secp256k1.Pt, yabtc.secp256k1.Fr]: prikey = prikey_implicit(prikey) - pubkey = btc.secp256k1.G * prikey - k = prikey_implicit(btc.secp256k1.Fr(random.randint(0, btc.secp256k1.N))) - r = btc.secp256k1.G * k + pubkey = yabtc.secp256k1.G * prikey + k = prikey_implicit(yabtc.secp256k1.Fr(random.randint(0, yabtc.secp256k1.N))) + r = yabtc.secp256k1.G * k e_data = bytearray(r.x.x.to_bytes(32) + pubkey.x.x.to_bytes(32) + m.x.to_bytes(32)) e_hash = hash('BIP0340/challenge', e_data) - e = btc.secp256k1.Fr(int.from_bytes(e_hash)) + e = yabtc.secp256k1.Fr(int.from_bytes(e_hash)) s = k + e * prikey return r, s -def verify(pubkey: btc.secp256k1.Pt, m: btc.secp256k1.Fr, r: btc.secp256k1.Pt, s: btc.secp256k1.Fr): +def verify(pubkey: yabtc.secp256k1.Pt, m: yabtc.secp256k1.Fr, r: yabtc.secp256k1.Pt, s: yabtc.secp256k1.Fr): pubkey = pubkey_implicit(pubkey) e_data = bytearray(r.x.x.to_bytes(32) + pubkey.x.x.to_bytes(32) + m.x.to_bytes(32)) e_hash = hash('BIP0340/challenge', e_data) - e = btc.secp256k1.Fr(int.from_bytes(e_hash)) - return btc.secp256k1.G * s == r + pubkey * e + e = yabtc.secp256k1.Fr(int.from_bytes(e_hash)) + return yabtc.secp256k1.G * s == r + pubkey * e diff --git a/btc/secp256k1.py b/yabtc/secp256k1.py similarity index 100% rename from btc/secp256k1.py rename to yabtc/secp256k1.py diff --git a/btc/wallet.py b/yabtc/wallet.py similarity index 57% rename from btc/wallet.py rename to yabtc/wallet.py index f3d3a87..4f270d3 100644 --- a/btc/wallet.py +++ b/yabtc/wallet.py @@ -1,17 +1,16 @@ -import btc.core -import btc.denomination -import btc.opcode -import btc.rpc -import btc.schnorr -import btc.secp256k1 import json import requests import typing - +import yabtc.core +import yabtc.denomination +import yabtc.opcode +import yabtc.rpc +import yabtc.schnorr +import yabtc.secp256k1 class Analyzer: # Analyzer is a simple transaction analyzer to reject transactions that are obviously wrong. - def __init__(self, tx: btc.core.Transaction) -> None: + def __init__(self, tx: yabtc.core.Transaction) -> None: self.tx = tx def analyze_mining_fee(self) -> None: @@ -32,7 +31,7 @@ def analyze(self) -> None: class Utxo: - def __init__(self, out_point: btc.core.OutPoint, out: btc.core.TxOut) -> None: + def __init__(self, out_point: yabtc.core.OutPoint, out: yabtc.core.TxOut) -> None: self.out_point = out_point self.out = out @@ -60,12 +59,12 @@ def __init__(self) -> None: def unspent(self, addr: str) -> typing.List[Utxo]: r = [] - for e in btc.rpc.list_unspent([addr]): - out_point = btc.core.OutPoint(bytearray.fromhex(e['txid'])[::-1], e['vout']) + for e in yabtc.rpc.list_unspent([addr]): + out_point = yabtc.core.OutPoint(bytearray.fromhex(e['txid'])[::-1], e['vout']) script_pubkey = bytearray.fromhex(e['scriptPubKey']) - amount = e['amount'] * btc.denomination.bitcoin + amount = e['amount'] * yabtc.denomination.bitcoin amount = int(amount.to_integral_exact()) - utxo = Utxo(out_point, btc.core.TxOut(amount, script_pubkey)) + utxo = Utxo(out_point, yabtc.core.TxOut(amount, script_pubkey)) r.append(utxo) return r @@ -87,11 +86,11 @@ def get_url(self, addr: str) -> str: def unspent(self, addr: str) -> typing.List[Utxo]: r = [] for e in requests.get(self.get_url(addr)).json(): - out_point = btc.core.OutPoint(bytearray.fromhex(e['txid'])[::-1], e['vout']) + out_point = yabtc.core.OutPoint(bytearray.fromhex(e['txid'])[::-1], e['vout']) # Mempool's api does not provide script_pubkey, so we have to infer it from the address. - script_pubkey = btc.core.script_pubkey(addr) + script_pubkey = yabtc.core.script_pubkey(addr) amount = e['value'] - utxo = Utxo(out_point, btc.core.TxOut(amount, script_pubkey)) + utxo = Utxo(out_point, yabtc.core.TxOut(amount, script_pubkey)) r.append(utxo) return r @@ -102,21 +101,21 @@ def __init__(self) -> None: pass def unspent(self, addr: str) -> typing.List[Utxo]: - if btc.config.current == btc.config.develop: + if yabtc.config.current == yabtc.config.develop: return SearcherCore().unspent(addr) - if btc.config.current == btc.config.mainnet: + if yabtc.config.current == yabtc.config.mainnet: return SearcherMempoolSpace('mainnet').unspent(addr) - if btc.config.current == btc.config.testnet: + if yabtc.config.current == yabtc.config.testnet: return SearcherMempoolSpace('testnet').unspent(addr) raise Exception class Tp2pkh: def __init__(self, prikey: int) -> None: - self.prikey = btc.core.PriKey(prikey) + self.prikey = yabtc.core.PriKey(prikey) self.pubkey = self.prikey.pubkey() - self.addr = btc.core.address_p2pkh(self.pubkey) - self.script = btc.core.script_pubkey_p2pkh(self.addr) + self.addr = yabtc.core.address_p2pkh(self.pubkey) + self.script = yabtc.core.script_pubkey_p2pkh(self.addr) def __repr__(self) -> str: return json.dumps(self.json()) @@ -129,33 +128,33 @@ def json(self) -> typing.Dict: 'script': self.script.hex(), } - def sign(self, tx: btc.core.Transaction) -> None: + def sign(self, tx: yabtc.core.Transaction) -> None: for i, e in enumerate(tx.vin): - s = self.prikey.sign_ecdsa_der(tx.digest_legacy(i, btc.core.sighash_all, e.out_point.load().script_pubkey)) - s.append(btc.core.sighash_all) - e.script_sig = btc.core.script([ - btc.opcode.op_pushdata(s), - btc.opcode.op_pushdata(self.pubkey.sec()) + s = self.prikey.sign_ecdsa_der(tx.digest_legacy(i, yabtc.core.sighash_all, e.out_point.load().script_pubkey)) + s.append(yabtc.core.sighash_all) + e.script_sig = yabtc.core.script([ + yabtc.opcode.op_pushdata(s), + yabtc.opcode.op_pushdata(self.pubkey.sec()) ]) - def txin(self, op: btc.core.OutPoint) -> btc.core.TxIn: - return btc.core.TxIn(op, bytearray(107), 0xffffffff, []) + def txin(self, op: yabtc.core.OutPoint) -> yabtc.core.TxIn: + return yabtc.core.TxIn(op, bytearray(107), 0xffffffff, []) class Tp2shp2ms: # Multi-signature: See https://en.bitcoin.it/wiki/Multi-signature. - def __init__(self, pubkey: typing.List[btc.core.PubKey], prikey: typing.List[int]) -> None: - self.prikey = [btc.core.PriKey(e) for e in prikey] + def __init__(self, pubkey: typing.List[yabtc.core.PubKey], prikey: typing.List[int]) -> None: + self.prikey = [yabtc.core.PriKey(e) for e in prikey] self.pubkey = pubkey script_asts = [] - script_asts.append(btc.opcode.op_n(len(prikey))) + script_asts.append(yabtc.opcode.op_n(len(prikey))) for e in self.pubkey: - script_asts.append(btc.opcode.op_pushdata(e.sec())) - script_asts.append(btc.opcode.op_n(len(pubkey))) - script_asts.append(btc.opcode.op_checkmultisig) - self.redeem = btc.core.script(script_asts) - self.addr = btc.core.address_p2sh(self.redeem) - self.script = btc.core.script_pubkey_p2sh(self.addr) + script_asts.append(yabtc.opcode.op_pushdata(e.sec())) + script_asts.append(yabtc.opcode.op_n(len(pubkey))) + script_asts.append(yabtc.opcode.op_checkmultisig) + self.redeem = yabtc.core.script(script_asts) + self.addr = yabtc.core.address_p2sh(self.redeem) + self.script = yabtc.core.script_pubkey_p2sh(self.addr) def __repr__(self) -> str: return json.dumps(self.json()) @@ -168,32 +167,32 @@ def json(self) -> typing.Dict: 'script': self.script.hex(), } - def sign(self, tx: btc.core.Transaction) -> None: + def sign(self, tx: yabtc.core.Transaction) -> None: for i, e in enumerate(tx.vin): script_sig = [] - script_sig.append(btc.opcode.op_0) + script_sig.append(yabtc.opcode.op_0) for prikey in self.prikey: - s = prikey.sign_ecdsa_der(tx.digest_legacy(i, btc.core.sighash_all, self.redeem)) - s.append(btc.core.sighash_all) - script_sig.append(btc.opcode.op_pushdata(s)) - script_sig.append(btc.opcode.op_pushdata(self.redeem)) - e.script_sig = btc.core.script(script_sig) + s = prikey.sign_ecdsa_der(tx.digest_legacy(i, yabtc.core.sighash_all, self.redeem)) + s.append(yabtc.core.sighash_all) + script_sig.append(yabtc.opcode.op_pushdata(s)) + script_sig.append(yabtc.opcode.op_pushdata(self.redeem)) + e.script_sig = yabtc.core.script(script_sig) - def txin(self, op: btc.core.OutPoint) -> btc.core.TxIn: + def txin(self, op: yabtc.core.OutPoint) -> yabtc.core.TxIn: script_sig = [] - script_sig.append(btc.opcode.op_0) + script_sig.append(yabtc.opcode.op_0) for _ in range(len(self.prikey)): - script_sig.append(btc.opcode.op_pushdata(bytearray(72))) - script_sig.append(btc.opcode.op_pushdata(self.redeem)) - return btc.core.TxIn(op, btc.core.script(script_sig), 0xffffffff, []) + script_sig.append(yabtc.opcode.op_pushdata(bytearray(72))) + script_sig.append(yabtc.opcode.op_pushdata(self.redeem)) + return yabtc.core.TxIn(op, yabtc.core.script(script_sig), 0xffffffff, []) class Tp2shp2wpkh: def __init__(self, prikey: int) -> None: - self.prikey = btc.core.PriKey(prikey) + self.prikey = yabtc.core.PriKey(prikey) self.pubkey = self.prikey.pubkey() - self.addr = btc.core.address_p2sh_p2wpkh(self.pubkey) - self.script = btc.core.script_pubkey_p2sh(self.addr) + self.addr = yabtc.core.address_p2sh_p2wpkh(self.pubkey) + self.script = yabtc.core.script_pubkey_p2sh(self.addr) def __repr__(self) -> str: return json.dumps(self.json()) @@ -206,38 +205,38 @@ def json(self) -> typing.Dict: 'script': self.script.hex(), } - def sign(self, tx: btc.core.Transaction) -> None: + def sign(self, tx: yabtc.core.Transaction) -> None: # See: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh-nested-in-bip16-p2sh - pubkey_hash = btc.core.hash160(self.pubkey.sec()) - script_code = btc.core.script([ - btc.opcode.op_pushdata(btc.core.script([ - btc.opcode.op_dup, - btc.opcode.op_hash160, - btc.opcode.op_pushdata(pubkey_hash), - btc.opcode.op_equalverify, - btc.opcode.op_checksig, + pubkey_hash = yabtc.core.hash160(self.pubkey.sec()) + script_code = yabtc.core.script([ + yabtc.opcode.op_pushdata(yabtc.core.script([ + yabtc.opcode.op_dup, + yabtc.opcode.op_hash160, + yabtc.opcode.op_pushdata(pubkey_hash), + yabtc.opcode.op_equalverify, + yabtc.opcode.op_checksig, ]))]) - script_sig = btc.core.script([btc.opcode.op_pushdata(btc.core.script([ - btc.opcode.op_0, - btc.opcode.op_pushdata(pubkey_hash) + script_sig = yabtc.core.script([yabtc.opcode.op_pushdata(yabtc.core.script([ + yabtc.opcode.op_0, + yabtc.opcode.op_pushdata(pubkey_hash) ]))]) for i, e in enumerate(tx.vin): e.script_sig = script_sig - s = self.prikey.sign_ecdsa_der(tx.digest_segwit_v0(i, btc.core.sighash_all, script_code)) - s.append(btc.core.sighash_all) + s = self.prikey.sign_ecdsa_der(tx.digest_segwit_v0(i, yabtc.core.sighash_all, script_code)) + s.append(yabtc.core.sighash_all) e.witness[0] = s e.witness[1] = self.pubkey.sec() - def txin(self, op: btc.core.OutPoint) -> btc.core.TxIn: - return btc.core.TxIn(op, bytearray(23), 0xffffffff, [bytearray(72), bytearray(33)]) + def txin(self, op: yabtc.core.OutPoint) -> yabtc.core.TxIn: + return yabtc.core.TxIn(op, bytearray(23), 0xffffffff, [bytearray(72), bytearray(33)]) class Tp2wpkh: def __init__(self, prikey: int) -> None: - self.prikey = btc.core.PriKey(prikey) + self.prikey = yabtc.core.PriKey(prikey) self.pubkey = self.prikey.pubkey() - self.addr = btc.core.address_p2wpkh(self.pubkey) - self.script = btc.core.script_pubkey_p2wpkh(self.addr) + self.addr = yabtc.core.address_p2wpkh(self.pubkey) + self.script = yabtc.core.script_pubkey_p2wpkh(self.addr) def __repr__(self) -> str: return json.dumps(self.json()) @@ -250,34 +249,34 @@ def json(self) -> typing.Dict: 'script': self.script.hex(), } - def sign(self, tx: btc.core.Transaction) -> None: + def sign(self, tx: yabtc.core.Transaction) -> None: # See: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh - pubkey_hash = btc.core.hash160(self.pubkey.sec()) - script_code = btc.core.script([ - btc.opcode.op_pushdata(btc.core.script([ - btc.opcode.op_dup, - btc.opcode.op_hash160, - btc.opcode.op_pushdata(pubkey_hash), - btc.opcode.op_equalverify, - btc.opcode.op_checksig, + pubkey_hash = yabtc.core.hash160(self.pubkey.sec()) + script_code = yabtc.core.script([ + yabtc.opcode.op_pushdata(yabtc.core.script([ + yabtc.opcode.op_dup, + yabtc.opcode.op_hash160, + yabtc.opcode.op_pushdata(pubkey_hash), + yabtc.opcode.op_equalverify, + yabtc.opcode.op_checksig, ]))]) for i, e in enumerate(tx.vin): - s = self.prikey.sign_ecdsa_der(tx.digest_segwit_v0(i, btc.core.sighash_all, script_code)) - s.append(btc.core.sighash_all) + s = self.prikey.sign_ecdsa_der(tx.digest_segwit_v0(i, yabtc.core.sighash_all, script_code)) + s.append(yabtc.core.sighash_all) e.witness[0] = s e.witness[1] = self.pubkey.sec() - def txin(self, op: btc.core.OutPoint) -> btc.core.TxIn: - return btc.core.TxIn(op, bytearray(), 0xffffffff, [bytearray(72), bytearray(33)]) + def txin(self, op: yabtc.core.OutPoint) -> yabtc.core.TxIn: + return yabtc.core.TxIn(op, bytearray(), 0xffffffff, [bytearray(72), bytearray(33)]) class Tp2tr: def __init__(self, prikey: int, root: bytearray) -> None: - self.prikey = btc.core.PriKey(prikey) + self.prikey = yabtc.core.PriKey(prikey) self.pubkey = self.prikey.pubkey() - self.addr = btc.core.address_p2tr(self.pubkey, root) + self.addr = yabtc.core.address_p2tr(self.pubkey, root) self.root = root - self.script = btc.core.script_pubkey_p2tr(self.addr) + self.script = yabtc.core.script_pubkey_p2tr(self.addr) def __repr__(self) -> str: return json.dumps(self.json()) @@ -291,21 +290,21 @@ def json(self) -> typing.Dict: 'script': self.script.hex(), } - def sign(self, tx: btc.core.Transaction) -> None: + def sign(self, tx: yabtc.core.Transaction) -> None: # See: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki - prikey = btc.secp256k1.Fr(self.prikey.n) - adjust_prikey_byte = btc.core.hashtag('TapTweak', bytearray(self.pubkey.x.to_bytes(32)) + self.root) - adjust_prikey = btc.secp256k1.Fr(int.from_bytes(adjust_prikey_byte)) + prikey = yabtc.secp256k1.Fr(self.prikey.n) + adjust_prikey_byte = yabtc.core.hashtag('TapTweak', bytearray(self.pubkey.x.to_bytes(32)) + self.root) + adjust_prikey = yabtc.secp256k1.Fr(int.from_bytes(adjust_prikey_byte)) output_prikey = prikey + adjust_prikey - output_prikey = btc.core.PriKey(output_prikey.x) + output_prikey = yabtc.core.PriKey(output_prikey.x) for i, e in enumerate(tx.vin): - m = tx.digest_segwit_v1(i, btc.core.sighash_all, bytearray()) - s = output_prikey.sign_schnorr(m) + bytearray([btc.core.sighash_all]) + m = tx.digest_segwit_v1(i, yabtc.core.sighash_all, bytearray()) + s = output_prikey.sign_schnorr(m) + bytearray([yabtc.core.sighash_all]) e.witness[0] = s return tx - def txin(self, op: btc.core.OutPoint) -> btc.core.TxIn: - return btc.core.TxIn(op, bytearray(), 0xffffffff, [bytearray(65)]) + def txin(self, op: yabtc.core.OutPoint) -> yabtc.core.TxIn: + return yabtc.core.TxIn(op, bytearray(), 0xffffffff, [bytearray(65)]) T = Tp2pkh | Tp2shp2ms | Tp2shp2wpkh | Tp2wpkh | Tp2tr @@ -333,11 +332,11 @@ def transfer(self, script: bytearray, value: int) -> bytearray: accept_script = script change_value = 0 change_script = self.script - fr = btc.rpc.estimates_mart_fee(6)['feerate'] * btc.denomination.bitcoin + fr = yabtc.rpc.estimates_mart_fee(6)['feerate'] * yabtc.denomination.bitcoin fr = int(fr.to_integral_exact()) // 1000 - tx = btc.core.Transaction(2, [], [], 0) - tx.vout.append(btc.core.TxOut(accept_value, accept_script)) - tx.vout.append(btc.core.TxOut(change_value, change_script)) + tx = yabtc.core.Transaction(2, [], [], 0) + tx.vout.append(yabtc.core.TxOut(accept_value, accept_script)) + tx.vout.append(yabtc.core.TxOut(change_value, change_script)) for utxo in self.unspent(): txin = self.signer.txin(utxo.out_point) tx.vin.append(txin) @@ -351,17 +350,17 @@ def transfer(self, script: bytearray, value: int) -> bytearray: tx.vout[1].value = change_value self.signer.sign(tx) Analyzer(tx).analyze() - txid = bytearray.fromhex(btc.rpc.send_raw_transaction(tx.serialize().hex()))[::-1] + txid = bytearray.fromhex(yabtc.rpc.send_raw_transaction(tx.serialize().hex()))[::-1] return txid def transfer_all(self, script: bytearray) -> bytearray: sender_value = 0 accept_value = 0 accept_script = script - fr = btc.rpc.estimates_mart_fee(6)['feerate'] * btc.denomination.bitcoin + fr = yabtc.rpc.estimates_mart_fee(6)['feerate'] * yabtc.denomination.bitcoin fr = int(fr.to_integral_exact()) // 1000 - tx = btc.core.Transaction(2, [], [], 0) - tx.vout.append(btc.core.TxOut(accept_value, accept_script)) + tx = yabtc.core.Transaction(2, [], [], 0) + tx.vout.append(yabtc.core.TxOut(accept_value, accept_script)) for utxo in self.unspent(): txin = self.signer.txin(utxo.out_point) tx.vin.append(txin) @@ -371,7 +370,7 @@ def transfer_all(self, script: bytearray) -> bytearray: tx.vout[0].value = accept_value self.signer.sign(tx) Analyzer(tx).analyze() - txid = bytearray.fromhex(btc.rpc.send_raw_transaction(tx.serialize().hex()))[::-1] + txid = bytearray.fromhex(yabtc.rpc.send_raw_transaction(tx.serialize().hex()))[::-1] return txid def unspent(self) -> typing.List[Utxo]: