mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-04 22:02:34 +00:00
commit
66ba8d09b4
@ -31,6 +31,8 @@
|
|||||||
#include "protect.h"
|
#include "protect.h"
|
||||||
#include "pinmatrix.h"
|
#include "pinmatrix.h"
|
||||||
#include "layout2.h"
|
#include "layout2.h"
|
||||||
|
#include "address.h"
|
||||||
|
#include "base58.h"
|
||||||
#include "ecdsa.h"
|
#include "ecdsa.h"
|
||||||
#include "reset.h"
|
#include "reset.h"
|
||||||
#include "recovery.h"
|
#include "recovery.h"
|
||||||
@ -608,6 +610,7 @@ void fsm_msgGetAddress(GetAddress *msg)
|
|||||||
HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count);
|
HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count);
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
hdnode_fill_public_key(node);
|
hdnode_fill_public_key(node);
|
||||||
|
int is_segwit = 0;
|
||||||
|
|
||||||
if (msg->has_multisig) {
|
if (msg->has_multisig) {
|
||||||
layoutProgressSwipe("Preparing", 0);
|
layoutProgressSwipe("Preparing", 0);
|
||||||
@ -625,11 +628,52 @@ void fsm_msgGetAddress(GetAddress *msg)
|
|||||||
ripemd160(buf, 32, buf + 1);
|
ripemd160(buf, 32, buf + 1);
|
||||||
buf[0] = coin->address_type_p2sh; // multisig cointype
|
buf[0] = coin->address_type_p2sh; // multisig cointype
|
||||||
base58_encode_check(buf, 21, resp->address, sizeof(resp->address));
|
base58_encode_check(buf, 21, resp->address, sizeof(resp->address));
|
||||||
|
} else if (msg->has_script_type
|
||||||
|
&& msg->script_type == InputScriptType_SPENDWITNESS
|
||||||
|
&& coin->has_address_type_p2wpkh) {
|
||||||
|
uint8_t raw[22+4];
|
||||||
|
int prelen = address_prefix_bytes_len(coin->address_type_p2wpkh);
|
||||||
|
address_write_prefix_bytes(coin->address_type_p2wpkh, raw);
|
||||||
|
raw[prelen] = 0; // version byte
|
||||||
|
raw[prelen + 1] = 0; // always 0, see bip-142
|
||||||
|
ecdsa_get_pubkeyhash(node->public_key, raw + prelen + 2);
|
||||||
|
if (!base58_encode_check(raw, prelen + 22, resp->address, sizeof(resp->address))) {
|
||||||
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address");
|
||||||
|
layoutHome();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
is_segwit = 1;
|
||||||
|
} else if (msg->has_script_type
|
||||||
|
&& msg->script_type == InputScriptType_SPENDP2SHWITNESS
|
||||||
|
&& coin->has_address_type_p2sh) {
|
||||||
|
uint8_t script[22];
|
||||||
|
uint8_t digest[32];
|
||||||
|
int prelen = address_prefix_bytes_len(coin->address_type_p2sh);
|
||||||
|
script[0] = 0; // version byte
|
||||||
|
script[1] = 20; // push 20 bytes
|
||||||
|
ecdsa_get_pubkeyhash(node->public_key, script + 2);
|
||||||
|
sha256_Raw(script, 22, digest);
|
||||||
|
ripemd160(digest, 32, digest + prelen);
|
||||||
|
address_write_prefix_bytes(coin->address_type_p2sh, digest);
|
||||||
|
if (!base58_encode_check(digest, 21, resp->address, sizeof(resp->address))) {
|
||||||
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address");
|
||||||
|
layoutHome();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
is_segwit = 1;
|
||||||
} else {
|
} else {
|
||||||
ecdsa_get_address(node->public_key, coin->address_type, resp->address, sizeof(resp->address));
|
ecdsa_get_address(node->public_key, coin->address_type, resp->address, sizeof(resp->address));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg->has_show_display && msg->show_display) {
|
if (msg->has_show_display && msg->show_display) {
|
||||||
|
if (is_segwit) {
|
||||||
|
layoutSegwitWarning();
|
||||||
|
if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) {
|
||||||
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled");
|
||||||
|
layoutHome();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
char desc[16];
|
char desc[16];
|
||||||
if (msg->has_multisig) {
|
if (msg->has_multisig) {
|
||||||
strlcpy(desc, "Msig __ of __:", sizeof(desc));
|
strlcpy(desc, "Msig __ of __:", sizeof(desc));
|
||||||
|
@ -391,3 +391,18 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico
|
|||||||
}
|
}
|
||||||
layoutDialog(appicon, NULL, verb, NULL, verb, "U2F security key?", NULL, appname, NULL, NULL);
|
layoutDialog(appicon, NULL, verb, NULL, verb, "U2F security key?", NULL, appname, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void layoutSegwitWarning()
|
||||||
|
{
|
||||||
|
layoutDialogSwipe(&bmp_icon_info,
|
||||||
|
"Cancel",
|
||||||
|
"Understood",
|
||||||
|
NULL,
|
||||||
|
"The following address",
|
||||||
|
"is for SegWit soft fork.",
|
||||||
|
NULL,
|
||||||
|
"It is unsafe to use",
|
||||||
|
"until segwit activates.",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -45,5 +45,6 @@ void layoutPublicKey(const uint8_t *pubkey);
|
|||||||
void layoutSignIdentity(const IdentityType *identity, const char *challenge);
|
void layoutSignIdentity(const IdentityType *identity, const char *challenge);
|
||||||
void layoutDecryptIdentity(const IdentityType *identity);
|
void layoutDecryptIdentity(const IdentityType *identity);
|
||||||
void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon);
|
void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon);
|
||||||
|
void layoutSegwitWarning(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,7 +32,7 @@ PublicKey.xpub max_size:113
|
|||||||
GetAddress.address_n max_count:8
|
GetAddress.address_n max_count:8
|
||||||
GetAddress.coin_name max_size:17
|
GetAddress.coin_name max_size:17
|
||||||
|
|
||||||
Address.address max_size:41
|
Address.address max_size:60
|
||||||
|
|
||||||
EthereumGetAddress.address_n max_count:8
|
EthereumGetAddress.address_n max_count:8
|
||||||
EthereumAddress.address max_size:20
|
EthereumAddress.address max_size:20
|
||||||
|
@ -315,6 +315,7 @@ bool compile_input_script_sig(TxInputType *tinput)
|
|||||||
// Failed to derive private key
|
// Failed to derive private key
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
hdnode_fill_public_key(&node);
|
||||||
if (tinput->has_multisig) {
|
if (tinput->has_multisig) {
|
||||||
tinput->script_sig.size = compile_script_multisig(&(tinput->multisig), tinput->script_sig.bytes);
|
tinput->script_sig.size = compile_script_multisig(&(tinput->multisig), tinput->script_sig.bytes);
|
||||||
} else { // SPENDADDRESS
|
} else { // SPENDADDRESS
|
||||||
@ -478,6 +479,7 @@ void signing_txack(TransactionType *tx)
|
|||||||
idx2++;
|
idx2++;
|
||||||
send_req_2_prev_output();
|
send_req_2_prev_output();
|
||||||
} else { // last output
|
} else { // last output
|
||||||
|
uint8_t hash[32];
|
||||||
if (tp.extra_data_len > 0) { // has extra data
|
if (tp.extra_data_len > 0) { // has extra data
|
||||||
send_req_2_prev_extradata(0, MIN(1024, tp.extra_data_len));
|
send_req_2_prev_extradata(0, MIN(1024, tp.extra_data_len));
|
||||||
return;
|
return;
|
||||||
@ -488,13 +490,7 @@ void signing_txack(TransactionType *tx)
|
|||||||
signing_abort();
|
signing_abort();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (idx1 < inputs_count - 1) {
|
phase1_request_next_input();
|
||||||
idx1++;
|
|
||||||
send_req_1_input();
|
|
||||||
} else {
|
|
||||||
idx1 = 0;
|
|
||||||
send_req_3_output();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case STAGE_REQUEST_2_PREV_EXTRADATA:
|
case STAGE_REQUEST_2_PREV_EXTRADATA:
|
||||||
@ -821,7 +817,7 @@ void signing_txack(TransactionType *tx)
|
|||||||
sha256_Update(&hashers[0], hash_prevouts, 32);
|
sha256_Update(&hashers[0], hash_prevouts, 32);
|
||||||
sha256_Update(&hashers[0], hash_sequence, 32);
|
sha256_Update(&hashers[0], hash_sequence, 32);
|
||||||
tx_prevout_hash(&hashers[0], &tx->inputs[0]);
|
tx_prevout_hash(&hashers[0], &tx->inputs[0]);
|
||||||
tx_script_hash(&hashers[0], tx->inputs[0].script_sig.size, tx->inputs[0].script_sig.bytes);
|
tx_script_hash(&hashers[0], tx->inputs[0].script_sig.size, tx->inputs[0].script_sig.bytes);
|
||||||
sha256_Update(&hashers[0], (const uint8_t*) &tx->inputs[0].amount, 8);
|
sha256_Update(&hashers[0], (const uint8_t*) &tx->inputs[0].amount, 8);
|
||||||
tx_sequence_hash(&hashers[0], &tx->inputs[0]);
|
tx_sequence_hash(&hashers[0], &tx->inputs[0]);
|
||||||
sha256_Update(&hashers[0], hash_outputs, 32);
|
sha256_Update(&hashers[0], hash_outputs, 32);
|
||||||
@ -835,7 +831,7 @@ void signing_txack(TransactionType *tx)
|
|||||||
resp.serialized.signature_index = idx1;
|
resp.serialized.signature_index = idx1;
|
||||||
resp.serialized.has_signature = true;
|
resp.serialized.has_signature = true;
|
||||||
resp.serialized.has_serialized_tx = true;
|
resp.serialized.has_serialized_tx = true;
|
||||||
ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, 0);
|
ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, NULL, NULL);
|
||||||
resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes);
|
resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes);
|
||||||
if (tx->inputs[0].has_multisig) {
|
if (tx->inputs[0].has_multisig) {
|
||||||
uint32_t r, i, script_len;
|
uint32_t r, i, script_len;
|
||||||
|
@ -63,7 +63,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
|
|||||||
memset(out, 0, sizeof(TxOutputBinType));
|
memset(out, 0, sizeof(TxOutputBinType));
|
||||||
out->amount = in->amount;
|
out->amount = in->amount;
|
||||||
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
|
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
|
||||||
int addr_raw_len;
|
size_t addr_raw_len;
|
||||||
|
|
||||||
if (in->has_address) { // address provided -> regular output
|
if (in->has_address) { // address provided -> regular output
|
||||||
addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE);
|
addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE);
|
||||||
@ -76,36 +76,37 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr_raw_len == 21 &&
|
size_t prefix_len;
|
||||||
addr_raw[0] == coin->address_type) { // p2pkh
|
if (address_check_prefix(addr_raw, coin->address_type) // p2pkh
|
||||||
|
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) {
|
||||||
|
|
||||||
out->script_pubkey.bytes[0] = 0x76; // OP_DUP
|
out->script_pubkey.bytes[0] = 0x76; // OP_DUP
|
||||||
out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160
|
out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160
|
||||||
out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes
|
out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes
|
||||||
memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20);
|
memcpy(out->script_pubkey.bytes + 3, addr_raw + prefix_len, 20);
|
||||||
out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY
|
out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY
|
||||||
out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG
|
out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG
|
||||||
out->script_pubkey.size = 25;
|
out->script_pubkey.size = 25;
|
||||||
} else if (addr_raw_len == 21
|
} else if (address_check_prefix(addr_raw, coin->address_type_p2sh) // p2sh
|
||||||
&& addr_raw[0] == coin->address_type_p2sh) { // p2sh
|
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh))) {
|
||||||
out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160
|
out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160
|
||||||
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
|
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
|
||||||
memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20);
|
memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20);
|
||||||
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
|
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
|
||||||
out->script_pubkey.size = 23;
|
out->script_pubkey.size = 23;
|
||||||
} else if (addr_raw_len == 23
|
} else if (address_check_prefix(addr_raw, coin->address_type_p2wpkh)
|
||||||
&& addr_raw[0] == coin->address_type_p2wpkh
|
&& addr_raw_len == 22 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wpkh))
|
||||||
&& addr_raw[1] == 0 && addr_raw[2] == 0) { // p2wpkh v0
|
&& addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wpkh v0
|
||||||
out->script_pubkey.bytes[0] = 0x00; // version 0
|
out->script_pubkey.bytes[0] = 0x00; // version 0
|
||||||
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
|
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
|
||||||
memcpy(out->script_pubkey.bytes + 2, addr_raw + 3, 20);
|
memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 20);
|
||||||
out->script_pubkey.size = 22;
|
out->script_pubkey.size = 22;
|
||||||
} else if (addr_raw_len == 35
|
} else if (address_check_prefix(addr_raw, coin->address_type_p2wsh)
|
||||||
&& addr_raw[0] == coin->address_type_p2wsh
|
&& addr_raw_len == 34 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wsh))
|
||||||
&& addr_raw[1] == 0 && addr_raw[2] == 0) { // p2wsh v0
|
&& addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wsh v0
|
||||||
out->script_pubkey.bytes[0] = 0x00; // version 0
|
out->script_pubkey.bytes[0] = 0x00; // version 0
|
||||||
out->script_pubkey.bytes[1] = 0x20; // pushing 32 bytes
|
out->script_pubkey.bytes[1] = 0x20; // pushing 32 bytes
|
||||||
memcpy(out->script_pubkey.bytes + 2, addr_raw + 3, 32);
|
memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 32);
|
||||||
out->script_pubkey.size = 34;
|
out->script_pubkey.size = 34;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user