mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-23 14:58:09 +00:00
signing: p2sh and witness native addresses
This commit is contained in:
parent
14b0d4439a
commit
8fbf89b7f3
@ -28,7 +28,7 @@ def get_address(script_type: InputScriptType, coin: CoinType, node) -> str:
|
||||
return address_p2wpkh(node.public_key(), coin.bech32_prefix)
|
||||
|
||||
elif script_type == InputScriptType.SPENDP2SHWITNESS: # p2wpkh using p2sh
|
||||
if not coin.segwit or not coin.address_type_p2sh:
|
||||
if not coin.segwit or coin.address_type_p2sh is None:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Segwit not enabled on this coin')
|
||||
return address_p2wpkh_in_p2sh(node.public_key(), coin.address_type_p2sh)
|
||||
@ -38,14 +38,22 @@ def get_address(script_type: InputScriptType, coin: CoinType, node) -> str:
|
||||
'Invalid script type')
|
||||
|
||||
|
||||
def address_p2wpkh_in_p2sh(pubkey: bytes, addrtype: int) -> str:
|
||||
def address_p2sh(redeem_script_hash: bytes, addrtype: int) -> str:
|
||||
s = bytearray(21)
|
||||
s[0] = addrtype
|
||||
s[1:21] = address_p2wpkh_in_p2sh_raw(pubkey)
|
||||
s[1:21] = redeem_script_hash
|
||||
return base58.encode_check(bytes(s))
|
||||
|
||||
|
||||
def address_p2wpkh_in_p2sh_raw(pubkey: bytes) -> bytes:
|
||||
# P2WPKH nested in P2SH. The P2SH redeem script hash is created using the
|
||||
# `raw` function
|
||||
def address_p2wpkh_in_p2sh(pubkey: bytes, addrtype: int) -> str:
|
||||
redeem_script_hash = address_p2wpkh_in_p2sh_script(pubkey)
|
||||
return address_p2sh(redeem_script_hash, addrtype)
|
||||
|
||||
|
||||
# Generates a P2SH redeem script based on a public key hash in a P2WPKH manner
|
||||
def address_p2wpkh_in_p2sh_script(pubkey: bytes) -> bytes:
|
||||
s = bytearray(22)
|
||||
s[0] = 0x00 # OP_0
|
||||
s[1] = 0x14 # pushing 20 bytes
|
||||
@ -55,6 +63,25 @@ def address_p2wpkh_in_p2sh_raw(pubkey: bytes) -> bytes:
|
||||
return h
|
||||
|
||||
|
||||
# P2WSH nested in P2SH. The P2SH redeem script hash is created using the
|
||||
# `raw` function
|
||||
def address_p2wsh_in_p2sh(witness_script_hash: bytes, addrtype: int) -> str:
|
||||
redeem_script_hash = address_p2wsh_in_p2sh_script(witness_script_hash)
|
||||
return address_p2sh(redeem_script_hash, addrtype)
|
||||
|
||||
|
||||
# Generates a P2SH redeem script based on a hash of a witness redeem script hash
|
||||
def address_p2wsh_in_p2sh_script(script_hash: bytes) -> bytes:
|
||||
s = bytearray(34)
|
||||
s[0] = 0x00 # OP_0
|
||||
s[1] = 0x20 # pushing 32 bytes
|
||||
s[2:34] = script_hash
|
||||
h = sha256(s).digest()
|
||||
h = ripemd160(h).digest()
|
||||
return h
|
||||
|
||||
|
||||
# Native Bech32 P2WPKH
|
||||
def address_p2wpkh(pubkey: bytes, hrp: str) -> str:
|
||||
pubkeyhash = ecdsa_hash_pubkey(pubkey)
|
||||
address = bech32.encode(hrp, _BECH32_WITVER, pubkeyhash)
|
||||
@ -64,6 +91,15 @@ def address_p2wpkh(pubkey: bytes, hrp: str) -> str:
|
||||
return address
|
||||
|
||||
|
||||
# Native Bech32 P2WSH, script_hash is 32-byte SHA256(script)
|
||||
def address_p2wsh(script_hash: bytes, hrp: str) -> str:
|
||||
address = bech32.encode(hrp, _BECH32_WITVER, script_hash)
|
||||
if address is None:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Invalid address')
|
||||
return address
|
||||
|
||||
|
||||
def decode_bech32_address(prefix: str, address: str) -> bytes:
|
||||
witver, raw = bech32.decode(prefix, address)
|
||||
if witver != _BECH32_WITVER:
|
||||
|
95
tests/test_apps.wallet.address.py
Normal file
95
tests/test_apps.wallet.address.py
Normal file
@ -0,0 +1,95 @@
|
||||
from common import *
|
||||
|
||||
from apps.wallet.sign_tx.signing import *
|
||||
from apps.common import coins
|
||||
from trezor.crypto import bip32, bip39
|
||||
|
||||
|
||||
class TestAddress(unittest.TestCase):
|
||||
# pylint: disable=C0301
|
||||
|
||||
def test_p2wpkh_in_p2sh_address(self):
|
||||
coin = coins.by_name('Testnet')
|
||||
address = address_p2wpkh_in_p2sh(
|
||||
unhexlify('03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f'),
|
||||
coin.address_type_p2sh
|
||||
)
|
||||
self.assertEqual(address, '2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2')
|
||||
|
||||
def test_p2wpkh_in_p2sh_script_address(self):
|
||||
raw = address_p2wpkh_in_p2sh_script(
|
||||
unhexlify('03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f')
|
||||
)
|
||||
self.assertEqual(raw, unhexlify('336caa13e08b96080a32b5d818d59b4ab3b36742'))
|
||||
|
||||
def test_p2wpkh_in_p2sh_node_derive_address(self):
|
||||
coin = coins.by_name('Testnet')
|
||||
seed = bip39.seed(' '.join(['all'] * 12), '')
|
||||
root = bip32.from_seed(seed, 'secp256k1')
|
||||
|
||||
node = node_derive(root, [49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0])
|
||||
address = address_p2wpkh_in_p2sh(node.public_key(), coin.address_type_p2sh)
|
||||
|
||||
self.assertEqual(address, '2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX')
|
||||
|
||||
node = node_derive(root, [49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 1])
|
||||
address = address_p2wpkh_in_p2sh(node.public_key(), coin.address_type_p2sh)
|
||||
|
||||
self.assertEqual(address, '2NFWLCJQBSpz1oUJwwLpX8ECifFWGznBVqs')
|
||||
|
||||
node = node_derive(root, [49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 0, 0])
|
||||
address = address_p2wpkh_in_p2sh(node.public_key(), coin.address_type_p2sh)
|
||||
|
||||
self.assertEqual(address, '2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp')
|
||||
|
||||
def test_p2wpkh_address(self):
|
||||
# data from https://bc-2.jp/tools/bech32demo/index.html
|
||||
coin = coins.by_name('Testnet')
|
||||
address = address_p2wpkh(
|
||||
unhexlify('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'),
|
||||
coin.bech32_prefix
|
||||
)
|
||||
self.assertEqual(address, 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx')
|
||||
|
||||
def test_p2sh_address(self):
|
||||
coin = coins.by_name('Testnet')
|
||||
|
||||
address = address_p2sh(
|
||||
unhexlify('7a55d61848e77ca266e79a39bfc85c580a6426c9'),
|
||||
coin.address_type_p2sh
|
||||
)
|
||||
self.assertEqual(address, '2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp')
|
||||
|
||||
def test_p2wsh_address(self):
|
||||
coin = coins.by_name('Testnet')
|
||||
|
||||
# pubkey OP_CHECKSIG
|
||||
script = unhexlify('210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac')
|
||||
h = HashWriter(sha256)
|
||||
write_bytes(h, script)
|
||||
|
||||
address = address_p2wsh(
|
||||
h.get_digest(),
|
||||
coin.bech32_prefix
|
||||
)
|
||||
self.assertEqual(address, 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7')
|
||||
|
||||
def test_p2wsh_in_p2sh_address(self):
|
||||
coin = coins.by_name('Bitcoin')
|
||||
|
||||
# data from Mastering Bitcoin
|
||||
address = address_p2wsh_in_p2sh(
|
||||
unhexlify('9592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73'),
|
||||
coin.address_type_p2sh
|
||||
)
|
||||
self.assertEqual(address, '3Dwz1MXhM6EfFoJChHCxh1jWHb8GQqRenG')
|
||||
|
||||
def test_p2wsh_in_p2sh_script_address(self):
|
||||
raw = address_p2wsh_in_p2sh_script(
|
||||
unhexlify('1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262')
|
||||
)
|
||||
self.assertEqual(raw, unhexlify('e4300531190587e3880d4c3004f5355d88ff928d'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -1,48 +0,0 @@
|
||||
from common import *
|
||||
|
||||
from apps.wallet.sign_tx.signing import *
|
||||
from apps.common import coins
|
||||
from trezor.crypto import bip32, bip39
|
||||
|
||||
|
||||
class TestSegwitAddress(unittest.TestCase):
|
||||
# pylint: disable=C0301
|
||||
|
||||
def test_p2wpkh_in_p2sh_address(self):
|
||||
coin = coins.by_name('Testnet')
|
||||
|
||||
address = address_p2wpkh_in_p2sh(
|
||||
unhexlify('03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f'),
|
||||
coin.address_type_p2sh
|
||||
)
|
||||
self.assertEqual(address, '2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2')
|
||||
|
||||
def test_p2wpkh_in_p2sh_raw_address(self):
|
||||
raw = address_p2wpkh_in_p2sh_raw(
|
||||
unhexlify('03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f')
|
||||
)
|
||||
self.assertEqual(raw, unhexlify('336caa13e08b96080a32b5d818d59b4ab3b36742'))
|
||||
|
||||
def test_p2wpkh_in_p2sh_node_derive_address(self):
|
||||
coin = coins.by_name('Testnet')
|
||||
seed = bip39.seed(' '.join(['all'] * 12), '')
|
||||
root = bip32.from_seed(seed, 'secp256k1')
|
||||
|
||||
node = node_derive(root, [49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0])
|
||||
address = address_p2wpkh_in_p2sh(node.public_key(), coin.address_type_p2sh)
|
||||
|
||||
self.assertEqual(address, '2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX')
|
||||
|
||||
node = node_derive(root, [49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 1])
|
||||
address = address_p2wpkh_in_p2sh(node.public_key(), coin.address_type_p2sh)
|
||||
|
||||
self.assertEqual(address, '2NFWLCJQBSpz1oUJwwLpX8ECifFWGznBVqs')
|
||||
|
||||
node = node_derive(root, [49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 0, 0])
|
||||
address = address_p2wpkh_in_p2sh(node.public_key(), coin.address_type_p2sh)
|
||||
|
||||
self.assertEqual(address, '2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in New Issue
Block a user