1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-24 15:28:10 +00:00

feat(legacy): Support Taproot signature verification.

This commit is contained in:
Andrew Kozlik 2021-11-13 09:16:51 +01:00 committed by Andrew Kozlik
parent 7597eb25ab
commit fa4d74ad30
2 changed files with 62 additions and 38 deletions

View File

@ -134,9 +134,10 @@ typedef struct {
static TxInfo info; static TxInfo info;
/* Variables specific to replacement transactions. */ /* Variables specific to replacement transactions. */
static bool is_replacement; // Is this a replacement transaction? static bool is_replacement; // Is this a replacement transaction?
static bool have_orig_verif_input; // Is orig_verif_input, sig and node set? static bool have_orig_verif_input; // Is orig_verif_input, sig and node set?
static TxInputType orig_verif_input; // The input for signature verification. static uint32_t orig_verif_input_idx; // Index of orig_verif_input in orig tx.
static TxInputType orig_verif_input; // The input for signature verification.
static TxInfo orig_info; static TxInfo orig_info;
static uint8_t orig_hash[32]; // TXID of the original transaction. static uint8_t orig_hash[32]; // TXID of the original transaction.
@ -898,6 +899,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin,
memzero(&resp, sizeof(TxRequest)); memzero(&resp, sizeof(TxRequest));
is_replacement = false; is_replacement = false;
have_orig_verif_input = false; have_orig_verif_input = false;
orig_verif_input_idx = 0xffffffff;
signing = true; signing = true;
progress = 0; progress = 0;
// we step by 500/inputs_count per input in phase1 and phase2 // we step by 500/inputs_count per input in phase1 and phase2
@ -1458,13 +1460,23 @@ static bool save_signature(TxInputType *txinput) {
size = bytes[0]; size = bytes[0];
bytes += 1; bytes += 1;
// Decode the DER-encoded signature and store in sig. if (txinput->script_type == InputScriptType_SPENDTAPROOT) {
if (bytes[size - 1] != SIGHASH_ALL || if (size != 64) {
ecdsa_sig_from_der(bytes, size - 1, sig) != 0) { fsm_sendFailure(FailureType_Failure_DataError,
fsm_sendFailure(FailureType_Failure_DataError, _("Unsupported signature script."));
_("Unsupported signature script.")); signing_abort();
signing_abort(); return false;
return false; }
memcpy(sig, bytes, size);
} else {
// Decode the DER-encoded signature and store in sig.
if (bytes[size - 1] != SIGHASH_ALL ||
ecdsa_sig_from_der(bytes, size - 1, sig) != 0) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Unsupported signature script."));
signing_abort();
return false;
}
} }
return true; return true;
@ -1538,6 +1550,7 @@ static bool signing_add_orig_input(TxInputType *orig_input) {
// Save the verification input with script_sig set to scriptPubKey. // Save the verification input with script_sig set to scriptPubKey.
memcpy(&orig_verif_input, orig_input, sizeof(TxInputType)); memcpy(&orig_verif_input, orig_input, sizeof(TxInputType));
orig_verif_input_idx = idx2;
have_orig_verif_input = true; have_orig_verif_input = true;
} else { } else {
orig_input->script_sig.size = 0; orig_input->script_sig.size = 0;
@ -1921,42 +1934,54 @@ static bool signing_check_orig_tx(void) {
return false; return false;
} }
// Compute the signed digest. // Finish computation of BIP-143/BIP-341/ZIP-243 sub-hashes.
tx_info_finish(&orig_info);
// Compute the signed digest and verify signature.
uint32_t hash_type = signing_hash_type(&orig_verif_input);
bool valid = false;
if (orig_verif_input.script_type == InputScriptType_SPENDTAPROOT) {
signing_hash_bip341(&orig_info, orig_verif_input_idx, hash_type & 0xff,
hash);
uint8_t output_public_key[32] = {0};
valid = (zkp_bip340_tweak_public_key(node.public_key + 1, NULL,
output_public_key) == 0) &&
(zkp_bip340_verify_digest(output_public_key, sig, hash) == 0);
} else {
#if !BITCOIN_ONLY #if !BITCOIN_ONLY
if (coin->overwintered) { if (coin->overwintered) {
tx_info_finish(&orig_info); signing_hash_zip243(&orig_info, &orig_verif_input, hash);
signing_hash_zip243(&orig_info, &orig_verif_input, hash); } else
} else
#endif #endif
{ {
if (is_segwit_input_script_type(&orig_verif_input) || coin->force_bip143) { if (is_segwit_input_script_type(&orig_verif_input) ||
tx_info_finish(&orig_info); coin->force_bip143) {
signing_hash_bip143(&orig_info, &orig_verif_input, hash); signing_hash_bip143(&orig_info, &orig_verif_input, hash);
} else { } else {
// Finalize legacy digest computation. // Finalize legacy digest computation.
uint32_t hash_type = signing_hash_type(&orig_verif_input); hasher_Update(&ti.hasher, (const uint8_t *)&hash_type, 4);
hasher_Update(&ti.hasher, (const uint8_t *)&hash_type, 4); tx_hash_final(&ti, hash, false);
tx_hash_final(&ti, hash, false); }
}
#ifdef USE_SECP256K1_ZKP_ECDSA
if (coin->curve->params == &secp256k1) {
valid = zkp_ecdsa_verify_digest(coin->curve->params, node.public_key, sig,
hash) == 0;
} else
#endif
{
valid = ecdsa_verify_digest(coin->curve->params, node.public_key, sig,
hash) == 0;
} }
} }
int ret = 0; if (!valid) {
#ifdef USE_SECP256K1_ZKP_ECDSA
if (coin->curve->params == &secp256k1) {
ret = zkp_ecdsa_verify_digest(coin->curve->params, node.public_key, sig,
hash);
} else
#endif
{
ret = ecdsa_verify_digest(coin->curve->params, node.public_key, sig, hash);
}
if (ret != 0) {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature.")); fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature."));
signing_abort(); signing_abort();
return false;
} }
return true; return valid;
} }
static void phase1_finish(void) { static void phase1_finish(void) {

View File

@ -204,7 +204,6 @@ def test_p2wpkh_op_return_fee_bump(client):
# txid 48bc29fc42a64b43d043b0b7b99b21aa39654234754608f791c60bcbd91a8e92 # txid 48bc29fc42a64b43d043b0b7b99b21aa39654234754608f791c60bcbd91a8e92
@pytest.mark.skip_t1
def test_p2tr_fee_bump(client): def test_p2tr_fee_bump(client):
inp1 = messages.TxInputType( inp1 = messages.TxInputType(
# tb1p8tvmvsvhsee73rhym86wt435qrqm92psfsyhy6a3n5gw455znnpqm8wald # tb1p8tvmvsvhsee73rhym86wt435qrqm92psfsyhy6a3n5gw455znnpqm8wald