Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/cosmos #188

Merged
merged 51 commits into from
Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
7d084d9
boil your plates
ProofOfKeags Nov 10, 2019
c8be2d2
partial
ProofOfKeags Nov 10, 2019
aa3c082
works on emulator
ProofOfKeags Nov 11, 2019
bbb31d9
tests passing
ProofOfKeags Nov 11, 2019
6f74447
fixes submodule deps for pr
ProofOfKeags Nov 12, 2019
c866112
missed conflict header in rebase
ProofOfKeags Nov 13, 2019
06a31e5
Update lib/firmware/cosmos.c
ProofOfKeags Nov 13, 2019
8c5f92e
moves import
ProofOfKeags Nov 13, 2019
0d493b8
Merge branch 'feature/cosmos' of github.com:Start9Labs/keepkey-firmwa…
ProofOfKeags Nov 13, 2019
0f2fcb9
puts responsibility on getAddress to fill pubkey
ProofOfKeags Nov 13, 2019
702b185
fixes confirmation dialogs
ProofOfKeags Nov 13, 2019
720a7ba
displays node_str instead of from address
ProofOfKeags Nov 13, 2019
e3048b2
fixes committed conflict
ProofOfKeags Nov 13, 2019
200efcd
fixes mismatch logic, adds EOS to account based calls
ProofOfKeags Nov 13, 2019
1ad286c
changes to rebased cosmos commit
ProofOfKeags Nov 13, 2019
3062856
temp change to start9 fork of trezor firmware
ProofOfKeags Nov 13, 2019
e22364d
changes trezor-firmware commit to include base conversion functionality
ProofOfKeags Nov 13, 2019
c4063bf
Update lib/firmware/coins.c
ProofOfKeags Nov 13, 2019
f9e3a40
Update lib/firmware/coins.c
ProofOfKeags Nov 13, 2019
66c7e6e
builds clean
ProofOfKeags Nov 13, 2019
605c587
removes commented code
ProofOfKeags Nov 13, 2019
aa3826d
changes back to keepkey remotes on submodules
ProofOfKeags Nov 13, 2019
2b3dac7
escaping
dr-bonez Nov 13, 2019
975b46b
Merge branch 'feature/cosmos' of github.com:Start9Labs/keepkey-firmwa…
dr-bonez Nov 13, 2019
a21af26
tests pass again
ProofOfKeags Nov 13, 2019
5b3680a
WIP: refactor message protocol for interactivity
ProofOfKeags Nov 14, 2019
5fd3abb
updates device protocol dependency
ProofOfKeags Nov 14, 2019
59d5358
WIP: trying to get unit tests to pass with refactor
ProofOfKeags Nov 14, 2019
17bd691
WIP: phase 2 works?
ProofOfKeags Nov 14, 2019
6e7c701
Unit Tests Pass For Real™
ProofOfKeags Nov 14, 2019
fe51ffc
switched to sizeof
ProofOfKeags Nov 14, 2019
5c2fa36
fix optionals
dr-bonez Nov 14, 2019
12bcaa2
Integration tests work
ProofOfKeags Nov 14, 2019
a10fa44
Update lib/firmware/cosmos.c
ProofOfKeags Nov 21, 2019
e3c7686
Update lib/firmware/fsm_msg_cosmos.h
ProofOfKeags Nov 21, 2019
cf90b53
dead code removal, macro inlining
ProofOfKeags Nov 21, 2019
979abbd
Merge branch 'feature/cosmos' of github.com:Start9Labs/keepkey-firmwa…
ProofOfKeags Nov 21, 2019
fa8473c
removes requirement of from_address, calculates it dynamically
ProofOfKeags Nov 21, 2019
291ac60
removes has_from_address check
ProofOfKeags Nov 21, 2019
c96ff1f
fix for bip32 derivation
ProofOfKeags Nov 22, 2019
4ad5419
Update trezor-firmware dep
keepkeyjon Nov 22, 2019
f56d76c
cosmos: rearrange msg signing for clarity
keepkeyjon Nov 22, 2019
223075e
cosmos: avoid UB in testcase
keepkeyjon Nov 22, 2019
de09ac8
fixes UB issue with copying
ProofOfKeags Nov 22, 2019
ac9393c
aborts and proper string formatting
ProofOfKeags Nov 22, 2019
6d571f8
Merge pull request #2 from keepkey/feature/cosmos
ProofOfKeags Nov 22, 2019
f6f663d
Merge branch 'master' into feature/cosmos
keepkeyjon Nov 22, 2019
be49036
cosmos: whole_account = false
keepkeyjon Nov 22, 2019
ec716cf
update device-protocol
keepkeyjon Nov 22, 2019
cf06bc4
Merge pull request #3 from keepkey/feature/cosmos
ProofOfKeags Nov 22, 2019
91dc4f4
Update lib/firmware/fsm_msg_cosmos.h
ProofOfKeags Nov 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deps/crypto/trezor-firmware
2 changes: 1 addition & 1 deletion deps/device-protocol
75 changes: 38 additions & 37 deletions include/keepkey/firmware/coins.def

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions include/keepkey/firmware/cosmos.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef __COSMOS_H__
#define __COSMOS_H__

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "crypto.h"
#include "fsm.h"
#include "messages.pb.h"
#include "trezor/crypto/bip32.h"

bool cosmos_path_mismatched(const CoinType *_coin,
const uint32_t *_address_n,
const uint32_t _address_n_count);
bool cosmos_getAddress(const HDNode *_node, char *address);
bool cosmos_signTxInit(const HDNode* _node,
const uint32_t* _address_n,
const size_t _address_n_count,
const uint64_t account_number,
const char *chain_id,
const size_t chain_id_length,
const uint32_t fee_uatom_amount,
const uint32_t gas,
const char *memo,
const size_t memo_length,
const uint64_t _sequence,
const uint32_t msg_count);
bool cosmos_signTxUpdateMsgSend(const uint64_t amount,
const char *to_address);
bool cosmos_signTxFinalize(uint8_t* public_key, uint8_t* signature);
bool cosmos_signingIsInited(void);
bool cosmos_signingIsFinished(void);
void cosmos_signAbort(void);
size_t cosmos_getAddressNCount(void);
bool cosmos_getAddressN(uint32_t* address_n, size_t address_n_count);

#endif
4 changes: 4 additions & 0 deletions include/keepkey/firmware/fsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ void fsm_msgEosGetPublicKey(const EosGetPublicKey *msg);
void fsm_msgEosSignTx(const EosSignTx *msg);
void fsm_msgEosTxActionAck(const EosTxActionAck *msg);

void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg);
void fsm_msgCosmosSignTx(const CosmosSignTx *msg);
void fsm_msgCosmosMsgAck(const CosmosMsgAck *msg);

#if DEBUG_LINK
//void fsm_msgDebugLinkDecision(DebugLinkDecision *msg);
void fsm_msgDebugLinkGetState(DebugLinkGetState *msg);
Expand Down
1 change: 1 addition & 0 deletions include/keepkey/transport/interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#undef delete

#include "messages-eos.pb.h"
#include "messages-cosmos.pb.h"

#include "types.pb.h"
#include "trezor_transport.h"
Expand Down
13 changes: 13 additions & 0 deletions include/keepkey/transport/messages-cosmos.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CosmosGetAddress.address_n max_count:10

CosmosAddress.address max_size:46

CosmosSignTx.address_n max_count:10
CosmosSignTx.chain_id max_size:32
CosmosSignTx.memo max_size:256

CosmosMsgSend.from_address max_size:46
CosmosMsgSend.to_address max_size:46

CosmosSignedTx.public_key max_size:33
CosmosSignedTx.signature max_size:64
1 change: 1 addition & 0 deletions lib/firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ set(sources
app_confirm.c
app_layout.c
coins.c
cosmos.c
crypto.c
eos.c
eos-contracts/eosio.system.c
Expand Down
12 changes: 10 additions & 2 deletions lib/firmware/coins.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,14 @@ static bool isEOS(const char *coin_name) {
return false;
}

static bool isAccountBased(const char* coin_name)
{
if (strcmp(coin_name, "Cosmos") == 0) { return true; }
ProofOfKeags marked this conversation as resolved.
Show resolved Hide resolved
if (isEthereumLike(coin_name)) { return true; }
if (isEOS(coin_name)) { return true; }
return false;
}

bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin,
const uint32_t *address_n, size_t address_n_count,
bool whole_account, bool show_addridx)
Expand All @@ -452,7 +460,7 @@ bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin,
return false;

// Only 0/1 for internal/external are valid paths on UTXO coins.
if (!isEthereumLike(coin_name) && !isEOS(coin_name) &&
if (!isAccountBased(coin_name) &&
address_n[3] != 0 && address_n[3] != 1)
return false;
}
Expand All @@ -464,7 +472,7 @@ bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin,
if (!prefix)
return false;

if (whole_account || isEthereumLike(coin_name) || isEOS(coin_name) || !show_addridx) {
if (whole_account || isAccountBased(coin_name) || !show_addridx) {
snprintf(node_str, len, "%s%s Account #%" PRIu32, prefix, coin_name,
address_n[2] & 0x7fffffff);
} else {
Expand Down
229 changes: 229 additions & 0 deletions lib/firmware/cosmos.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
#include "keepkey/firmware/cosmos.h"

#include "keepkey/board/confirm_sm.h"
#include "keepkey/board/util.h"
#include "keepkey/firmware/home_sm.h"
#include "keepkey/firmware/storage.h"
#include "trezor/crypto/ecdsa.h"
#include "trezor/crypto/memzero.h"
#include "trezor/crypto/segwit_addr.h"
#include <stdbool.h>
#include <time.h>

static CONFIDENTIAL HDNode node;
static SHA256_CTX ctx;
static bool has_message;
static bool initialized;
static uint32_t address_n[8];
static size_t address_n_count;
static uint32_t msgs_remaining;
static uint64_t sequence;

bool cosmos_path_mismatched(const CoinType *_coin,
const uint32_t *_address_n,
const uint32_t _address_n_count)
{
// m/44' : BIP44-like path
// m / purpose' / bip44_account_path' / account' / x / y
bool mismatch = false;
mismatch |= _address_n_count != 5;
mismatch |= _address_n_count > 0 && (_address_n[0] != (0x80000000 + 44));
mismatch |= _address_n_count > 1 && (_address_n[1] != _coin->bip44_account_path);
mismatch |= _address_n_count > 2 && (_address_n[2] & 0x80000000) == 0;
mismatch |= _address_n_count > 3 && _address_n[3] != 0;
mismatch |= _address_n_count > 4 && _address_n[4] != 0;
return mismatch;
}

/*
* Gets the address
*
* _node: HDNode from which the address is to be derived
* address: output buffer
*
* returns true if successful
*/
bool cosmos_getAddress(const HDNode *_node, char *address)
{
uint8_t hash160Buf[RIPEMD160_DIGEST_LENGTH];
ecdsa_get_pubkeyhash(_node->public_key, HASHER_SHA2_RIPEMD, hash160Buf);

uint8_t fiveBitExpanded[RIPEMD160_DIGEST_LENGTH * 8 / 5];
size_t len = 0;
convert_bits(fiveBitExpanded, &len, 5, hash160Buf, 20, 8, 1);
return bech32_encode(address, "cosmos", fiveBitExpanded, len) == 1;
}

void sha256UpdateEscaped(SHA256_CTX *_ctx, const char *s, size_t len)
{
while (len > 0)
{
if (s[0] == '"')
{
sha256_Update(_ctx, (uint8_t *)"\\\"", 2);
}
else if (s[0] == '\\')
{
sha256_Update(_ctx, (uint8_t *)"\\\\", 2);
}
else
{
sha256_Update(_ctx, (uint8_t *)&s[0], 1);
}
s = &s[1];
len--;
}
}

bool cosmos_signTxInit(const HDNode* _node,
const uint32_t* _address_n,
const size_t _address_n_count,
const uint64_t account_number,
const char *chain_id,
const size_t chain_id_length,
const uint32_t fee_uatom_amount,
const uint32_t gas,
const char *memo,
const size_t memo_length,
const uint64_t _sequence,
const uint32_t msg_count)
{

initialized = true;
msgs_remaining = msg_count;
has_message = false;
sequence = _sequence;

memzero(&node, sizeof(node));
memcpy(&node, _node, sizeof(node));
memzero(address_n, sizeof(address_n));
if (_address_n_count > sizeof(address_n)/sizeof(address_n[0])) { return false; }
memcpy(address_n, _address_n, _address_n_count * sizeof(*address_n));
address_n_count = _address_n_count;

int n;
sha256_Init(&ctx);
char buffer[64 + 1];

// Each segment guaranteed to be less than or equal to 64 bytes
// 19 + ^20 + 1 = ^40
n = snprintf(buffer, sizeof(buffer), "{\"account_number\":\"%" PRIu64 "\"", account_number);
if (n < 0) { return false; }
sha256_Update(&ctx, (uint8_t *)buffer, n);

// <escape chain_id>
const char *const chainid_prefix = ",\"chain_id\":\"";
sha256_Update(&ctx, (uint8_t *)chainid_prefix, strlen(chainid_prefix));
sha256UpdateEscaped(&ctx, chain_id, chain_id_length);

// 30 + ^10 + 19 = ^59
n = snprintf(buffer, sizeof(buffer), "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}]", fee_uatom_amount);
if (n < 0) { return false; }
sha256_Update(&ctx, (uint8_t *)buffer, n);

// 8 + ^10 + 2 = ^20
n = snprintf(buffer, sizeof(buffer), ",\"gas\":\"%" PRIu32 "\"}", gas);
if (n < 0) { return false; }
sha256_Update(&ctx, (uint8_t *)buffer, n);

// <escape memo>
const char *const memo_prefix = ",\"memo\":\"";
sha256_Update(&ctx, (uint8_t *)memo_prefix, strlen(memo_prefix));
sha256UpdateEscaped(&ctx, memo, memo_length);

// 10
sha256_Update(&ctx, (uint8_t *)"\",\"msgs\":[", 10);

return true;
}

bool cosmos_signTxUpdateMsgSend(const uint64_t amount,
const char *to_address)
{
int n;
char buffer[64 + 1];

size_t decoded_len;
char hrp[45];
uint8_t decoded[38];
if (!bech32_decode(hrp, decoded, &decoded_len, to_address)) { return false; }

char from_address[46];
if (!cosmos_getAddress(&node, from_address)) { return false; }

if (has_message) {
sha256_Update(&ctx, (uint8_t*)",", 1);
}

const char *const prelude = "{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{";
sha256_Update(&ctx, (uint8_t *)prelude, strlen(prelude));

// 21 + ^20 + 19 = ^60
n = snprintf(buffer, sizeof(buffer), "\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"uatom\"}]", amount);
if (n < 0) { return false; }
sha256_Update(&ctx, (uint8_t*)buffer, n);

// 17 + 45 + 1 = 63
n = snprintf(buffer, sizeof(buffer), ",\"from_address\":\"%s\"", from_address);
if (n < 0) { return false; }
sha256_Update(&ctx, (uint8_t*)buffer, n);

// 15 + 45 + 3 = 63
n = snprintf(buffer, sizeof(buffer), ",\"to_address\":\"%s\"}}", to_address);
if (n < 0) { return false; }
sha256_Update(&ctx, (uint8_t*)buffer, n);

has_message = true;
msgs_remaining--;
return true;
}

bool cosmos_signTxFinalize(uint8_t* public_key, uint8_t* signature)
{
int n;
char buffer[SHA256_DIGEST_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH

// 16 + ^20 = ^36
n = snprintf(buffer, SHA256_DIGEST_LENGTH + 1, "],\"sequence\":\"%" PRIu64 "\"}", sequence);
if (n < 0) { return false; }
sha256_Update(&ctx, (uint8_t*)buffer, n);

hdnode_fill_public_key(&node);
memcpy(public_key, node.public_key, 33);

uint8_t hash[SHA256_DIGEST_LENGTH];
sha256_Final(&ctx, hash);
return ecdsa_sign_digest(&secp256k1, node.private_key, hash, signature, NULL, NULL) == 0;
}

bool cosmos_signingIsInited(void) {
return initialized;
}

bool cosmos_signingIsFinished(void) {
return msgs_remaining == 0;
}

void cosmos_signAbort(void) {
initialized = false;
has_message = false;
memzero(&ctx, sizeof(ctx));
memzero(&node, sizeof(node));
memzero(&sequence, sizeof(sequence));
msgs_remaining = 0;
sequence = 0;
}

size_t cosmos_getAddressNCount(void) {
return address_n_count;
}

bool cosmos_getAddressN(uint32_t* _address_n, size_t _address_n_count)
{
if (_address_n_count < address_n_count) {
return false;
}

memcpy(_address_n, address_n, sizeof(uint32_t) * address_n_count);
return true;
}
Loading