mirror of
https://github.com/bitcoin/bips.git
synced 2026-05-04 16:41:51 +00:00
Add reference.py with test vectors
* reference.py contains the silent payment specific code * secp256k1.py for doing the EC operations * bech32m.py contains code for encoding/decoding bech32(m) addresses * bitcoin_utils.py contains some helper code, not specific to silent payments * send_and_receive_test_vectors.json contains the wallet unit test vectors Co-Authored-By: S3RK <1466284+S3RK@users.noreply.github.com> Co-Authored-By: Oghenovo Usiwoma <37949128+Eunovo@users.noreply.github.com> Co-authored-by: S.Blagogee <34041358+setavenger@users.noreply.github.com>
This commit is contained in:
158
bip-0352/bitcoin_utils.py
Normal file
158
bip-0352/bitcoin_utils.py
Normal file
@@ -0,0 +1,158 @@
|
||||
import hashlib
|
||||
import struct
|
||||
from io import BytesIO
|
||||
from secp256k1 import ECKey
|
||||
from typing import Union
|
||||
|
||||
|
||||
def from_hex(hex_string):
|
||||
"""Deserialize from a hex string representation (e.g. from RPC)"""
|
||||
return BytesIO(bytes.fromhex(hex_string))
|
||||
|
||||
|
||||
def ser_uint32(u: int) -> bytes:
|
||||
return u.to_bytes(4, "big")
|
||||
|
||||
|
||||
def ser_uint256(u):
|
||||
return u.to_bytes(32, 'little')
|
||||
|
||||
|
||||
def deser_uint256(f):
|
||||
return int.from_bytes(f.read(32), 'little')
|
||||
|
||||
|
||||
def deser_txid(txid: str):
|
||||
# recall that txids are serialized little-endian, but displayed big-endian
|
||||
# this means when converting from a human readable hex txid, we need to first
|
||||
# reverse it before deserializing it
|
||||
dixt = "".join(map(str.__add__, txid[-2::-2], txid[-1::-2]))
|
||||
return bytes.fromhex(dixt)
|
||||
|
||||
|
||||
def deser_compact_size(f: BytesIO):
|
||||
view = f.getbuffer()
|
||||
nbytes = view.nbytes;
|
||||
view.release()
|
||||
if (nbytes == 0):
|
||||
return 0 # end of stream
|
||||
|
||||
nit = struct.unpack("<B", f.read(1))[0]
|
||||
if nit == 253:
|
||||
nit = struct.unpack("<H", f.read(2))[0]
|
||||
elif nit == 254:
|
||||
nit = struct.unpack("<I", f.read(4))[0]
|
||||
elif nit == 255:
|
||||
nit = struct.unpack("<Q", f.read(8))[0]
|
||||
return nit
|
||||
|
||||
|
||||
def deser_string(f: BytesIO):
|
||||
nit = deser_compact_size(f)
|
||||
return f.read(nit)
|
||||
|
||||
|
||||
def deser_string_vector(f: BytesIO):
|
||||
nit = deser_compact_size(f)
|
||||
r = []
|
||||
for _ in range(nit):
|
||||
t = deser_string(f)
|
||||
r.append(t)
|
||||
return r
|
||||
|
||||
|
||||
class COutPoint:
|
||||
__slots__ = ("hash", "n",)
|
||||
|
||||
def __init__(self, hash=b"", n=0,):
|
||||
self.hash = hash
|
||||
self.n = n
|
||||
|
||||
def serialize(self):
|
||||
r = b""
|
||||
r += self.hash
|
||||
r += struct.pack("<I", self.n)
|
||||
return r
|
||||
|
||||
def deserialize(self, f):
|
||||
self.hash = f.read(32)
|
||||
self.n = struct.unpack("<I", f.read(4))[0]
|
||||
|
||||
|
||||
class VinInfo:
|
||||
__slots__ = ("outpoint", "scriptSig", "txinwitness", "prevout", "private_key")
|
||||
|
||||
def __init__(self, outpoint=None, scriptSig=b"", txinwitness=None, prevout=b"", private_key=None):
|
||||
if outpoint is None:
|
||||
self.outpoint = COutPoint()
|
||||
else:
|
||||
self.outpoint = outpoint
|
||||
if txinwitness is None:
|
||||
self.txinwitness = CTxInWitness()
|
||||
else:
|
||||
self.txinwitness = txinwitness
|
||||
if private_key is None:
|
||||
self.private_key = ECKey()
|
||||
else:
|
||||
self.private_key = private_key
|
||||
self.scriptSig = scriptSig
|
||||
self.prevout = prevout
|
||||
|
||||
|
||||
class CScriptWitness:
|
||||
__slots__ = ("stack",)
|
||||
|
||||
def __init__(self):
|
||||
# stack is a vector of strings
|
||||
self.stack = []
|
||||
|
||||
def is_null(self):
|
||||
if self.stack:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class CTxInWitness:
|
||||
__slots__ = ("scriptWitness",)
|
||||
|
||||
def __init__(self):
|
||||
self.scriptWitness = CScriptWitness()
|
||||
|
||||
def deserialize(self, f: BytesIO):
|
||||
self.scriptWitness.stack = deser_string_vector(f)
|
||||
return self
|
||||
|
||||
def is_null(self):
|
||||
return self.scriptWitness.is_null()
|
||||
|
||||
|
||||
def hash160(s: Union[bytes, bytearray]) -> bytes:
|
||||
return hashlib.new("ripemd160", hashlib.sha256(s).digest()).digest()
|
||||
|
||||
|
||||
def is_p2tr(spk: bytes) -> bool:
|
||||
if len(spk) != 34:
|
||||
return False
|
||||
# OP_1 OP_PUSHBYTES_32 <32 bytes>
|
||||
return (spk[0] == 0x51) & (spk[1] == 0x20)
|
||||
|
||||
|
||||
def is_p2wpkh(spk: bytes) -> bool:
|
||||
if len(spk) != 22:
|
||||
return False
|
||||
# OP_0 OP_PUSHBYTES_20 <20 bytes>
|
||||
return (spk[0] == 0x00) & (spk[1] == 0x14)
|
||||
|
||||
|
||||
def is_p2sh(spk: bytes) -> bool:
|
||||
if len(spk) != 23:
|
||||
return False
|
||||
# OP_HASH160 OP_PUSHBYTES_20 <20 bytes> OP_EQUAL
|
||||
return (spk[0] == 0xA9) & (spk[1] == 0x14) & (spk[-1] == 0x87)
|
||||
|
||||
|
||||
def is_p2pkh(spk: bytes) -> bool:
|
||||
if len(spk) != 25:
|
||||
return False
|
||||
# OP_DUP OP_HASH160 OP_PUSHBYTES_20 <20 bytes> OP_EQUALVERIFY OP_CHECKSIG
|
||||
return (spk[0] == 0x76) & (spk[1] == 0xA9) & (spk[2] == 0x14) & (spk[-2] == 0x88) & (spk[-1] == 0xAC)
|
||||
Reference in New Issue
Block a user