Selaa lähdekoodia

update naming, adding coin prototyping, adding WIP BIP32 code

Struan Clark 2 vuotta sitten
vanhempi
commit
b47b6ab854
9 muutettua tiedostoa jossa 1236 lisäystä ja 6 poistoa
  1. 3 3
      application.fam
  2. 194 0
      coins/coin_info.c
  3. 13 0
      coins/coin_info.h
  4. 84 0
      coins/coins.c
  5. 76 0
      coins/coins.h
  6. 727 0
      coins/crypto.c
  7. 87 0
      coins/crypto.h
  8. 45 0
      views/flipbip39_scene_1.c
  9. 7 3
      views/flipbip39_startscreen.c

+ 3 - 3
application.fam

@@ -1,9 +1,9 @@
 App(
-    appid="flipbip39",
-    name="Flip-BIP39",
+    appid="FlipBIP",
+    name="BIP39 Tool",
     apptype=FlipperAppType.EXTERNAL,
     entry_point="flipbip39_app",
-    cdefines=["APP_FLIPBIP39"],
+    cdefines=["APP_FLIPBIP"],
     requires=[
         "gui",
     ],

+ 194 - 0
coins/coin_info.c

@@ -0,0 +1,194 @@
+// This file is automatically generated from coin_info.c.mako
+
+// DO NOT EDIT
+
+
+
+#include "coins.h"
+
+
+
+#include "../crypto/curves.h"
+
+#include "../crypto/secp256k1.h"
+
+
+
+const CoinInfo coins[COINS_COUNT] = {
+
+{
+
+	.coin_name = "Bitcoin",
+
+	.coin_shortcut = "BTC",
+
+	.maxfee_kb = 2000000,
+
+	.signed_message_header = "\x18" "Bitcoin Signed Message:\n",
+
+	.has_segwit = true,
+
+	.has_taproot = true,
+
+	.has_fork_id = false,
+
+	.force_bip143 = false,
+
+	.decred = false,
+
+	.decimals = 8,
+
+	.address_type = 0,
+
+	.address_type_p2sh = 5,
+
+	.xpub_magic = 0x0488b21e,
+
+	.xpub_magic_segwit_p2sh = 0x049d7cb2,
+
+	.xpub_magic_segwit_native = 0x04b24746,
+
+	.xpub_magic_multisig_segwit_p2sh = 0x0295b43f,
+
+	.xpub_magic_multisig_segwit_native = 0x02aa7ed3,
+
+	.fork_id = 0,
+
+	.bech32_prefix = "bc",
+
+	.cashaddr_prefix = NULL,
+
+	.coin_type = (0 | 0x80000000),
+
+	.negative_fee = false,
+
+	.curve_name = SECP256K1_NAME,
+
+	.curve = &secp256k1_info,
+
+	.extra_data = false,
+
+	.timestamp = false,
+
+	.overwintered = false,
+
+},
+
+{
+
+	.coin_name = "Regtest",
+
+	.coin_shortcut = "REGTEST",
+
+	.maxfee_kb = 10000000,
+
+	.signed_message_header = "\x18" "Bitcoin Signed Message:\n",
+
+	.has_segwit = true,
+
+	.has_taproot = true,
+
+	.has_fork_id = false,
+
+	.force_bip143 = false,
+
+	.decred = false,
+
+	.decimals = 8,
+
+	.address_type = 111,
+
+	.address_type_p2sh = 196,
+
+	.xpub_magic = 0x043587cf,
+
+	.xpub_magic_segwit_p2sh = 0x044a5262,
+
+	.xpub_magic_segwit_native = 0x045f1cf6,
+
+	.xpub_magic_multisig_segwit_p2sh = 0x024289ef,
+
+	.xpub_magic_multisig_segwit_native = 0x02575483,
+
+	.fork_id = 0,
+
+	.bech32_prefix = "bcrt",
+
+	.cashaddr_prefix = NULL,
+
+	.coin_type = (1 | 0x80000000),
+
+	.negative_fee = false,
+
+	.curve_name = SECP256K1_NAME,
+
+	.curve = &secp256k1_info,
+
+	.extra_data = false,
+
+	.timestamp = false,
+
+	.overwintered = false,
+
+},
+
+{
+
+	.coin_name = "Testnet",
+
+	.coin_shortcut = "TEST",
+
+	.maxfee_kb = 10000000,
+
+	.signed_message_header = "\x18" "Bitcoin Signed Message:\n",
+
+	.has_segwit = true,
+
+	.has_taproot = true,
+
+	.has_fork_id = false,
+
+	.force_bip143 = false,
+
+	.decred = false,
+
+	.decimals = 8,
+
+	.address_type = 111,
+
+	.address_type_p2sh = 196,
+
+	.xpub_magic = 0x043587cf,
+
+	.xpub_magic_segwit_p2sh = 0x044a5262,
+
+	.xpub_magic_segwit_native = 0x045f1cf6,
+
+	.xpub_magic_multisig_segwit_p2sh = 0x024289ef,
+
+	.xpub_magic_multisig_segwit_native = 0x02575483,
+
+	.fork_id = 0,
+
+	.bech32_prefix = "tb",
+
+	.cashaddr_prefix = NULL,
+
+	.coin_type = (1 | 0x80000000),
+
+	.negative_fee = false,
+
+	.curve_name = SECP256K1_NAME,
+
+	.curve = &secp256k1_info,
+
+	.extra_data = false,
+
+	.timestamp = false,
+
+	.overwintered = false,
+
+},
+
+};
+

+ 13 - 0
coins/coin_info.h

@@ -0,0 +1,13 @@
+// This file is automatically generated from coin_info.h.mako

+// DO NOT EDIT

+

+#ifndef __COIN_INFO_H__

+#define __COIN_INFO_H__

+

+#include "coins.h"

+

+#define COINS_COUNT (3)

+

+extern const CoinInfo coins[COINS_COUNT];

+

+#endif


+ 84 - 0
coins/coins.c

@@ -0,0 +1,84 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "coins.h"
+#include <string.h>
+#include "../crypto/address.h"
+#include "../crypto/base58.h"
+#include "../crypto/ecdsa.h"
+
+const CoinInfo *coinByName(const char *name) {
+  if (!name) return 0;
+  for (int i = 0; i < COINS_COUNT; i++) {
+    if (strcmp(name, coins[i].coin_name) == 0) {
+      return &(coins[i]);
+    }
+  }
+  return 0;
+}
+
+const CoinInfo *coinByAddressType(uint32_t address_type) {
+  for (int i = 0; i < COINS_COUNT; i++) {
+    if (address_type == coins[i].address_type) {
+      return &(coins[i]);
+    }
+  }
+  return 0;
+}
+
+const CoinInfo *coinBySlip44(uint32_t coin_type) {
+  if (coin_type == SLIP44_TESTNET) {
+    // The slip44 coin type is the same for all testnets, so we return the
+    // Bitcoin Testnet.
+    return coinByName("Testnet");
+  }
+
+  for (int i = 0; i < COINS_COUNT; i++) {
+    if (coin_type == coins[i].coin_type) {
+      return &(coins[i]);
+    }
+  }
+  return 0;
+}
+
+bool coinExtractAddressType(const CoinInfo *coin, const char *addr,
+                            uint32_t *address_type) {
+  if (!addr) return false;
+  uint8_t addr_raw[MAX_ADDR_RAW_SIZE] = {0};
+  int len = base58_decode_check(addr, coin->curve->hasher_base58, addr_raw,
+                                MAX_ADDR_RAW_SIZE);
+  if (len >= 21) {
+    return coinExtractAddressTypeRaw(coin, addr_raw, address_type);
+  }
+  return false;
+}
+
+bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw,
+                               uint32_t *address_type) {
+  if (address_check_prefix(addr_raw, coin->address_type)) {
+    *address_type = coin->address_type;
+    return true;
+  }
+  if (address_check_prefix(addr_raw, coin->address_type_p2sh)) {
+    *address_type = coin->address_type_p2sh;
+    return true;
+  }
+  *address_type = 0;
+  return false;
+}

+ 76 - 0
coins/coins.h

@@ -0,0 +1,76 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __COINS_H__
+#define __COINS_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "../crypto/bip32.h"
+#include "../crypto/hasher.h"
+
+typedef struct _CoinInfo {
+  const char *coin_name;
+  const char *coin_shortcut;
+  uint64_t maxfee_kb;
+  const char *signed_message_header;
+  uint32_t decimals;
+  bool has_segwit;
+  bool has_taproot;
+  bool has_fork_id;
+  bool force_bip143;
+  bool decred;
+  // address types > 0xFF represent a two-byte prefix in big-endian order
+  uint32_t address_type;
+  uint32_t address_type_p2sh;
+  uint32_t xpub_magic;
+  uint32_t xpub_magic_segwit_p2sh;
+  uint32_t xpub_magic_segwit_native;
+  uint32_t xpub_magic_multisig_segwit_p2sh;
+  uint32_t xpub_magic_multisig_segwit_native;
+  uint32_t fork_id;
+  const char *bech32_prefix;
+  const char *cashaddr_prefix;
+  uint32_t coin_type;
+  bool negative_fee;
+  const char *curve_name;
+  const curve_info *curve;
+  bool extra_data;
+  bool timestamp;
+  bool overwintered;
+} CoinInfo;
+
+#include "coin_info.h"
+
+// SLIP-44 hardened coin type for Bitcoin
+#define SLIP44_BITCOIN 0x80000000
+
+// SLIP-44 hardened coin type for all Testnet coins
+#define SLIP44_TESTNET 0x80000001
+
+const CoinInfo *coinByName(const char *name);
+const CoinInfo *coinByAddressType(uint32_t address_type);
+const CoinInfo *coinBySlip44(uint32_t coin_type);
+bool coinExtractAddressType(const CoinInfo *coin, const char *addr,
+                            uint32_t *address_type);
+bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw,
+                               uint32_t *address_type);
+
+#endif

+ 727 - 0
coins/crypto.c

@@ -0,0 +1,727 @@
+// /*
+//  * This file is part of the Trezor project, https://trezor.io/
+//  *
+//  * Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
+//  *
+//  * This library is free software: you can redistribute it and/or modify
+//  * it under the terms of the GNU Lesser General Public License as published by
+//  * the Free Software Foundation, either version 3 of the License, or
+//  * (at your option) any later version.
+//  *
+//  * This library is distributed in the hope that it will be useful,
+//  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  * GNU Lesser General Public License for more details.
+//  *
+//  * You should have received a copy of the GNU Lesser General Public License
+//  * along with this library.  If not, see <http://www.gnu.org/licenses/>.
+//  */
+
+// #include "crypto.h"
+// #include <string.h>
+// #include "../crypto/address.h"
+// #include "../crypto/aes/aes.h"
+// #include "../crypto/base58.h"
+// #include "../crypto/bip32.h"
+// #include "coins.h"
+// #include "../crypto/curves.h"
+// #include "../crypto/hmac.h"
+// //#include "layout.h"
+// #include "../crypto/pbkdf2.h"
+// #include "../crypto/secp256k1.h"
+// #include "../crypto/segwit_addr.h"
+// #include "../crypto/sha2.h"
+
+// #if !BITCOIN_ONLY
+// #include "cash_addr.h"
+// #endif
+
+// uint32_t ser_length(uint32_t len, uint8_t *out) {
+//   if (len < 253) {
+//     out[0] = len & 0xFF;
+//     return 1;
+//   }
+//   if (len < 0x10000) {
+//     out[0] = 253;
+//     out[1] = len & 0xFF;
+//     out[2] = (len >> 8) & 0xFF;
+//     return 3;
+//   }
+//   out[0] = 254;
+//   out[1] = len & 0xFF;
+//   out[2] = (len >> 8) & 0xFF;
+//   out[3] = (len >> 16) & 0xFF;
+//   out[4] = (len >> 24) & 0xFF;
+//   return 5;
+// }
+
+// uint32_t ser_length_hash(Hasher *hasher, uint32_t len) {
+//   if (len < 253) {
+//     hasher_Update(hasher, (const uint8_t *)&len, 1);
+//     return 1;
+//   }
+//   if (len < 0x10000) {
+//     uint8_t d = 253;
+//     hasher_Update(hasher, &d, 1);
+//     hasher_Update(hasher, (const uint8_t *)&len, 2);
+//     return 3;
+//   }
+//   uint8_t d = 254;
+//   hasher_Update(hasher, &d, 1);
+//   hasher_Update(hasher, (const uint8_t *)&len, 4);
+//   return 5;
+// }
+
+// uint32_t deser_length(const uint8_t *in, uint32_t *out) {
+//   if (in[0] < 253) {
+//     *out = in[0];
+//     return 1;
+//   }
+//   if (in[0] == 253) {
+//     *out = in[1] + (in[2] << 8);
+//     return 1 + 2;
+//   }
+//   if (in[0] == 254) {
+//     *out = in[1] + (in[2] << 8) + (in[3] << 16) + ((uint32_t)in[4] << 24);
+//     return 1 + 4;
+//   }
+//   *out = 0;  // ignore 64 bit
+//   return 1 + 8;
+// }
+
+// int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
+//                    uint8_t *signature) {
+//   signature[0] = 0;  // prefix: pad with zero, so all signatures are 65 bytes
+//   return hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1,
+//                      NULL, NULL);
+// }
+
+// int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
+//                    uint8_t *signature) {
+//   signature[0] = 0;  // prefix: pad with zero, so all signatures are 65 bytes
+//   const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME);
+//   if (ed25519_curve_info && node->curve == ed25519_curve_info) {
+//     // GPG supports variable size digest for Ed25519 signatures
+//     return hdnode_sign(node, message, message_len, 0, signature + 1, NULL,
+//                        NULL);
+//   } else {
+//     // Ensure 256-bit digest before proceeding
+//     if (message_len != 32) {
+//       return 1;
+//     }
+//     return hdnode_sign_digest(node, message, signature + 1, NULL, NULL);
+//   }
+// }
+
+// int signifyMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
+//                        uint8_t *signature) {
+//   signature[0] = 0;  // prefix: pad with zero, so all signatures are 65 bytes
+//   const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME);
+//   // only ed25519 is supported
+//   if (!ed25519_curve_info || node->curve != ed25519_curve_info) {
+//     return 1;
+//   }
+//   return hdnode_sign(node, message, message_len, 0, signature + 1, NULL, NULL);
+// }
+
+// static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message,
+//                               size_t message_len,
+//                               uint8_t hash[HASHER_DIGEST_LENGTH]) {
+//   Hasher hasher = {0};
+//   hasher_Init(&hasher, coin->curve->hasher_sign);
+//   hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header,
+//                 strlen(coin->signed_message_header));
+//   uint8_t varint[5] = {0};
+//   uint32_t l = ser_length(message_len, varint);
+//   hasher_Update(&hasher, varint, l);
+//   hasher_Update(&hasher, message, message_len);
+//   hasher_Final(&hasher, hash);
+// }
+
+// int cryptoMessageSign(const CoinInfo *coin, HDNode *node,
+//                       InputScriptType script_type, bool no_script_type,
+//                       const uint8_t *message, size_t message_len,
+//                       uint8_t *signature) {
+//   uint8_t script_type_info = 0;
+//   switch (script_type) {
+//     case InputScriptType_SPENDADDRESS:
+//       // p2pkh
+//       script_type_info = 0;
+//       break;
+//     case InputScriptType_SPENDP2SHWITNESS:
+//       // segwit-in-p2sh
+//       script_type_info = 4;
+//       break;
+//     case InputScriptType_SPENDWITNESS:
+//       // segwit
+//       script_type_info = 8;
+//       break;
+//     default:
+//       // unsupported script type
+//       return 1;
+//   }
+
+//   if (no_script_type) {
+//     script_type_info = 0;
+//   }
+
+//   uint8_t hash[HASHER_DIGEST_LENGTH] = {0};
+//   cryptoMessageHash(coin, message, message_len, hash);
+
+//   uint8_t pby = 0;
+//   int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL);
+//   if (result == 0) {
+//     signature[0] = 31 + pby + script_type_info;
+//   }
+//   return result;
+// }
+
+// // Determines the script type from a non-multisig address.
+// static InputScriptType address_to_script_type(const CoinInfo *coin,
+//                                               const char *address) {
+//   uint8_t addr_raw[MAX_ADDR_RAW_SIZE] = {0};
+//   size_t addr_raw_len = 0;
+
+//   // Native SegWit
+//   if (coin->bech32_prefix) {
+//     int witver = 0;
+//     if (segwit_addr_decode(&witver, addr_raw, &addr_raw_len,
+//                            coin->bech32_prefix, address)) {
+//       switch (witver) {
+//         case 0:
+//           return InputScriptType_SPENDWITNESS;
+//         case 1:
+//           return InputScriptType_SPENDTAPROOT;
+//         default:
+//           return InputScriptType_EXTERNAL;  // unknown script type
+//       }
+//     }
+//   }
+
+// #if !BITCOIN_ONLY
+//   if (coin->cashaddr_prefix &&
+//       cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix,
+//                        address)) {
+//     return InputScriptType_SPENDADDRESS;
+//   }
+// #endif
+
+//   addr_raw_len = base58_decode_check(address, coin->curve->hasher_base58,
+//                                      addr_raw, sizeof(addr_raw));
+
+//   // P2PKH
+//   if (addr_raw_len > address_prefix_bytes_len(coin->address_type) &&
+//       address_check_prefix(addr_raw, coin->address_type)) {
+//     return InputScriptType_SPENDADDRESS;
+//   }
+
+//   // P2SH
+//   if (addr_raw_len > address_prefix_bytes_len(coin->address_type_p2sh) &&
+//       address_check_prefix(addr_raw, coin->address_type_p2sh)) {
+//     return InputScriptType_SPENDP2SHWITNESS;
+//   }
+
+//   return InputScriptType_EXTERNAL;  // unknown script type
+// }
+
+// int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message,
+//                         size_t message_len, const char *address,
+//                         const uint8_t *signature) {
+//   // check if the address is correct
+//   InputScriptType script_type = address_to_script_type(coin, address);
+//   if (script_type == InputScriptType_EXTERNAL) {
+//     return 1;  // invalid address
+//   }
+
+//   if (signature[0] >= 27 && signature[0] <= 34) {
+//     // p2pkh or no script type provided
+//     // use the script type from the address
+//   } else if (signature[0] >= 35 && signature[0] <= 38) {
+//     // segwit-in-p2sh
+//     if (script_type != InputScriptType_SPENDP2SHWITNESS) {
+//       return 2;  // script type mismatch
+//     }
+//   } else if (signature[0] >= 39 && signature[0] <= 42) {
+//     // segwit
+//     if (script_type != InputScriptType_SPENDWITNESS) {
+//       return 2;  // script type mismatch
+//     }
+//   } else {
+//     return 3;  // invalid signature prefix
+//   }
+
+//   uint8_t hash[HASHER_DIGEST_LENGTH] = {0};
+//   cryptoMessageHash(coin, message, message_len, hash);
+
+//   uint8_t recid = (signature[0] - 27) % 4;
+//   bool compressed = signature[0] >= 31;
+
+//   // check if signature verifies the digest and recover the public key
+//   uint8_t pubkey[65] = {0};
+//   if (ecdsa_recover_pub_from_sig(coin->curve->params, pubkey, signature + 1,
+//                                  hash, recid) != 0) {
+//     return 4;  // invalid signature data
+//   }
+
+//   // convert public key to compressed pubkey if necessary
+//   if (compressed) {
+//     pubkey[0] = 0x02 | (pubkey[64] & 1);
+//   }
+
+//   uint8_t addr_raw[MAX_ADDR_RAW_SIZE] = {0};
+//   uint8_t recovered_raw[MAX_ADDR_RAW_SIZE] = {0};
+
+//   if (script_type == InputScriptType_SPENDADDRESS) {
+//     // p2pkh
+//     size_t len = 0;
+// #if !BITCOIN_ONLY
+//     if (coin->cashaddr_prefix) {
+//       if (!cash_addr_decode(addr_raw, &len, coin->cashaddr_prefix, address)) {
+//         return 1;  // invalid address
+//       }
+//     } else
+// #endif
+//     {
+//       len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw,
+//                                 MAX_ADDR_RAW_SIZE);
+//     }
+//     ecdsa_get_address_raw(pubkey, coin->address_type,
+//                           coin->curve->hasher_pubkey, recovered_raw);
+//     if (memcmp(recovered_raw, addr_raw, len) != 0 ||
+//         len != address_prefix_bytes_len(coin->address_type) + 20) {
+//       return 5;  // signature does not match address and message
+//     }
+//   } else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
+//     // segwit-in-p2sh
+//     size_t len = base58_decode_check(address, coin->curve->hasher_base58,
+//                                      addr_raw, MAX_ADDR_RAW_SIZE);
+//     ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh,
+//                                       coin->curve->hasher_pubkey,
+//                                       recovered_raw);
+//     if (memcmp(recovered_raw, addr_raw, len) != 0 ||
+//         len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) {
+//       return 5;  // signature does not match address and message
+//     }
+//   } else if (script_type == InputScriptType_SPENDWITNESS) {
+//     // segwit
+//     int witver = 0;
+//     size_t len = 0;
+//     if (!coin->bech32_prefix ||
+//         !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix,
+//                             address)) {
+//       return 1;  // invalid address
+//     }
+//     ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_pubkey, addr_raw);
+//     if (memcmp(recovered_raw, addr_raw, len) != 0 || witver != 0 || len != 20) {
+//       return 5;  // signature does not match address and message
+//     }
+//   } else {
+//     return 1;  // invalid address
+//   }
+
+//   return 0;
+// }
+
+// const HDNode *cryptoMultisigPubkey(const CoinInfo *coin,
+//                                    const MultisigRedeemScriptType *multisig,
+//                                    uint32_t index) {
+//   const HDNodeType *node_ptr = NULL;
+//   const uint32_t *address_n = NULL;
+//   uint32_t address_n_count = 0;
+//   if (multisig->nodes_count) {  // use multisig->nodes
+//     if (index >= multisig->nodes_count) {
+//       return 0;
+//     }
+//     node_ptr = &(multisig->nodes[index]);
+//     address_n = multisig->address_n;
+//     address_n_count = multisig->address_n_count;
+//   } else if (multisig->pubkeys_count) {  // use multisig->pubkeys
+//     if (index >= multisig->pubkeys_count) {
+//       return 0;
+//     }
+//     node_ptr = &(multisig->pubkeys[index].node);
+//     address_n = multisig->pubkeys[index].address_n;
+//     address_n_count = multisig->pubkeys[index].address_n_count;
+//   } else {
+//     return 0;
+//   }
+//   if (node_ptr->chain_code.size != 32) return 0;
+//   if (node_ptr->public_key.size != 33) return 0;
+//   static HDNode node;
+//   if (!hdnode_from_xpub(node_ptr->depth, node_ptr->child_num,
+//                         node_ptr->chain_code.bytes, node_ptr->public_key.bytes,
+//                         coin->curve_name, &node)) {
+//     return 0;
+//   }
+//   //layoutProgressUpdate(true);
+//   for (uint32_t i = 0; i < address_n_count; i++) {
+//     if (!hdnode_public_ckd(&node, address_n[i])) {
+//       return 0;
+//     }
+//     //layoutProgressUpdate(true);
+//   }
+//   return &node;
+// }
+
+// uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) {
+//   return multisig->nodes_count ? multisig->nodes_count
+//                                : multisig->pubkeys_count;
+// }
+
+// int cryptoMultisigPubkeyIndex(const CoinInfo *coin,
+//                               const MultisigRedeemScriptType *multisig,
+//                               const uint8_t *pubkey) {
+//   for (size_t i = 0; i < cryptoMultisigPubkeyCount(multisig); i++) {
+//     const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i);
+//     if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) {
+//       return i;
+//     }
+//   }
+//   return -1;
+// }
+
+// int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig,
+//                               uint8_t *hash) {
+//   static const HDNodeType *pubnodes[15], *swap;
+//   const uint32_t n = cryptoMultisigPubkeyCount(multisig);
+//   if (n < 1 || n > 15) {
+//     return 0;
+//   }
+//   if (multisig->m < 1 || multisig->m > 15) {
+//     return 0;
+//   }
+//   for (uint32_t i = 0; i < n; i++) {
+//     if (multisig->nodes_count) {  // use multisig->nodes
+//       pubnodes[i] = &(multisig->nodes[i]);
+//     } else if (multisig->pubkeys_count) {  // use multisig->pubkeys
+//       pubnodes[i] = &(multisig->pubkeys[i].node);
+//     } else {
+//       return 0;
+//     }
+//   }
+//   for (uint32_t i = 0; i < n; i++) {
+//     if (pubnodes[i]->public_key.size != 33) return 0;
+//     if (pubnodes[i]->chain_code.size != 32) return 0;
+//   }
+//   // minsort according to pubkey
+//   for (uint32_t i = 0; i < n - 1; i++) {
+//     for (uint32_t j = n - 1; j > i; j--) {
+//       if (memcmp(pubnodes[i]->public_key.bytes, pubnodes[j]->public_key.bytes,
+//                  33) > 0) {
+//         swap = pubnodes[i];
+//         pubnodes[i] = pubnodes[j];
+//         pubnodes[j] = swap;
+//       }
+//     }
+//   }
+//   // hash sorted nodes
+//   SHA256_CTX ctx = {0};
+//   sha256_Init(&ctx);
+//   sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t));
+//   for (uint32_t i = 0; i < n; i++) {
+//     sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth),
+//                   sizeof(uint32_t));
+//     sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->fingerprint),
+//                   sizeof(uint32_t));
+//     sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num),
+//                   sizeof(uint32_t));
+//     sha256_Update(&ctx, pubnodes[i]->chain_code.bytes, 32);
+//     sha256_Update(&ctx, pubnodes[i]->public_key.bytes, 33);
+//   }
+//   sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t));
+//   sha256_Final(&ctx, hash);
+//   //layoutProgressUpdate(true);
+//   return 1;
+// }
+
+// int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) {
+//   SHA256_CTX ctx = {0};
+//   sha256_Init(&ctx);
+//   sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t));
+//   if (identity->has_proto && identity->proto[0]) {
+//     sha256_Update(&ctx, (const uint8_t *)(identity->proto),
+//                   strlen(identity->proto));
+//     sha256_Update(&ctx, (const uint8_t *)"://", 3);
+//   }
+//   if (identity->has_user && identity->user[0]) {
+//     sha256_Update(&ctx, (const uint8_t *)(identity->user),
+//                   strlen(identity->user));
+//     sha256_Update(&ctx, (const uint8_t *)"@", 1);
+//   }
+//   if (identity->has_host && identity->host[0]) {
+//     sha256_Update(&ctx, (const uint8_t *)(identity->host),
+//                   strlen(identity->host));
+//   }
+//   if (identity->has_port && identity->port[0]) {
+//     sha256_Update(&ctx, (const uint8_t *)":", 1);
+//     sha256_Update(&ctx, (const uint8_t *)(identity->port),
+//                   strlen(identity->port));
+//   }
+//   if (identity->has_path && identity->path[0]) {
+//     sha256_Update(&ctx, (const uint8_t *)(identity->path),
+//                   strlen(identity->path));
+//   }
+//   sha256_Final(&ctx, hash);
+//   return 1;
+// }
+
+// static bool check_cointype(const CoinInfo *coin, uint32_t slip44, bool full) {
+// #if BITCOIN_ONLY
+//   (void)full;
+// #else
+//   if (!full) {
+//     // Some wallets such as Electron-Cash (BCH) store coins on Bitcoin paths.
+//     // We can allow spending these coins from Bitcoin paths if the coin has
+//     // implemented strong replay protection via SIGHASH_FORKID. However, we
+//     // cannot allow spending any testnet coins from Bitcoin paths, because
+//     // otherwise an attacker could trick the user into spending BCH on a Bitcoin
+//     // path by signing a seemingly harmless BCH Testnet transaction.
+//     if (slip44 == SLIP44_BITCOIN && coin->has_fork_id &&
+//         coin->coin_type != SLIP44_TESTNET) {
+//       return true;
+//     }
+//   }
+// #endif
+//   return coin->coin_type == slip44;
+// }
+
+// bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
+//                      uint32_t address_n_count, const uint32_t *address_n,
+//                      bool has_multisig, bool full_check) {
+//   // This function checks that the path is a recognized path for the given coin.
+//   // Used by GetAddress to prevent ransom attacks where a user could be coerced
+//   // to use an address with an unenumerable path and used by SignTx to ensure
+//   // that a user cannot be coerced into signing a testnet transaction or a
+//   // Litecoin transaction which in fact spends Bitcoin. If full_check is true,
+//   // then this function also checks that the path fully matches the script type
+//   // and coin type. This is used to determine whether a warning should be shown.
+
+//   if (address_n_count == 0) {
+//     return false;
+//   }
+
+//   bool valid = true;
+//   // m/44' : BIP44 Legacy
+//   // m / purpose' / coin_type' / account' / change / address_index
+//   if (address_n[0] == PATH_HARDENED + 44) {
+//     valid = valid && (address_n_count == 5);
+//     valid = valid && check_cointype(coin, address_n[1], full_check);
+//     valid = valid && (address_n[2] & PATH_HARDENED);
+//     valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
+//     valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
+//     valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
+//     if (full_check) {
+//       valid = valid && (script_type == InputScriptType_SPENDADDRESS);
+//       valid = valid && (!has_multisig);
+//     }
+//     return valid;
+//   }
+
+//   if (address_n[0] == PATH_HARDENED + 45) {
+//     if (address_n_count == 4) {
+//       // m/45' - BIP45 Copay Abandoned Multisig P2SH
+//       // m / purpose' / cosigner_index / change / address_index
+//       // Patterns without a coin_type field must be treated as Bitcoin paths.
+//       valid = valid && check_cointype(coin, SLIP44_BITCOIN, false);
+//       valid = valid && (address_n[1] <= 100);
+//       valid = valid && (address_n[2] <= PATH_MAX_CHANGE);
+//       valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
+//     } else if (address_n_count == 5) {
+//       // Unchained Capital compatibility pattern. Will be removed in the
+//       // future.
+//       // m / 45' / coin_type' / account' / [0-1000000] / address_index
+//       valid = valid && check_cointype(coin, address_n[1], full_check);
+//       valid = valid && (address_n[2] & PATH_HARDENED);
+//       valid =
+//           valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
+//       valid = valid && (address_n[3] <= 1000000);
+//       valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
+//     } else if (address_n_count == 6) {
+//       // Unchained Capital compatibility pattern. Will be removed in the
+//       // future.
+//       // m/45'/coin_type'/account'/[0-1000000]/change/address_index
+//       // m/45'/coin_type/account/[0-1000000]/change/address_index
+//       valid = valid &&
+//               check_cointype(coin, PATH_HARDENED | address_n[1], full_check);
+//       valid = valid && ((address_n[1] & PATH_HARDENED) ==
+//                         (address_n[2] & PATH_HARDENED));
+//       valid =
+//           valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
+//       valid = valid && (address_n[3] <= 1000000);
+//       valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
+//       valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
+//     } else {
+//       return false;
+//     }
+
+//     if (full_check) {
+//       valid = valid && (script_type == InputScriptType_SPENDADDRESS ||
+//                         script_type == InputScriptType_SPENDMULTISIG);
+//       valid = valid && has_multisig;
+//     }
+
+//     return valid;
+//   }
+
+//   if (address_n[0] == PATH_HARDENED + 48) {
+//     valid = valid && (address_n_count == 5 || address_n_count == 6);
+//     valid = valid && check_cointype(coin, address_n[1], full_check);
+//     valid = valid && (address_n[2] & PATH_HARDENED);
+//     valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
+//     if (address_n_count == 5) {
+//       // [OBSOLETE] m/48' Copay Multisig P2SH
+//       // m / purpose' / coin_type' / account' / change / address_index
+//       // NOTE: this pattern is not recognized by trezor-core
+//       valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
+//       valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
+//       if (full_check) {
+//         valid = valid && has_multisig;
+//         valid = valid && (script_type == InputScriptType_SPENDMULTISIG);
+//       }
+//     } else if (address_n_count == 6) {
+//       // BIP-48:
+//       // m / purpose' / coin_type' / account' / type' / change / address_index
+//       valid = valid && (address_n[3] & PATH_HARDENED);
+//       uint32_t type = address_n[3] & PATH_UNHARDEN_MASK;
+//       valid = valid && (type <= 2);
+//       valid = valid && (type == 0 || coin->has_segwit);
+//       valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
+//       valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
+//       if (full_check) {
+//         valid = valid && has_multisig;
+//         switch (type) {
+//           case 0:
+//             valid = valid && (script_type == InputScriptType_SPENDMULTISIG ||
+//                               script_type == InputScriptType_SPENDADDRESS);
+//             break;
+//           case 1:
+//             valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
+//             break;
+//           case 2:
+//             valid = valid && (script_type == InputScriptType_SPENDWITNESS);
+//             break;
+//           default:
+//             return false;
+//         }
+//       }
+//     } else {
+//       return false;
+//     }
+//     return valid;
+//   }
+
+//   // m/49' : BIP49 SegWit
+//   // m / purpose' / coin_type' / account' / change / address_index
+//   if (address_n[0] == PATH_HARDENED + 49) {
+//     valid = valid && coin->has_segwit;
+//     valid = valid && (address_n_count == 5);
+//     valid = valid && check_cointype(coin, address_n[1], full_check);
+//     valid = valid && (address_n[2] & PATH_HARDENED);
+//     valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
+//     valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
+//     valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
+//     if (full_check) {
+//       valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
+//     }
+//     return valid;
+//   }
+
+//   // m/84' : BIP84 Native SegWit
+//   // m / purpose' / coin_type' / account' / change / address_index
+//   if (address_n[0] == PATH_HARDENED + 84) {
+//     valid = valid && coin->has_segwit;
+//     valid = valid && (coin->bech32_prefix != NULL);
+//     valid = valid && (address_n_count == 5);
+//     valid = valid && check_cointype(coin, address_n[1], full_check);
+//     valid = valid && (address_n[2] & PATH_HARDENED);
+//     valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
+//     valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
+//     valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
+//     if (full_check) {
+//       valid = valid && (script_type == InputScriptType_SPENDWITNESS);
+//     }
+//     return valid;
+//   }
+
+//   // m/86' : BIP86 Taproot
+//   // m / purpose' / coin_type' / account' / change / address_index
+//   if (address_n[0] == PATH_HARDENED + 86) {
+//     valid = valid && coin->has_taproot;
+//     valid = valid && (coin->bech32_prefix != NULL);
+//     valid = valid && (address_n_count == 5);
+//     valid = valid && check_cointype(coin, address_n[1], full_check);
+//     valid = valid && (address_n[2] & PATH_HARDENED);
+//     valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
+//     valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
+//     valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
+//     if (full_check) {
+//       // we do not support Multisig with Taproot yet
+//       valid = valid && !has_multisig;
+//       valid = valid && (script_type == InputScriptType_SPENDTAPROOT);
+//     }
+//     return valid;
+//   }
+
+//   // Green Address compatibility pattern. Will be removed in the future.
+//   // m / [1,4] / address_index
+//   if (address_n[0] == 1 || address_n[0] == 4) {
+//     valid = valid && (coin->coin_type == SLIP44_BITCOIN);
+//     valid = valid && (address_n_count == 2);
+//     valid = valid && (address_n[1] <= PATH_MAX_ADDRESS_INDEX);
+//     if (full_check) {
+//       valid = valid && (script_type != InputScriptType_SPENDTAPROOT);
+//     }
+//     return valid;
+//   }
+
+//   // Green Address compatibility pattern. Will be removed in the future.
+//   // m / 3' / [1-100]' / [1,4] / address_index
+//   if (address_n[0] == PATH_HARDENED + 3) {
+//     valid = valid && (coin->coin_type == SLIP44_BITCOIN);
+//     valid = valid && (address_n_count == 4);
+//     valid = valid && (address_n[1] & PATH_HARDENED);
+//     valid = valid && ((address_n[1] & PATH_UNHARDEN_MASK) <= 100);
+//     valid = valid && (address_n[2] == 1 || address_n[2] == 4);
+//     valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
+//     if (full_check) {
+//       valid = valid && (script_type != InputScriptType_SPENDTAPROOT);
+//     }
+//     return valid;
+//   }
+
+//   // Green Address compatibility patterns. Will be removed in the future.
+//   // m / 1195487518
+//   // m / 1195487518 / 6 / address_index
+//   if (address_n[0] == 1195487518) {
+//     valid = valid && (coin->coin_type == SLIP44_BITCOIN);
+//     if (address_n_count == 3) {
+//       valid = valid && (address_n[1] == 6);
+//       valid = valid && (address_n[2] <= PATH_MAX_ADDRESS_INDEX);
+//     } else if (address_n_count != 1) {
+//       return false;
+//     }
+//     if (full_check) {
+//       return false;
+//     }
+//     return valid;
+//   }
+
+//   // Casa compatibility pattern. Will be removed in the future.
+//   // m / 49 / coin_type / account / change / address_index
+//   if (address_n[0] == 49) {
+//     valid = valid && (address_n_count == 5);
+//     valid =
+//         valid && check_cointype(coin, PATH_HARDENED | address_n[1], full_check);
+//     valid = valid && ((address_n[1] & PATH_HARDENED) == 0);
+//     valid = valid && (address_n[2] <= PATH_MAX_ACCOUNT);
+//     valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
+//     valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
+//     if (full_check) {
+//       valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
+//     }
+//     return valid;
+//   }
+
+//   // unknown path
+//   return false;
+// }

+ 87 - 0
coins/crypto.h

@@ -0,0 +1,87 @@
+// /*
+//  * This file is part of the Trezor project, https://trezor.io/
+//  *
+//  * Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
+//  *
+//  * This library is free software: you can redistribute it and/or modify
+//  * it under the terms of the GNU Lesser General Public License as published by
+//  * the Free Software Foundation, either version 3 of the License, or
+//  * (at your option) any later version.
+//  *
+//  * This library is distributed in the hope that it will be useful,
+//  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  * GNU Lesser General Public License for more details.
+//  *
+//  * You should have received a copy of the GNU Lesser General Public License
+//  * along with this library.  If not, see <http://www.gnu.org/licenses/>.
+//  */
+
+// #ifndef __CRYPTO_H__
+// #define __CRYPTO_H__
+
+// #include "../crypto/bip32.h"
+// #include "../crypto/ecdsa.h"
+// #include <pb.h>
+// #include "../crypto/sha2.h"
+// #include <stdbool.h>
+// #include <stdint.h>
+// #include <stdlib.h>
+// #include "coins.h"
+// #include "../crypto/hasher.h"
+// // #include "messages-bitcoin.pb.h"
+// // #include "messages-crypto.pb.h"
+
+// #define BITCOIN_ONLY 1
+
+// #define PATH_HARDENED 0x80000000
+// #define PATH_UNHARDEN_MASK 0x7fffffff
+// #define PATH_MAX_ACCOUNT 100
+// #define PATH_MAX_CHANGE 1
+// #define PATH_MAX_ADDRESS_INDEX 1000000
+// #define PATH_SLIP25_PURPOSE (PATH_HARDENED | 10025)
+
+// #define ser_length_size(len) ((len) < 253 ? 1 : (len) < 0x10000 ? 3 : 5)
+
+// uint32_t ser_length(uint32_t len, uint8_t *out);
+
+// uint32_t ser_length_hash(Hasher *hasher, uint32_t len);
+
+// int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
+//                    uint8_t *signature);
+
+// int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
+//                    uint8_t *signature);
+
+// int signifyMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
+//                        uint8_t *signature);
+
+// int cryptoMessageSign(const CoinInfo *coin, HDNode *node,
+//                       InputScriptType script_type, bool no_script_type,
+//                       const uint8_t *message, size_t message_len,
+//                       uint8_t *signature);
+
+// int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message,
+//                         size_t message_len, const char *address,
+//                         const uint8_t *signature);
+
+// const HDNode *cryptoMultisigPubkey(const CoinInfo *coin,
+//                                    const MultisigRedeemScriptType *multisig,
+//                                    uint32_t index);
+
+// uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig);
+
+// int cryptoMultisigPubkeyIndex(const CoinInfo *coin,
+//                               const MultisigRedeemScriptType *multisig,
+//                               const uint8_t *pubkey);
+
+// int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig,
+//                               uint8_t *hash);
+
+// int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash);
+
+// bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
+//                      uint32_t address_n_count, const uint32_t *address_n,
+//                      bool has_multisig, bool full_check);
+
+// #endif

+ 45 - 0
views/flipbip39_scene_1.c

@@ -97,6 +97,51 @@ static void flipbip39_scene_1_model_init(FlipBip39Scene1Model* const model, cons
         ptr = strtok(NULL, ",");
     }
 
+    // WIP / TODO: Generate a BIP32 root key from the mnemonic
+
+    // //bool root_set = false;
+    // HDNode root;
+    // uint8_t seed[64];
+    // mnemonic_to_seed(mnemonic, "", seed, 0);
+    // hdnode_from_seed(seed, 64, SECP256K1_NAME, &root);
+    // //root_set = true;
+
+    // int arg1 = 1;
+    // // constants for Bitcoin
+    // const uint32_t version_public = 0x0488b21e;
+    // const uint32_t version_private = 0x0488ade4;
+    // const char addr_version = 0x00, wif_version = 0x80;
+    // const size_t buflen = 128;
+    // char buf[buflen + 1];
+    // HDNode node;
+    // uint32_t fingerprint;
+    // // external chain
+    // for (int chain = 0; chain < 2; chain++) {
+    //     //QTableWidget *list = chain == 0 ? ui->listAddress : ui->listChange;
+    //     node = root;
+    //     hdnode_private_ckd(&node, 44 | 0x80000000);
+    //     hdnode_private_ckd(&node, 0 | 0x80000000); // bitcoin
+    //     hdnode_private_ckd(&node, (arg1 - 1) | 0x80000000);
+    //     fingerprint = hdnode_fingerprint(&node);
+    //     hdnode_serialize_private(&node, fingerprint, version_private, buf, buflen); 
+    //     //QString xprv = QString(buf); ui->lineXprv->setText(xprv);
+    //     hdnode_serialize_public(&node, fingerprint, version_public, buf, buflen); 
+    //     //QString xpub = QString(buf); ui->lineXpub->setText(xpub);
+    //     hdnode_private_ckd(&node, chain); // external / internal
+    //     for (int i = 0; i < 10; i++) {
+    //         HDNode node2 = node;
+    //         hdnode_private_ckd(&node2, i);
+    //         hdnode_fill_public_key(&node2);
+    //         ecdsa_get_address(node2.public_key, addr_version, HASHER_SHA2_RIPEMD, HASHER_SHA2D, buf, buflen); 
+    //         //QString address = QString(buf);
+    //         ecdsa_get_wif(node2.private_key, wif_version, HASHER_SHA2D, buf, buflen); 
+    //         //QString wif = QString(buf);
+    //         // list->setItem(i, 0, new QTableWidgetItem(address));
+    //         // list->setItem(i, 1, new QTableWidgetItem(wif));
+    //         // list->setItem(i, 2, new QTableWidgetItem("0.0"));
+    //     }
+    // }
+
     // Clear the mnemonic
     mnemonic_clear();
     bip39_cache_clear();

+ 7 - 3
views/flipbip39_startscreen.c

@@ -3,7 +3,7 @@
 #include <furi_hal.h>
 #include <input/input.h>
 #include <gui/elements.h>
-#include "flipbip39_icons.h"
+#include "FlipBIP_icons.h"
 
 struct FlipBip39Startscreen {
     View* view;
@@ -34,10 +34,14 @@ void flipbip39_startscreen_draw(Canvas* canvas, FlipBip39StartscreenModel* model
     canvas_draw_icon(canvas, 1, 33, &I_Auth_62x31);
 
     canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str(canvas, 74, 11, "Flip-BIP39");
+    //canvas_draw_str(canvas, 69, 11, "Flipper-BIP");
+    //canvas_draw_str(canvas, 57, 11, "Flipper-BIP39");
+    //canvas_draw_str(canvas, 60, 11, "Flipper BIP39");
+    canvas_draw_str(canvas, 72, 11, "BIP39 Tool");
 
     canvas_set_font(canvas, FontSecondary);
-    canvas_draw_str(canvas, 30, 23, "Crypto tools for Flipper");
+    //canvas_draw_str(canvas, 30, 23, "Crypto tools for Flipper");
+    canvas_draw_str(canvas, 23, 22, "Crypto toolkit for Flipper");
     
     elements_button_right(canvas, "Start"); 
 }