diff --git a/deps/crypto/trezor-firmware b/deps/crypto/trezor-firmware index 3740fa946..d251f3e56 160000 --- a/deps/crypto/trezor-firmware +++ b/deps/crypto/trezor-firmware @@ -1 +1 @@ -Subproject commit 3740fa946d6486525f4239c824c5a6d78c4cb7f8 +Subproject commit d251f3e5636ee3b9a31a2b3436f0ea651414d355 diff --git a/deps/device-protocol b/deps/device-protocol index 88e294107..d1e2d52b9 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit 88e29410753b26d27882ed66460e8bd61d6980c6 +Subproject commit d1e2d52b910aa939fc1eebf3d5e2b5c12ffd98f3 diff --git a/deps/python-keepkey b/deps/python-keepkey index b4af5b4ba..0140bb456 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit b4af5b4bab81b5567490136d02a0681b9ac1a266 +Subproject commit 0140bb4562db1d25b85c0ed43a5f0b38286ebe2e diff --git a/include/keepkey/firmware/coins.def b/include/keepkey/firmware/coins.def index 4f34d478f..2afb6d4fe 100644 --- a/include/keepkey/firmware/coins.def +++ b/include/keepkey/firmware/coins.def @@ -1,41 +1,42 @@ #define NO_CONTRACT {0, {0}} //coin_name coin_shortcut address_type maxfee_kb p2sh signed_message_header bip44_account_path forkid/chain_id decimals contract_address xpub_magic segwit force_bip143 curve_name cashaddr_prefix bech32_prefix decred xpub_magic_segwit_p2sh xpub_mmagic_segwit_native nanoaddr_prefix -X(true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000000, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "bc", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "Bitcoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true, SECP256K1_STRING, false, "", true, "tb", false, false, true, 71979618, true, 73342198, false, "" ) -X(true, "BitcoinCash", true, "BCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000091, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, true, "Namecoin Signed Message:\n", true, 0x80000007, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000002, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, false, 0, false, 0, false, "" ) -X(true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, true, "Dogecoin Signed Message:\n", true, 0x80000003, false, 0, true, 8, false, NO_CONTRACT, true, 49990397, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, true, "DarkCoin Signed Message:\n", true, 0x80000005, false, 0, true, 8, false, NO_CONTRACT, true, 50221772, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, ETHEREUM, true, "ETH", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x8000003c, true, 1, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, ETHEREUM_CLS, true, "ETC", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x8000003d, true, 62, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "BitcoinGold", true, "BTG", true, 38, true, 500000, true, 23, true, "Bitcoin Gold Signed Message:\n", true, 0x8000009c, true, 79, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, true, true, SECP256K1_STRING, false, "", true, "btg", false, false, true, 77429938, false, 0, false, "" ) -X(true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, true, "Zcash Signed Message:\n", true, 0x80000085, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Zcash Testnet",true, "TAZ", true, 7461, true, 10000000, true, 7354, true, "Zcash Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "DigiByte", true, "DGB", true, 30, true, 500000, true, 63, true, "DigiByte Signed Message:\n", true, 0x80000014, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, false, false, true, SECP256K1_STRING, false, "", true, "dgb", false, false, false, 0, false, 0, false, "" ) -X(true, "EOS", true, "EOS", false, NA, false, 0, false, NA, false, {0}, true, 0x800000c2, false, 0, false, 0, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Axe", true, "AXE", true, 55, true, 100000, true, 16, true, "DarkCoin Signed Message:\n", true, 0x80001092, false, 0, true, 8, false, NO_CONTRACT, true, 50221772, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Bitcore", true, "BTX", true, 3, true, 100000, true, 125, true, "BitCore Signed Message:\n", true, 0x800000a0, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "btx", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Fujicoin", true, "FJC", true, 36, true, 10000000, true, 16, true, "FujiCoin Signed Message:\n", true, 0x8000004b, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "fc", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Denarius", true, "D", true, 30, true, 100000, true, 90, true, "Denarius Signed Message:\n", true, 0x80000074, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Bitsend", true, "BSD", true, 102, true, 1000000, true, 5, true, "Bitsend Signed Message:\n", true, 0x8000005b, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Bitcloud", true, "BTDX", true, 25, true, 1000000, true, 5, true, "Diamond Signed Message:\n", true, 0x800000da, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "BitcoinSV", true, "BSV", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x800000ec, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Komodo", true, "KMD", true, 60, true, 1000000, true, 85, true, "Komodo Signed Message:\n", true, 0x8000008d, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Ravencoin", true, "RVN", true, 60, true, 2000000, true, 122, true, "Ravencoin Signed Message:\n", true, 0x800000af, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Decred", true, "DCR", true,1855, true, 1000000, true,1818, true, "Decred Signed Message:\n", true, 0x8000002a, false, 0, true, 8, false, NO_CONTRACT, true, 50178342, true, false, true, false, true,"secp256k1-decred", false, "", false, "", true, true, false, 0, false, 0, false, "" ) -X(true, "Vertcoin", true, "VTC", true, 71, true, 40000000, true, 5, true, "Vertcoin Signed Message:\n", true, 0x8000001c, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "vtc", false, false, true, 77429938, false, 0, false, "" ) -X(true, "GameCredits", true, "GAME", true, 38, true, 5000000, true, 62, true, "GameCredits Signed Message:\n", true, 0x80000065, false, 0, true, 8, false, NO_CONTRACT, true, 27106558, true, true, true, false, true, SECP256K1_STRING, false, "", true, "game", false, false, true, 28471030, false, 0, false, "" ) -X(true, "Monacoin", true, "MONA", true, 50, true, 5000000, true, 55, true, "Monacoin Signed Message:\n", true, 0x80000016, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "mona", false, false, true, 77429938, false, 0, false, "" ) -X(true, "Electra", true, "ECA", true, 33, true, 10000, true, 40, true, "Electra very Signed Message:\n", true, 0x800000f9, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Nano", true, "NANO", true, NA, false, NA, false, NA, true, "Nano Signed Message:\n", true, 0x800000a5, false, 0, true, 30, false, NO_CONTRACT, false, 0, false, false, false, false, true, ED25519_BLAKE2B_NANO_STRING, false, "", false, "", false, false, false, 0, false, 0, true, "xrb_") -X(true, "Groestlcoin", true, "GRS", true, 36, true, 100000, true, 5, true, "GroestlCoin Signed Message:\n", true, 0x80000011, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true,"secp256k1-groestl", false, "", true, "grs", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Megacoin", true, "MEC", true, 50, true, 1000000, true, 5, true, "MegaCoin Signed Message:\n", true, 0x800000d9, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Terracoin", true, "TRC", true, 0, true, 100000, true, 5, true, "DarkCoin Signed Message:\n", true, 0x80000053, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Qtum", true, "QTUM", true, 58, true, 40000000, true, 50, true, "Qtum Signed Message:\n", true, 0x800008fd, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "qc", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "GRS Testnet", true, "tGRS", true, 111, true, 100000 , true, 196, true, "GroestlCoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true,"secp256k1-groestl", false, "", true, "tgrs", false, false, true, 71979618, true, 73342198, false, "" ) -X(true, "BCH Testnet", true, "tBCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000001, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "LTC Testnet", true, "tLTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, false, 0, false, 0, false, "" ) -X(true, ETHEREUM_TST, true, "tETH", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x80000001, true, 1, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000000, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "bc", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "Bitcoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true, SECP256K1_STRING, false, "", true, "tb", false, false, true, 71979618, true, 73342198, false, "" ) +X(true, "BitcoinCash", true, "BCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000091, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, true, "Namecoin Signed Message:\n", true, 0x80000007, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000002, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, false, 0, false, 0, false, "" ) +X(true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, true, "Dogecoin Signed Message:\n", true, 0x80000003, false, 0, true, 8, false, NO_CONTRACT, true, 49990397, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, true, "DarkCoin Signed Message:\n", true, 0x80000005, false, 0, true, 8, false, NO_CONTRACT, true, 50221772, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, ETHEREUM, true, "ETH", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x8000003c, true, 1, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, ETHEREUM_CLS, true, "ETC", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x8000003d, true, 62, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "BitcoinGold", true, "BTG", true, 38, true, 500000, true, 23, true, "Bitcoin Gold Signed Message:\n", true, 0x8000009c, true, 79, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, true, true, SECP256K1_STRING, false, "", true, "btg", false, false, true, 77429938, false, 0, false, "" ) +X(true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, true, "Zcash Signed Message:\n", true, 0x80000085, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Zcash Testnet",true, "TAZ", true, 7461, true, 10000000, true, 7354, true, "Zcash Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "DigiByte", true, "DGB", true, 30, true, 500000, true, 63, true, "DigiByte Signed Message:\n", true, 0x80000014, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, false, false, true, SECP256K1_STRING, false, "", true, "dgb", false, false, false, 0, false, 0, false, "" ) +X(true, "EOS", true, "EOS", false, NA, false, 0, false, NA, false, {0}, true, 0x800000c2, false, 0, false, 0, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Axe", true, "AXE", true, 55, true, 100000, true, 16, true, "DarkCoin Signed Message:\n", true, 0x80001092, false, 0, true, 8, false, NO_CONTRACT, true, 50221772, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Bitcore", true, "BTX", true, 3, true, 100000, true, 125, true, "BitCore Signed Message:\n", true, 0x800000a0, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "btx", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Fujicoin", true, "FJC", true, 36, true, 10000000, true, 16, true, "FujiCoin Signed Message:\n", true, 0x8000004b, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "fc", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Denarius", true, "D", true, 30, true, 100000, true, 90, true, "Denarius Signed Message:\n", true, 0x80000074, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Bitsend", true, "BSD", true, 102, true, 1000000, true, 5, true, "Bitsend Signed Message:\n", true, 0x8000005b, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Bitcloud", true, "BTDX", true, 25, true, 1000000, true, 5, true, "Diamond Signed Message:\n", true, 0x800000da, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "BitcoinSV", true, "BSV", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x800000ec, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Komodo", true, "KMD", true, 60, true, 1000000, true, 85, true, "Komodo Signed Message:\n", true, 0x8000008d, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Ravencoin", true, "RVN", true, 60, true, 2000000, true, 122, true, "Ravencoin Signed Message:\n", true, 0x800000af, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Decred", true, "DCR", true,1855, true, 1000000, true,1818, true, "Decred Signed Message:\n", true, 0x8000002a, false, 0, true, 8, false, NO_CONTRACT, true, 50178342, true, false, true, false, true,"secp256k1-decred", false, "", false, "", true, true, false, 0, false, 0, false, "" ) +X(true, "Vertcoin", true, "VTC", true, 71, true, 40000000, true, 5, true, "Vertcoin Signed Message:\n", true, 0x8000001c, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "vtc", false, false, true, 77429938, false, 0, false, "" ) +X(true, "GameCredits", true, "GAME", true, 38, true, 5000000, true, 62, true, "GameCredits Signed Message:\n", true, 0x80000065, false, 0, true, 8, false, NO_CONTRACT, true, 27106558, true, true, true, false, true, SECP256K1_STRING, false, "", true, "game", false, false, true, 28471030, false, 0, false, "" ) +X(true, "Monacoin", true, "MONA", true, 50, true, 5000000, true, 55, true, "Monacoin Signed Message:\n", true, 0x80000016, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "mona", false, false, true, 77429938, false, 0, false, "" ) +X(true, "Electra", true, "ECA", true, 33, true, 10000, true, 40, true, "Electra very Signed Message:\n", true, 0x800000f9, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Nano", true, "NANO", true, NA, false, NA, false, NA, true, "Nano Signed Message:\n", true, 0x800000a5, false, 0, true, 30, false, NO_CONTRACT, false, 0, false, false, false, false, true, ED25519_BLAKE2B_NANO_STRING, false, "", false, "", false, false, false, 0, false, 0, true, "xrb_") +X(true, "Groestlcoin", true, "GRS", true, 36, true, 100000, true, 5, true, "GroestlCoin Signed Message:\n", true, 0x80000011, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true,"secp256k1-groestl", false, "", true, "grs", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Megacoin", true, "MEC", true, 50, true, 1000000, true, 5, true, "MegaCoin Signed Message:\n", true, 0x800000d9, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Terracoin", true, "TRC", true, 0, true, 100000, true, 5, true, "DarkCoin Signed Message:\n", true, 0x80000053, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Qtum", true, "QTUM", true, 58, true, 40000000, true, 50, true, "Qtum Signed Message:\n", true, 0x800008fd, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "qc", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "GRS Testnet", true, "tGRS", true, 111, true, 100000 , true, 196, true, "GroestlCoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true,"secp256k1-groestl", false, "", true, "tgrs", false, false, true, 71979618, true, 73342198, false, "" ) +X(true, "BCH Testnet", true, "tBCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000001, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "LTC Testnet", true, "tLTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, false, 0, false, 0, false, "" ) +X(true, ETHEREUM_TST, true, "tETH", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x80000001, true, 1, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Cosmos", true, "ATOM", false, NA, false, NA, false, NA, false, {0}, true, 0x80000076, false, 0, true, 6, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "cosmos", false, false, false, 0, false, 0, false, "" ) #undef X #undef NO_CONTRACT diff --git a/include/keepkey/firmware/cosmos.h b/include/keepkey/firmware/cosmos.h new file mode 100644 index 000000000..826cf6ed5 --- /dev/null +++ b/include/keepkey/firmware/cosmos.h @@ -0,0 +1,37 @@ +#ifndef __COSMOS_H__ +#define __COSMOS_H__ + +#include +#include +#include +#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 \ No newline at end of file diff --git a/include/keepkey/firmware/fsm.h b/include/keepkey/firmware/fsm.h index 4311db0d1..c331afec2 100644 --- a/include/keepkey/firmware/fsm.h +++ b/include/keepkey/firmware/fsm.h @@ -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); diff --git a/include/keepkey/transport/interface.h b/include/keepkey/transport/interface.h index f30cf1266..a0966729a 100644 --- a/include/keepkey/transport/interface.h +++ b/include/keepkey/transport/interface.h @@ -27,6 +27,7 @@ #undef delete #include "messages-eos.pb.h" +#include "messages-cosmos.pb.h" #include "types.pb.h" #include "trezor_transport.h" diff --git a/include/keepkey/transport/messages-cosmos.options b/include/keepkey/transport/messages-cosmos.options new file mode 100644 index 000000000..08b2916a8 --- /dev/null +++ b/include/keepkey/transport/messages-cosmos.options @@ -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 \ No newline at end of file diff --git a/lib/firmware/CMakeLists.txt b/lib/firmware/CMakeLists.txt index 56e0178a3..55dd5085a 100644 --- a/lib/firmware/CMakeLists.txt +++ b/lib/firmware/CMakeLists.txt @@ -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 diff --git a/lib/firmware/coins.c b/lib/firmware/coins.c index 5dca70d37..957039357 100644 --- a/lib/firmware/coins.c +++ b/lib/firmware/coins.c @@ -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; } + 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) @@ -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; } @@ -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 { diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c new file mode 100644 index 000000000..8d44ecc3e --- /dev/null +++ b/lib/firmware/cosmos.c @@ -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 +#include + +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); + + // + 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); + + // + 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; +} diff --git a/lib/firmware/fsm.c b/lib/firmware/fsm.c index 6d2c48ea0..d3888246f 100644 --- a/lib/firmware/fsm.c +++ b/lib/firmware/fsm.c @@ -35,6 +35,7 @@ #include "keepkey/firmware/app_confirm.h" #include "keepkey/firmware/app_layout.h" #include "keepkey/firmware/coins.h" +#include "keepkey/firmware/cosmos.h" #include "keepkey/firmware/crypto.h" #include "keepkey/firmware/eos.h" #include "keepkey/firmware/eos-contracts.h" @@ -67,6 +68,7 @@ #include "trezor/crypto/secp256k1.h" #include "messages.pb.h" +#include "messages-cosmos.pb.h" #include "messages-eos.pb.h" #include "messages-nano.pb.h" @@ -76,35 +78,40 @@ static uint8_t msg_resp[MAX_FRAME_SIZE] __attribute__((aligned(4))); -#define CHECK_INITIALIZED \ - if (!storage_isInitialized()) { \ +#define CHECK_INITIALIZED \ + if (!storage_isInitialized()) \ + { \ fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); \ - return; \ + return; \ } -#define CHECK_NOT_INITIALIZED \ - if (storage_isInitialized()) { \ +#define CHECK_NOT_INITIALIZED \ + if (storage_isInitialized()) \ + { \ fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); \ - return; \ + return; \ } -#define CHECK_PIN \ - if (!pin_protect_cached()) { \ - layoutHome(); \ - return; \ +#define CHECK_PIN \ + if (!pin_protect_cached()) \ + { \ + layoutHome(); \ + return; \ } -#define CHECK_PIN_UNCACHED \ - if (!pin_protect_uncached()) { \ - layoutHome(); \ - return; \ +#define CHECK_PIN_UNCACHED \ + if (!pin_protect_uncached()) \ + { \ + layoutHome(); \ + return; \ } -#define CHECK_PARAM_RET(cond, errormsg, retval) \ - if (!(cond)) { \ +#define CHECK_PARAM_RET(cond, errormsg, retval) \ + if (!(cond)) \ + { \ fsm_sendFailure(FailureType_Failure_Other, (errormsg)); \ - layoutHome(); \ - return retval; \ + layoutHome(); \ + return retval; \ } #define CHECK_PARAM(cond, errormsg) \ @@ -116,18 +123,18 @@ static const MessagesMap_t MessagesMap[] = { #undef MSG_IN #define MSG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); + _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); #undef MSG_OUT #define MSG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) #undef RAW_IN #define RAW_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); + _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); #undef DEBUG_IN #define DEBUG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); + _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); #undef DEBUG_OUT #define DEBUG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) @@ -139,12 +146,15 @@ extern bool reset_msg_stack; static const CoinType *fsm_getCoin(bool has_name, const char *name) { const CoinType *coin; - if (has_name) { + if (has_name) + { coin = coinByName(name); - } else { + } + else + { coin = coinByName("Bitcoin"); } - if(!coin) + if (!coin) { fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); layoutHome(); @@ -157,17 +167,19 @@ static const CoinType *fsm_getCoin(bool has_name, const char *name) static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, size_t address_n_count, uint32_t *fingerprint) { static HDNode CONFIDENTIAL node; - if (fingerprint) { + if (fingerprint) + { *fingerprint = 0; } - if (!get_curve_by_name(curve)) { + if (!get_curve_by_name(curve)) + { fsm_sendFailure(FailureType_Failure_SyntaxError, "Unknown ecdsa curve"); layoutHome(); return 0; } - if(!storage_getRootNode(curve, true, &node)) + if (!storage_getRootNode(curve, true, &node)) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled"); @@ -175,12 +187,12 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, return 0; } - if(!address_n || address_n_count == 0) + if (!address_n || address_n_count == 0) { return &node; } - if(hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); layoutHome(); @@ -191,7 +203,8 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, } #if DEBUG_LINK -static void sendFailureWrapper(FailureType code, const char *text) { +static void sendFailureWrapper(FailureType code, const char *text) +{ fsm_sendFailure(code, text); } #endif @@ -217,7 +230,7 @@ void fsm_init(void) void fsm_sendSuccess(const char *text) { - if(reset_msg_stack) + if (reset_msg_stack) { fsm_msgInitialize((Initialize *)0); reset_msg_stack = false; @@ -226,7 +239,7 @@ void fsm_sendSuccess(const char *text) RESP_INIT(Success); - if(text) + if (text) { resp->has_message = true; strlcpy(resp->message, text, sizeof(resp->message)); @@ -241,7 +254,7 @@ void fsm_sendFailureDebug(FailureType code, const char *text, const char *source void fsm_sendFailure(FailureType code, const char *text) #endif { - if(reset_msg_stack) + if (reset_msg_stack) { fsm_msgInitialize((Initialize *)0); reset_msg_stack = false; @@ -255,7 +268,8 @@ void fsm_sendFailure(FailureType code, const char *text) #if DEBUG_LINK resp->has_message = true; strlcpy(resp->message, source, sizeof(resp->message)); - if (text) { + if (text) + { strlcat(resp->message, text, sizeof(resp->message)); } #else @@ -268,7 +282,6 @@ void fsm_sendFailure(FailureType code, const char *text) msg_write(MessageType_MessageType_Failure, resp); } - void fsm_msgClearSession(ClearSession *msg) { (void)msg; @@ -283,3 +296,4 @@ void fsm_msgClearSession(ClearSession *msg) #include "fsm_msg_crypto.h" #include "fsm_msg_debug.h" #include "fsm_msg_eos.h" +#include "fsm_msg_cosmos.h" diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h new file mode 100644 index 000000000..ec4601a80 --- /dev/null +++ b/lib/firmware/fsm_msg_cosmos.h @@ -0,0 +1,194 @@ + +void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) +{ + RESP_INIT(CosmosAddress); + + CHECK_INITIALIZED + + CHECK_PIN + + const char *coin_name = "Cosmos"; + const CoinType *coin = fsm_getCoin(true, coin_name); + if (!coin) { return; } + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) { return; } + + hdnode_fill_public_key(node); + + if (!cosmos_getAddress(node, resp->address)) { + fsm_sendFailure(FailureType_Failure_FirmwareError, _("Can't encode address")); + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count, /*whole_account=*/false, + /*show_addridx=*/false) && + !bip32_path_to_string(node_str, sizeof(node_str), + msg->address_n, msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + fsm_sendFailure(FailureType_Failure_FirmwareError, _("Can't create Bip32 Path String")); + layoutHome(); + } + bool mismatch = cosmos_path_mismatched(coin, msg->address_n, msg->address_n_count); + + if (mismatch) { + if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", "Wrong address path for selected coin. Continue at your own risk!")) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + if(!confirm_address(node_str, resp->address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); + layoutHome(); + return; + } + } + + resp->has_address = true; + + layoutHome(); + msg_write(MessageType_MessageType_CosmosAddress, resp); +} + +void fsm_msgCosmosSignTx(const CosmosSignTx *msg) +{ + CHECK_INITIALIZED + CHECK_PIN + + if (!msg->has_account_number || + !msg->has_chain_id || + !msg->has_fee_amount || + !msg->has_gas || + !msg->has_sequence) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Missing Fields On Message"); + layoutHome(); + return; + } + + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) { return; } + + hdnode_fill_public_key(node); + + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %" PRIu32 " uATOM\nGas: %" PRIu32 "", msg->fee_amount, msg->gas)) + { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (msg->has_memo && !confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Aux Details"), "Memo: \"%s\"\nChain ID: %s", msg->memo, msg->chain_id)) + { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + RESP_INIT(CosmosMsgRequest); + + if (!cosmos_signTxInit(node, + msg->address_n, + msg->address_n_count, + msg->account_number, + msg->chain_id, + strlen(msg->chain_id), + msg->fee_amount, + msg->gas, + msg->has_memo ? msg->memo : "", + msg->has_memo ? strlen(msg->memo) : 0, + msg->sequence, + msg->msg_count)) + { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to initialize transaction signing")); + layoutHome(); + return; + } + + + + layoutHome(); + msg_write(MessageType_MessageType_CosmosMsgRequest, resp); +} + +void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { + // Confirm transaction basics + CHECK_PARAM(cosmos_signingIsInited(), "Must call CosmosSignTx to initiate signing"); + if (!msg->has_send || !msg->send.has_to_address || !msg->send.has_amount) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Invalid Cosmos Message Type")); + layoutHome(); + return; + } + + const char *coin_name = "Cosmos"; + const CoinType *coin = fsm_getCoin(true, coin_name); + if (!coin) { return; } + + uint32_t address_n[8]; + if(!cosmos_getAddressN(address_n, 8)) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to get derivation path"); + layoutHome(); + return; + } + size_t address_n_count = cosmos_getAddressNCount(); + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, address_n, + address_n_count, /*whole_account=*/false, + /*show_addridx=*/false) && + !bip32_path_to_string(node_str, sizeof(node_str), + address_n, address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + } + + char canonicFormatAmount[32]; + bn_format_uint64(msg->send.amount, NULL, NULL, 6, 0, false, canonicFormatAmount, sizeof(canonicFormatAmount)); + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Send Details"), "From: %s\nTo: %s\nAmount: %s ATOM", node_str, msg->send.to_address, canonicFormatAmount)) + { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if(!cosmos_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address)) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to include send message in transaction"); + layoutHome(); + return; + } + + if (!cosmos_signingIsFinished()) { + RESP_INIT(CosmosMsgRequest); + msg_write(MessageType_MessageType_CosmosMsgRequest, resp); + return; + } + + RESP_INIT(CosmosSignedTx); + + if(!cosmos_signTxFinalize(resp->public_key.bytes, resp->signature.bytes)) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to finalize signature"); + layoutHome(); + return; + } + + resp->public_key.size = 33; + resp->has_public_key = true; + resp->signature.size = 64; + resp->has_signature = true; + cosmos_signAbort(); + layoutHome(); + msg_write(MessageType_MessageType_CosmosSignedTx, resp); +} diff --git a/lib/firmware/messagemap.def b/lib/firmware/messagemap.def index 55cafec88..a2f4c278c 100644 --- a/lib/firmware/messagemap.def +++ b/lib/firmware/messagemap.def @@ -41,6 +41,10 @@ MSG_IN(MessageType_MessageType_NanoGetAddress, NanoGetAddress, fsm_msgNanoGetAddress) MSG_IN(MessageType_MessageType_NanoSignTx, NanoSignTx, fsm_msgNanoSignTx) + MSG_IN(MessageType_MessageType_CosmosGetAddress, CosmosGetAddress, fsm_msgCosmosGetAddress) + MSG_IN(MessageType_MessageType_CosmosSignTx, CosmosSignTx, fsm_msgCosmosSignTx) + MSG_IN(MessageType_MessageType_CosmosMsgAck, CosmosMsgAck, fsm_msgCosmosMsgAck) + MSG_IN(MessageType_MessageType_EosGetPublicKey, EosGetPublicKey, fsm_msgEosGetPublicKey) MSG_IN(MessageType_MessageType_EosSignTx, EosSignTx, fsm_msgEosSignTx) MSG_IN(MessageType_MessageType_EosTxActionAck, EosTxActionAck, fsm_msgEosTxActionAck) @@ -73,6 +77,10 @@ MSG_OUT(MessageType_MessageType_NanoAddress, NanoAddress, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_NanoSignedTx, NanoSignedTx, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_CosmosAddress, CosmosAddress, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_CosmosMsgRequest, CosmosMsgRequest, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_CosmosSignedTx, CosmosSignedTx, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_EosPublicKey, EosPublicKey, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_EosTxActionRequest, EosTxActionRequest, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_EosSignedTx, EosSignedTx, NO_PROCESS_FUNC) diff --git a/lib/transport/CMakeLists.txt b/lib/transport/CMakeLists.txt index 2b991ed81..e929785ee 100644 --- a/lib/transport/CMakeLists.txt +++ b/lib/transport/CMakeLists.txt @@ -7,6 +7,7 @@ set(protoc_pb_sources ${DEVICE_PROTOCOL}/exchange.proto ${DEVICE_PROTOCOL}/messages-eos.proto ${DEVICE_PROTOCOL}/messages-nano.proto + ${DEVICE_PROTOCOL}/messages-cosmos.proto ${DEVICE_PROTOCOL}/messages.proto) set(protoc_pb_options @@ -14,6 +15,7 @@ set(protoc_pb_options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/exchange.options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-eos.options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-nano.options + ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-cosmos.options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages.options) set(protoc_c_sources @@ -21,6 +23,7 @@ set(protoc_c_sources ${CMAKE_BINARY_DIR}/lib/transport/exchange.pb.c ${CMAKE_BINARY_DIR}/lib/transport/messages-eos.pb.c ${CMAKE_BINARY_DIR}/lib/transport/messages-nano.pb.c + ${CMAKE_BINARY_DIR}/lib/transport/messages-cosmos.pb.c ${CMAKE_BINARY_DIR}/lib/transport/messages.pb.c) set(protoc_c_headers @@ -28,6 +31,7 @@ set(protoc_c_headers ${CMAKE_BINARY_DIR}/include/exchange.pb.h ${CMAKE_BINARY_DIR}/include/messages-eos.pb.h ${CMAKE_BINARY_DIR}/include/messages-nano.pb.h + ${CMAKE_BINARY_DIR}/include/messages-cosmos.pb.h ${CMAKE_BINARY_DIR}/include/messages.pb.h) set(protoc_pb_sources_moved @@ -35,6 +39,7 @@ set(protoc_pb_sources_moved ${CMAKE_BINARY_DIR}/lib/transport/exchange.proto ${CMAKE_BINARY_DIR}/lib/transport/messages-eos.proto ${CMAKE_BINARY_DIR}/lib/transport/messages-nano.proto + ${CMAKE_BINARY_DIR}/lib/transport/messages-cosmos.proto ${CMAKE_BINARY_DIR}/lib/transport/messages.proto) add_custom_command( @@ -72,6 +77,10 @@ add_custom_command( ${PROTOC_BINARY} -I. -I/usr/include --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb "--nanopb_out=-f messages-nano.options:." messages-nano.proto + COMMAND + ${PROTOC_BINARY} -I. -I/usr/include + --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb + "--nanopb_out=-f messages-cosmos.options:." messages-cosmos.proto COMMAND ${PROTOC_BINARY} -I. -I/usr/include --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb diff --git a/unittests/firmware/CMakeLists.txt b/unittests/firmware/CMakeLists.txt index 5cd46aafc..7d055b883 100644 --- a/unittests/firmware/CMakeLists.txt +++ b/unittests/firmware/CMakeLists.txt @@ -1,5 +1,6 @@ set(sources coins.cpp + cosmos.cpp eos.cpp ethereum.cpp nano.cpp diff --git a/unittests/firmware/coins.cpp b/unittests/firmware/coins.cpp index 508cb5b64..e1bbbe4cf 100644 --- a/unittests/firmware/coins.cpp +++ b/unittests/firmware/coins.cpp @@ -11,8 +11,7 @@ extern "C" { static const int MaxLength = 256; -template -static std::string arrayToStr(const uint32_t (&address_n)[size]) { +template static std::string arrayToStr(const uint32_t (&address_n)[size]) { std::string str; std::stringstream OS(str); OS << "{"; @@ -162,6 +161,11 @@ TEST(Coins, BIP32AccountName) { { 0x80000000|44, 0x80000000|194, 0x80000000|42, 0, 0 }, 5, true, "EOS Account #42" }, + { + "Cosmos", + { 0x80000000|44, 0x80000000|118, 0x80000000|9, 0, 0 }, + 5, true, "Cosmos Account #9" + } }; for (const auto &vec : vector) { diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp new file mode 100644 index 000000000..d1f5c1b44 --- /dev/null +++ b/unittests/firmware/cosmos.cpp @@ -0,0 +1,46 @@ +extern "C" +{ +#include "keepkey/firmware/coins.h" +#include "keepkey/firmware/cosmos.h" +} + +#include "gtest/gtest.h" +#include + +TEST(Cosmos, CosmosGetAddress) +{ + HDNode node = { + 0, + 0, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0x03, 0xb7, 0x32, 0x9f, 0x67, 0x8e, 0x0a, 0xc1, 0x21, 0x4b, 0x77, 0x23, 0x57, 0x54, 0x66, 0x21, 0x9c, 0x77, 0xfe, 0xdb, 0xdd, 0x95, 0x5c, 0x33, 0x29, 0x1a, 0x74, 0xf1, 0x8b, 0xf5, 0xc8, 0xa4, 0xe2}, + &secp256k1_info}; + char addr[46]; + ASSERT_TRUE(cosmos_getAddress(&node, addr)); + EXPECT_EQ(std::string("cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q"), addr); +} + +TEST(Cosmos, CosmosSignTx) +{ + HDNode node = { + 0, + 0, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0x04, 0xde, 0xc0, 0xcc, 0x01, 0x3c, 0xd8, 0xab, 0x70, 0x87, 0xca, 0x14, 0x96, 0x0b, 0x76, 0x8c, 0x3d, 0x83, 0x45, 0x24, 0x48, 0xaa, 0x00, 0x64, 0xda, 0xe6, 0xfb, 0x04, 0xb5, 0xd9, 0x34, 0x76 }, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + &secp256k1_info + }; + hdnode_fill_public_key(&node); + const uint8_t *privkey = (uint8_t *)"\x04\xde\xc0\xcc\x01\x3c\xd8\xab\x70\x87\xca\x14\x96\x0b\x76\x8c\x3d\x83\x45\x24\x48\xaa\x00\x64\xda\xe6\xfb\x04\xb5\xd9\x34\x76"; + const uint8_t *expected = (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39"; + const uint32_t address_n[8] = {0x80000000|44, 0x80000000|118, 0x80000000, 0, 0}; + ASSERT_TRUE(cosmos_signTxInit(&node, address_n, 5, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 0, 1)); + ASSERT_TRUE(cosmos_signTxUpdateMsgSend(100000, "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); + uint8_t public_key[33]; + uint8_t signature[64]; + ASSERT_TRUE(cosmos_signTxFinalize(public_key, signature)); + EXPECT_TRUE(memcmp(expected, signature, 64) == 0); +}