Airgapped hardware wallet based on STM32F469-Discovery board using SD card to pass transaction data

Dependencies:   mbed QSPI_DISCO_F469NI BSP_DISCO_F469NI

Committer:
stepansnigirev
Date:
Sat Jul 20 15:16:38 2019 +0000
Revision:
0:f43431023689
Child:
1:b88ef7630eb3
working demo

Who changed what in which revision?

UserRevisionLine numberNew contents of line
stepansnigirev 0:f43431023689 1 #include "mbed.h"
stepansnigirev 0:f43431023689 2 #include "helpers.h"
stepansnigirev 0:f43431023689 3
stepansnigirev 0:f43431023689 4 // bitcoin lib
stepansnigirev 0:f43431023689 5 #include "Bitcoin.h"
stepansnigirev 0:f43431023689 6 #include "PSBT.h"
stepansnigirev 0:f43431023689 7
stepansnigirev 0:f43431023689 8 /*********** forward declarations **************/
stepansnigirev 0:f43431023689 9
stepansnigirev 0:f43431023689 10 // generates a new mnemonic
stepansnigirev 0:f43431023689 11 string generateNewMnemonic();
stepansnigirev 0:f43431023689 12
stepansnigirev 0:f43431023689 13 // generates hd keys from the mnemonic
stepansnigirev 0:f43431023689 14 void initKeys(const string mnemonic, const string password = "");
stepansnigirev 0:f43431023689 15
stepansnigirev 0:f43431023689 16 /****************** GUI classes ****************/
stepansnigirev 0:f43431023689 17
stepansnigirev 0:f43431023689 18 Label titleLbl;
stepansnigirev 0:f43431023689 19 Label dataLbl;
stepansnigirev 0:f43431023689 20 QR qr;
stepansnigirev 0:f43431023689 21
stepansnigirev 0:f43431023689 22 Button btn;
stepansnigirev 0:f43431023689 23 Button printBtn;
stepansnigirev 0:f43431023689 24 Label lbl;
stepansnigirev 0:f43431023689 25
stepansnigirev 0:f43431023689 26 /***************** GUI functions ***************/
stepansnigirev 0:f43431023689 27
stepansnigirev 0:f43431023689 28 // if mnemonic is not present we can generate or recover it
stepansnigirev 0:f43431023689 29 void showInitScreen();
stepansnigirev 0:f43431023689 30 // if mnemonic is there we go directly to the main menu
stepansnigirev 0:f43431023689 31 void showMenu();
stepansnigirev 0:f43431023689 32 // handy function to display information to the user
stepansnigirev 0:f43431023689 33 // with a title, a message and OK button that goes to the menu
stepansnigirev 0:f43431023689 34 void showMessage(const string title, const string message);
stepansnigirev 0:f43431023689 35 static lv_res_t toMenuCallback(lv_obj_t * btn);
stepansnigirev 0:f43431023689 36 static lv_res_t showAddressesCallback(lv_obj_t * btn);
stepansnigirev 0:f43431023689 37 static lv_res_t saveXpubCallback(lv_obj_t * btn);
stepansnigirev 0:f43431023689 38 static lv_res_t signPSBTCallback(lv_obj_t * btn);
stepansnigirev 0:f43431023689 39 static lv_res_t showMnemonicCallback(lv_obj_t * btn);
stepansnigirev 0:f43431023689 40 static lv_res_t wipeCallback(lv_obj_t * btn);
stepansnigirev 0:f43431023689 41 static lv_res_t newMnemonicCallback(lv_obj_t * btn);
stepansnigirev 0:f43431023689 42 static lv_res_t enterMnemonicCallback(lv_obj_t * btn);
stepansnigirev 0:f43431023689 43 void showAddress(unsigned int child_index, bool change);
stepansnigirev 0:f43431023689 44
stepansnigirev 0:f43431023689 45 /***************** bitcoin keys ***************/
stepansnigirev 0:f43431023689 46
stepansnigirev 0:f43431023689 47 HDPrivateKey root; // root private key
stepansnigirev 0:f43431023689 48 HDPrivateKey account; // account master private key
stepansnigirev 0:f43431023689 49 HDPublicKey xpub; // account master public key
stepansnigirev 0:f43431023689 50 bool change = false; // internal or external address
stepansnigirev 0:f43431023689 51 unsigned int child_index = 0; // current child index
stepansnigirev 0:f43431023689 52
stepansnigirev 0:f43431023689 53 PSBT psbt; // psbt transaction we will be signing
stepansnigirev 0:f43431023689 54
stepansnigirev 0:f43431023689 55 /******************* Main part *****************/
stepansnigirev 0:f43431023689 56
stepansnigirev 0:f43431023689 57 int main(){
stepansnigirev 0:f43431023689 58 init();
stepansnigirev 0:f43431023689 59
stepansnigirev 0:f43431023689 60 string mnemonic = loadMnemonic();
stepansnigirev 0:f43431023689 61 if(mnemonic.length() == 0){
stepansnigirev 0:f43431023689 62 showInitScreen();
stepansnigirev 0:f43431023689 63 }else{
stepansnigirev 0:f43431023689 64 initKeys(mnemonic);
stepansnigirev 0:f43431023689 65 showMenu();
stepansnigirev 0:f43431023689 66 }
stepansnigirev 0:f43431023689 67
stepansnigirev 0:f43431023689 68 while(1){
stepansnigirev 0:f43431023689 69 gui.update();
stepansnigirev 0:f43431023689 70 }
stepansnigirev 0:f43431023689 71 }
stepansnigirev 0:f43431023689 72
stepansnigirev 0:f43431023689 73 /****************** GUI stuff *****************/
stepansnigirev 0:f43431023689 74 void showInitScreen(){
stepansnigirev 0:f43431023689 75 gui.clear();
stepansnigirev 0:f43431023689 76 titleLbl = Label("Let's set it up!");
stepansnigirev 0:f43431023689 77 titleLbl.size(gui.width(), 20);
stepansnigirev 0:f43431023689 78 titleLbl.position(0, 40);
stepansnigirev 0:f43431023689 79 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 0:f43431023689 80
stepansnigirev 0:f43431023689 81 Button btn(newMnemonicCallback, "Generate new mnemonic");
stepansnigirev 0:f43431023689 82 btn.size(gui.width()-100, 80);
stepansnigirev 0:f43431023689 83 btn.position(0, 200);
stepansnigirev 0:f43431023689 84 btn.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 85
stepansnigirev 0:f43431023689 86 Button btn2(enterMnemonicCallback, "Enter existing mnemonic");
stepansnigirev 0:f43431023689 87 btn2.size(gui.width()-100, 80);
stepansnigirev 0:f43431023689 88 btn2.position(0, 300);
stepansnigirev 0:f43431023689 89 btn2.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 90 }
stepansnigirev 0:f43431023689 91
stepansnigirev 0:f43431023689 92 void showMenu(){
stepansnigirev 0:f43431023689 93 gui.clear();
stepansnigirev 0:f43431023689 94 titleLbl = Label("What do you want to do?");
stepansnigirev 0:f43431023689 95 titleLbl.size(gui.width(), 20);
stepansnigirev 0:f43431023689 96 titleLbl.position(0, 40);
stepansnigirev 0:f43431023689 97 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 0:f43431023689 98
stepansnigirev 0:f43431023689 99 Button btn(showAddressesCallback, "Show addresses");
stepansnigirev 0:f43431023689 100 btn.size(gui.width()-100, 80);
stepansnigirev 0:f43431023689 101 btn.position(0, 100);
stepansnigirev 0:f43431023689 102 btn.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 103
stepansnigirev 0:f43431023689 104 Button btn2(saveXpubCallback, "Export xpub");
stepansnigirev 0:f43431023689 105 btn2.size(gui.width()-100, 80);
stepansnigirev 0:f43431023689 106 btn2.position(0, 300);
stepansnigirev 0:f43431023689 107 btn2.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 108
stepansnigirev 0:f43431023689 109 Button btn3(signPSBTCallback, "Sign PSBT transaction");
stepansnigirev 0:f43431023689 110 btn3.size(gui.width()-100, 80);
stepansnigirev 0:f43431023689 111 btn3.position(0, 400);
stepansnigirev 0:f43431023689 112 btn3.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 113
stepansnigirev 0:f43431023689 114 Button btn4(wipeCallback, "Wipe device");
stepansnigirev 0:f43431023689 115 btn4.size(gui.width()-100, 80);
stepansnigirev 0:f43431023689 116 btn4.position(0, 600);
stepansnigirev 0:f43431023689 117 btn4.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 118
stepansnigirev 0:f43431023689 119 Button btn5(showMnemonicCallback, "Show mnemonic");
stepansnigirev 0:f43431023689 120 btn5.size(gui.width()-100, 80);
stepansnigirev 0:f43431023689 121 btn5.position(0, 700);
stepansnigirev 0:f43431023689 122 btn5.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 123 }
stepansnigirev 0:f43431023689 124
stepansnigirev 0:f43431023689 125 void showMessage(const string title, const string message){
stepansnigirev 0:f43431023689 126 gui.clear();
stepansnigirev 0:f43431023689 127 titleLbl = Label(title);
stepansnigirev 0:f43431023689 128 titleLbl.size(gui.width(), 20);
stepansnigirev 0:f43431023689 129 titleLbl.position(0, 40);
stepansnigirev 0:f43431023689 130 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 0:f43431023689 131
stepansnigirev 0:f43431023689 132 dataLbl = Label(message);
stepansnigirev 0:f43431023689 133 dataLbl.size(gui.width()-100, 100);
stepansnigirev 0:f43431023689 134 dataLbl.position(50, 300);
stepansnigirev 0:f43431023689 135 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 0:f43431023689 136
stepansnigirev 0:f43431023689 137 Button btn(toMenuCallback, "OK");
stepansnigirev 0:f43431023689 138 btn.size(gui.width()-100, 80);
stepansnigirev 0:f43431023689 139 btn.position(0, gui.height()-100);
stepansnigirev 0:f43431023689 140 btn.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 141 }
stepansnigirev 0:f43431023689 142
stepansnigirev 0:f43431023689 143 static lv_res_t nextCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 144 child_index++;
stepansnigirev 0:f43431023689 145 showAddress(child_index, change);
stepansnigirev 0:f43431023689 146 return LV_RES_OK;
stepansnigirev 0:f43431023689 147 }
stepansnigirev 0:f43431023689 148 static lv_res_t prevCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 149 if(child_index > 0){
stepansnigirev 0:f43431023689 150 child_index--;
stepansnigirev 0:f43431023689 151 showAddress(child_index, change);
stepansnigirev 0:f43431023689 152 }
stepansnigirev 0:f43431023689 153 return LV_RES_OK;
stepansnigirev 0:f43431023689 154 }
stepansnigirev 0:f43431023689 155 static lv_res_t changeCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 156 change = !change;
stepansnigirev 0:f43431023689 157 showAddress(child_index, change);
stepansnigirev 0:f43431023689 158 return LV_RES_OK;
stepansnigirev 0:f43431023689 159 }
stepansnigirev 0:f43431023689 160 static lv_res_t xpubCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 161 titleLbl.text("Your master public key");
stepansnigirev 0:f43431023689 162 qr.text(xpub.toString());
stepansnigirev 0:f43431023689 163 dataLbl.text(xpub.toString());
stepansnigirev 0:f43431023689 164 qr.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 165 dataLbl.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 166 return LV_RES_OK;
stepansnigirev 0:f43431023689 167 }
stepansnigirev 0:f43431023689 168
stepansnigirev 0:f43431023689 169 void showAddress(unsigned int child_index, bool change){
stepansnigirev 0:f43431023689 170 stringstream title;
stepansnigirev 0:f43431023689 171 title << "Your ";
stepansnigirev 0:f43431023689 172 if(change){
stepansnigirev 0:f43431023689 173 title << "change ";
stepansnigirev 0:f43431023689 174 }else{
stepansnigirev 0:f43431023689 175 title << "receiving ";
stepansnigirev 0:f43431023689 176 }
stepansnigirev 0:f43431023689 177 title << "address #" << child_index << ":";
stepansnigirev 0:f43431023689 178 titleLbl.text(title.str());
stepansnigirev 0:f43431023689 179 string address = xpub.child(change).child(child_index).address();
stepansnigirev 0:f43431023689 180 dataLbl.text(address);
stepansnigirev 0:f43431023689 181 dataLbl.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 182 qr.text(string("bitcoin:") + address);
stepansnigirev 0:f43431023689 183 qr.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 184 }
stepansnigirev 0:f43431023689 185
stepansnigirev 0:f43431023689 186 void showAddressScreen(){
stepansnigirev 0:f43431023689 187 gui.clear();
stepansnigirev 0:f43431023689 188 titleLbl = Label("Your address");
stepansnigirev 0:f43431023689 189 titleLbl.size(gui.width(), 20);
stepansnigirev 0:f43431023689 190 titleLbl.position(0, 40);
stepansnigirev 0:f43431023689 191 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 0:f43431023689 192
stepansnigirev 0:f43431023689 193 dataLbl = Label(" ");
stepansnigirev 0:f43431023689 194 dataLbl.size(gui.width()-100, 100); // full width
stepansnigirev 0:f43431023689 195 dataLbl.position(50, gui.height()-300);
stepansnigirev 0:f43431023689 196 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 0:f43431023689 197
stepansnigirev 0:f43431023689 198 qr = QR(" ");
stepansnigirev 0:f43431023689 199 qr.size(gui.width()-100);
stepansnigirev 0:f43431023689 200 qr.position(0, 100);
stepansnigirev 0:f43431023689 201 qr.align(ALIGN_CENTER);
stepansnigirev 0:f43431023689 202
stepansnigirev 0:f43431023689 203 Button btn(nextCallback, "Next address");
stepansnigirev 0:f43431023689 204 btn.size(gui.width()/3-20, 80);
stepansnigirev 0:f43431023689 205 btn.position(gui.width()*2/3 + 10, gui.height()-100);
stepansnigirev 0:f43431023689 206
stepansnigirev 0:f43431023689 207 Button btn2(prevCallback, "Previous address");
stepansnigirev 0:f43431023689 208 btn2.size(gui.width()/3-20, 80);
stepansnigirev 0:f43431023689 209 btn2.position(10, gui.height()-100);
stepansnigirev 0:f43431023689 210
stepansnigirev 0:f43431023689 211 Button btn3(changeCallback, "Toggle\nchange");
stepansnigirev 0:f43431023689 212 btn3.size(gui.width()/3-20, 80);
stepansnigirev 0:f43431023689 213 btn3.position(gui.width()/3 + 10, gui.height()-100);
stepansnigirev 0:f43431023689 214
stepansnigirev 0:f43431023689 215 Button btn4(xpubCallback, "Show xpub");
stepansnigirev 0:f43431023689 216 btn4.size(gui.width()/2-20, 80);
stepansnigirev 0:f43431023689 217 btn4.position(gui.width()/2+10, gui.height()-200);
stepansnigirev 0:f43431023689 218
stepansnigirev 0:f43431023689 219 Button btn5(toMenuCallback, "Menu");
stepansnigirev 0:f43431023689 220 btn5.size(gui.width()/2-20, 80);
stepansnigirev 0:f43431023689 221 btn5.position(10, gui.height()-200);
stepansnigirev 0:f43431023689 222 }
stepansnigirev 0:f43431023689 223
stepansnigirev 0:f43431023689 224 static lv_res_t toMenuCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 225 showMenu();
stepansnigirev 0:f43431023689 226 return LV_RES_OK;
stepansnigirev 0:f43431023689 227 }
stepansnigirev 0:f43431023689 228
stepansnigirev 0:f43431023689 229 static lv_res_t showAddressesCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 230 showAddressScreen();
stepansnigirev 0:f43431023689 231 showAddress(child_index, change);
stepansnigirev 0:f43431023689 232 return LV_RES_OK;
stepansnigirev 0:f43431023689 233 }
stepansnigirev 0:f43431023689 234 static lv_res_t saveXpubCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 235 // TODO:
stepansnigirev 0:f43431023689 236 // - check if SD card present
stepansnigirev 0:f43431023689 237 // - save xpub to the "xpub.txt"
stepansnigirev 0:f43431023689 238 // - check if write was sucessful
stepansnigirev 0:f43431023689 239 // - show success / fail message
stepansnigirev 0:f43431023689 240 if(!SD.detected()){
stepansnigirev 0:f43431023689 241 showMessage("Error", "SD card is not present");
stepansnigirev 0:f43431023689 242 return LV_RES_OK;
stepansnigirev 0:f43431023689 243 }
stepansnigirev 0:f43431023689 244 int res = SD.save("xpub.txt", xpub.toString());
stepansnigirev 0:f43431023689 245 if(res != SD_SUCCESS){
stepansnigirev 0:f43431023689 246 showMessage("Error", "Something wrong with SD card");
stepansnigirev 0:f43431023689 247 return LV_RES_OK;
stepansnigirev 0:f43431023689 248 }
stepansnigirev 0:f43431023689 249 showMessage("Success","Master public key is saved to the SD card");
stepansnigirev 0:f43431023689 250 return LV_RES_OK;
stepansnigirev 0:f43431023689 251 }
stepansnigirev 0:f43431023689 252 static lv_res_t signConfirmCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 253 if(!SD.detected()){
stepansnigirev 0:f43431023689 254 showMessage("Error", "SD card is not present");
stepansnigirev 0:f43431023689 255 return LV_RES_OK;
stepansnigirev 0:f43431023689 256 }
stepansnigirev 0:f43431023689 257 psbt.sign(account);
stepansnigirev 0:f43431023689 258
stepansnigirev 0:f43431023689 259 uint8_t * raw = (uint8_t *)calloc(psbt.length(), sizeof(uint8_t));
stepansnigirev 0:f43431023689 260 size_t len = psbt.serialize(raw, psbt.length());
stepansnigirev 0:f43431023689 261 psbt = PSBT();
stepansnigirev 0:f43431023689 262 // cout << len << endl;
stepansnigirev 0:f43431023689 263 char * b64 = (char *)calloc(2*len+1, sizeof(char));
stepansnigirev 0:f43431023689 264 len = toBase64(raw, len, b64, 2*len+1);
stepansnigirev 0:f43431023689 265 free(raw);
stepansnigirev 0:f43431023689 266
stepansnigirev 0:f43431023689 267 int res = SD.save("signed.psbt", b64);
stepansnigirev 0:f43431023689 268 free(b64);
stepansnigirev 0:f43431023689 269 if(res != SD_SUCCESS){
stepansnigirev 0:f43431023689 270 showMessage("Error", "Something wrong with SD card");
stepansnigirev 0:f43431023689 271 return LV_RES_OK;
stepansnigirev 0:f43431023689 272 }
stepansnigirev 0:f43431023689 273 showMessage("Success", "Signed transaction saved to the SD card");
stepansnigirev 0:f43431023689 274 return LV_RES_OK;
stepansnigirev 0:f43431023689 275 }
stepansnigirev 0:f43431023689 276 void showSignRequest(){
stepansnigirev 0:f43431023689 277 stringstream ss;
stepansnigirev 0:f43431023689 278 ss << "Sending:\n\n";
stepansnigirev 0:f43431023689 279 for(unsigned int i=0; i<psbt.tx.outputsNumber; i++){
stepansnigirev 0:f43431023689 280 // TODO: better to put it into PSBT method like check_output or something
stepansnigirev 0:f43431023689 281 bool mine = false;
stepansnigirev 0:f43431023689 282 if(psbt.txOutsMeta[i].derivationsLen > 0){
stepansnigirev 0:f43431023689 283 for(unsigned int j=0; j<psbt.txOutsMeta[i].derivationsLen; j++){
stepansnigirev 0:f43431023689 284 HDPrivateKey prv = account.derive(psbt.txOutsMeta[i].derivations[j].derivation, psbt.txOutsMeta[i].derivations[j].derivationLen);
stepansnigirev 0:f43431023689 285 PublicKey pub = prv.publicKey();
stepansnigirev 0:f43431023689 286 // TODO: fix public key comparison
stepansnigirev 0:f43431023689 287 if(pub.toString() == psbt.txOutsMeta[i].derivations[j].pubkey.toString()){
stepansnigirev 0:f43431023689 288 mine = true;
stepansnigirev 0:f43431023689 289 }
stepansnigirev 0:f43431023689 290 }
stepansnigirev 0:f43431023689 291 }
stepansnigirev 0:f43431023689 292 ss << psbt.tx.txOuts[i].address(&Testnet);
stepansnigirev 0:f43431023689 293 if(mine){
stepansnigirev 0:f43431023689 294 ss << " (change)";
stepansnigirev 0:f43431023689 295 }
stepansnigirev 0:f43431023689 296 ss << ": " << (float(psbt.tx.txOuts[i].amount)/1e5) << " mBTC\n\n";
stepansnigirev 0:f43431023689 297 }
stepansnigirev 0:f43431023689 298 ss << "Fee: " << (float(psbt.fee())/1e5) << " mBTC";
stepansnigirev 0:f43431023689 299
stepansnigirev 0:f43431023689 300 gui.clear();
stepansnigirev 0:f43431023689 301 titleLbl = Label("Sign transaction?");
stepansnigirev 0:f43431023689 302 titleLbl.size(gui.width(), 20);
stepansnigirev 0:f43431023689 303 titleLbl.position(0, 40);
stepansnigirev 0:f43431023689 304 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 0:f43431023689 305
stepansnigirev 0:f43431023689 306 dataLbl = Label(ss.str());
stepansnigirev 0:f43431023689 307 dataLbl.size(gui.width()-100, 100);
stepansnigirev 0:f43431023689 308 dataLbl.position(50, 300);
stepansnigirev 0:f43431023689 309 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 0:f43431023689 310
stepansnigirev 0:f43431023689 311 Button btn(toMenuCallback, "Cancel");
stepansnigirev 0:f43431023689 312 btn.size(gui.width()/2-45, 80);
stepansnigirev 0:f43431023689 313 btn.position(30, gui.height()-100);
stepansnigirev 0:f43431023689 314
stepansnigirev 0:f43431023689 315 Button btn2(signConfirmCallback, "Confirm");
stepansnigirev 0:f43431023689 316 btn2.size(gui.width()/2-45, 80);
stepansnigirev 0:f43431023689 317 btn2.position(gui.width()/2+30, gui.height()-100);
stepansnigirev 0:f43431023689 318 }
stepansnigirev 0:f43431023689 319 static lv_res_t signPSBTCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 320 if(!SD.detected()){
stepansnigirev 0:f43431023689 321 showMessage("Error", "SD card is not present");
stepansnigirev 0:f43431023689 322 return LV_RES_OK;
stepansnigirev 0:f43431023689 323 }
stepansnigirev 0:f43431023689 324 string s = SD.read("unsigned.psbt");
stepansnigirev 0:f43431023689 325 if(s.length() == 0){
stepansnigirev 0:f43431023689 326 showMessage("Fail", "Can't read unsigned.psbt file");
stepansnigirev 0:f43431023689 327 return LV_RES_OK;
stepansnigirev 0:f43431023689 328 }
stepansnigirev 0:f43431023689 329 uint8_t raw[1000];
stepansnigirev 0:f43431023689 330 unsigned int len = fromBase64(s.c_str(), s.length(), raw, sizeof(raw));
stepansnigirev 0:f43431023689 331 if(len == 0){
stepansnigirev 0:f43431023689 332 showMessage("Fail", "Can't convert from base64");
stepansnigirev 0:f43431023689 333 return LV_RES_OK;
stepansnigirev 0:f43431023689 334 }
stepansnigirev 0:f43431023689 335 psbt.reset();
stepansnigirev 0:f43431023689 336 len = psbt.parse(raw, len);
stepansnigirev 0:f43431023689 337 if(len == 0){
stepansnigirev 0:f43431023689 338 showMessage("Fail", "Can't parse PSBT");
stepansnigirev 0:f43431023689 339 return LV_RES_OK;
stepansnigirev 0:f43431023689 340 }
stepansnigirev 0:f43431023689 341 showSignRequest();
stepansnigirev 0:f43431023689 342 return LV_RES_OK;
stepansnigirev 0:f43431023689 343 }
stepansnigirev 0:f43431023689 344 static lv_res_t wipeCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 345 wipe();
stepansnigirev 0:f43431023689 346 return LV_RES_OK;
stepansnigirev 0:f43431023689 347 }
stepansnigirev 0:f43431023689 348
stepansnigirev 0:f43431023689 349 /*************** mnemonic stuff ***************/
stepansnigirev 0:f43431023689 350
stepansnigirev 0:f43431023689 351 static lv_res_t newMnemonicCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 352 // TODO:
stepansnigirev 0:f43431023689 353 // - generate random buffer (16 or 32 bytes)
stepansnigirev 0:f43431023689 354 // - create a new mnemonic from it
stepansnigirev 0:f43431023689 355 // - save this mnemonic
stepansnigirev 0:f43431023689 356 // - display it to the user
stepansnigirev 0:f43431023689 357 uint8_t randomBuffer[16];
stepansnigirev 0:f43431023689 358 getRandomBuffer(randomBuffer, sizeof(randomBuffer));
stepansnigirev 0:f43431023689 359 string mnemonic = generateMnemonic(randomBuffer, sizeof(randomBuffer));
stepansnigirev 0:f43431023689 360 saveMnemonic(mnemonic);
stepansnigirev 0:f43431023689 361 showMessage("Write down your recovery phrase:", mnemonic);
stepansnigirev 0:f43431023689 362 initKeys(mnemonic);
stepansnigirev 0:f43431023689 363 return LV_RES_OK;
stepansnigirev 0:f43431023689 364 }
stepansnigirev 0:f43431023689 365
stepansnigirev 0:f43431023689 366 static lv_res_t showMnemonicCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 367 string mnemonic = loadMnemonic();
stepansnigirev 0:f43431023689 368 showMessage("Here is your recovery phrase:", mnemonic);
stepansnigirev 0:f43431023689 369 return LV_RES_OK;
stepansnigirev 0:f43431023689 370 }
stepansnigirev 0:f43431023689 371
stepansnigirev 0:f43431023689 372 static lv_res_t enterMnemonicCallback(lv_obj_t * btn){
stepansnigirev 0:f43431023689 373 return LV_RES_OK;
stepansnigirev 0:f43431023689 374 }
stepansnigirev 0:f43431023689 375
stepansnigirev 0:f43431023689 376 void initKeys(const string mnemonic, const string password){
stepansnigirev 0:f43431023689 377 // TODO:
stepansnigirev 0:f43431023689 378 // - derive root key from the mnemonic and empty password
stepansnigirev 0:f43431023689 379 // - derive account key using m/84'/1'/0'/ derivation path
stepansnigirev 0:f43431023689 380 // - get account master public key
stepansnigirev 0:f43431023689 381 root.fromMnemonic(mnemonic, password);
stepansnigirev 0:f43431023689 382 account = root.derive("m/84'/1'/0'/");
stepansnigirev 0:f43431023689 383 xpub = account.xpub();
stepansnigirev 0:f43431023689 384 }