From 7cba60895d86a934ae3cfa8a6dfd1618accd355d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 5 Jun 2014 23:45:01 +0200 Subject: [PATCH] update protobuf, disable SimpleSignTx --- firmware/fsm.c | 131 +------------------------------ firmware/fsm.h | 1 - firmware/messages.c | 6 -- firmware/messages.h | 4 +- firmware/protob/messages.options | 23 ++++-- firmware/protob/messages.pb.c | 21 ++++- firmware/protob/messages.pb.h | 60 ++++++++++++-- firmware/protob/types.options | 37 +++++---- firmware/protob/types.pb.c | 16 +++- firmware/protob/types.pb.h | 105 +++++++++++++++---------- firmware/transaction.c | 78 +----------------- firmware/transaction.h | 4 - trezor-common | 2 +- 13 files changed, 194 insertions(+), 294 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index ca94898..834bdbb 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -343,131 +343,6 @@ void fsm_msgSignTx(SignTx *msg) signing_init(msg->inputs_count, msg->outputs_count, coin, node); } -void fsm_msgSimpleSignTx(SimpleSignTx *msg) -{ - RESP_INIT(TxRequest); - - if (msg->inputs_count < 1) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); - layoutHome(); - return; - } - - if (msg->outputs_count < 1) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one output"); - layoutHome(); - return; - } - - if (!protectPin(true)) { - layoutHome(); - return; - } - - HDNode *node = fsm_getRootNode(); - if (!node) return; - const CoinType *coin = coinByName(msg->coin_name); - if (!coin) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); - layoutHome(); - return; - } - - uint32_t version = 1; - uint32_t lock_time = 0; - int tx_size = transactionSimpleSign(coin, node, msg->inputs, msg->inputs_count, msg->outputs, msg->outputs_count, version, lock_time, resp->serialized.serialized_tx.bytes); - if (tx_size < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); - layoutHome(); - return; - } - if (tx_size == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error signing transaction"); - layoutHome(); - return; - } - - size_t i, j; - - // determine change address - uint64_t change_spend = 0; - for (i = 0; i < msg->outputs_count; i++) { - if (msg->outputs[i].address_n_count > 0) { // address_n set -> change address - if (change_spend == 0) { // not set - change_spend = msg->outputs[i].amount; - } else { - fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); - layoutHome(); - return; - } - } - } - - // check origin transactions - uint8_t prev_hashes[ pb_arraysize(SimpleSignTx, transactions) ][32]; - for (i = 0; i < msg->transactions_count; i++) { - if (!transactionHash(&(msg->transactions[i]), prev_hashes[i])) { - memset(prev_hashes[i], 0, 32); - } - } - - // calculate spendings - uint64_t to_spend = 0; - bool found; - for (i = 0; i < msg->inputs_count; i++) { - found = false; - for (j = 0; j < msg->transactions_count; j++) { - if (memcmp(msg->inputs[i].prev_hash.bytes, prev_hashes[j], 32) == 0) { // found prev TX - if (msg->inputs[i].prev_index < msg->transactions[j].bin_outputs_count) { - to_spend += msg->transactions[j].bin_outputs[msg->inputs[i].prev_index].amount; - found = true; - break; - } - } - } - if (!found) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid prevhash"); - layoutHome(); - return; - } - } - - uint64_t spending = 0; - for (i = 0; i < msg->outputs_count; i++) { - spending += msg->outputs[i].amount; - } - if (spending > to_spend) { - fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); - layoutHome(); - return; - } - - uint64_t fee = to_spend - spending; - if (fee > (((uint64_t)tx_size + 999) / 1000) * coin->maxfee_kb) { - layoutFeeOverThreshold(coin, fee, ((uint64_t)tx_size + 999) / 1000); - if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); - layoutHome(); - return; - } - } - - // last confirmation - layoutConfirmTx(coin, to_spend - change_spend - fee, fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); - } else { - resp->has_request_type = true; - resp->request_type = RequestType_TXFINISHED; - resp->has_serialized = true; - resp->serialized.has_serialized_tx = true; - resp->serialized.serialized_tx.size = (uint32_t)tx_size; - msg_write(MessageType_MessageType_TxRequest, resp); - } - - layoutHome(); -} - void fsm_msgCancel(Cancel *msg) { (void)msg; @@ -636,9 +511,9 @@ void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) (void)msg; RESP_INIT(DebugLinkState); -// resp->has_layout = true; -// resp->layout.size = OLED_BUFSIZE; -// memcpy(resp->layout.bytes, oledGetBuffer(), OLED_BUFSIZE); + resp->has_layout = true; + resp->layout.size = OLED_BUFSIZE; + memcpy(resp->layout.bytes, oledGetBuffer(), OLED_BUFSIZE); if (storage.has_pin) { resp->has_pin = true; diff --git a/firmware/fsm.h b/firmware/fsm.h index 8344f67..030d7af 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -38,7 +38,6 @@ void fsm_msgGetPublicKey(GetPublicKey *msg); void fsm_msgLoadDevice(LoadDevice *msg); void fsm_msgResetDevice(ResetDevice *msg); void fsm_msgSignTx(SignTx *msg); -void fsm_msgSimpleSignTx(SimpleSignTx *msg); //void fsm_msgPinMatrixAck(PinMatrixAck *msg); void fsm_msgCancel(Cancel *msg); void fsm_msgTxAck(TxAck *msg); diff --git a/firmware/messages.c b/firmware/messages.c index 70ff6da..403d1e8 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -29,11 +29,6 @@ #include "pb_encode.h" #include "messages.pb.h" -// SimpleSignTx_size is the largest message we operate with -#if MSG_IN_SIZE < SimpleSignTx_size -#error "MSG_IN_SIZE is too small!" -#endif - struct MessagesMap_t { char type; // n = normal, d = debug char dir; // i = in, o = out @@ -55,7 +50,6 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_LoadDevice, LoadDevice_fields, (void (*)(void *))fsm_msgLoadDevice}, {'n', 'i', MessageType_MessageType_ResetDevice, ResetDevice_fields, (void (*)(void *))fsm_msgResetDevice}, {'n', 'i', MessageType_MessageType_SignTx, SignTx_fields, (void (*)(void *))fsm_msgSignTx}, - {'n', 'i', MessageType_MessageType_SimpleSignTx, SimpleSignTx_fields, (void (*)(void *))fsm_msgSimpleSignTx}, // {'n', 'i', MessageType_MessageType_PinMatrixAck, PinMatrixAck_fields, (void (*)(void *))fsm_msgPinMatrixAck}, {'n', 'i', MessageType_MessageType_Cancel, Cancel_fields, (void (*)(void *))fsm_msgCancel}, {'n', 'i', MessageType_MessageType_TxAck, TxAck_fields, (void (*)(void *))fsm_msgTxAck}, diff --git a/firmware/messages.h b/firmware/messages.h index 6f3b83e..d2a5136 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -24,7 +24,7 @@ #include #include "trezor.h" -#define MSG_IN_SIZE (24*1024) +#define MSG_IN_SIZE (9*1024) #define MSG_OUT_SIZE (9*1024) @@ -34,7 +34,7 @@ uint8_t *msg_out_data(void); #if DEBUG_LINK -#define MSG_DEBUG_OUT_SIZE (2*1024) +#define MSG_DEBUG_OUT_SIZE (4*1024) #define msg_debug_read(buf, len) msg_read_common('d', (buf), (len)) #define msg_debug_write(id, ptr) msg_write_common('d', (id), (ptr)) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 56c540b..1d80312 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -9,9 +9,10 @@ Features.bootloader_hash max_size:32 ApplySettings.language max_size:17 ApplySettings.label max_size:33 -Ping.message max_size:256 +Ping.message max_size:256 -Success.message max_size:256 +Success.message max_size:256 +Success.payload max_size:1024 Failure.message max_size:256 @@ -56,16 +57,26 @@ VerifyMessage.message max_size:256 MessageSignature.address max_size:35 MessageSignature.signature max_size:65 +EncryptKeyValue.address_n max_count:8 +EncryptKeyValue.key max_size:256 +EncryptKeyValue.value max_size:1024 + +DecryptKeyValue.address_n max_count:8 +DecryptKeyValue.key max_size:256 +DecryptKeyValue.value max_size:1024 + EstimateTxSize.coin_name max_size:17 SignTx.coin_name max_size:17 -SimpleSignTx.inputs max_count:4 -SimpleSignTx.outputs max_count:4 -SimpleSignTx.transactions max_count:4 +# not used in firmware +SimpleSignTx.inputs max_count:0 +SimpleSignTx.outputs max_count:0 +SimpleSignTx.transactions max_count:0 SimpleSignTx.coin_name max_size:17 -FirmwareUpload.payload max_size:0 # not used in firmware +# not used in firmware +FirmwareUpload.payload max_size:0 DebugLinkState.layout max_size:1024 DebugLinkState.pin max_size:10 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 8a13557..077cd7e 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -56,8 +56,9 @@ const pb_field_t Ping_fields[5] = { PB_LAST_FIELD }; -const pb_field_t Success_fields[2] = { +const pb_field_t Success_fields[3] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Success, message, message, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, Success, payload, message, 0), PB_LAST_FIELD }; @@ -204,6 +205,20 @@ const pb_field_t MessageSignature_fields[3] = { PB_LAST_FIELD }; +const pb_field_t EncryptKeyValue_fields[4] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EncryptKeyValue, address_n, address_n, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, EncryptKeyValue, key, address_n, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EncryptKeyValue, value, key, 0), + PB_LAST_FIELD +}; + +const pb_field_t DecryptKeyValue_fields[4] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, DecryptKeyValue, address_n, address_n, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DecryptKeyValue, key, address_n, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, DecryptKeyValue, value, key, 0), + PB_LAST_FIELD +}; + const pb_field_t EstimateTxSize_fields[4] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, EstimateTxSize, outputs_count, outputs_count, 0), PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, EstimateTxSize, inputs_count, outputs_count, 0), @@ -296,11 +311,11 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptKeyValue_DecryptKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -#error Field descriptor for Entropy.entropy is too large. Define PB_FIELD_16BIT to fix this. +#error Field descriptor for Success.payload is too large. Define PB_FIELD_16BIT to fix this. #endif diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 22713c7..c3518d1 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -34,6 +34,8 @@ typedef enum _MessageType { MessageType_MessageType_Cancel = 20, MessageType_MessageType_TxRequest = 21, MessageType_MessageType_TxAck = 22, + MessageType_MessageType_EncryptKeyValue = 23, + MessageType_MessageType_DecryptKeyValue = 24, MessageType_MessageType_ApplySettings = 25, MessageType_MessageType_ButtonRequest = 26, MessageType_MessageType_ButtonAck = 27, @@ -168,6 +170,34 @@ typedef struct _DebugLinkState { uint32_t recovery_word_pos; } DebugLinkState; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} DecryptKeyValue_value_t; + +typedef struct _DecryptKeyValue { + size_t address_n_count; + uint32_t address_n[8]; + bool has_key; + char key[256]; + bool has_value; + DecryptKeyValue_value_t value; +} DecryptKeyValue; + +typedef struct { + size_t size; + uint8_t bytes[1024]; +} EncryptKeyValue_value_t; + +typedef struct _EncryptKeyValue { + size_t address_n_count; + uint32_t address_n[8]; + bool has_key; + char key[256]; + bool has_value; + EncryptKeyValue_value_t value; +} EncryptKeyValue; + typedef struct { size_t size; uint8_t bytes[1024]; @@ -378,18 +408,25 @@ typedef struct _SignTx { typedef struct _SimpleSignTx { size_t inputs_count; - TxInputType inputs[4]; + TxInputType inputs[0]; size_t outputs_count; - TxOutputType outputs[4]; + TxOutputType outputs[0]; size_t transactions_count; - TransactionType transactions[4]; + TransactionType transactions[0]; bool has_coin_name; char coin_name[17]; } SimpleSignTx; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} Success_payload_t; + typedef struct _Success { bool has_message; char message[256]; + bool has_payload; + Success_payload_t payload; } Success; typedef struct _TxAck { @@ -466,6 +503,12 @@ extern const char SimpleSignTx_coin_name_default[17]; #define DebugLinkState_reset_entropy_tag 8 #define DebugLinkState_recovery_fake_word_tag 9 #define DebugLinkState_recovery_word_pos_tag 10 +#define DecryptKeyValue_address_n_tag 1 +#define DecryptKeyValue_key_tag 2 +#define DecryptKeyValue_value_tag 3 +#define EncryptKeyValue_address_n_tag 1 +#define EncryptKeyValue_key_tag 2 +#define EncryptKeyValue_value_tag 3 #define Entropy_entropy_tag 1 #define EntropyAck_entropy_tag 1 #define EstimateTxSize_outputs_count_tag 1 @@ -533,6 +576,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SimpleSignTx_transactions_tag 3 #define SimpleSignTx_coin_name_tag 4 #define Success_message_tag 1 +#define Success_payload_tag 2 #define TxAck_tx_tag 1 #define TxRequest_request_type_tag 1 #define TxRequest_details_tag 2 @@ -549,7 +593,7 @@ extern const pb_field_t Features_fields[16]; extern const pb_field_t ApplySettings_fields[3]; extern const pb_field_t ChangePin_fields[2]; extern const pb_field_t Ping_fields[5]; -extern const pb_field_t Success_fields[2]; +extern const pb_field_t Success_fields[3]; extern const pb_field_t Failure_fields[3]; extern const pb_field_t ButtonRequest_fields[3]; extern const pb_field_t ButtonAck_fields[1]; @@ -575,6 +619,8 @@ extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[4]; extern const pb_field_t MessageSignature_fields[3]; +extern const pb_field_t EncryptKeyValue_fields[4]; +extern const pb_field_t DecryptKeyValue_fields[4]; extern const pb_field_t EstimateTxSize_fields[4]; extern const pb_field_t TxSize_fields[2]; extern const pb_field_t SignTx_fields[4]; @@ -595,7 +641,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define ApplySettings_size 54 #define ChangePin_size 2 #define Ping_size 265 -#define Success_size 259 +#define Success_size 1286 #define Failure_size 265 #define ButtonRequest_size 265 #define ButtonAck_size 0 @@ -621,10 +667,12 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define SignMessage_size 326 #define VerifyMessage_size 363 #define MessageSignature_size 104 +#define EncryptKeyValue_size 1334 +#define DecryptKeyValue_size 1334 #define EstimateTxSize_size 31 #define TxSize_size 6 #define SignTx_size 31 -#define SimpleSignTx_size (91 + 4*TxInputType_size + 4*TxOutputType_size + 4*TransactionType_size) +#define SimpleSignTx_size (19 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) #define FirmwareErase_size 0 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index d3297e9..477ebb3 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -1,26 +1,29 @@ -HDNodeType.chain_code max_size:32 -HDNodeType.private_key max_size:32 -HDNodeType.public_key max_size:33 +HDNodeType.chain_code max_size:32 +HDNodeType.private_key max_size:32 +HDNodeType.public_key max_size:33 -CoinType.coin_name max_size:17 -CoinType.coin_shortcut max_size:9 +CoinType.coin_name max_size:17 +CoinType.coin_shortcut max_size:9 -TxInputType.address_n max_count:8 -TxInputType.prev_hash max_size:32 -TxInputType.script_sig max_size:520 +TxInputType.address_n max_count:8 +TxInputType.prev_hash max_size:32 +TxInputType.script_sig max_size:520 -TxOutputType.address max_size:35 -TxOutputType.address_n max_count:8 -TxOutputType.script_args max_count:3 -TxOutputType.script_args max_size:16 +TxOutputType.address max_size:35 +TxOutputType.address_n max_count:8 -TxOutputBinType.script_pubkey max_size:256 +TxOutputBinType.script_pubkey max_size:256 -TransactionType.inputs max_count:8 -TransactionType.bin_outputs max_count:4 -TransactionType.outputs max_count:4 +TransactionType.inputs max_count:1 +TransactionType.bin_outputs max_count:1 +TransactionType.outputs max_count:1 -TxRequestDetailsType.tx_hash max_size:32 +TxRequestDetailsType.tx_hash max_size:32 TxRequestSerializedType.signature max_size:80 TxRequestSerializedType.serialized_tx max_size:1024 + +MultisigRedeemScriptType.pubkeys max_count:5 +MultisigRedeemScriptType.pubkeys max_size:33 +MultisigRedeemScriptType.signatures max_count:4 +MultisigRedeemScriptType.signatures max_size:80 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 5b6ef60..1d9e61f 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -4,6 +4,7 @@ #include "types.pb.h" const uint32_t TxInputType_sequence_default = 4294967295u; +const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; const pb_field_t HDNodeType_fields[7] = { @@ -24,21 +25,28 @@ const pb_field_t CoinType_fields[5] = { PB_LAST_FIELD }; -const pb_field_t TxInputType_fields[6] = { +const pb_field_t MultisigRedeemScriptType_fields[3] = { + PB_FIELD2( 1, BYTES , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, 0), + PB_FIELD2( 2, BYTES , REPEATED, STATIC , OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxInputType_fields[8] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, TxInputType, address_n, address_n, 0), PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxInputType, prev_hash, address_n, 0), PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, TxInputType, script_sig, prev_index, 0), PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), + PB_FIELD2( 6, ENUM , OPTIONAL, STATIC , OTHER, TxInputType, script_type, sequence, &TxInputType_script_type_default), + PB_FIELD2( 7, MESSAGE , OPTIONAL, STATIC , OTHER, TxInputType, multisig, script_type, &MultisigRedeemScriptType_fields), PB_LAST_FIELD }; -const pb_field_t TxOutputType_fields[6] = { +const pb_field_t TxOutputType_fields[5] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), PB_FIELD2( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), PB_FIELD2( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), PB_FIELD2( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), - PB_FIELD2( 5, BYTES , REPEATED, STATIC , OTHER, TxOutputType, script_args, script_type, 0), PB_LAST_FIELD }; @@ -134,7 +142,7 @@ const pb_extension_type_t wire_debug_out = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_CoinType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) +STATIC_ASSERT((pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index b910112..fb674ea 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -24,10 +24,15 @@ typedef enum _FailureType { FailureType_Failure_FirmwareError = 99 } FailureType; -typedef enum _ScriptType { - ScriptType_PAYTOADDRESS = 0, - ScriptType_PAYTOSCRIPTHASH = 1 -} ScriptType; +typedef enum _OutputScriptType { + OutputScriptType_PAYTOADDRESS = 0, + OutputScriptType_PAYTOSCRIPTHASH = 1 +} OutputScriptType; + +typedef enum _InputScriptType { + InputScriptType_SPENDADDRESS = 0, + InputScriptType_SPENDMULTISIG = 1 +} InputScriptType; typedef enum _RequestType { RequestType_TXINPUT = 0, @@ -93,24 +98,20 @@ typedef struct _HDNodeType { typedef struct { size_t size; - uint8_t bytes[32]; -} TxInputType_prev_hash_t; + uint8_t bytes[33]; +} MultisigRedeemScriptType_pubkeys_t; typedef struct { size_t size; - uint8_t bytes[256]; -} TxInputType_script_sig_t; + uint8_t bytes[80]; +} MultisigRedeemScriptType_signatures_t; -typedef struct _TxInputType { - size_t address_n_count; - uint32_t address_n[8]; - TxInputType_prev_hash_t prev_hash; - uint32_t prev_index; - bool has_script_sig; - TxInputType_script_sig_t script_sig; - bool has_sequence; - uint32_t sequence; -} TxInputType; +typedef struct _MultisigRedeemScriptType { + size_t pubkeys_count; + MultisigRedeemScriptType_pubkeys_t pubkeys[5]; + size_t signatures_count; + MultisigRedeemScriptType_signatures_t signatures[4]; +} MultisigRedeemScriptType; typedef struct { size_t size; @@ -122,20 +123,13 @@ typedef struct _TxOutputBinType { TxOutputBinType_script_pubkey_t script_pubkey; } TxOutputBinType; -typedef struct { - size_t size; - uint8_t bytes[16]; -} TxOutputType_script_args_t; - typedef struct _TxOutputType { bool has_address; char address[35]; size_t address_n_count; uint32_t address_n[8]; uint64_t amount; - ScriptType script_type; - size_t script_args_count; - TxOutputType_script_args_t script_args[3]; + OutputScriptType script_type; } TxOutputType; typedef struct { @@ -169,17 +163,42 @@ typedef struct _TxRequestSerializedType { TxRequestSerializedType_serialized_tx_t serialized_tx; } TxRequestSerializedType; +typedef struct { + size_t size; + uint8_t bytes[32]; +} TxInputType_prev_hash_t; + +typedef struct { + size_t size; + uint8_t bytes[520]; +} TxInputType_script_sig_t; + +typedef struct _TxInputType { + size_t address_n_count; + uint32_t address_n[8]; + TxInputType_prev_hash_t prev_hash; + uint32_t prev_index; + bool has_script_sig; + TxInputType_script_sig_t script_sig; + bool has_sequence; + uint32_t sequence; + bool has_script_type; + InputScriptType script_type; + bool has_multisig; + MultisigRedeemScriptType multisig; +} TxInputType; + typedef struct _TransactionType { bool has_version; uint32_t version; size_t inputs_count; - TxInputType inputs[8]; + TxInputType inputs[1]; size_t bin_outputs_count; - TxOutputBinType bin_outputs[4]; + TxOutputBinType bin_outputs[1]; bool has_lock_time; uint32_t lock_time; size_t outputs_count; - TxOutputType outputs[4]; + TxOutputType outputs[1]; bool has_inputs_cnt; uint32_t inputs_cnt; bool has_outputs_cnt; @@ -194,6 +213,7 @@ extern const pb_extension_type_t wire_debug_out; /* Default values for struct fields */ extern const uint32_t TxInputType_sequence_default; +extern const InputScriptType TxInputType_script_type_default; /* Field tags (for use in manual encoding/decoding) */ #define CoinType_coin_name_tag 1 @@ -206,23 +226,26 @@ extern const uint32_t TxInputType_sequence_default; #define HDNodeType_chain_code_tag 4 #define HDNodeType_private_key_tag 5 #define HDNodeType_public_key_tag 6 -#define TxInputType_address_n_tag 1 -#define TxInputType_prev_hash_tag 2 -#define TxInputType_prev_index_tag 3 -#define TxInputType_script_sig_tag 4 -#define TxInputType_sequence_tag 5 +#define MultisigRedeemScriptType_pubkeys_tag 1 +#define MultisigRedeemScriptType_signatures_tag 2 #define TxOutputBinType_amount_tag 1 #define TxOutputBinType_script_pubkey_tag 2 #define TxOutputType_address_tag 1 #define TxOutputType_address_n_tag 2 #define TxOutputType_amount_tag 3 #define TxOutputType_script_type_tag 4 -#define TxOutputType_script_args_tag 5 #define TxRequestDetailsType_request_index_tag 1 #define TxRequestDetailsType_tx_hash_tag 2 #define TxRequestSerializedType_signature_index_tag 1 #define TxRequestSerializedType_signature_tag 2 #define TxRequestSerializedType_serialized_tx_tag 3 +#define TxInputType_address_n_tag 1 +#define TxInputType_prev_hash_tag 2 +#define TxInputType_prev_index_tag 3 +#define TxInputType_script_sig_tag 4 +#define TxInputType_sequence_tag 5 +#define TxInputType_script_type_tag 6 +#define TxInputType_multisig_tag 7 #define TransactionType_version_tag 1 #define TransactionType_inputs_tag 2 #define TransactionType_bin_outputs_tag 3 @@ -238,8 +261,9 @@ extern const uint32_t TxInputType_sequence_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t CoinType_fields[5]; -extern const pb_field_t TxInputType_fields[6]; -extern const pb_field_t TxOutputType_fields[6]; +extern const pb_field_t MultisigRedeemScriptType_fields[3]; +extern const pb_field_t TxInputType_fields[8]; +extern const pb_field_t TxOutputType_fields[5]; extern const pb_field_t TxOutputBinType_fields[3]; extern const pb_field_t TransactionType_fields[8]; extern const pb_field_t TxRequestDetailsType_fields[3]; @@ -248,10 +272,11 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define CoinType_size 47 -#define TxInputType_size 353 -#define TxOutputType_size 156 +#define MultisigRedeemScriptType_size 503 +#define TxInputType_size 1129 +#define TxOutputType_size 102 #define TxOutputBinType_size 270 -#define TransactionType_size 4600 +#define TransactionType_size 1533 #define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 1115 diff --git a/firmware/transaction.c b/firmware/transaction.c index 38d1480..c97b018 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -98,7 +98,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; - if (in->script_type == ScriptType_PAYTOADDRESS) { + if (in->script_type == OutputScriptType_PAYTOADDRESS) { out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes @@ -113,7 +113,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T return 25; } - if (in->script_type == ScriptType_PAYTOSCRIPTHASH) { + if (in->script_type == OutputScriptType_PAYTOSCRIPTHASH) { out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes uint8_t decoded[21]; @@ -275,80 +275,6 @@ void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) } } -bool transactionHash(TransactionType *tx, uint8_t *hash) -{ - TxStruct t; - uint32_t i; - tx_init(&t, tx->inputs_count, tx->bin_outputs_count, tx->version, tx->lock_time, false); - for (i = 0; i < tx->inputs_count; i++) { - if (!tx_hash_input(&t, &(tx->inputs[i]))) return false; - } - for (i = 0; i < tx->bin_outputs_count; i++) { - if (!tx_hash_output(&t, &(tx->bin_outputs[i]))) return false; - } - tx_hash_final(&t, hash, true); - return true; -} - -int transactionSimpleSign(const CoinType *coin, HDNode *root, TxInputType *inputs, uint32_t inputs_count, TxOutputType *outputs, uint32_t outputs_count, uint32_t version, uint32_t lock_time, uint8_t *out) -{ - uint32_t idx, i, k, r = 0; - TxStruct ti, to; - uint8_t buf[512]; - TxInputType input; - TxOutputBinType output; - HDNode node; - uint8_t privkey[32], pubkey[33], hash[32], sig[64]; - - layoutProgressSwipe("Signing", 0, 0); - tx_init(&to, inputs_count, outputs_count, version, lock_time, false); - for (idx = 0; idx < inputs_count; idx++) { - // compute inner transaction - memcpy(&input, &(inputs[idx]), sizeof(TxInputType)); - tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); - memset(privkey, 0, 32); - memset(pubkey, 0, 33); - for (i = 0; i < inputs_count; i++) { - if (i == idx) { - memcpy(&node, root, sizeof(HDNode)); - for (k = 0; k < inputs[i].address_n_count; k++) { - hdnode_private_ckd(&node, inputs[i].address_n[k]); - } - ecdsa_get_pubkeyhash(node.public_key, hash); - inputs[i].script_sig.size = compile_script_sig(coin->address_type, hash, inputs[i].script_sig.bytes); - if (inputs[i].script_sig.size == 0) { - return 0; - } - memcpy(privkey, node.private_key, 32); - memcpy(pubkey, node.public_key, 33); - } else { - inputs[i].script_sig.size = 0; - } - if (!tx_hash_input(&ti, &(inputs[i]))) return 0; - } - for (i = 0; i < outputs_count; i++) { - int co = compile_output(coin, root, &(outputs[i]), &output, idx == 0); - if (co <= 0) { - return co; - } - if (!tx_hash_output(&ti, &output)) return 0; - } - tx_hash_final(&ti, hash, false); - ecdsa_sign_digest(privkey, hash, sig); - int der_len = ecdsa_sig_to_der(sig, buf); - input.script_sig.size = serialize_script_sig(buf, der_len, pubkey, 33, input.script_sig.bytes); - r += tx_serialize_input(&to, input.prev_hash.bytes, input.prev_index, input.script_sig.bytes, input.script_sig.size, input.sequence, out + r); - layoutProgress("Signing", 1000 * idx / inputs_count, idx); - } - for (i = 0; i < outputs_count; i++) { - if (compile_output(coin, root, &(outputs[i]), &output, false) <= 0) { - return 0; - } - r += tx_serialize_output(&to, output.amount, output.script_pubkey.bytes, output.script_pubkey.size, out + r); - } - return r; -} - uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs) { return 10 + inputs * 149 + outputs * 35; diff --git a/firmware/transaction.h b/firmware/transaction.h index c63e7ce..0939ea3 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -52,10 +52,6 @@ bool tx_hash_input(TxStruct *t, TxInputType *input); bool tx_hash_output(TxStruct *t, TxOutputBinType *output); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); -bool transactionHash(TransactionType *tx, uint8_t *hash); - -int transactionSimpleSign(const CoinType *coin, HDNode *root, TxInputType *inputs, uint32_t inputs_count, TxOutputType *outputs, uint32_t outputs_count, uint32_t version, uint32_t lock_time, uint8_t *out); - uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); uint32_t transactionEstimateSizeKb(uint32_t inputs, uint32_t outputs); diff --git a/trezor-common b/trezor-common index 1865a04..06f4aee 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 1865a0428d1803416174f31a1d6b53b6632384a9 +Subproject commit 06f4aee3fd45ec533e7e0e5a2ac06c98ae9975d6