1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 20:38:10 +00:00

feat(core): Support ownership proofs for Taproot addresses.

This commit is contained in:
Andrew Kozlik 2021-12-01 14:19:04 +01:00 committed by Andrew Kozlik
parent b0f2d43884
commit ef5994d9f3
4 changed files with 44 additions and 2 deletions

View File

@ -0,0 +1 @@
Support ownership proofs for Taproot addresses.

View File

@ -56,6 +56,8 @@ def generate_proof(
InputScriptType.SPENDP2SHWITNESS, InputScriptType.SPENDP2SHWITNESS,
): ):
signature = common.ecdsa_sign(node, sighash.digest()) signature = common.ecdsa_sign(node, sighash.digest())
elif script_type == InputScriptType.SPENDTAPROOT:
signature = common.bip340_sign(node, sighash.digest())
else: else:
raise wire.DataError("Unsupported script type.") raise wire.DataError("Unsupported script type.")
public_key = node.public_key() public_key = node.public_key()

View File

@ -609,7 +609,9 @@ def write_bip322_signature_proof(
w, script_type, multisig, coin, SigHashType.SIGHASH_ALL, public_key, signature w, script_type, multisig, coin, SigHashType.SIGHASH_ALL, public_key, signature
) )
if script_type in common.SEGWIT_INPUT_SCRIPT_TYPES: if script_type == InputScriptType.SPENDTAPROOT:
write_witness_p2tr(w, signature, SigHashType.SIGHASH_ALL_TAPROOT)
elif script_type in common.SEGWIT_INPUT_SCRIPT_TYPES:
if multisig: if multisig:
# find the place of our signature based on the public key # find the place of our signature based on the public key
signature_index = multisig_pubkey_index(multisig, public_key) signature_index = multisig_pubkey_index(multisig, public_key)

View File

@ -8,7 +8,7 @@ from apps.common import coins
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
from apps.common.paths import HARDENED, AlwaysMatchingSchema from apps.common.paths import HARDENED, AlwaysMatchingSchema
from apps.bitcoin import ownership, scripts from apps.bitcoin import ownership, scripts
from apps.bitcoin.addresses import address_p2wpkh, address_p2wpkh_in_p2sh, address_multisig_p2wsh, address_multisig_p2wsh_in_p2sh, address_multisig_p2sh from apps.bitcoin.addresses import address_p2tr, address_p2wpkh, address_p2wpkh_in_p2sh, address_multisig_p2wsh, address_multisig_p2wsh_in_p2sh, address_multisig_p2sh
from apps.bitcoin.multisig import multisig_get_pubkeys from apps.bitcoin.multisig import multisig_get_pubkeys
@ -67,6 +67,32 @@ class TestOwnershipProof(unittest.TestCase):
self.assertEqual(proof, unhexlify("534c0019000192caf0b8daf78f1d388dbbceaec34bd2dabc31b217e32343663667f6694a3f4617160014e0cffbee1925a411844f44c3b8d81365ab51d03602483045022100a37330dca699725db613dd1b30059843d1248340642162a0adef114509c9849402201126c9044b998065d40b44fd2399b52c409794bbc3bfdd358cd5fb450c94316d012103a961687895a78da9aef98eed8e1f2a3e91cfb69d2f3cf11cbd0bb1773d951928")) self.assertEqual(proof, unhexlify("534c0019000192caf0b8daf78f1d388dbbceaec34bd2dabc31b217e32343663667f6694a3f4617160014e0cffbee1925a411844f44c3b8d81365ab51d03602483045022100a37330dca699725db613dd1b30059843d1248340642162a0adef114509c9849402201126c9044b998065d40b44fd2399b52c409794bbc3bfdd358cd5fb450c94316d012103a961687895a78da9aef98eed8e1f2a3e91cfb69d2f3cf11cbd0bb1773d951928"))
self.assertFalse(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin)) self.assertFalse(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
def test_p2tr_gen_proof(self):
coin = coins.by_name('Bitcoin')
seed = bip39.seed(' '.join(['all'] * 12), '')
keychain = Keychain(seed, coin.curve_name, [AlwaysMatchingSchema], slip21_namespaces=[[b"SLIP-0019"]])
commitment_data = b""
node = keychain.derive([86 | HARDENED, 0 | HARDENED, 0 | HARDENED, 1, 0])
address = address_p2tr(node.public_key(), coin)
script_pubkey = scripts.output_derive_script(address, coin)
ownership_id = ownership.get_identifier(script_pubkey, keychain)
self.assertEqual(ownership_id, unhexlify("dc18066224b9e30e306303436dc18ab881c7266c13790350a3fe415e438135ec"))
proof, signature = ownership.generate_proof(
node=node,
script_type=InputScriptType.SPENDTAPROOT,
multisig=None,
coin=coin,
user_confirmed=False,
ownership_ids=[ownership_id],
script_pubkey=script_pubkey,
commitment_data=commitment_data,
)
self.assertEqual(signature, unhexlify("6cd08474ea019c9ab4b9b7b76ec03c4dd4db76abc3a460434a91cfc1b190174949eb7111c8e762407730a215421a0da0b5e01f48de62d7ccea0abea046e2a496"))
self.assertEqual(proof, unhexlify("534c00190001dc18066224b9e30e306303436dc18ab881c7266c13790350a3fe415e438135ec0001406cd08474ea019c9ab4b9b7b76ec03c4dd4db76abc3a460434a91cfc1b190174949eb7111c8e762407730a215421a0da0b5e01f48de62d7ccea0abea046e2a496"))
self.assertFalse(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
def test_p2pkh_gen_proof(self): def test_p2pkh_gen_proof(self):
coin = coins.by_name('Bitcoin') coin = coins.by_name('Bitcoin')
seed = bip39.seed(' '.join(['all'] * 12), 'TREZOR') seed = bip39.seed(' '.join(['all'] * 12), 'TREZOR')
@ -104,6 +130,17 @@ class TestOwnershipProof(unittest.TestCase):
proof = unhexlify("534c00190001a122407efc198211c81af4450f40b235d54775efd934d16b9e31c6ce9bad57070002483045022100e5eaf2cb0a473b4545115c7b85323809e75cb106175ace38129fd62323d73df30220363dbc7acb7afcda022b1f8d97acb8f47c42043cfe0595583aa26e30bc8b3bb50121032ef68318c8f6aaa0adec0199c69901f0db7d3485eb38d9ad235221dc3d61154b") proof = unhexlify("534c00190001a122407efc198211c81af4450f40b235d54775efd934d16b9e31c6ce9bad57070002483045022100e5eaf2cb0a473b4545115c7b85323809e75cb106175ace38129fd62323d73df30220363dbc7acb7afcda022b1f8d97acb8f47c42043cfe0595583aa26e30bc8b3bb50121032ef68318c8f6aaa0adec0199c69901f0db7d3485eb38d9ad235221dc3d61154b")
self.assertTrue(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin)) self.assertTrue(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
def test_p2tr_verify_proof(self):
coin = coins.by_name('Bitcoin')
seed = bip39.seed(' '.join(['all'] * 12), 'TREZOR')
keychain = Keychain(seed, coin.curve_name, [AlwaysMatchingSchema], slip21_namespaces=[[b"SLIP-0019"]])
commitment_data = b""
# Proof for "all all ... all" seed without passphrase.
script_pubkey = unhexlify("51204102897557de0cafea0a8401ea5b59668eccb753e4b100aebe6a19609f3cc79f")
proof = unhexlify("534c00190001dc18066224b9e30e306303436dc18ab881c7266c13790350a3fe415e438135ec0001406cd08474ea019c9ab4b9b7b76ec03c4dd4db76abc3a460434a91cfc1b190174949eb7111c8e762407730a215421a0da0b5e01f48de62d7ccea0abea046e2a496")
self.assertTrue(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
def test_p2wsh_gen_proof(self): def test_p2wsh_gen_proof(self):
coin = coins.by_name('Bitcoin') coin = coins.by_name('Bitcoin')
seed = bip39.seed(' '.join(['all'] * 12), '') seed = bip39.seed(' '.join(['all'] * 12), '')