mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-24 15:28:10 +00:00
feat(legacy): Implement Taproot signing.
This commit is contained in:
parent
9f65165887
commit
c9d1ff93f5
1
legacy/firmware/.changelog.d/1656.added.2
Normal file
1
legacy/firmware/.changelog.d/1656.added.2
Normal file
@ -0,0 +1 @@
|
|||||||
|
Support spending from Taproot UTXOs.
|
@ -30,6 +30,7 @@
|
|||||||
#include "protect.h"
|
#include "protect.h"
|
||||||
#include "secp256k1.h"
|
#include "secp256k1.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
|
#include "zkp_bip340.h"
|
||||||
#ifdef USE_SECP256K1_ZKP_ECDSA
|
#ifdef USE_SECP256K1_ZKP_ECDSA
|
||||||
#include "zkp_ecdsa.h"
|
#include "zkp_ecdsa.h"
|
||||||
#endif
|
#endif
|
||||||
@ -2038,8 +2039,8 @@ static void signing_hash_decred(const TxInputType *txinput,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool signing_sign_hash(TxInputType *txinput, const uint8_t *private_key,
|
static bool signing_sign_ecdsa(TxInputType *txinput, const uint8_t *private_key,
|
||||||
const uint8_t *public_key, const uint8_t *hash) {
|
const uint8_t *public_key, const uint8_t *hash) {
|
||||||
resp.serialized.has_signature_index = true;
|
resp.serialized.has_signature_index = true;
|
||||||
resp.serialized.signature_index = idx1;
|
resp.serialized.signature_index = idx1;
|
||||||
resp.serialized.has_signature = true;
|
resp.serialized.has_signature = true;
|
||||||
@ -2096,6 +2097,31 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t *private_key,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool signing_sign_bip340(const uint8_t *private_key,
|
||||||
|
const uint8_t *hash) {
|
||||||
|
resp.has_serialized = true;
|
||||||
|
resp.serialized.has_signature_index = true;
|
||||||
|
resp.serialized.signature_index = idx1;
|
||||||
|
resp.serialized.has_signature = true;
|
||||||
|
resp.serialized.has_serialized_tx = true;
|
||||||
|
resp.serialized.signature.size = 64;
|
||||||
|
|
||||||
|
uint8_t output_private_key[32] = {0};
|
||||||
|
bool ret = (zkp_bip340_tweak_private_key(private_key, NULL,
|
||||||
|
output_private_key) == 0);
|
||||||
|
ret = ret &&
|
||||||
|
(zkp_bip340_sign_digest(output_private_key, hash,
|
||||||
|
resp.serialized.signature.bytes, NULL) == 0);
|
||||||
|
memzero(output_private_key, sizeof(output_private_key));
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed"));
|
||||||
|
signing_abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static bool signing_sign_input(void) {
|
static bool signing_sign_input(void) {
|
||||||
uint8_t hash[32] = {0};
|
uint8_t hash[32] = {0};
|
||||||
hasher_Final(&hasher_check, hash);
|
hasher_Final(&hasher_check, hash);
|
||||||
@ -2110,7 +2136,7 @@ static bool signing_sign_input(void) {
|
|||||||
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);
|
||||||
resp.has_serialized = true;
|
resp.has_serialized = true;
|
||||||
if (!signing_sign_hash(&input, privkey, pubkey, hash)) return false;
|
if (!signing_sign_ecdsa(&input, privkey, pubkey, hash)) return false;
|
||||||
resp.serialized.serialized_tx.size =
|
resp.serialized.serialized_tx.size =
|
||||||
tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes);
|
tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes);
|
||||||
return true;
|
return true;
|
||||||
@ -2120,7 +2146,23 @@ static bool signing_sign_segwit_input(TxInputType *txinput) {
|
|||||||
// idx1: index to sign
|
// idx1: index to sign
|
||||||
uint8_t hash[32] = {0};
|
uint8_t hash[32] = {0};
|
||||||
|
|
||||||
if (is_segwit_input_script_type(txinput)) {
|
if (txinput->script_type == InputScriptType_SPENDTAPROOT) {
|
||||||
|
signing_hash_bip341(&info, idx1, signing_hash_type(txinput), hash);
|
||||||
|
|
||||||
|
if (!tx_info_check_input(&info, txinput) || !derive_node(txinput) ||
|
||||||
|
!signing_sign_bip340(node.private_key, hash)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t r = 0;
|
||||||
|
// write witness (number of stack items followed by signature)
|
||||||
|
r += ser_length(1, resp.serialized.serialized_tx.bytes + r);
|
||||||
|
r += tx_serialize_script(resp.serialized.signature.size,
|
||||||
|
resp.serialized.signature.bytes,
|
||||||
|
resp.serialized.serialized_tx.bytes + r);
|
||||||
|
resp.serialized.serialized_tx.size = r;
|
||||||
|
} else if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS ||
|
||||||
|
txinput->script_type == InputScriptType_SPENDWITNESS) {
|
||||||
if (!txinput->has_amount) {
|
if (!txinput->has_amount) {
|
||||||
fsm_sendFailure(FailureType_Failure_DataError,
|
fsm_sendFailure(FailureType_Failure_DataError,
|
||||||
_("Segwit input without amount"));
|
_("Segwit input without amount"));
|
||||||
@ -2136,7 +2178,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) {
|
|||||||
signing_hash_bip143(&info, txinput, hash);
|
signing_hash_bip143(&info, txinput, hash);
|
||||||
|
|
||||||
resp.has_serialized = true;
|
resp.has_serialized = true;
|
||||||
if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash))
|
if (!signing_sign_ecdsa(txinput, node.private_key, node.public_key, hash))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint8_t sighash = signing_hash_type(txinput) & 0xff;
|
uint8_t sighash = signing_hash_type(txinput) & 0xff;
|
||||||
@ -2199,7 +2241,7 @@ static bool signing_sign_decred_input(TxInputType *txinput) {
|
|||||||
tx_hash_final(&ti, hash_witness, false);
|
tx_hash_final(&ti, hash_witness, false);
|
||||||
signing_hash_decred(txinput, hash_witness, hash);
|
signing_hash_decred(txinput, hash_witness, hash);
|
||||||
resp.has_serialized = true;
|
resp.has_serialized = true;
|
||||||
if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash))
|
if (!signing_sign_ecdsa(txinput, node.private_key, node.public_key, hash))
|
||||||
return false;
|
return false;
|
||||||
resp.serialized.serialized_tx.size = tx_serialize_decred_witness(
|
resp.serialized.serialized_tx.size = tx_serialize_decred_witness(
|
||||||
&to, txinput, resp.serialized.serialized_tx.bytes);
|
&to, txinput, resp.serialized.serialized_tx.bytes);
|
||||||
@ -2733,8 +2775,8 @@ void signing_txack(TransactionType *tx) {
|
|||||||
{
|
{
|
||||||
signing_hash_bip143(&info, &tx->inputs[0], hash);
|
signing_hash_bip143(&info, &tx->inputs[0], hash);
|
||||||
}
|
}
|
||||||
if (!signing_sign_hash(&tx->inputs[0], node.private_key,
|
if (!signing_sign_ecdsa(&tx->inputs[0], node.private_key,
|
||||||
node.public_key, hash))
|
node.public_key, hash))
|
||||||
return;
|
return;
|
||||||
// since this took a longer time, update progress
|
// since this took a longer time, update progress
|
||||||
signatures++;
|
signatures++;
|
||||||
|
@ -49,7 +49,6 @@ TXHASH_65b811 = bytes.fromhex(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip_t1
|
|
||||||
class TestMsgSigntxTaproot:
|
class TestMsgSigntxTaproot:
|
||||||
def test_send_p2tr(self, client):
|
def test_send_p2tr(self, client):
|
||||||
inp1 = messages.TxInputType(
|
inp1 = messages.TxInputType(
|
||||||
@ -269,6 +268,7 @@ class TestMsgSigntxTaproot:
|
|||||||
request_input(0),
|
request_input(0),
|
||||||
request_input(1),
|
request_input(1),
|
||||||
request_input(2),
|
request_input(2),
|
||||||
|
(client.features.model == "1", request_input(3)),
|
||||||
request_finished(),
|
request_finished(),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user